summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/contentprotection/ContentProtectionEventProcessor.java26
-rw-r--r--core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java52
2 files changed, 78 insertions, 0 deletions
diff --git a/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java b/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java
index e49df21692c5..b44abf3eb04d 100644
--- a/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java
+++ b/core/java/android/view/contentprotection/ContentProtectionEventProcessor.java
@@ -75,6 +75,8 @@ public class ContentProtectionEventProcessor {
ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED)));
+ private static final int RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS = 150;
+
@NonNull private final RingBuffer<ContentCaptureEvent> mEventBuffer;
@NonNull private final Handler mHandler;
@@ -93,6 +95,8 @@ public class ContentProtectionEventProcessor {
@Nullable
public Instant mLastFlushTime;
+ private int mResetLoginRemainingEventsToProcess;
+
public ContentProtectionEventProcessor(
@NonNull RingBuffer<ContentCaptureEvent> eventBuffer,
@NonNull Handler handler,
@@ -130,6 +134,8 @@ public class ContentProtectionEventProcessor {
mSuspiciousTextDetected |= isSuspiciousText(event);
if (mPasswordFieldDetected && mSuspiciousTextDetected) {
loginDetected();
+ } else {
+ maybeResetLoginFlags();
}
}
@@ -139,8 +145,28 @@ public class ContentProtectionEventProcessor {
|| Instant.now().isAfter(mLastFlushTime.plus(MIN_DURATION_BETWEEN_FLUSHING))) {
flush();
}
+ resetLoginFlags();
+ }
+
+ @UiThread
+ private void resetLoginFlags() {
mPasswordFieldDetected = false;
mSuspiciousTextDetected = false;
+ mResetLoginRemainingEventsToProcess = 0;
+ }
+
+ @UiThread
+ private void maybeResetLoginFlags() {
+ if (mPasswordFieldDetected || mSuspiciousTextDetected) {
+ if (mResetLoginRemainingEventsToProcess <= 0) {
+ mResetLoginRemainingEventsToProcess = RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS;
+ } else {
+ mResetLoginRemainingEventsToProcess--;
+ if (mResetLoginRemainingEventsToProcess <= 0) {
+ resetLoginFlags();
+ }
+ }
+ }
}
@UiThread
diff --git a/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java b/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java
index 4adadf11903e..39a2e0e048e8 100644
--- a/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java
+++ b/core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java
@@ -91,6 +91,8 @@ public class ContentProtectionEventProcessorTest {
private static final Set<Integer> EVENT_TYPES_TO_STORE =
ImmutableSet.of(TYPE_VIEW_APPEARED, TYPE_VIEW_DISAPPEARED, TYPE_VIEW_TEXT_CHANGED);
+ private static final int RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS = 150;
+
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private RingBuffer<ContentCaptureEvent> mMockEventBuffer;
@@ -232,6 +234,56 @@ public class ContentProtectionEventProcessorTest {
}
@Test
+ public void processEvent_loginDetected_belowResetLimit() throws Exception {
+ when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
+ mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
+ ContentCaptureEvent event =
+ createAndroidPasswordFieldEvent(
+ ANDROID_CLASS_NAME, InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+ for (int i = 0; i < RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS; i++) {
+ mContentProtectionEventProcessor.processEvent(PROCESS_EVENT);
+ }
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
+ verify(mMockEventBuffer, never()).clear();
+ verify(mMockEventBuffer, never()).toArray();
+
+ mContentProtectionEventProcessor.processEvent(event);
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
+ verify(mMockEventBuffer).clear();
+ verify(mMockEventBuffer).toArray();
+ assertOnLoginDetected();
+ }
+
+ @Test
+ public void processEvent_loginDetected_aboveResetLimit() throws Exception {
+ mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
+ ContentCaptureEvent event =
+ createAndroidPasswordFieldEvent(
+ ANDROID_CLASS_NAME, InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+ for (int i = 0; i < RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS + 1; i++) {
+ mContentProtectionEventProcessor.processEvent(PROCESS_EVENT);
+ }
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
+ verify(mMockEventBuffer, never()).clear();
+ verify(mMockEventBuffer, never()).toArray();
+
+ mContentProtectionEventProcessor.processEvent(event);
+
+ assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isTrue();
+ assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
+ verify(mMockEventBuffer, never()).clear();
+ verify(mMockEventBuffer, never()).toArray();
+ }
+
+ @Test
public void processEvent_multipleLoginsDetected_belowFlushThreshold() throws Exception {
when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);