Loading packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +44 −38 Original line number Diff line number Diff line Loading @@ -46,7 +46,6 @@ import java.util.Queue; import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; import javax.inject.Named; Loading Loading @@ -107,11 +106,14 @@ public class BrightLineFalsingManager implements FalsingManager { } }; private final FalsingDataProvider.GestureCompleteListener mGestureCompleteListener = new FalsingDataProvider.GestureCompleteListener() { private final FalsingDataProvider.GestureFinalizedListener mGestureFinalizedListener = new FalsingDataProvider.GestureFinalizedListener() { @Override public void onGestureComplete(long completionTimeMs) { public void onGestureFinalized(long completionTimeMs) { if (mPriorResults != null) { boolean boolResult = mPriorResults.stream().anyMatch( FalsingClassifier.Result::isFalse); mPriorResults.forEach(result -> { if (result.isFalse()) { String reason = result.getReason(); Loading @@ -121,8 +123,28 @@ public class BrightLineFalsingManager implements FalsingManager { } }); if (Build.IS_ENG || Build.IS_USERDEBUG) { // Copy motion events, as the results returned by // #getRecentMotionEvents are recycled elsewhere. RECENT_SWIPES.add(new DebugSwipeRecord( boolResult, mPriorInteractionType, mDataProvider.getRecentMotionEvents().stream().map( motionEvent -> new XYDt( (int) motionEvent.getX(), (int) motionEvent.getY(), (int) (motionEvent.getEventTime() - motionEvent.getDownTime()))) .collect(Collectors.toList()))); while (RECENT_SWIPES.size() > RECENT_INFO_LOG_SIZE) { RECENT_SWIPES.remove(); } } mHistoryTracker.addResults(mPriorResults, completionTimeMs); mPriorResults = null; mPriorInteractionType = Classifier.GENERIC; } else { // Gestures that were not classified get treated as a false. mHistoryTracker.addResults( Loading @@ -135,6 +157,7 @@ public class BrightLineFalsingManager implements FalsingManager { }; private Collection<FalsingClassifier.Result> mPriorResults; private @Classifier.InteractionType int mPriorInteractionType = Classifier.GENERIC; @Inject public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, Loading @@ -154,7 +177,7 @@ public class BrightLineFalsingManager implements FalsingManager { mTestHarness = testHarness; mDataProvider.addSessionListener(mSessionListener); mDataProvider.addGestureCompleteListener(mGestureCompleteListener); mDataProvider.addGestureCompleteListener(mGestureFinalizedListener); mHistoryTracker.addBeliefListener(mBeliefListener); } Loading @@ -165,50 +188,33 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { mPriorInteractionType = interactionType; if (skipFalsing()) { return false; } boolean result; final boolean booleanResult; if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) { Stream<FalsingClassifier.Result> results = mClassifiers.stream().map(falsingClassifier -> falsingClassifier.classifyGesture( final boolean[] localResult = {false}; mPriorResults = mClassifiers.stream().map(falsingClassifier -> { FalsingClassifier.Result r = falsingClassifier.classifyGesture( interactionType, mHistoryTracker.falseBelief(), mHistoryTracker.falseConfidence())); mPriorResults = new ArrayList<>(); final boolean[] localResult = {false}; results.forEach(classifierResult -> { localResult[0] |= classifierResult.isFalse(); mPriorResults.add(classifierResult); }); result = localResult[0]; mHistoryTracker.falseConfidence()); localResult[0] |= r.isFalse(); return r; }).collect(Collectors.toList()); booleanResult = localResult[0]; } else { result = false; booleanResult = false; mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1)); } logDebug("False Gesture: " + result); if (Build.IS_ENG || Build.IS_USERDEBUG) { // Copy motion events, as the passed in list gets emptied out elsewhere in the code. RECENT_SWIPES.add(new DebugSwipeRecord( result, interactionType, mDataProvider.getRecentMotionEvents().stream().map( motionEvent -> new XYDt( (int) motionEvent.getX(), (int) motionEvent.getY(), (int) (motionEvent.getEventTime() - motionEvent.getDownTime()))) .collect(Collectors.toList()))); while (RECENT_SWIPES.size() > RECENT_INFO_LOG_SIZE) { RECENT_SWIPES.remove(); } } logDebug("False Gesture: " + booleanResult); return result; return booleanResult; } @Override Loading Loading @@ -354,7 +360,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void cleanup() { mDataProvider.removeSessionListener(mSessionListener); mDataProvider.removeGestureCompleteListener(mGestureCompleteListener); mDataProvider.removeGestureCompleteListener(mGestureFinalizedListener); mClassifiers.forEach(FalsingClassifier::cleanup); mFalsingBeliefListeners.clear(); mHistoryTracker.removeBeliefListener(mBeliefListener); Loading packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +16 −12 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ public class FalsingDataProvider { private final float mYdpi; private final List<SessionListener> mSessionListeners = new ArrayList<>(); private final List<MotionEventListener> mMotionEventListeners = new ArrayList<>(); private final List<GestureCompleteListener> mGestureCompleteListeners = new ArrayList<>(); private final List<GestureFinalizedListener> mGestureFinalizedListeners = new ArrayList<>(); private TimeLimitedMotionEventBuffer mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS); Loading Loading @@ -90,7 +90,7 @@ public class FalsingDataProvider { mMotionEventListeners.forEach(listener -> listener.onMotionEvent(motionEvent)); // We explicitly do not complete a gesture on UP or CANCEL events. // We explicitly do not "finalize" a gesture on UP or CANCEL events. // We wait for the next gesture to start before marking the prior gesture as complete. This // has multiple benefits. First, it makes it trivial to track the "current" or "recent" // gesture, as it will always be found in mRecentMotionEvents. Second, and most importantly, Loading @@ -102,7 +102,7 @@ public class FalsingDataProvider { private void completePriorGesture() { if (!mRecentMotionEvents.isEmpty()) { mGestureCompleteListeners.forEach(listener -> listener.onGestureComplete( mGestureFinalizedListeners.forEach(listener -> listener.onGestureFinalized( mRecentMotionEvents.get(mRecentMotionEvents.size() - 1).getEventTime())); mPriorMotionEvents = mRecentMotionEvents; Loading Loading @@ -312,14 +312,14 @@ public class FalsingDataProvider { mMotionEventListeners.remove(listener); } /** Register a {@link GestureCompleteListener}. */ public void addGestureCompleteListener(GestureCompleteListener listener) { mGestureCompleteListeners.add(listener); /** Register a {@link GestureFinalizedListener}. */ public void addGestureCompleteListener(GestureFinalizedListener listener) { mGestureFinalizedListeners.add(listener); } /** Unregister a {@link GestureCompleteListener}. */ public void removeGestureCompleteListener(GestureCompleteListener listener) { mGestureCompleteListeners.remove(listener); /** Unregister a {@link GestureFinalizedListener}. */ public void removeGestureCompleteListener(GestureFinalizedListener listener) { mGestureFinalizedListeners.remove(listener); } void onSessionStarted() { Loading Loading @@ -362,8 +362,12 @@ public class FalsingDataProvider { } /** Callback to be alerted when the current gesture ends. */ public interface GestureCompleteListener { /** */ void onGestureComplete(long completionTimeMs); public interface GestureFinalizedListener { /** * Called just before a new gesture starts. * * Any pending work on a prior gesture can be considered cemented in place. */ void onGestureFinalized(long completionTimeMs); } } packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +11 −11 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingDataProvider.GestureCompleteListener; import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener; import com.android.systemui.dock.DockManagerFake; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; Loading Loading @@ -82,7 +82,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), ""); private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1); private GestureCompleteListener mGestureCompleteListener; private GestureFinalizedListener mGestureFinalizedListener; @Before public void setup() { Loading @@ -103,13 +103,13 @@ public class BrightLineClassifierTest extends SysuiTestCase { mHistoryTracker, mKeyguardStateController, false); ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor = ArgumentCaptor.forClass(GestureCompleteListener.class); ArgumentCaptor<GestureFinalizedListener> gestureCompleteListenerCaptor = ArgumentCaptor.forClass(GestureFinalizedListener.class); verify(mFalsingDataProvider).addGestureCompleteListener( gestureCompleteListenerCaptor.capture()); mGestureCompleteListener = gestureCompleteListenerCaptor.getValue(); mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue(); } @Test Loading Loading @@ -211,7 +211,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test public void testHistory() { mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); } Loading @@ -220,7 +220,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testHistory_singleTap() { // When trying to classify single taps, we don't immediately add results to history. mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); } Loading @@ -228,9 +228,9 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testHistory_multipleSingleTaps() { // When trying to classify single taps, we don't immediately add results to history. mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(2000); mGestureFinalizedListener.onGestureFinalized(2000); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); verify(mHistoryTracker).addResults(anyCollection(), eq(2000L)); } Loading @@ -239,11 +239,11 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testHistory_doubleTap() { // When trying to classify single taps, we don't immediately add results to history. mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); // Before checking for double tap, we may check for single-tap on the second gesture. mBrightLineFalsingManager.isFalseTap(false, 0); mBrightLineFalsingManager.isFalseDoubleTap(); mGestureCompleteListener.onGestureComplete(2000); mGestureFinalizedListener.onGestureFinalized(2000); // Double tap is immediately added to history. Single tap is never added. verify(mHistoryTracker).addResults(anyCollection(), eq(2000L)); Loading Loading
packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +44 −38 Original line number Diff line number Diff line Loading @@ -46,7 +46,6 @@ import java.util.Queue; import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; import javax.inject.Named; Loading Loading @@ -107,11 +106,14 @@ public class BrightLineFalsingManager implements FalsingManager { } }; private final FalsingDataProvider.GestureCompleteListener mGestureCompleteListener = new FalsingDataProvider.GestureCompleteListener() { private final FalsingDataProvider.GestureFinalizedListener mGestureFinalizedListener = new FalsingDataProvider.GestureFinalizedListener() { @Override public void onGestureComplete(long completionTimeMs) { public void onGestureFinalized(long completionTimeMs) { if (mPriorResults != null) { boolean boolResult = mPriorResults.stream().anyMatch( FalsingClassifier.Result::isFalse); mPriorResults.forEach(result -> { if (result.isFalse()) { String reason = result.getReason(); Loading @@ -121,8 +123,28 @@ public class BrightLineFalsingManager implements FalsingManager { } }); if (Build.IS_ENG || Build.IS_USERDEBUG) { // Copy motion events, as the results returned by // #getRecentMotionEvents are recycled elsewhere. RECENT_SWIPES.add(new DebugSwipeRecord( boolResult, mPriorInteractionType, mDataProvider.getRecentMotionEvents().stream().map( motionEvent -> new XYDt( (int) motionEvent.getX(), (int) motionEvent.getY(), (int) (motionEvent.getEventTime() - motionEvent.getDownTime()))) .collect(Collectors.toList()))); while (RECENT_SWIPES.size() > RECENT_INFO_LOG_SIZE) { RECENT_SWIPES.remove(); } } mHistoryTracker.addResults(mPriorResults, completionTimeMs); mPriorResults = null; mPriorInteractionType = Classifier.GENERIC; } else { // Gestures that were not classified get treated as a false. mHistoryTracker.addResults( Loading @@ -135,6 +157,7 @@ public class BrightLineFalsingManager implements FalsingManager { }; private Collection<FalsingClassifier.Result> mPriorResults; private @Classifier.InteractionType int mPriorInteractionType = Classifier.GENERIC; @Inject public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, Loading @@ -154,7 +177,7 @@ public class BrightLineFalsingManager implements FalsingManager { mTestHarness = testHarness; mDataProvider.addSessionListener(mSessionListener); mDataProvider.addGestureCompleteListener(mGestureCompleteListener); mDataProvider.addGestureCompleteListener(mGestureFinalizedListener); mHistoryTracker.addBeliefListener(mBeliefListener); } Loading @@ -165,50 +188,33 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { mPriorInteractionType = interactionType; if (skipFalsing()) { return false; } boolean result; final boolean booleanResult; if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) { Stream<FalsingClassifier.Result> results = mClassifiers.stream().map(falsingClassifier -> falsingClassifier.classifyGesture( final boolean[] localResult = {false}; mPriorResults = mClassifiers.stream().map(falsingClassifier -> { FalsingClassifier.Result r = falsingClassifier.classifyGesture( interactionType, mHistoryTracker.falseBelief(), mHistoryTracker.falseConfidence())); mPriorResults = new ArrayList<>(); final boolean[] localResult = {false}; results.forEach(classifierResult -> { localResult[0] |= classifierResult.isFalse(); mPriorResults.add(classifierResult); }); result = localResult[0]; mHistoryTracker.falseConfidence()); localResult[0] |= r.isFalse(); return r; }).collect(Collectors.toList()); booleanResult = localResult[0]; } else { result = false; booleanResult = false; mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1)); } logDebug("False Gesture: " + result); if (Build.IS_ENG || Build.IS_USERDEBUG) { // Copy motion events, as the passed in list gets emptied out elsewhere in the code. RECENT_SWIPES.add(new DebugSwipeRecord( result, interactionType, mDataProvider.getRecentMotionEvents().stream().map( motionEvent -> new XYDt( (int) motionEvent.getX(), (int) motionEvent.getY(), (int) (motionEvent.getEventTime() - motionEvent.getDownTime()))) .collect(Collectors.toList()))); while (RECENT_SWIPES.size() > RECENT_INFO_LOG_SIZE) { RECENT_SWIPES.remove(); } } logDebug("False Gesture: " + booleanResult); return result; return booleanResult; } @Override Loading Loading @@ -354,7 +360,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void cleanup() { mDataProvider.removeSessionListener(mSessionListener); mDataProvider.removeGestureCompleteListener(mGestureCompleteListener); mDataProvider.removeGestureCompleteListener(mGestureFinalizedListener); mClassifiers.forEach(FalsingClassifier::cleanup); mFalsingBeliefListeners.clear(); mHistoryTracker.removeBeliefListener(mBeliefListener); Loading
packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +16 −12 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ public class FalsingDataProvider { private final float mYdpi; private final List<SessionListener> mSessionListeners = new ArrayList<>(); private final List<MotionEventListener> mMotionEventListeners = new ArrayList<>(); private final List<GestureCompleteListener> mGestureCompleteListeners = new ArrayList<>(); private final List<GestureFinalizedListener> mGestureFinalizedListeners = new ArrayList<>(); private TimeLimitedMotionEventBuffer mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS); Loading Loading @@ -90,7 +90,7 @@ public class FalsingDataProvider { mMotionEventListeners.forEach(listener -> listener.onMotionEvent(motionEvent)); // We explicitly do not complete a gesture on UP or CANCEL events. // We explicitly do not "finalize" a gesture on UP or CANCEL events. // We wait for the next gesture to start before marking the prior gesture as complete. This // has multiple benefits. First, it makes it trivial to track the "current" or "recent" // gesture, as it will always be found in mRecentMotionEvents. Second, and most importantly, Loading @@ -102,7 +102,7 @@ public class FalsingDataProvider { private void completePriorGesture() { if (!mRecentMotionEvents.isEmpty()) { mGestureCompleteListeners.forEach(listener -> listener.onGestureComplete( mGestureFinalizedListeners.forEach(listener -> listener.onGestureFinalized( mRecentMotionEvents.get(mRecentMotionEvents.size() - 1).getEventTime())); mPriorMotionEvents = mRecentMotionEvents; Loading Loading @@ -312,14 +312,14 @@ public class FalsingDataProvider { mMotionEventListeners.remove(listener); } /** Register a {@link GestureCompleteListener}. */ public void addGestureCompleteListener(GestureCompleteListener listener) { mGestureCompleteListeners.add(listener); /** Register a {@link GestureFinalizedListener}. */ public void addGestureCompleteListener(GestureFinalizedListener listener) { mGestureFinalizedListeners.add(listener); } /** Unregister a {@link GestureCompleteListener}. */ public void removeGestureCompleteListener(GestureCompleteListener listener) { mGestureCompleteListeners.remove(listener); /** Unregister a {@link GestureFinalizedListener}. */ public void removeGestureCompleteListener(GestureFinalizedListener listener) { mGestureFinalizedListeners.remove(listener); } void onSessionStarted() { Loading Loading @@ -362,8 +362,12 @@ public class FalsingDataProvider { } /** Callback to be alerted when the current gesture ends. */ public interface GestureCompleteListener { /** */ void onGestureComplete(long completionTimeMs); public interface GestureFinalizedListener { /** * Called just before a new gesture starts. * * Any pending work on a prior gesture can be considered cemented in place. */ void onGestureFinalized(long completionTimeMs); } }
packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +11 −11 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingDataProvider.GestureCompleteListener; import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener; import com.android.systemui.dock.DockManagerFake; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; Loading Loading @@ -82,7 +82,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), ""); private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1); private GestureCompleteListener mGestureCompleteListener; private GestureFinalizedListener mGestureFinalizedListener; @Before public void setup() { Loading @@ -103,13 +103,13 @@ public class BrightLineClassifierTest extends SysuiTestCase { mHistoryTracker, mKeyguardStateController, false); ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor = ArgumentCaptor.forClass(GestureCompleteListener.class); ArgumentCaptor<GestureFinalizedListener> gestureCompleteListenerCaptor = ArgumentCaptor.forClass(GestureFinalizedListener.class); verify(mFalsingDataProvider).addGestureCompleteListener( gestureCompleteListenerCaptor.capture()); mGestureCompleteListener = gestureCompleteListenerCaptor.getValue(); mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue(); } @Test Loading Loading @@ -211,7 +211,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test public void testHistory() { mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); } Loading @@ -220,7 +220,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testHistory_singleTap() { // When trying to classify single taps, we don't immediately add results to history. mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); } Loading @@ -228,9 +228,9 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testHistory_multipleSingleTaps() { // When trying to classify single taps, we don't immediately add results to history. mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(2000); mGestureFinalizedListener.onGestureFinalized(2000); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); verify(mHistoryTracker).addResults(anyCollection(), eq(2000L)); } Loading @@ -239,11 +239,11 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testHistory_doubleTap() { // When trying to classify single taps, we don't immediately add results to history. mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); mGestureFinalizedListener.onGestureFinalized(1000); // Before checking for double tap, we may check for single-tap on the second gesture. mBrightLineFalsingManager.isFalseTap(false, 0); mBrightLineFalsingManager.isFalseDoubleTap(); mGestureCompleteListener.onGestureComplete(2000); mGestureFinalizedListener.onGestureFinalized(2000); // Double tap is immediately added to history. Single tap is never added. verify(mHistoryTracker).addResults(anyCollection(), eq(2000L)); Loading