Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e9c5aac authored by Michael Mikhail's avatar Michael Mikhail Committed by Android (Google) Code Review
Browse files

Merge "Cancel vertical seekbar grab" into udc-dev

parents 3b2fc2f3 fd2c9fba
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.view.View
import android.view.ViewConfiguration
import android.widget.SeekBar
import androidx.annotation.AnyThread
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import androidx.core.view.GestureDetectorCompat
import androidx.lifecycle.LiveData
@@ -37,6 +38,7 @@ import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.util.concurrency.RepeatableExecutor
import javax.inject.Inject
import kotlin.math.abs

private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L
private const val MIN_FLING_VELOCITY_SCALE_FACTOR = 10
@@ -325,6 +327,10 @@ constructor(
            return SeekBarChangeListener(this, falsingManager)
        }

    /** first and last motion events of seekbar grab. */
    @VisibleForTesting var firstMotionEvent: MotionEvent? = null
    @VisibleForTesting var lastMotionEvent: MotionEvent? = null

    /** Attach touch handlers to the seek bar view. */
    fun attachTouchHandlers(bar: SeekBar) {
        bar.setOnSeekBarChangeListener(seekBarListener)
@@ -351,6 +357,23 @@ constructor(
        }
    }

    /**
     * This method specifies if user made a bad seekbar grab or not. If the vertical distance from
     * first touch on seekbar is more than the horizontal distance, this means that the seekbar grab
     * is more vertical and should be rejected. Seekbar accepts horizontal grabs only.
     *
     * Single tap has the same first and last motion event, it is counted as a valid grab.
     *
     * @return whether the touch on seekbar is valid.
     */
    private fun isValidSeekbarGrab(): Boolean {
        if (firstMotionEvent == null || lastMotionEvent == null) {
            return true
        }
        return abs(firstMotionEvent!!.x - lastMotionEvent!!.x) >=
            abs(firstMotionEvent!!.y - lastMotionEvent!!.y)
    }

    /** Listener interface to be notified when the user starts or stops scrubbing. */
    interface ScrubbingChangeListener {
        fun onScrubbingChanged(scrubbing: Boolean)
@@ -376,7 +399,7 @@ constructor(
        }

        override fun onStopTrackingTouch(bar: SeekBar) {
            if (falsingManager.isFalseTouch(MEDIA_SEEKBAR)) {
            if (!viewModel.isValidSeekbarGrab() || falsingManager.isFalseTouch(MEDIA_SEEKBAR)) {
                viewModel.onSeekFalse()
            }
            viewModel.onSeek(bar.progress.toLong())
@@ -424,6 +447,8 @@ constructor(
                return false
            }
            detector.onTouchEvent(event)
            // Store the last motion event done on seekbar.
            viewModel.lastMotionEvent = event.copy()
            return !shouldGoToSeekBar
        }

@@ -468,6 +493,8 @@ constructor(
            if (shouldGoToSeekBar) {
                bar.parent?.requestDisallowInterceptTouchEvent(true)
            }
            // Store the first motion event done on seekbar.
            viewModel.firstMotionEvent = event.copy()
            return shouldGoToSeekBar
        }

+48 −5
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.MotionEvent
import android.widget.SeekBar
import androidx.arch.core.executor.ArchTaskExecutor
import androidx.arch.core.executor.TaskExecutor
@@ -466,20 +467,62 @@ public class SeekBarViewModelTest : SysuiTestCase() {
        whenever(mockController.getTransportControls()).thenReturn(mockTransport)
        whenever(falsingManager.isFalseTouch(Classifier.MEDIA_SEEKBAR)).thenReturn(true)
        whenever(falsingManager.isFalseTap(anyInt())).thenReturn(true)

        viewModel.updateController(mockController)
        val pos = 169
        val pos = 40
        val bar = SeekBar(context).apply { progress = pos }
        with(viewModel.seekBarListener) {
            onStartTrackingTouch(bar)
            onStopTrackingTouch(bar)
        }
        fakeExecutor.runAllReady()

        // THEN transport controls should not be used
        verify(mockTransport, never()).seekTo(pos.toLong())
    }

    @Test
    fun onSeekbarGrabInvalidTouch() {
        whenever(mockController.getTransportControls()).thenReturn(mockTransport)
        viewModel.firstMotionEvent =
            MotionEvent.obtain(12L, 13L, MotionEvent.ACTION_DOWN, 76F, 0F, 0)
        viewModel.lastMotionEvent = MotionEvent.obtain(12L, 14L, MotionEvent.ACTION_UP, 78F, 4F, 0)
        val pos = 78

        viewModel.attachTouchHandlers(mockBar)
        viewModel.updateController(mockController)
        // WHEN user ends drag
        val bar = SeekBar(context).apply { progress = pos }
        with(viewModel.seekBarListener) {
            onStartTrackingTouch(mockBar)
            onProgressChanged(mockBar, pos, true)
            onStopTrackingTouch(mockBar)
            onStartTrackingTouch(bar)
            onStopTrackingTouch(bar)
        }
        fakeExecutor.runAllReady()

        // THEN transport controls should not be used
        verify(mockTransport, never()).seekTo(pos.toLong())
    }

    @Test
    fun onSeekbarGrabValidTouch() {
        whenever(mockController.transportControls).thenReturn(mockTransport)
        viewModel.firstMotionEvent =
            MotionEvent.obtain(12L, 13L, MotionEvent.ACTION_DOWN, 36F, 0F, 0)
        viewModel.lastMotionEvent = MotionEvent.obtain(12L, 14L, MotionEvent.ACTION_UP, 40F, 1F, 0)
        val pos = 40

        viewModel.updateController(mockController)
        // WHEN user ends drag
        val bar = SeekBar(context).apply { progress = pos }
        with(viewModel.seekBarListener) {
            onStartTrackingTouch(bar)
            onStopTrackingTouch(bar)
        }
        fakeExecutor.runAllReady()

        // THEN transport controls should be used
        verify(mockTransport).seekTo(pos.toLong())
    }

    @Test
    fun queuePollTaskWhenPlaying() {
        // GIVEN that the track is playing