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

Commit ae03aa54 authored by Michael Mikhail's avatar Michael Mikhail Committed by Automerger Merge Worker
Browse files

Merge "Add falsing to undo button" into tm-qpr-dev am: a1700296

parents 1d178b3b a1700296
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@
<!-- Wrap in a frame layout so that we can update the margins on the inner layout. (Since this view
<!-- Wrap in a frame layout so that we can update the margins on the inner layout. (Since this view
     is the root view of a window, we cannot change the root view's margins.) -->
     is the root view of a window, we cannot change the root view's margins.) -->
<!-- Alphas start as 0 because the view will be animated in. -->
<!-- Alphas start as 0 because the view will be animated in. -->
<FrameLayout
<com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    android:id="@+id/media_ttt_sender_chip"
    android:id="@+id/media_ttt_sender_chip"
@@ -97,4 +97,4 @@
            />
            />


    </LinearLayout>
    </LinearLayout>
</FrameLayout>
</com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView>
+11 −3
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import androidx.annotation.StringRes
import com.android.internal.logging.UiEventLogger
import com.android.internal.logging.UiEventLogger
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS


/**
/**
@@ -107,12 +108,15 @@ enum class ChipStateSender(
            controllerSender: MediaTttChipControllerSender,
            controllerSender: MediaTttChipControllerSender,
            routeInfo: MediaRoute2Info,
            routeInfo: MediaRoute2Info,
            undoCallback: IUndoMediaTransferCallback?,
            undoCallback: IUndoMediaTransferCallback?,
            uiEventLogger: MediaTttSenderUiEventLogger
            uiEventLogger: MediaTttSenderUiEventLogger,
            falsingManager: FalsingManager,
        ): View.OnClickListener? {
        ): View.OnClickListener? {
            if (undoCallback == null) {
            if (undoCallback == null) {
                return null
                return null
            }
            }
            return View.OnClickListener {
            return View.OnClickListener {
                if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@OnClickListener

                uiEventLogger.logUndoClicked(
                uiEventLogger.logUndoClicked(
                    MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED
                    MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED
                )
                )
@@ -143,12 +147,15 @@ enum class ChipStateSender(
            controllerSender: MediaTttChipControllerSender,
            controllerSender: MediaTttChipControllerSender,
            routeInfo: MediaRoute2Info,
            routeInfo: MediaRoute2Info,
            undoCallback: IUndoMediaTransferCallback?,
            undoCallback: IUndoMediaTransferCallback?,
            uiEventLogger: MediaTttSenderUiEventLogger
            uiEventLogger: MediaTttSenderUiEventLogger,
            falsingManager: FalsingManager,
        ): View.OnClickListener? {
        ): View.OnClickListener? {
            if (undoCallback == null) {
            if (undoCallback == null) {
                return null
                return null
            }
            }
            return View.OnClickListener {
            return View.OnClickListener {
                if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@OnClickListener

                uiEventLogger.logUndoClicked(
                uiEventLogger.logUndoClicked(
                    MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
                    MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
                )
                )
@@ -215,7 +222,8 @@ enum class ChipStateSender(
        controllerSender: MediaTttChipControllerSender,
        controllerSender: MediaTttChipControllerSender,
        routeInfo: MediaRoute2Info,
        routeInfo: MediaRoute2Info,
        undoCallback: IUndoMediaTransferCallback?,
        undoCallback: IUndoMediaTransferCallback?,
        uiEventLogger: MediaTttSenderUiEventLogger
        uiEventLogger: MediaTttSenderUiEventLogger,
        falsingManager: FalsingManager,
    ): View.OnClickListener? = null
    ): View.OnClickListener? = null


    companion object {
    companion object {
+27 −2
Original line number Original line Diff line number Diff line
@@ -22,25 +22,30 @@ import android.media.MediaRoute2Info
import android.os.PowerManager
import android.os.PowerManager
import android.util.Log
import android.util.Log
import android.view.Gravity
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
import android.view.WindowManager
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import android.view.accessibility.AccessibilityManager
import android.widget.TextView
import android.widget.TextView
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.common.MediaTttUtils
import com.android.systemui.media.taptotransfer.common.MediaTttUtils
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
import javax.inject.Inject
import javax.inject.Inject


/**
/**
@@ -57,7 +62,11 @@ class MediaTttChipControllerSender @Inject constructor(
        accessibilityManager: AccessibilityManager,
        accessibilityManager: AccessibilityManager,
        configurationController: ConfigurationController,
        configurationController: ConfigurationController,
        powerManager: PowerManager,
        powerManager: PowerManager,
        private val uiEventLogger: MediaTttSenderUiEventLogger
        private val uiEventLogger: MediaTttSenderUiEventLogger,
        // Added Lazy<> to delay the time we create Falsing instances.
        // And overcome performance issue, check [b/247817628] for details.
        private val falsingManager: Lazy<FalsingManager>,
        private val falsingCollector: Lazy<FalsingCollector>,
) : TemporaryViewDisplayController<ChipSenderInfo, MediaTttLogger>(
) : TemporaryViewDisplayController<ChipSenderInfo, MediaTttLogger>(
        context,
        context,
        logger,
        logger,
@@ -70,6 +79,9 @@ class MediaTttChipControllerSender @Inject constructor(
        MediaTttUtils.WINDOW_TITLE,
        MediaTttUtils.WINDOW_TITLE,
        MediaTttUtils.WAKE_REASON,
        MediaTttUtils.WAKE_REASON,
) {
) {

    private lateinit var parent: MediaTttChipRootView

    override val windowLayoutParams = commonWindowLayoutParams.apply {
    override val windowLayoutParams = commonWindowLayoutParams.apply {
        gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
        gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
    }
    }
@@ -120,6 +132,15 @@ class MediaTttChipControllerSender @Inject constructor(


        val chipState = newInfo.state
        val chipState = newInfo.state


        // Detect falsing touches on the chip.
        parent = currentView.requireViewById(R.id.media_ttt_sender_chip)
        parent.touchHandler = object : Gefingerpoken {
            override fun onTouchEvent(ev: MotionEvent?): Boolean {
                falsingCollector.get().onTouchEvent(ev)
                return false
            }
        }

        // App icon
        // App icon
        val iconInfo = MediaTttUtils.getIconInfoFromPackageName(
        val iconInfo = MediaTttUtils.getIconInfoFromPackageName(
            context, newInfo.routeInfo.clientPackageName, logger
            context, newInfo.routeInfo.clientPackageName, logger
@@ -142,7 +163,11 @@ class MediaTttChipControllerSender @Inject constructor(
        // Undo
        // Undo
        val undoView = currentView.requireViewById<View>(R.id.undo)
        val undoView = currentView.requireViewById<View>(R.id.undo)
        val undoClickListener = chipState.undoClickListener(
        val undoClickListener = chipState.undoClickListener(
                this, newInfo.routeInfo, newInfo.undoCallback, uiEventLogger
                this,
                newInfo.routeInfo,
                newInfo.undoCallback,
                uiEventLogger,
                falsingManager.get(),
        )
        )
        undoView.setOnClickListener(undoClickListener)
        undoView.setOnClickListener(undoClickListener)
        undoView.visibility = (undoClickListener != null).visibleIfTrue()
        undoView.visibility = (undoClickListener != null).visibleIfTrue()
+38 −0
Original line number Original line Diff line number Diff line
/*
 * 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.media.taptotransfer.sender

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout
import com.android.systemui.Gefingerpoken

/** A simple subclass that allows for observing touch events on chip. */
class MediaTttChipRootView(
        context: Context,
        attrs: AttributeSet?
) : FrameLayout(context, attrs) {

    /** Assign this field to observe touch events. */
    var touchHandler: Gefingerpoken? = null

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        touchHandler?.onTouchEvent(ev)
        return super.dispatchTouchEvent(ev)
    }
}
+49 −1
Original line number Original line Diff line number Diff line
@@ -35,7 +35,9 @@ import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.FakeExecutor
@@ -43,10 +45,12 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import dagger.Lazy
import org.junit.Before
import org.junit.Before
import org.junit.Test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verify
@@ -75,6 +79,14 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
    private lateinit var windowManager: WindowManager
    private lateinit var windowManager: WindowManager
    @Mock
    @Mock
    private lateinit var commandQueue: CommandQueue
    private lateinit var commandQueue: CommandQueue
    @Mock
    private lateinit var lazyFalsingManager: Lazy<FalsingManager>
    @Mock
    private lateinit var falsingManager: FalsingManager
    @Mock
    private lateinit var lazyFalsingCollector: Lazy<FalsingCollector>
    @Mock
    private lateinit var falsingCollector: FalsingCollector
    private lateinit var commandQueueCallback: CommandQueue.Callbacks
    private lateinit var commandQueueCallback: CommandQueue.Callbacks
    private lateinit var fakeAppIconDrawable: Drawable
    private lateinit var fakeAppIconDrawable: Drawable
    private lateinit var fakeClock: FakeSystemClock
    private lateinit var fakeClock: FakeSystemClock
@@ -101,6 +113,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
        senderUiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake)
        senderUiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake)


        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT)
        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT)
        whenever(lazyFalsingManager.get()).thenReturn(falsingManager)
        whenever(lazyFalsingCollector.get()).thenReturn(falsingCollector)


        controllerSender = MediaTttChipControllerSender(
        controllerSender = MediaTttChipControllerSender(
            commandQueue,
            commandQueue,
@@ -111,7 +125,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
            accessibilityManager,
            accessibilityManager,
            configurationController,
            configurationController,
            powerManager,
            powerManager,
            senderUiEventLogger
            senderUiEventLogger,
            lazyFalsingManager,
            lazyFalsingCollector
        )
        )


        val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
        val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
@@ -416,6 +432,38 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
        assertThat(undoCallbackCalled).isTrue()
        assertThat(undoCallbackCalled).isTrue()
    }
    }


    @Test
    fun transferToReceiverSucceeded_withUndoRunnable_falseTap_callbackNotRun() {
        whenever(lazyFalsingManager.get().isFalseTap(anyInt())).thenReturn(true)
        var undoCallbackCalled = false
        val undoCallback = object : IUndoMediaTransferCallback.Stub() {
            override fun onUndoTriggered() {
                undoCallbackCalled = true
            }
        }

        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
        getChipView().getUndoButton().performClick()

        assertThat(undoCallbackCalled).isFalse()
    }

    @Test
    fun transferToReceiverSucceeded_withUndoRunnable_realTap_callbackRun() {
        whenever(lazyFalsingManager.get().isFalseTap(anyInt())).thenReturn(false)
        var undoCallbackCalled = false
        val undoCallback = object : IUndoMediaTransferCallback.Stub() {
            override fun onUndoTriggered() {
                undoCallbackCalled = true
            }
        }

        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
        getChipView().getUndoButton().performClick()

        assertThat(undoCallbackCalled).isTrue()
    }

    @Test
    @Test
    fun transferToReceiverSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggered() {
    fun transferToReceiverSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggered() {
        val undoCallback = object : IUndoMediaTransferCallback.Stub() {
        val undoCallback = object : IUndoMediaTransferCallback.Stub() {