diff options
| -rw-r--r-- | core/java/android/view/contentprotection/ContentProtectionEventProcessor.java | 26 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/contentprotection/ContentProtectionEventProcessorTest.java | 52 |
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); |