Add Falsing to the QS BrightnessSlider

This ensures that interactions with the BrightnessSlider are
classified as valid gestures by the FalsingManager.

Bug: 172655679
Test: manual
Change-Id: Ifeb235befc6b1342fc64b671b7704d0fdaa39349
This commit is contained in:
Dave Mankoff
2021-03-25 11:32:32 -04:00
parent fa7aca14e7
commit 07182d5226
12 changed files with 157 additions and 27 deletions

View File

@@ -37,6 +37,7 @@ public abstract class Classifier {
public static final int GENERIC = 7;
public static final int BOUNCER_UNLOCK = 8;
public static final int PULSE_EXPAND = 9;
public static final int BRIGHTNESS_SLIDER = 10;
@IntDef({
QUICK_SETTINGS,
@@ -48,7 +49,8 @@ public abstract class Classifier {
RIGHT_AFFORDANCE,
GENERIC,
BOUNCER_UNLOCK,
PULSE_EXPAND
PULSE_EXPAND,
BRIGHTNESS_SLIDER
})
@Retention(RetentionPolicy.SOURCE)
public @interface InteractionType {}

View File

@@ -148,6 +148,10 @@ class DistanceClassifier extends FalsingClassifier {
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
if (interactionType == Classifier.BRIGHTNESS_SLIDER) {
return Result.passed(0);
}
return !getPassedFlingThreshold() ? falsed(0.5, getReason()) : Result.passed(0.5);
}

View File

@@ -17,6 +17,7 @@
package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.provider.DeviceConfig;
@@ -115,7 +116,7 @@ class ProximityClassifier extends FalsingClassifier {
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
if (interactionType == QUICK_SETTINGS) {
if (interactionType == QUICK_SETTINGS || interactionType == BRIGHTNESS_SLIDER) {
return Result.passed(0);
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
@@ -45,6 +46,7 @@ public class TypeClassifier extends FalsingClassifier {
boolean up = isUp();
boolean right = isRight();
double confidence = 1;
boolean wrongDirection = true;
switch (interactionType) {
case QUICK_SETTINGS:
@@ -52,6 +54,11 @@ public class TypeClassifier extends FalsingClassifier {
case NOTIFICATION_DRAG_DOWN:
wrongDirection = !vertical || up;
break;
case BRIGHTNESS_SLIDER:
confidence = 0; // Owners may return to original brightness.
// A more sophisticated thing to do here would be to look at the size of the
// vertical change relative to the screen size. _Some_ amount of vertical
// change should be expected.
case NOTIFICATION_DISMISS:
wrongDirection = vertical;
break;
@@ -70,7 +77,7 @@ public class TypeClassifier extends FalsingClassifier {
break;
}
return wrongDirection ? falsed(1, getReason(interactionType)) : Result.passed(0.5);
return wrongDirection ? falsed(confidence, getReason(interactionType)) : Result.passed(0.5);
}
private String getReason(int interactionType) {

View File

@@ -20,6 +20,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHT
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import android.graphics.Point;
import android.provider.DeviceConfig;
@@ -87,6 +88,10 @@ class ZigZagClassifier extends FalsingClassifier {
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
if (interactionType == BRIGHTNESS_SLIDER) {
return Result.passed(0);
}
List<MotionEvent> motionEvents = getRecentMotionEvents();
// Rotate horizontal gestures to be horizontal between their first and last point.
// Rotate vertical gestures to be vertical between their first and last point.

View File

@@ -27,7 +27,10 @@ import android.widget.SeekBar;
import androidx.annotation.Nullable;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.util.ViewController;
@@ -42,9 +45,7 @@ import javax.inject.Inject;
*
* @see BrightnessMirrorController
*/
public class BrightnessSlider
extends ViewController<View>
implements ToggleSlider {
public class BrightnessSlider extends ViewController<View> implements ToggleSlider {
private Listener mListener;
private ToggleSlider mMirror;
@@ -52,15 +53,34 @@ public class BrightnessSlider
private BrightnessMirrorController mMirrorController;
private boolean mTracking;
private final boolean mUseMirror;
private final FalsingManager mFalsingManager;
private final Gefingerpoken mOnInterceptListener = new Gefingerpoken() {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
mFalsingManager.isFalseTouch(Classifier.BRIGHTNESS_SLIDER);
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
};
BrightnessSlider(
View rootView,
BrightnessSliderView brightnessSliderView,
boolean useMirror
) {
boolean useMirror,
FalsingManager falsingManager) {
super(rootView);
mBrightnessSliderView = brightnessSliderView;
mUseMirror = useMirror;
mFalsingManager = falsingManager;
}
/**
@@ -78,6 +98,7 @@ public class BrightnessSlider
protected void onViewAttached() {
mBrightnessSliderView.setOnSeekBarChangeListener(mSeekListener);
mBrightnessSliderView.setOnCheckedChangeListener(mCheckListener);
mBrightnessSliderView.setOnInterceptListener(mOnInterceptListener);
}
@Override
@@ -85,6 +106,7 @@ public class BrightnessSlider
mBrightnessSliderView.setOnSeekBarChangeListener(null);
mBrightnessSliderView.setOnCheckedChangeListener(null);
mBrightnessSliderView.setOnDispatchTouchEventListener(null);
mBrightnessSliderView.setOnInterceptListener(null);
}
@Override
@@ -247,10 +269,12 @@ public class BrightnessSlider
public static class Factory {
BrightnessControllerSettings mSettings;
private final FalsingManager mFalsingManager;
@Inject
public Factory(BrightnessControllerSettings settings) {
public Factory(BrightnessControllerSettings settings, FalsingManager falsingManager) {
mSettings = settings;
mFalsingManager = falsingManager;
}
/**
@@ -270,7 +294,7 @@ public class BrightnessSlider
private BrightnessSlider fromTree(ViewGroup root, boolean useMirror) {
BrightnessSliderView v = root.requireViewById(R.id.brightness_slider);
return new BrightnessSlider(root, v, useMirror);
return new BrightnessSlider(root, v, useMirror, mFalsingManager);
}
/** Get the layout to inflate based on what slider to use */

View File

@@ -31,6 +31,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
/**
@@ -54,6 +55,7 @@ public class BrightnessSliderView extends FrameLayout {
private TextView mLabel;
private final CharSequence mText;
private DispatchTouchEventListener mListener;
private Gefingerpoken mOnInterceptListener;
public BrightnessSliderView(Context context) {
this(context, null);
@@ -105,6 +107,15 @@ public class BrightnessSliderView extends FrameLayout {
return super.dispatchTouchEvent(ev);
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
// We prevent disallowing on this view, but bubble it up to our parents.
// We need interception to handle falsing.
if (mParent != null) {
mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}
/**
* Attaches a listener to the {@link ToggleSeekBar} in the view so changes can be observed
* @param seekListener use {@code null} to remove listener
@@ -195,6 +206,18 @@ public class BrightnessSliderView extends FrameLayout {
return mSlider.getProgress();
}
public void setOnInterceptListener(Gefingerpoken onInterceptListener) {
mOnInterceptListener = onInterceptListener;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mOnInterceptListener != null) {
return mOnInterceptListener.onInterceptTouchEvent(ev);
}
return super.onInterceptTouchEvent(ev);
}
/**
* Interface to attach a listener for {@link View#dispatchTouchEvent}.
*/

View File

@@ -16,6 +16,8 @@
package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.google.common.truth.Truth.assertThat;
import android.testing.AndroidTestingRunner;
@@ -96,13 +98,9 @@ public class DistanceClassifierTest extends ClassifierTest {
}
@Test
public void testPass_swipe() {
public void testPass_BrightnessSliderAlwaysPasses() {
mClassifier.onTouchEvent(appendDownEvent(1, 1));
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
mClassifier.onTouchEvent(appendMoveEvent(1, mDataProvider.getYdpi() * 3, 3));
mClassifier.onTouchEvent(appendUpEvent(1, mDataProvider.getYdpi() * 3, 300));
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 1).isFalse())
.isFalse();
}
}

View File

@@ -16,11 +16,12 @@
package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
@@ -72,7 +73,7 @@ public class ProximityClassifierTest extends ClassifierTest {
public void testPass_uncovered() {
touchDown();
touchUp(10);
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(false));
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
}
@Test
@@ -81,7 +82,7 @@ public class ProximityClassifierTest extends ClassifierTest {
mClassifier.onProximityEvent(createSensorEvent(true, 1));
mClassifier.onProximityEvent(createSensorEvent(false, 2));
touchUp(20);
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(false));
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
}
@Test
@@ -90,7 +91,17 @@ public class ProximityClassifierTest extends ClassifierTest {
mClassifier.onProximityEvent(createSensorEvent(true, 1));
mClassifier.onProximityEvent(createSensorEvent(false, 11));
touchUp(10);
assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse(), is(false));
assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse()).isFalse();
}
@Test
public void testPass_brightnessSlider() {
touchDown();
mClassifier.onProximityEvent(createSensorEvent(true, 1));
mClassifier.onProximityEvent(createSensorEvent(false, 11));
touchUp(10);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse())
.isFalse();
}
@Test
@@ -99,7 +110,7 @@ public class ProximityClassifierTest extends ClassifierTest {
mClassifier.onProximityEvent(createSensorEvent(true, 1));
mClassifier.onProximityEvent(createSensorEvent(false, 11));
touchUp(10);
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(true));
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
}
@Test
@@ -110,7 +121,7 @@ public class ProximityClassifierTest extends ClassifierTest {
mClassifier.onProximityEvent(createSensorEvent(true, 96));
mClassifier.onProximityEvent(createSensorEvent(false, 100));
touchUp(100);
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(true));
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
}
@Test
@@ -120,7 +131,7 @@ public class ProximityClassifierTest extends ClassifierTest {
mClassifier.onProximityEvent(createSensorEvent(false, 11));
touchUp(10);
when(mDistanceClassifier.isLongSwipe()).thenReturn(mPassedResult);
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(false));
assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
}
private void touchDown() {

View File

@@ -17,6 +17,7 @@
package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
@@ -277,4 +278,46 @@ public class TypeClassifierTest extends ClassifierTest {
when(mDataProvider.isRight()).thenReturn(true);
assertThat(mClassifier.classifyGesture(RIGHT_AFFORDANCE, 0.5, 0).isFalse()).isTrue();
}
@Test
public void testPass_BrightnessSlider() {
when(mDataProvider.isVertical()).thenReturn(false);
when(mDataProvider.isUp()).thenReturn(false); // up and right should cause no effect.
when(mDataProvider.isRight()).thenReturn(false);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isFalse();
when(mDataProvider.isUp()).thenReturn(true);
when(mDataProvider.isRight()).thenReturn(false);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isFalse();
when(mDataProvider.isUp()).thenReturn(false);
when(mDataProvider.isRight()).thenReturn(true);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isFalse();
when(mDataProvider.isUp()).thenReturn(true);
when(mDataProvider.isRight()).thenReturn(true);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isFalse();
}
@Test
public void testFalse_BrightnessSlider() {
when(mDataProvider.isVertical()).thenReturn(true);
when(mDataProvider.isUp()).thenReturn(false); // up and right should cause no effect.
when(mDataProvider.isRight()).thenReturn(false);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isTrue();
when(mDataProvider.isUp()).thenReturn(true);
when(mDataProvider.isRight()).thenReturn(false);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isTrue();
when(mDataProvider.isUp()).thenReturn(false);
when(mDataProvider.isRight()).thenReturn(true);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isTrue();
when(mDataProvider.isUp()).thenReturn(true);
when(mDataProvider.isRight()).thenReturn(true);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 0).isFalse()).isTrue();
}
}

View File

@@ -16,6 +16,8 @@
package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.google.common.truth.Truth.assertThat;
import android.testing.AndroidTestingRunner;
@@ -82,6 +84,13 @@ public class ZigZagClassifierTest extends ClassifierTest {
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
}
@Test
public void testPass_brightnessSliderAlwaysPasses() {
appendMoveEvent(0, 0);
appendMoveEvent(0, 100);
appendMoveEvent(0, 1);
assertThat(mClassifier.classifyGesture(BRIGHTNESS_SLIDER, 0.5, 1).isFalse()).isFalse();
}
@Test
public void testFail_minimumTouchesVertical() {

View File

@@ -25,6 +25,7 @@ import android.widget.SeekBar
import androidx.test.filters.SmallTest
import com.android.settingslib.RestrictedLockUtils
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.statusbar.policy.BrightnessMirrorController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
@@ -75,6 +76,7 @@ class BrightnessSliderTest : SysuiTestCase() {
private lateinit var checkedChangeCaptor: ArgumentCaptor<CompoundButton.OnCheckedChangeListener>
@Mock
private lateinit var compoundButton: CompoundButton
private var mFalsingManager: FalsingManagerFake = FalsingManagerFake()
private lateinit var mController: BrightnessSlider
@@ -85,7 +87,7 @@ class BrightnessSliderTest : SysuiTestCase() {
whenever(mirrorController.toggleSlider).thenReturn(mirror)
whenever(motionEvent.copy()).thenReturn(motionEvent)
mController = BrightnessSlider(rootView, brightnessSliderView, true)
mController = BrightnessSlider(rootView, brightnessSliderView, true, mFalsingManager)
mController.init()
mController.setOnChangedListener(listener)
}
@@ -160,7 +162,8 @@ class BrightnessSliderTest : SysuiTestCase() {
@Test
fun testSettingMirrorWhenNotUseMirrorIsNoOp() {
val otherController = BrightnessSlider(rootView, brightnessSliderView, false)
val otherController = BrightnessSlider(
rootView, brightnessSliderView, false, mFalsingManager)
otherController.init()
otherController.setMirrorControllerAndMirror(mirrorController)