Rewrite layout of EditEntryActivity to not use TableLayout

This prevents excessive overdraw and fixes the UI tests
This commit is contained in:
Alexander Bakker 2021-01-24 12:53:29 +01:00
parent 44ff321f8f
commit 68436fba9c
8 changed files with 130 additions and 135 deletions

View file

@ -2,9 +2,9 @@ package com.beemdevelopment.aegis;
import androidx.annotation.IdRes;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.espresso.AmbiguousViewMatcherException;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.contrib.RecyclerViewActions;
import androidx.test.espresso.matcher.RootMatchers;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
@ -26,7 +26,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.openContextualActionModeOverflowMenu;
import static androidx.test.espresso.action.ViewActions.clearText;
@ -42,7 +41,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.Matchers.anything;
@RunWith(AndroidJUnit4.class)
@LargeTest
@ -79,7 +77,8 @@ public class OverallTest extends AegisTest {
List<VaultEntry> realEntries = new ArrayList<>(vault.getEntries());
for (int i = 0; i < realEntries.size(); i++) {
assertTrue(realEntries.get(i).equivalates(entries.get(i)));
String message = String.format("%s != %s", realEntries.get(i).toJson().toString(), entries.get(i).toJson().toString());
assertTrue(message, realEntries.get(i).equivalates(entries.get(i)));
}
for (int i = 0; i < 10; i++) {
@ -93,7 +92,7 @@ public class OverallTest extends AegisTest {
onView(withId(R.id.action_edit)).perform(click());
onView(withId(R.id.text_name)).perform(clearText(), typeText("Bob"), closeSoftKeyboard());
onView(withId(R.id.dropdown_group)).perform(click());
onData(anything()).atPosition(1).perform(click());
onView(withText(R.string.new_group)).inRoot(RootMatchers.isPlatformPopup()).perform(click());
onView(withId(R.id.text_input)).perform(typeText(_groupName), closeSoftKeyboard());
onView(withId(android.R.id.button1)).perform(click());
onView(isRoot()).perform(pressBack());
@ -105,9 +104,9 @@ public class OverallTest extends AegisTest {
changeSort(R.string.sort_alphabetically_reverse);
changeSort(R.string.sort_custom);
changeFilter(_groupName);
/*changeFilter(_groupName);
changeFilter(R.string.filter_ungrouped);
changeFilter(R.string.all);
changeFilter(R.string.all);*/
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(1, longClick()));
onView(withId(R.id.rvKeyProfiles)).perform(RecyclerViewActions.actionOnItemAtPosition(2, click()));
@ -128,13 +127,13 @@ public class OverallTest extends AegisTest {
openContextualActionModeOverflowMenu();
onView(withText(R.string.action_settings)).perform(click());
onView(withId(androidx.preference.R.id.recycler_view)).perform(RecyclerViewActions.actionOnItem(hasDescendant(withText(R.string.pref_section_security_title)), click()));
onView(withId(androidx.preference.R.id.recycler_view)).perform(RecyclerViewActions.actionOnItem(hasDescendant(withText(R.string.pref_encryption_title)), click()));
onView(withId(androidx.preference.R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(1, click()));
onView(withId(android.R.id.button1)).perform(click());
assertFalse(vault.isEncryptionEnabled());
assertNull(vault.getCredentials());
onView(withId(androidx.preference.R.id.recycler_view)).perform(RecyclerViewActions.actionOnItem(hasDescendant(withText(R.string.pref_encryption_title)), click()));
onView(withId(androidx.preference.R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(1, click()));
onView(withId(R.id.text_password)).perform(typeText(VAULT_PASSWORD), closeSoftKeyboard());
onView(withId(R.id.text_password_confirm)).perform(typeText(VAULT_PASSWORD), closeSoftKeyboard());
onView(withId(android.R.id.button1)).perform(click());
@ -166,18 +165,20 @@ public class OverallTest extends AegisTest {
onView(withId(R.id.text_issuer)).perform(typeText(entry.getIssuer()), closeSoftKeyboard());
if (entry.getInfo().getClass() != TotpInfo.class) {
int i = entry.getInfo() instanceof HotpInfo ? 1 : 2;
try {
onView(withId(R.id.dropdown_type)).perform(click());
onData(anything()).atPosition(i).perform(click());
} catch (AmbiguousViewMatcherException e) {
// for some reason, clicking twice is sometimes necessary, otherwise the test fails on the next line
onView(withId(R.id.dropdown_type)).perform(click());
onData(anything()).atPosition(i).perform(click());
}
String otpType;
if (entry.getInfo() instanceof HotpInfo) {
onView(withId(R.id.text_period_counter)).perform(typeText("0"), closeSoftKeyboard());
otpType = "HOTP";
} else if (entry.getInfo() instanceof SteamInfo) {
otpType = "Steam";
} else if (entry.getInfo() instanceof TotpInfo) {
otpType = "TOTP";
} else {
throw new RuntimeException(String.format("Unexpected entry type: %s", entry.getInfo().getClass().getSimpleName()));
}
onView(withId(R.id.dropdown_type)).perform(click());
onView(withText(otpType)).inRoot(RootMatchers.isPlatformPopup()).perform(click());
if (entry.getInfo() instanceof SteamInfo) {
onView(withId(R.id.text_digits)).perform(clearText(), typeText("5"), closeSoftKeyboard());
}

View file

@ -39,7 +39,7 @@ public class HotpInfo extends OtpInfo {
}
@Override
public String getType() {
public String getTypeId() {
return ID;
}

View file

@ -26,7 +26,11 @@ public abstract class OtpInfo implements Serializable {
public abstract String getOtp();
public abstract String getType();
public abstract String getTypeId();
public String getType() {
return getType().toUpperCase();
}
public JSONObject toJson() {
JSONObject obj = new JSONObject();
@ -127,7 +131,7 @@ public abstract class OtpInfo implements Serializable {
}
OtpInfo info = (OtpInfo) o;
return getType().equals(info.getType())
return getTypeId().equals(info.getTypeId())
&& Arrays.equals(getSecret(), info.getSecret())
&& getAlgorithm(false).equals(info.getAlgorithm(false))
&& getDigits() == info.getDigits();

View file

@ -28,7 +28,13 @@ public class SteamInfo extends TotpInfo {
}
@Override
public String getType() {
public String getTypeId() {
return ID;
}
@Override
public String getType() {
String id = getTypeId();
return id.substring(0, 1).toUpperCase() + id.substring(1);
}
}

View file

@ -44,7 +44,7 @@ public class TotpInfo extends OtpInfo {
}
@Override
public String getType() {
public String getTypeId() {
return ID;
}

View file

@ -172,7 +172,7 @@ public class EditEntryActivity extends AegisActivity {
_textSecret.setText(secretString);
}
_dropdownType.setText(_origEntry.getInfo().getType().toUpperCase(), false);
_dropdownType.setText(_origEntry.getInfo().getTypeId().toUpperCase(), false);
_dropdownAlgo.setText(_origEntry.getInfo().getAlgorithm(false), false);
String group = _origEntry.getGroup();

View file

@ -53,7 +53,7 @@ public class VaultEntry extends UUIDMap.Value {
JSONObject obj = new JSONObject();
try {
obj.put("type", _info.getType());
obj.put("type", _info.getTypeId());
obj.put("uuid", getUUID().toString());
obj.put("name", _name);
obj.put("issuer", _issuer);

View file

@ -68,28 +68,24 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider" />
<TableLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:stretchColumns="1"
android:layout_marginEnd="15dp">
<TableRow
android:layout_marginTop="10dp"
android:layout_marginBottom="5dp">
android:layout_margin="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_column="0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_person_black_24dp"
app:tint="?attr/iconColorPrimary"
android:layout_marginStart="15dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="15dp"
android:layout_gravity="center_vertical"/>
<com.google.android.material.textfield.TextInputLayout
android:layout_column="1"
android:hint="@string/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
@ -100,17 +96,13 @@
android:layout_height="wrap_content"
android:inputType="text"/>
</com.google.android.material.textfield.TextInputLayout>
</TableRow>
<TableRow
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp">
<LinearLayout android:layout_column="1"
android:layout_width="0dp"
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="center_vertical">
android:layout_marginTop="10dp"
android:layout_marginStart="44.5dp">
<com.google.android.material.textfield.TextInputLayout
android:hint="@string/issuer"
android:layout_width="0dp"
@ -126,6 +118,7 @@
<com.google.android.material.textfield.TextInputLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:hint="@string/group"
style="?attr/dropdownStyle">
@ -136,8 +129,7 @@
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</TableRow>
</TableLayout>
</LinearLayout>
<RelativeLayout
android:foreground="?android:attr/selectableItemBackground"
@ -173,38 +165,35 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
<TableLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:stretchColumns="1"
android:layout_marginEnd="15dp">
<TableRow
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp">
<ImageView android:layout_column="0"
android:layout_marginHorizontal="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_info_outline_black_24dp"
app:tint="?attr/iconColorPrimary"
android:layout_marginStart="15dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="15dp"
android:layout_gravity="center_vertical"/>
<LinearLayout android:layout_column="1"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="center_vertical">
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:gravity="start"
android:layout_gravity="start"
android:layout_weight="2"
android:hint="@string/type"
style="?attr/dropdownStyle">
<AutoCompleteTextView
@ -215,8 +204,9 @@
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="2"
android:hint="@string/algorithm_hint"
style="?attr/dropdownStyle">
<AutoCompleteTextView
@ -226,26 +216,20 @@
android:inputType="none" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</TableRow>
<TableRow
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp">
<LinearLayout android:layout_column="1"
android:layout_width="0dp"
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="center_vertical">
android:layout_marginTop="10dp"
android:layout_marginStart="44.5dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_period_counter_layout"
android:hint="@string/period_hint"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:gravity="start"
android:layout_gravity="start">
android:layout_weight="1">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/text_period_counter"
android:layout_width="match_parent"
@ -256,7 +240,8 @@
android:hint="@string/digits"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4">
android:layout_marginStart="5dp"
android:layout_weight="1">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/text_digits"
android:layout_width="match_parent"
@ -264,17 +249,17 @@
android:inputType="text"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</TableRow>
<TableRow
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp">
<ImageView android:layout_column="0"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_vpn_key_black_24dp"
app:tint="?attr/iconColorPrimary"
android:layout_marginStart="15dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="15dp"
android:layout_gravity="center_vertical"/>
@ -292,10 +277,9 @@
android:hint="@string/secret"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
</TableRow>
</TableLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>