diff options
| -rw-r--r-- | core/java/android/view/autofill/AutofillStateFingerprint.java | 90 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/autofill/AutofillStateFingerprintTest.java | 11 |
2 files changed, 82 insertions, 19 deletions
diff --git a/core/java/android/view/autofill/AutofillStateFingerprint.java b/core/java/android/view/autofill/AutofillStateFingerprint.java index eb857e034ec6..2db4285f0820 100644 --- a/core/java/android/view/autofill/AutofillStateFingerprint.java +++ b/core/java/android/view/autofill/AutofillStateFingerprint.java @@ -29,6 +29,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -61,7 +62,11 @@ public final class AutofillStateFingerprint { private static final String TAG = "AutofillStateFingerprint"; - static AutofillStateFingerprint createInstance() { + /** + * Returns an instance of this class + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public static AutofillStateFingerprint createInstance() { return new AutofillStateFingerprint(); } @@ -92,11 +97,13 @@ public final class AutofillStateFingerprint { if (sDebug) { Log.d(TAG, "Autofillable views count prior to auth:" + autofillableViews.size()); } - ArrayList<Integer> hashes = getFingerprintIds(autofillableViews); - for (int i = 0; i < hashes.size(); i++) { - View view = autofillableViews.get(i); +// ArrayList<Integer> hashes = getFingerprintIds(autofillableViews); + + ArrayMap<Integer, View> hashes = getFingerprintIds(autofillableViews); + for (Map.Entry<Integer, View> entry : hashes.entrySet()) { + View view = entry.getValue(); if (view != null) { - mHashToAutofillIdMap.put(hashes.get(i), view.getAutofillId()); + mHashToAutofillIdMap.put(entry.getKey(), view.getAutofillId()); } else { if (sDebug) { Log.d(TAG, "Encountered null view"); @@ -114,7 +121,7 @@ public final class AutofillStateFingerprint { for (int i = 0; i < autofillIdsArr.length; i++) { View view = views[i]; if (view != null) { - int id = getEphemeralFingerprintId(view); + int id = getEphemeralFingerprintId(view, 0 /* position irrelevant */); AutofillId autofillId = view.getAutofillId(); autofillId.setSessionId(mSessionId); mHashToAutofillIdMap.put(id, autofillId); @@ -159,14 +166,14 @@ public final class AutofillStateFingerprint { dumpCurrentState(); } // For the autofillable views, compute their hashes - ArrayList<Integer> currentHashes = getFingerprintIds(currentAutofillableViews); + ArrayMap<Integer, View> currentHashes = getFingerprintIds(currentAutofillableViews); // For the computed hashes, try to look for the old fingerprints. // If match found, update the new autofill ids of those views Map<AutofillId, View> oldFailedIdsToCurrentViewMap = new HashMap<>(); - for (int i = 0; i < currentAutofillableViews.size(); i++) { - View view = currentAutofillableViews.get(i); - int currentHash = currentHashes.get(i); + for (Map.Entry<Integer, View> entry : currentHashes.entrySet()) { + View view = entry.getValue(); + int currentHash = entry.getKey(); AutofillId currentAutofillId = view.getAutofillId(); currentAutofillId.setSessionId(mSessionId); if (mHashToAutofillIdMap.containsKey(currentHash)) { @@ -219,19 +226,51 @@ public final class AutofillStateFingerprint { /** * Retrieves fingerprint hashes for the views */ - ArrayList<Integer> getFingerprintIds(@NonNull List<View> views) { - ArrayList<Integer> ids = new ArrayList(views.size()); + ArrayMap<Integer, View> getFingerprintIds(@NonNull List<View> views) { + ArrayMap<Integer, View> map = new ArrayMap<>(); + if (mUseRelativePosition) { + Collections.sort(views, (View v1, View v2) -> { + int[] posV1 = v1.getLocationOnScreen(); + int[] posV2 = v2.getLocationOnScreen(); + + int compare = posV1[0] - posV2[0]; // x coordinate + if (compare != 0) { + return compare; + } + compare = posV1[1] - posV2[1]; // y coordinate + if (compare != 0) { + return compare; + } + // Sort on vertical + compare = compareTop(v1, v2); + if (compare != 0) { + return compare; + } + compare = compareBottom(v1, v2); + if (compare != 0) { + return compare; + } + compare = compareLeft(v1, v2); + if (compare != 0) { + return compare; + } + return compareRight(v1, v2); + // Note that if compareRight also returned 0, that means both the views have exact + // same location, so just treat them as equal + }); + } for (int i = 0; i < views.size(); i++) { - ids.add(getEphemeralFingerprintId(views.get(i))); + View view = views.get(i); + map.put(getEphemeralFingerprintId(view, i), view); } - return ids; + return map; } /** * Returns fingerprint hash for the view. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public static int getEphemeralFingerprintId(View v) { + public int getEphemeralFingerprintId(View v, int position) { if (v == null) return -1; int inputType = Integer.MIN_VALUE; int imeOptions = Integer.MIN_VALUE; @@ -268,6 +307,9 @@ public final class AutofillStateFingerprint { int hash = Objects.hash(visibility, inputType, imeOptions, isSingleLine, hints, contentDesc, tooltip, autofillType, Arrays.deepHashCode(autofillHints), paddingBottom, paddingTop, paddingRight, paddingLeft); + if (mUseRelativePosition) { + hash = Objects.hash(hash, position); + } if (sDebug) { Log.d(TAG, "Hash: " + hash + " for AutofillId:" + v.getAutofillId() + " visibility:" + visibility @@ -285,8 +327,26 @@ public final class AutofillStateFingerprint { + " paddingRight:" + paddingRight + " paddingTop:" + paddingTop + " paddingBottom:" + paddingBottom + + " mUseRelativePosition" + mUseRelativePosition + + " position:" + position ); } return hash; } + + private int compareTop(View v1, View v2) { + return v1.getTop() - v2.getTop(); + } + + private int compareBottom(View v1, View v2) { + return v1.getBottom() - v2.getBottom(); + } + + private int compareLeft(View v1, View v2) { + return v1.getLeft() - v2.getLeft(); + } + + private int compareRight(View v1, View v2) { + return v1.getRight() - v2.getRight(); + } } diff --git a/core/tests/coretests/src/android/view/autofill/AutofillStateFingerprintTest.java b/core/tests/coretests/src/android/view/autofill/AutofillStateFingerprintTest.java index fb50e988c417..7cbfc40a62f1 100644 --- a/core/tests/coretests/src/android/view/autofill/AutofillStateFingerprintTest.java +++ b/core/tests/coretests/src/android/view/autofill/AutofillStateFingerprintTest.java @@ -38,6 +38,9 @@ public class AutofillStateFingerprintTest { private static final int MAGIC_AUTOFILL_NUMBER = 1000; + private AutofillStateFingerprint mAutofillStateFingerprint = + AutofillStateFingerprint.createInstance(); + @Test public void testSameFingerprintsForTextView() throws Exception { TextView tv = new TextView(sContext); @@ -87,13 +90,13 @@ public class AutofillStateFingerprintTest { } private void assertIdsEqual(View v1, View v2) { - assertEquals(AutofillStateFingerprint.getEphemeralFingerprintId(v1), - AutofillStateFingerprint.getEphemeralFingerprintId(v2)); + assertEquals(mAutofillStateFingerprint.getEphemeralFingerprintId(v1, 0), + mAutofillStateFingerprint.getEphemeralFingerprintId(v2, 0)); } private void assertIdsNotEqual(View v1, View v2) { - assertNotEquals(AutofillStateFingerprint.getEphemeralFingerprintId(v1), - AutofillStateFingerprint.getEphemeralFingerprintId(v2)); + assertNotEquals(mAutofillStateFingerprint.getEphemeralFingerprintId(v1, 0), + mAutofillStateFingerprint.getEphemeralFingerprintId(v2, 0)); } private void fillViewProperties(View view) { |