Apply falsing manager on seekbar

Check false taps and touches on seekbar change listener whenever touch
is finished. This ensures that all falsing actions are handled besides
OnFling events that are handled.

Bug: 243040927
Test: manual
Test: atest SeekBarViewModelTest
Change-Id: I60bcc3196cc2a4b3410c7851f798bfaf87d9e456
This commit is contained in:
Michael Mikhail
2022-09-08 21:49:30 +00:00
parent 4e528edd31
commit a3495a193c
7 changed files with 57 additions and 10 deletions

View File

@@ -45,6 +45,7 @@ public abstract class Classifier {
public static final int QS_SWIPE_SIDE = 15;
public static final int BACK_GESTURE = 16;
public static final int QS_SWIPE_NESTED = 17;
public static final int MEDIA_SEEKBAR = 18;
@IntDef({
QUICK_SETTINGS,
@@ -65,7 +66,8 @@ public abstract class Classifier {
LOCK_ICON,
QS_SWIPE_SIDE,
QS_SWIPE_NESTED,
BACK_GESTURE
BACK_GESTURE,
MEDIA_SEEKBAR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InteractionType {}

View File

@@ -23,6 +23,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHT
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QS_SWIPE_NESTED;
import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
@@ -153,6 +154,7 @@ class DistanceClassifier extends FalsingClassifier {
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
if (interactionType == BRIGHTNESS_SLIDER
|| interactionType == MEDIA_SEEKBAR
|| interactionType == SHADE_DRAG
|| interactionType == QS_COLLAPSE
|| interactionType == Classifier.UDFPS_AUTHENTICATION

View File

@@ -18,6 +18,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.MEDIA_SEEKBAR;
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QS_SWIPE_SIDE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -119,7 +120,8 @@ class ProximityClassifier extends FalsingClassifier {
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
if (interactionType == QUICK_SETTINGS || interactionType == BRIGHTNESS_SLIDER
|| interactionType == QS_COLLAPSE || interactionType == QS_SWIPE_SIDE) {
|| interactionType == QS_COLLAPSE || interactionType == QS_SWIPE_SIDE
|| interactionType == MEDIA_SEEKBAR) {
return Result.passed(0);
}

View File

@@ -20,6 +20,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.MEDIA_SEEKBAR;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
import static com.android.systemui.classifier.Classifier.PULSE_EXPAND;
@@ -93,6 +94,10 @@ public class TypeClassifier extends FalsingClassifier {
case QS_SWIPE_NESTED:
wrongDirection = !vertical;
break;
case MEDIA_SEEKBAR:
confidence = 0;
wrongDirection = vertical;
break;
default:
wrongDirection = true;
break;

View File

@@ -22,6 +22,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHT
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.LOCK_ICON;
import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
import android.graphics.Point;
@@ -91,6 +92,7 @@ class ZigZagClassifier extends FalsingClassifier {
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
if (interactionType == BRIGHTNESS_SLIDER
|| interactionType == MEDIA_SEEKBAR
|| interactionType == SHADE_DRAG
|| interactionType == LOCK_ICON) {
return Result.passed(0);

View File

@@ -30,7 +30,10 @@ import androidx.annotation.WorkerThread
import androidx.core.view.GestureDetectorCompat
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.util.concurrency.RepeatableExecutor
import javax.inject.Inject
@@ -72,7 +75,8 @@ private fun PlaybackState.computePosition(duration: Long): Long {
/** ViewModel for seek bar in QS media player. */
class SeekBarViewModel @Inject constructor(
@Background private val bgExecutor: RepeatableExecutor
@Background private val bgExecutor: RepeatableExecutor,
private val falsingManager: FalsingManager,
) {
private var _data = Progress(false, false, false, false, null, 0)
set(value) {
@@ -275,7 +279,7 @@ class SeekBarViewModel @Inject constructor(
/** Gets a listener to attach to the seek bar to handle seeking. */
val seekBarListener: SeekBar.OnSeekBarChangeListener
get() {
return SeekBarChangeListener(this)
return SeekBarChangeListener(this, falsingManager)
}
/** Attach touch handlers to the seek bar view. */
@@ -315,7 +319,8 @@ class SeekBarViewModel @Inject constructor(
}
private class SeekBarChangeListener(
val viewModel: SeekBarViewModel
val viewModel: SeekBarViewModel,
val falsingManager: FalsingManager,
) : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(bar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
@@ -328,6 +333,13 @@ class SeekBarViewModel @Inject constructor(
}
override fun onStopTrackingTouch(bar: SeekBar) {
// in addition to the normal functionality of both functions.
// isFalseTouch returns true if there is a real/false tap since it is not a move.
// isFalseTap returns true if there is a real/false move since it is not a tap.
if (falsingManager.isFalseTouch(MEDIA_SEEKBAR) &&
falsingManager.isFalseTap(LOW_PENALTY)) {
viewModel.onSeekFalse()
}
viewModel.onSeek(bar.progress.toLong())
}
}
@@ -340,7 +352,7 @@ class SeekBarViewModel @Inject constructor(
*/
private class SeekBarTouchListener(
private val viewModel: SeekBarViewModel,
private val bar: SeekBar
private val bar: SeekBar,
) : View.OnTouchListener, GestureDetector.OnGestureListener {
// Gesture detector helps decide which touch events to intercept.

View File

@@ -26,13 +26,13 @@ import android.widget.SeekBar
import androidx.arch.core.executor.ArchTaskExecutor
import androidx.arch.core.executor.TaskExecutor
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.Classifier
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.FakeRepeatableExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -47,8 +47,8 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -70,6 +70,8 @@ public class SeekBarViewModelTest : SysuiTestCase() {
}
@Mock private lateinit var mockController: MediaController
@Mock private lateinit var mockTransport: MediaController.TransportControls
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var mockBar: SeekBar
private val token1 = MediaSession.Token(1, null)
private val token2 = MediaSession.Token(2, null)
@@ -78,9 +80,10 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Before
fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock())
viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor))
viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor), falsingManager)
viewModel.logSeek = { }
whenever(mockController.sessionToken).thenReturn(token1)
whenever(mockBar.context).thenReturn(context)
// LiveData to run synchronously
ArchTaskExecutor.getInstance().setDelegate(taskExecutor)
@@ -453,6 +456,25 @@ public class SeekBarViewModelTest : SysuiTestCase() {
verify(mockTransport).seekTo(eq(pos.toLong()))
}
@Test
fun onFalseTapOrTouch() {
whenever(mockController.getTransportControls()).thenReturn(mockTransport)
whenever(falsingManager.isFalseTouch(Classifier.MEDIA_SEEKBAR)).thenReturn(true)
whenever(falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)).thenReturn(true)
viewModel.updateController(mockController)
val pos = 169
viewModel.attachTouchHandlers(mockBar)
with(viewModel.seekBarListener) {
onStartTrackingTouch(mockBar)
onProgressChanged(mockBar, pos, true)
onStopTrackingTouch(mockBar)
}
// THEN transport controls should not be used
verify(mockTransport, never()).seekTo(pos.toLong())
}
@Test
fun queuePollTaskWhenPlaying() {
// GIVEN that the track is playing