Merge "Adding isFalseLongTap method" into tm-qpr-dev am: 4562cb6733
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20190664 Change-Id: I5952444a9f50ad5b580ce52c2c35ad55708d702a Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -81,6 +81,18 @@ public interface FalsingManager {
|
|||||||
*/
|
*/
|
||||||
boolean isFalseTap(@Penalty int penalty);
|
boolean isFalseTap(@Penalty int penalty);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the FalsingManager thinks the last gesture was not a valid long tap.
|
||||||
|
*
|
||||||
|
* Use this method to validate a long tap for launching an action, like long press on a UMO
|
||||||
|
*
|
||||||
|
* The only parameter, penalty, indicates how much this should affect future gesture
|
||||||
|
* classifications if this long tap looks like a false.
|
||||||
|
* As long taps are hard to confirm as false or otherwise,
|
||||||
|
* a low penalty value is encouraged unless context indicates otherwise.
|
||||||
|
*/
|
||||||
|
boolean isFalseLongTap(@Penalty int penalty);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the last two gestures do not look like a double tap.
|
* Returns true if the last two gestures do not look like a double tap.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import com.android.internal.logging.MetricsLogger;
|
|||||||
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
|
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
|
||||||
import com.android.systemui.classifier.HistoryTracker.BeliefListener;
|
import com.android.systemui.classifier.HistoryTracker.BeliefListener;
|
||||||
import com.android.systemui.dagger.qualifiers.TestHarness;
|
import com.android.systemui.dagger.qualifiers.TestHarness;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ public class BrightLineFalsingManager implements FalsingManager {
|
|||||||
private static final double FALSE_BELIEF_THRESHOLD = 0.9;
|
private static final double FALSE_BELIEF_THRESHOLD = 0.9;
|
||||||
|
|
||||||
private final FalsingDataProvider mDataProvider;
|
private final FalsingDataProvider mDataProvider;
|
||||||
|
private final LongTapClassifier mLongTapClassifier;
|
||||||
private final SingleTapClassifier mSingleTapClassifier;
|
private final SingleTapClassifier mSingleTapClassifier;
|
||||||
private final DoubleTapClassifier mDoubleTapClassifier;
|
private final DoubleTapClassifier mDoubleTapClassifier;
|
||||||
private final HistoryTracker mHistoryTracker;
|
private final HistoryTracker mHistoryTracker;
|
||||||
@@ -73,6 +76,7 @@ public class BrightLineFalsingManager implements FalsingManager {
|
|||||||
private final boolean mTestHarness;
|
private final boolean mTestHarness;
|
||||||
private final MetricsLogger mMetricsLogger;
|
private final MetricsLogger mMetricsLogger;
|
||||||
private int mIsFalseTouchCalls;
|
private int mIsFalseTouchCalls;
|
||||||
|
private FeatureFlags mFeatureFlags;
|
||||||
private static final Queue<String> RECENT_INFO_LOG =
|
private static final Queue<String> RECENT_INFO_LOG =
|
||||||
new ArrayDeque<>(RECENT_INFO_LOG_SIZE + 1);
|
new ArrayDeque<>(RECENT_INFO_LOG_SIZE + 1);
|
||||||
private static final Queue<DebugSwipeRecord> RECENT_SWIPES =
|
private static final Queue<DebugSwipeRecord> RECENT_SWIPES =
|
||||||
@@ -175,19 +179,23 @@ public class BrightLineFalsingManager implements FalsingManager {
|
|||||||
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
|
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
|
||||||
MetricsLogger metricsLogger,
|
MetricsLogger metricsLogger,
|
||||||
@Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
|
@Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
|
||||||
SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier,
|
SingleTapClassifier singleTapClassifier, LongTapClassifier longTapClassifier,
|
||||||
HistoryTracker historyTracker, KeyguardStateController keyguardStateController,
|
DoubleTapClassifier doubleTapClassifier, HistoryTracker historyTracker,
|
||||||
|
KeyguardStateController keyguardStateController,
|
||||||
AccessibilityManager accessibilityManager,
|
AccessibilityManager accessibilityManager,
|
||||||
@TestHarness boolean testHarness) {
|
@TestHarness boolean testHarness,
|
||||||
|
FeatureFlags featureFlags) {
|
||||||
mDataProvider = falsingDataProvider;
|
mDataProvider = falsingDataProvider;
|
||||||
mMetricsLogger = metricsLogger;
|
mMetricsLogger = metricsLogger;
|
||||||
mClassifiers = classifiers;
|
mClassifiers = classifiers;
|
||||||
mSingleTapClassifier = singleTapClassifier;
|
mSingleTapClassifier = singleTapClassifier;
|
||||||
|
mLongTapClassifier = longTapClassifier;
|
||||||
mDoubleTapClassifier = doubleTapClassifier;
|
mDoubleTapClassifier = doubleTapClassifier;
|
||||||
mHistoryTracker = historyTracker;
|
mHistoryTracker = historyTracker;
|
||||||
mKeyguardStateController = keyguardStateController;
|
mKeyguardStateController = keyguardStateController;
|
||||||
mAccessibilityManager = accessibilityManager;
|
mAccessibilityManager = accessibilityManager;
|
||||||
mTestHarness = testHarness;
|
mTestHarness = testHarness;
|
||||||
|
mFeatureFlags = featureFlags;
|
||||||
|
|
||||||
mDataProvider.addSessionListener(mSessionListener);
|
mDataProvider.addSessionListener(mSessionListener);
|
||||||
mDataProvider.addGestureCompleteListener(mGestureFinalizedListener);
|
mDataProvider.addGestureCompleteListener(mGestureFinalizedListener);
|
||||||
@@ -312,6 +320,58 @@ public class BrightLineFalsingManager implements FalsingManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFalseLongTap(@Penalty int penalty) {
|
||||||
|
if (!mFeatureFlags.isEnabled(Flags.FALSING_FOR_LONG_TAPS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkDestroyed();
|
||||||
|
|
||||||
|
if (skipFalsing(GENERIC)) {
|
||||||
|
mPriorResults = getPassedResult(1);
|
||||||
|
logDebug("Skipped falsing");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double falsePenalty = 0;
|
||||||
|
switch(penalty) {
|
||||||
|
case NO_PENALTY:
|
||||||
|
falsePenalty = 0;
|
||||||
|
break;
|
||||||
|
case LOW_PENALTY:
|
||||||
|
falsePenalty = 0.1;
|
||||||
|
break;
|
||||||
|
case MODERATE_PENALTY:
|
||||||
|
falsePenalty = 0.3;
|
||||||
|
break;
|
||||||
|
case HIGH_PENALTY:
|
||||||
|
falsePenalty = 0.6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FalsingClassifier.Result longTapResult =
|
||||||
|
mLongTapClassifier.isTap(mDataProvider.getRecentMotionEvents().isEmpty()
|
||||||
|
? mDataProvider.getPriorMotionEvents()
|
||||||
|
: mDataProvider.getRecentMotionEvents(), falsePenalty);
|
||||||
|
mPriorResults = Collections.singleton(longTapResult);
|
||||||
|
|
||||||
|
if (!longTapResult.isFalse()) {
|
||||||
|
if (mDataProvider.isJustUnlockedWithFace()) {
|
||||||
|
// Immediately pass if a face is detected.
|
||||||
|
mPriorResults = getPassedResult(1);
|
||||||
|
logDebug("False Long Tap: false (face detected)");
|
||||||
|
} else {
|
||||||
|
mPriorResults = getPassedResult(0.1);
|
||||||
|
logDebug("False Long Tap: false (default)");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
logDebug("False Long Tap: " + longTapResult.isFalse() + " (simple)");
|
||||||
|
return longTapResult.isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFalseDoubleTap() {
|
public boolean isFalseDoubleTap() {
|
||||||
checkDestroyed();
|
checkDestroyed();
|
||||||
|
|||||||
@@ -138,6 +138,11 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
|
|||||||
return mInternalFalsingManager.isFalseTap(penalty);
|
return mInternalFalsingManager.isFalseTap(penalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFalseLongTap(int penalty) {
|
||||||
|
return mInternalFalsingManager.isFalseLongTap(penalty);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFalseDoubleTap() {
|
public boolean isFalseDoubleTap() {
|
||||||
return mInternalFalsingManager.isFalseDoubleTap();
|
return mInternalFalsingManager.isFalseDoubleTap();
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import dagger.multibindings.ElementsIntoSet;
|
|||||||
public interface FalsingModule {
|
public interface FalsingModule {
|
||||||
String BRIGHT_LINE_GESTURE_CLASSIFERS = "bright_line_gesture_classifiers";
|
String BRIGHT_LINE_GESTURE_CLASSIFERS = "bright_line_gesture_classifiers";
|
||||||
String SINGLE_TAP_TOUCH_SLOP = "falsing_single_tap_touch_slop";
|
String SINGLE_TAP_TOUCH_SLOP = "falsing_single_tap_touch_slop";
|
||||||
|
String LONG_TAP_TOUCH_SLOP = "falsing_long_tap_slop";
|
||||||
String DOUBLE_TAP_TOUCH_SLOP = "falsing_double_tap_touch_slop";
|
String DOUBLE_TAP_TOUCH_SLOP = "falsing_double_tap_touch_slop";
|
||||||
String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms";
|
String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms";
|
||||||
|
|
||||||
@@ -81,4 +82,11 @@ public interface FalsingModule {
|
|||||||
static float providesSingleTapTouchSlop(ViewConfiguration viewConfiguration) {
|
static float providesSingleTapTouchSlop(ViewConfiguration viewConfiguration) {
|
||||||
return viewConfiguration.getScaledTouchSlop();
|
return viewConfiguration.getScaledTouchSlop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Provides
|
||||||
|
@Named(LONG_TAP_TOUCH_SLOP)
|
||||||
|
static float providesLongTapTouchSlop(ViewConfiguration viewConfiguration) {
|
||||||
|
return viewConfiguration.getScaledTouchSlop() * 1.25f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.classifier;
|
||||||
|
|
||||||
|
import static com.android.systemui.classifier.FalsingModule.LONG_TAP_TOUCH_SLOP;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Falsing classifier that accepts or rejects a gesture as a long tap.
|
||||||
|
*/
|
||||||
|
public class LongTapClassifier extends TapClassifier{
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
LongTapClassifier(FalsingDataProvider dataProvider,
|
||||||
|
@Named(LONG_TAP_TOUCH_SLOP) float touchSlop) {
|
||||||
|
super(dataProvider, touchSlop);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,57 +18,17 @@ package com.android.systemui.classifier;
|
|||||||
|
|
||||||
import static com.android.systemui.classifier.FalsingModule.SINGLE_TAP_TOUCH_SLOP;
|
import static com.android.systemui.classifier.FalsingModule.SINGLE_TAP_TOUCH_SLOP;
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Falsing classifier that accepts or rejects a single gesture as a tap.
|
* Falsing classifier that accepts or rejects a gesture as a single tap.
|
||||||
*/
|
*/
|
||||||
public class SingleTapClassifier extends FalsingClassifier {
|
public class SingleTapClassifier extends TapClassifier {
|
||||||
private final float mTouchSlop;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SingleTapClassifier(FalsingDataProvider dataProvider,
|
SingleTapClassifier(FalsingDataProvider dataProvider,
|
||||||
@Named(SINGLE_TAP_TOUCH_SLOP) float touchSlop) {
|
@Named(SINGLE_TAP_TOUCH_SLOP) float touchSlop) {
|
||||||
super(dataProvider);
|
super(dataProvider, touchSlop);
|
||||||
mTouchSlop = touchSlop;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Result calculateFalsingResult(
|
|
||||||
@Classifier.InteractionType int interactionType,
|
|
||||||
double historyBelief, double historyConfidence) {
|
|
||||||
return isTap(getRecentMotionEvents(), 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */
|
|
||||||
public Result isTap(List<MotionEvent> motionEvents, double falsePenalty) {
|
|
||||||
if (motionEvents.isEmpty()) {
|
|
||||||
return falsed(0, "no motion events");
|
|
||||||
}
|
|
||||||
float downX = motionEvents.get(0).getX();
|
|
||||||
float downY = motionEvents.get(0).getY();
|
|
||||||
|
|
||||||
for (MotionEvent event : motionEvents) {
|
|
||||||
String reason;
|
|
||||||
if (Math.abs(event.getX() - downX) >= mTouchSlop) {
|
|
||||||
reason = "dX too big for a tap: "
|
|
||||||
+ Math.abs(event.getX() - downX)
|
|
||||||
+ "vs "
|
|
||||||
+ mTouchSlop;
|
|
||||||
return falsed(falsePenalty, reason);
|
|
||||||
} else if (Math.abs(event.getY() - downY) >= mTouchSlop) {
|
|
||||||
reason = "dY too big for a tap: "
|
|
||||||
+ Math.abs(event.getY() - downY)
|
|
||||||
+ " vs "
|
|
||||||
+ mTouchSlop;
|
|
||||||
return falsed(falsePenalty, reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Result.passed(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.classifier;
|
||||||
|
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Falsing classifier that accepts or rejects a gesture as a tap.
|
||||||
|
*/
|
||||||
|
public abstract class TapClassifier extends FalsingClassifier{
|
||||||
|
private final float mTouchSlop;
|
||||||
|
|
||||||
|
TapClassifier(FalsingDataProvider dataProvider,
|
||||||
|
float touchSlop) {
|
||||||
|
super(dataProvider);
|
||||||
|
mTouchSlop = touchSlop;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Result calculateFalsingResult(
|
||||||
|
@Classifier.InteractionType int interactionType,
|
||||||
|
double historyBelief, double historyConfidence) {
|
||||||
|
return isTap(getRecentMotionEvents(), 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */
|
||||||
|
public Result isTap(List<MotionEvent> motionEvents, double falsePenalty) {
|
||||||
|
if (motionEvents.isEmpty()) {
|
||||||
|
return falsed(0, "no motion events");
|
||||||
|
}
|
||||||
|
float downX = motionEvents.get(0).getX();
|
||||||
|
float downY = motionEvents.get(0).getY();
|
||||||
|
|
||||||
|
for (MotionEvent event : motionEvents) {
|
||||||
|
String reason;
|
||||||
|
if (Math.abs(event.getX() - downX) >= mTouchSlop) {
|
||||||
|
reason = "dX too big for a tap: "
|
||||||
|
+ Math.abs(event.getX() - downX)
|
||||||
|
+ "vs "
|
||||||
|
+ mTouchSlop;
|
||||||
|
return falsed(falsePenalty, reason);
|
||||||
|
} else if (Math.abs(event.getY() - downY) >= mTouchSlop) {
|
||||||
|
reason = "dY too big for a tap: "
|
||||||
|
+ Math.abs(event.getY() - downY)
|
||||||
|
+ " vs "
|
||||||
|
+ mTouchSlop;
|
||||||
|
return falsed(falsePenalty, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.passed(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -349,6 +349,9 @@ object Flags {
|
|||||||
// 2000 - device controls
|
// 2000 - device controls
|
||||||
@Keep val USE_APP_PANELS = UnreleasedFlag(2000, true)
|
@Keep val USE_APP_PANELS = UnreleasedFlag(2000, true)
|
||||||
|
|
||||||
|
// 2100 - Falsing Manager
|
||||||
|
@JvmField val FALSING_FOR_LONG_TAPS = ReleasedFlag(2100)
|
||||||
|
|
||||||
// Pay no attention to the reflection behind the curtain.
|
// Pay no attention to the reflection behind the curtain.
|
||||||
// ========================== Curtain ==========================
|
// ========================== Curtain ==========================
|
||||||
// | |
|
// | |
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import com.android.internal.logging.MetricsLogger;
|
|||||||
import com.android.internal.logging.testing.FakeMetricsLogger;
|
import com.android.internal.logging.testing.FakeMetricsLogger;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener;
|
import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener;
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||||
import com.android.systemui.util.time.FakeSystemClock;
|
import com.android.systemui.util.time.FakeSystemClock;
|
||||||
@@ -66,6 +68,8 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
private SingleTapClassifier mSingleTapClassfier;
|
private SingleTapClassifier mSingleTapClassfier;
|
||||||
@Mock
|
@Mock
|
||||||
|
private LongTapClassifier mLongTapClassifier;
|
||||||
|
@Mock
|
||||||
private DoubleTapClassifier mDoubleTapClassifier;
|
private DoubleTapClassifier mDoubleTapClassifier;
|
||||||
@Mock
|
@Mock
|
||||||
private FalsingClassifier mClassifierA;
|
private FalsingClassifier mClassifierA;
|
||||||
@@ -80,6 +84,7 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
private AccessibilityManager mAccessibilityManager;
|
private AccessibilityManager mAccessibilityManager;
|
||||||
|
|
||||||
private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
|
private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
|
private final FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags();
|
||||||
|
|
||||||
private final FalsingClassifier.Result mFalsedResult =
|
private final FalsingClassifier.Result mFalsedResult =
|
||||||
FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), "");
|
FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), "");
|
||||||
@@ -94,6 +99,7 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
when(mClassifierB.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
when(mClassifierB.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
||||||
.thenReturn(mPassedResult);
|
.thenReturn(mPassedResult);
|
||||||
when(mSingleTapClassfier.isTap(any(List.class), anyDouble())).thenReturn(mPassedResult);
|
when(mSingleTapClassfier.isTap(any(List.class), anyDouble())).thenReturn(mPassedResult);
|
||||||
|
when(mLongTapClassifier.isTap(any(List.class), anyDouble())).thenReturn(mFalsedResult);
|
||||||
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
||||||
.thenReturn(mPassedResult);
|
.thenReturn(mPassedResult);
|
||||||
mClassifiers.add(mClassifierA);
|
mClassifiers.add(mClassifierA);
|
||||||
@@ -101,9 +107,9 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
|
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
|
||||||
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
||||||
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
|
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
|
||||||
mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier,
|
mMetricsLogger, mClassifiers, mSingleTapClassfier, mLongTapClassifier,
|
||||||
mHistoryTracker, mKeyguardStateController, mAccessibilityManager,
|
mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController,
|
||||||
false);
|
mAccessibilityManager, false, mFakeFeatureFlags);
|
||||||
|
|
||||||
|
|
||||||
ArgumentCaptor<GestureFinalizedListener> gestureCompleteListenerCaptor =
|
ArgumentCaptor<GestureFinalizedListener> gestureCompleteListenerCaptor =
|
||||||
@@ -113,6 +119,7 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
gestureCompleteListenerCaptor.capture());
|
gestureCompleteListenerCaptor.capture());
|
||||||
|
|
||||||
mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue();
|
mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue();
|
||||||
|
mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -212,7 +219,7 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsFalseTap_EmptyRecentEvents() {
|
public void testIsFalseSingleTap_EmptyRecentEvents() {
|
||||||
// Ensure we look at prior events if recent events has already been emptied.
|
// Ensure we look at prior events if recent events has already been emptied.
|
||||||
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(new ArrayList<>());
|
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(new ArrayList<>());
|
||||||
when(mFalsingDataProvider.getPriorMotionEvents()).thenReturn(mMotionEventList);
|
when(mFalsingDataProvider.getPriorMotionEvents()).thenReturn(mMotionEventList);
|
||||||
@@ -223,7 +230,7 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsFalseTap_RobustCheck_NoFaceAuth() {
|
public void testIsFalseSingleTap_RobustCheck_NoFaceAuth() {
|
||||||
when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
|
when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
|
||||||
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
||||||
.thenReturn(mFalsedResult);
|
.thenReturn(mFalsedResult);
|
||||||
@@ -233,12 +240,49 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsFalseTap_RobustCheck_FaceAuth() {
|
public void testIsFalseSingleTap_RobustCheck_FaceAuth() {
|
||||||
when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
|
when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
|
||||||
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
|
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
|
||||||
assertThat(mBrightLineFalsingManager.isFalseTap(NO_PENALTY)).isFalse();
|
assertThat(mBrightLineFalsingManager.isFalseTap(NO_PENALTY)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFalseLongTap_EmptyRecentEvents() {
|
||||||
|
// Ensure we look at prior events if recent events has already been emptied.
|
||||||
|
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(new ArrayList<>());
|
||||||
|
when(mFalsingDataProvider.getPriorMotionEvents()).thenReturn(mMotionEventList);
|
||||||
|
|
||||||
|
mBrightLineFalsingManager.isFalseLongTap(0);
|
||||||
|
verify(mLongTapClassifier).isTap(mMotionEventList, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFalseLongTap_FalseLongTap_NotFlagged() {
|
||||||
|
mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, false);
|
||||||
|
when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult);
|
||||||
|
assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFalseLongTap_FalseLongTap() {
|
||||||
|
when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult);
|
||||||
|
assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFalseLongTap_RobustCheck_NoFaceAuth() {
|
||||||
|
when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
|
||||||
|
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(false);
|
||||||
|
assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsFalseLongTap_RobustCheck_FaceAuth() {
|
||||||
|
when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult);
|
||||||
|
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
|
||||||
|
assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsFalseDoubleTap() {
|
public void testIsFalseDoubleTap() {
|
||||||
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import androidx.test.filters.SmallTest;
|
|||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.internal.logging.testing.FakeMetricsLogger;
|
import com.android.internal.logging.testing.FakeMetricsLogger;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
|
|
||||||
@@ -57,6 +59,8 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
private SingleTapClassifier mSingleTapClassifier;
|
private SingleTapClassifier mSingleTapClassifier;
|
||||||
@Mock
|
@Mock
|
||||||
|
private LongTapClassifier mLongTapClassifier;
|
||||||
|
@Mock
|
||||||
private DoubleTapClassifier mDoubleTapClassifier;
|
private DoubleTapClassifier mDoubleTapClassifier;
|
||||||
@Mock
|
@Mock
|
||||||
private FalsingClassifier mClassifierA;
|
private FalsingClassifier mClassifierA;
|
||||||
@@ -71,6 +75,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
|
private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
|
||||||
private final FalsingClassifier.Result mFalsedResult =
|
private final FalsingClassifier.Result mFalsedResult =
|
||||||
FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), "");
|
FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), "");
|
||||||
|
private final FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
@@ -78,15 +83,17 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
||||||
.thenReturn(mFalsedResult);
|
.thenReturn(mFalsedResult);
|
||||||
when(mSingleTapClassifier.isTap(any(List.class), anyDouble())).thenReturn(mFalsedResult);
|
when(mSingleTapClassifier.isTap(any(List.class), anyDouble())).thenReturn(mFalsedResult);
|
||||||
|
when(mLongTapClassifier.isTap(any(List.class), anyDouble())).thenReturn(mFalsedResult);
|
||||||
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
|
||||||
.thenReturn(mFalsedResult);
|
.thenReturn(mFalsedResult);
|
||||||
mClassifiers.add(mClassifierA);
|
mClassifiers.add(mClassifierA);
|
||||||
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
|
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
|
||||||
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
||||||
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
|
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
|
||||||
mMetricsLogger, mClassifiers, mSingleTapClassifier, mDoubleTapClassifier,
|
mMetricsLogger, mClassifiers, mSingleTapClassifier, mLongTapClassifier,
|
||||||
mHistoryTracker, mKeyguardStateController, mAccessibilityManager,
|
mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController,
|
||||||
false);
|
mAccessibilityManager, false, mFakeFeatureFlags);
|
||||||
|
mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -104,6 +111,13 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testA11yDisablesLongTap() {
|
||||||
|
assertThat(mBrightLineFalsingManager.isFalseLongTap(1)).isTrue();
|
||||||
|
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
|
||||||
|
assertThat(mBrightLineFalsingManager.isFalseLongTap(1)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testA11yDisablesDoubleTap() {
|
public void testA11yDisablesDoubleTap() {
|
||||||
assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue();
|
assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public class FalsingManagerFake implements FalsingManager {
|
|||||||
private boolean mShouldEnforceBouncer;
|
private boolean mShouldEnforceBouncer;
|
||||||
private boolean mIsReportingEnabled;
|
private boolean mIsReportingEnabled;
|
||||||
private boolean mIsFalseRobustTap;
|
private boolean mIsFalseRobustTap;
|
||||||
|
private boolean mIsFalseLongTap;
|
||||||
private boolean mDestroyed;
|
private boolean mDestroyed;
|
||||||
private boolean mIsProximityNear;
|
private boolean mIsProximityNear;
|
||||||
|
|
||||||
@@ -87,6 +88,10 @@ public class FalsingManagerFake implements FalsingManager {
|
|||||||
mIsProximityNear = proxNear;
|
mIsProximityNear = proxNear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFalseLongTap(boolean falseLongTap) {
|
||||||
|
mIsFalseLongTap = falseLongTap;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSimpleTap() {
|
public boolean isSimpleTap() {
|
||||||
checkDestroyed();
|
checkDestroyed();
|
||||||
@@ -99,6 +104,12 @@ public class FalsingManagerFake implements FalsingManager {
|
|||||||
return mIsFalseRobustTap;
|
return mIsFalseRobustTap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFalseLongTap(int penalty) {
|
||||||
|
checkDestroyed();
|
||||||
|
return mIsFalseLongTap;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFalseDoubleTap() {
|
public boolean isFalseDoubleTap() {
|
||||||
checkDestroyed();
|
checkDestroyed();
|
||||||
|
|||||||
Reference in New Issue
Block a user