Merge changes I28706e2e,I0af8480c into tm-qpr-dev

* changes:
  [Chipbar] Move the Media TTT callback listener to a media-specific coordinator class.
  [Chipbar] Rename MediaTttChipControllerSender to ChipbarCoordinator, since it has all the chipbar logic.
This commit is contained in:
TreeHugger Robot
2022-10-18 08:00:17 +00:00
committed by Android (Google) Code Review
15 changed files with 754 additions and 438 deletions

View File

@@ -246,8 +246,6 @@
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt -packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt -packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt -packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt -packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt -packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt
-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt -packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
@@ -528,6 +526,8 @@
-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt -packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt -packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt -packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
-packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
-packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarRootView.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt -packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt -packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
-packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt -packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
@@ -678,7 +678,6 @@
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt -packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt -packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
@@ -833,6 +832,7 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt

View File

@@ -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. -->
<com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView <com.android.systemui.temporarydisplay.chipbar.ChipbarRootView
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>
</com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView> </com.android.systemui.temporarydisplay.chipbar.ChipbarRootView>

View File

@@ -34,13 +34,14 @@ import com.android.systemui.log.SessionTracker
import com.android.systemui.media.RingtonePlayer import com.android.systemui.media.RingtonePlayer
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender import com.android.systemui.media.taptotransfer.sender.MediaTttSenderCoordinator
import com.android.systemui.power.PowerUI import com.android.systemui.power.PowerUI
import com.android.systemui.recents.Recents import com.android.systemui.recents.Recents
import com.android.systemui.settings.dagger.MultiUserUtilsModule import com.android.systemui.settings.dagger.MultiUserUtilsModule
import com.android.systemui.shortcut.ShortcutKeyDispatcher import com.android.systemui.shortcut.ShortcutKeyDispatcher
import com.android.systemui.statusbar.notification.InstantAppNotifier import com.android.systemui.statusbar.notification.InstantAppNotifier
import com.android.systemui.statusbar.phone.KeyguardLiftController import com.android.systemui.statusbar.phone.KeyguardLiftController
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.theme.ThemeOverlayController import com.android.systemui.theme.ThemeOverlayController
import com.android.systemui.toast.ToastUI import com.android.systemui.toast.ToastUI
import com.android.systemui.usb.StorageNotification import com.android.systemui.usb.StorageNotification
@@ -217,6 +218,12 @@ abstract class SystemUICoreStartableModule {
@ClassKey(KeyguardLiftController::class) @ClassKey(KeyguardLiftController::class)
abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
/** Inject into MediaTttSenderCoordinator. */
@Binds
@IntoMap
@ClassKey(MediaTttSenderCoordinator::class)
abstract fun bindMediaTttSenderCoordinator(sysui: MediaTttSenderCoordinator): CoreStartable
/** Inject into MediaTttChipControllerReceiver. */ /** Inject into MediaTttChipControllerReceiver. */
@Binds @Binds
@IntoMap @IntoMap
@@ -225,17 +232,15 @@ abstract class SystemUICoreStartableModule {
sysui: MediaTttChipControllerReceiver sysui: MediaTttChipControllerReceiver
): CoreStartable ): CoreStartable
/** Inject into MediaTttChipControllerSender. */
@Binds
@IntoMap
@ClassKey(MediaTttChipControllerSender::class)
abstract fun bindMediaTttChipControllerSender(
sysui: MediaTttChipControllerSender
): CoreStartable
/** Inject into MediaTttCommandLineHelper. */ /** Inject into MediaTttCommandLineHelper. */
@Binds @Binds
@IntoMap @IntoMap
@ClassKey(MediaTttCommandLineHelper::class) @ClassKey(MediaTttCommandLineHelper::class)
abstract fun bindMediaTttCommandLineHelper(sysui: MediaTttCommandLineHelper): CoreStartable abstract fun bindMediaTttCommandLineHelper(sysui: MediaTttCommandLineHelper): CoreStartable
/** Inject into ChipbarCoordinator. */
@Binds
@IntoMap
@ClassKey(ChipbarCoordinator::class)
abstract fun bindChipbarController(sysui: ChipbarCoordinator): CoreStartable
} }

View File

@@ -31,9 +31,7 @@ import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper; import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.MediaTttFlags; import com.android.systemui.media.taptotransfer.MediaTttFlags;
import com.android.systemui.media.taptotransfer.common.MediaTttLogger; import com.android.systemui.media.taptotransfer.common.MediaTttLogger;
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger; import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger;
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger; import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger;
import java.util.Optional; import java.util.Optional;
@@ -94,30 +92,6 @@ public interface MediaModule {
return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager); return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager);
} }
/** */
@Provides
@SysUISingleton
static Optional<MediaTttChipControllerSender> providesMediaTttChipControllerSender(
MediaTttFlags mediaTttFlags,
Lazy<MediaTttChipControllerSender> controllerSenderLazy) {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
}
return Optional.of(controllerSenderLazy.get());
}
/** */
@Provides
@SysUISingleton
static Optional<MediaTttChipControllerReceiver> providesMediaTttChipControllerReceiver(
MediaTttFlags mediaTttFlags,
Lazy<MediaTttChipControllerReceiver> controllerReceiverLazy) {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
}
return Optional.of(controllerReceiverLazy.get());
}
@Provides @Provides
@SysUISingleton @SysUISingleton
@MediaTttSenderLogger @MediaTttSenderLogger

View File

@@ -41,3 +41,5 @@ in the `receiver` package, and code that's shared between them is in the `common
## Testing ## Testing
If you want to test out the tap-to-transfer chip without using the `@SystemApi`s, you can use adb If you want to test out the tap-to-transfer chip without using the `@SystemApi`s, you can use adb
commands instead. Refer to `MediaTttCommandLineHelper` for information about adb commands. commands instead. Refer to `MediaTttCommandLineHelper` for information about adb commands.
TODO(b/245610654): Update this page once the chipbar migration is complete.

View File

@@ -36,6 +36,7 @@ import com.android.settingslib.Utils
import com.android.systemui.R import com.android.systemui.R
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.MediaTttFlags
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.statusbar.CommandQueue import com.android.systemui.statusbar.CommandQueue
@@ -52,6 +53,8 @@ import javax.inject.Inject
* A controller to display and hide the Media Tap-To-Transfer chip on the **receiving** device. * A controller to display and hide the Media Tap-To-Transfer chip on the **receiving** device.
* *
* This chip is shown when a user is transferring media to/from a sending device and this device. * This chip is shown when a user is transferring media to/from a sending device and this device.
*
* TODO(b/245610654): Re-name this to be MediaTttReceiverCoordinator.
*/ */
@SysUISingleton @SysUISingleton
class MediaTttChipControllerReceiver @Inject constructor( class MediaTttChipControllerReceiver @Inject constructor(
@@ -64,6 +67,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
configurationController: ConfigurationController, configurationController: ConfigurationController,
powerManager: PowerManager, powerManager: PowerManager,
@Main private val mainHandler: Handler, @Main private val mainHandler: Handler,
private val mediaTttFlags: MediaTttFlags,
private val uiEventLogger: MediaTttReceiverUiEventLogger, private val uiEventLogger: MediaTttReceiverUiEventLogger,
private val viewUtil: ViewUtil, private val viewUtil: ViewUtil,
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>( ) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>(
@@ -118,7 +122,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
uiEventLogger.logReceiverStateChange(chipState) uiEventLogger.logReceiverStateChange(chipState)
if (chipState == ChipStateReceiver.FAR_FROM_SENDER) { if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!) removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER.name)
return return
} }
if (appIcon == null) { if (appIcon == null) {
@@ -138,8 +142,10 @@ class MediaTttChipControllerReceiver @Inject constructor(
} }
override fun start() { override fun start() {
if (mediaTttFlags.isMediaTttEnabled()) {
commandQueue.addCallback(commandQueueCallbacks) commandQueue.addCallback(commandQueueCallbacks)
} }
}
override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) { override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
val iconInfo = MediaTttUtils.getIconInfoFromPackageName( val iconInfo = MediaTttUtils.getIconInfoFromPackageName(

View File

@@ -27,6 +27,8 @@ 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.plugins.FalsingManager
import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
import com.android.systemui.temporarydisplay.chipbar.ChipSenderInfo
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
/** /**
* A class enumerating all the possible states of the media tap-to-transfer chip on the sender * A class enumerating all the possible states of the media tap-to-transfer chip on the sender
@@ -105,7 +107,7 @@ enum class ChipStateSender(
transferStatus = TransferStatus.SUCCEEDED, transferStatus = TransferStatus.SUCCEEDED,
) { ) {
override fun undoClickListener( override fun undoClickListener(
controllerSender: MediaTttChipControllerSender, chipbarCoordinator: ChipbarCoordinator,
routeInfo: MediaRoute2Info, routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?, undoCallback: IUndoMediaTransferCallback?,
uiEventLogger: MediaTttSenderUiEventLogger, uiEventLogger: MediaTttSenderUiEventLogger,
@@ -125,7 +127,7 @@ enum class ChipStateSender(
// state, but that may take too long to go through the binder and the user may be // state, but that may take too long to go through the binder and the user may be
// confused as to why the UI hasn't changed yet. So, we immediately change the UI // confused as to why the UI hasn't changed yet. So, we immediately change the UI
// here. // here.
controllerSender.displayView( chipbarCoordinator.displayView(
ChipSenderInfo( ChipSenderInfo(
TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback
) )
@@ -144,7 +146,7 @@ enum class ChipStateSender(
transferStatus = TransferStatus.SUCCEEDED, transferStatus = TransferStatus.SUCCEEDED,
) { ) {
override fun undoClickListener( override fun undoClickListener(
controllerSender: MediaTttChipControllerSender, chipbarCoordinator: ChipbarCoordinator,
routeInfo: MediaRoute2Info, routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?, undoCallback: IUndoMediaTransferCallback?,
uiEventLogger: MediaTttSenderUiEventLogger, uiEventLogger: MediaTttSenderUiEventLogger,
@@ -164,7 +166,7 @@ enum class ChipStateSender(
// state, but that may take too long to go through the binder and the user may be // state, but that may take too long to go through the binder and the user may be
// confused as to why the UI hasn't changed yet. So, we immediately change the UI // confused as to why the UI hasn't changed yet. So, we immediately change the UI
// here. // here.
controllerSender.displayView( chipbarCoordinator.displayView(
ChipSenderInfo( ChipSenderInfo(
TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback
) )
@@ -213,13 +215,13 @@ enum class ChipStateSender(
* Returns a click listener for the undo button on the chip. Returns null if this chip state * Returns a click listener for the undo button on the chip. Returns null if this chip state
* doesn't have an undo button. * doesn't have an undo button.
* *
* @param controllerSender passed as a parameter in case we want to display a new chip state * @param chipbarCoordinator passed as a parameter in case we want to display a new chipbar
* when undo is clicked. * when undo is clicked.
* @param undoCallback if present, the callback that should be called when the user clicks the * @param undoCallback if present, the callback that should be called when the user clicks the
* undo button. The undo button will only be shown if this is non-null. * undo button. The undo button will only be shown if this is non-null.
*/ */
open fun undoClickListener( open fun undoClickListener(
controllerSender: MediaTttChipControllerSender, chipbarCoordinator: ChipbarCoordinator,
routeInfo: MediaRoute2Info, routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?, undoCallback: IUndoMediaTransferCallback?,
uiEventLogger: MediaTttSenderUiEventLogger, uiEventLogger: MediaTttSenderUiEventLogger,

View File

@@ -0,0 +1,92 @@
/*
* 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.app.StatusBarManager
import android.content.Context
import android.media.MediaRoute2Info
import android.util.Log
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.temporarydisplay.chipbar.ChipSenderInfo
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.SENDER_TAG
import javax.inject.Inject
/**
* A coordinator for showing/hiding the Media Tap-To-Transfer UI on the **sending** device. This UI
* is shown when a user is transferring media to/from this device and a receiver device.
*/
@SysUISingleton
class MediaTttSenderCoordinator
@Inject
constructor(
private val chipbarCoordinator: ChipbarCoordinator,
private val commandQueue: CommandQueue,
private val context: Context,
@MediaTttSenderLogger private val logger: MediaTttLogger,
private val mediaTttFlags: MediaTttFlags,
private val uiEventLogger: MediaTttSenderUiEventLogger,
) : CoreStartable {
private val commandQueueCallbacks =
object : CommandQueue.Callbacks {
override fun updateMediaTapToTransferSenderDisplay(
@StatusBarManager.MediaTransferSenderState displayState: Int,
routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?
) {
this@MediaTttSenderCoordinator.updateMediaTapToTransferSenderDisplay(
displayState,
routeInfo,
undoCallback
)
}
}
override fun start() {
if (mediaTttFlags.isMediaTttEnabled()) {
commandQueue.addCallback(commandQueueCallbacks)
}
}
private fun updateMediaTapToTransferSenderDisplay(
@StatusBarManager.MediaTransferSenderState displayState: Int,
routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?
) {
val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState)
val stateName = chipState?.name ?: "Invalid"
logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName)
if (chipState == null) {
Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
return
}
uiEventLogger.logSenderStateChange(chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
chipbarCoordinator.removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER.name)
} else {
chipbarCoordinator.displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
}
}
}

View File

@@ -14,14 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.systemui.media.taptotransfer.sender package com.android.systemui.temporarydisplay.chipbar
import android.app.StatusBarManager
import android.content.Context import android.content.Context
import android.graphics.Rect import android.graphics.Rect
import android.media.MediaRoute2Info import android.media.MediaRoute2Info
import android.os.PowerManager import android.os.PowerManager
import android.util.Log
import android.view.Gravity import android.view.Gravity
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
@@ -40,8 +38,11 @@ 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.media.taptotransfer.sender.ChipStateSender
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEventLogger
import com.android.systemui.media.taptotransfer.sender.TransferStatus
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
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
@@ -51,12 +52,26 @@ import com.android.systemui.util.view.ViewUtil
import javax.inject.Inject import javax.inject.Inject
/** /**
* A controller to display and hide the Media Tap-To-Transfer chip on the **sending** device. This * A coordinator for showing/hiding the chipbar.
* chip is shown when a user is transferring media to/from this device and a receiver device. *
* The chipbar is a UI element that displays on top of all content. It appears at the top of the
* screen and consists of an icon, one line of text, and an optional end icon or action. It will
* auto-dismiss after some amount of seconds. The user is *not* able to manually dismiss the
* chipbar.
*
* It should be only be used for critical and temporary information that the user *must* be aware
* of. In general, prefer using heads-up notifications, since they are dismissable and will remain
* in the list of notifications until the user dismisses them.
*
* Only one chipbar may be shown at a time.
* TODO(b/245610654): Should we just display whichever chipbar was most recently requested, or do we
* need to maintain a priority ordering?
*
* TODO(b/245610654): Remove all media-related items from this class so it's just for generic
* chipbars.
*/ */
@SysUISingleton @SysUISingleton
open class MediaTttChipControllerSender @Inject constructor( open class ChipbarCoordinator @Inject constructor(
private val commandQueue: CommandQueue,
context: Context, context: Context,
@MediaTttSenderLogger logger: MediaTttLogger, @MediaTttSenderLogger logger: MediaTttLogger,
windowManager: WindowManager, windowManager: WindowManager,
@@ -76,59 +91,25 @@ open class MediaTttChipControllerSender @Inject constructor(
accessibilityManager, accessibilityManager,
configurationController, configurationController,
powerManager, powerManager,
R.layout.media_ttt_chip, R.layout.chipbar,
MediaTttUtils.WINDOW_TITLE, MediaTttUtils.WINDOW_TITLE,
MediaTttUtils.WAKE_REASON, MediaTttUtils.WAKE_REASON,
) { ) {
private lateinit var parent: MediaTttChipRootView private lateinit var parent: ChipbarRootView
override val windowLayoutParams = commonWindowLayoutParams.apply { override val windowLayoutParams = commonWindowLayoutParams.apply {
gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
} }
private val commandQueueCallbacks = object : CommandQueue.Callbacks { override fun start() {}
override fun updateMediaTapToTransferSenderDisplay(
@StatusBarManager.MediaTransferSenderState displayState: Int,
routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?
) {
this@MediaTttChipControllerSender.updateMediaTapToTransferSenderDisplay(
displayState, routeInfo, undoCallback
)
}
}
private fun updateMediaTapToTransferSenderDisplay(
@StatusBarManager.MediaTransferSenderState displayState: Int,
routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?
) {
val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState)
val stateName = chipState?.name ?: "Invalid"
logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName)
if (chipState == null) {
Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
return
}
uiEventLogger.logSenderStateChange(chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER.name)
} else {
displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
}
}
override fun start() {
commandQueue.addCallback(commandQueueCallbacks)
}
override fun updateView( override fun updateView(
newInfo: ChipSenderInfo, newInfo: ChipSenderInfo,
currentView: ViewGroup currentView: ViewGroup
) { ) {
// TODO(b/245610654): Adding logging here.
val chipState = newInfo.state val chipState = newInfo.state
// Detect falsing touches on the chip. // Detect falsing touches on the chip.

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.systemui.media.taptotransfer.sender package com.android.systemui.temporarydisplay.chipbar
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
@@ -22,8 +22,8 @@ import android.view.MotionEvent
import android.widget.FrameLayout import android.widget.FrameLayout
import com.android.systemui.Gefingerpoken import com.android.systemui.Gefingerpoken
/** A simple subclass that allows for observing touch events on chip. */ /** A simple subclass that allows for observing touch events on chipbar. */
class MediaTttChipRootView( class ChipbarRootView(
context: Context, context: Context,
attrs: AttributeSet? attrs: AttributeSet?
) : FrameLayout(context, attrs) { ) : FrameLayout(context, attrs) {

View File

@@ -34,6 +34,7 @@ import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.media.taptotransfer.common.MediaTttLogger
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
@@ -49,6 +50,7 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor import org.mockito.ArgumentCaptor
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.never import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@@ -70,6 +72,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
@Mock @Mock
private lateinit var configurationController: ConfigurationController private lateinit var configurationController: ConfigurationController
@Mock @Mock
private lateinit var mediaTttFlags: MediaTttFlags
@Mock
private lateinit var powerManager: PowerManager private lateinit var powerManager: PowerManager
@Mock @Mock
private lateinit var viewUtil: ViewUtil private lateinit var viewUtil: ViewUtil
@@ -85,6 +89,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(true)
fakeAppIconDrawable = context.getDrawable(R.drawable.ic_cake)!! fakeAppIconDrawable = context.getDrawable(R.drawable.ic_cake)!!
whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(fakeAppIconDrawable) whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(fakeAppIconDrawable)
@@ -107,6 +112,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
configurationController, configurationController,
powerManager, powerManager,
Handler.getMain(), Handler.getMain(),
mediaTttFlags,
receiverUiEventLogger, receiverUiEventLogger,
viewUtil, viewUtil,
) )
@@ -117,6 +123,30 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
commandQueueCallback = callbackCaptor.value!! commandQueueCallback = callbackCaptor.value!!
} }
@Test
fun commandQueueCallback_flagOff_noCallbackAdded() {
reset(commandQueue)
whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(false)
controllerReceiver = MediaTttChipControllerReceiver(
commandQueue,
context,
logger,
windowManager,
FakeExecutor(FakeSystemClock()),
accessibilityManager,
configurationController,
powerManager,
Handler.getMain(),
mediaTttFlags,
receiverUiEventLogger,
viewUtil,
)
controllerReceiver.start()
verify(commandQueue, never()).addCallback(any())
}
@Test @Test
fun commandQueueCallback_closeToSender_triggersChip() { fun commandQueueCallback_closeToSender_triggersChip() {
val appName = "FakeAppName" val appName = "FakeAppName"

View File

@@ -0,0 +1,442 @@
/*
* 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.app.StatusBarManager
import android.media.MediaRoute2Info
import android.os.PowerManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import android.widget.TextView
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.media.taptotransfer.MediaTttFlags
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.policy.ConfigurationController
import com.android.systemui.temporarydisplay.chipbar.ChipSenderInfo
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class MediaTttSenderCoordinatorTest : SysuiTestCase() {
private lateinit var underTest: MediaTttSenderCoordinator
@Mock private lateinit var accessibilityManager: AccessibilityManager
@Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var logger: MediaTttLogger
@Mock private lateinit var mediaTttFlags: MediaTttFlags
@Mock private lateinit var powerManager: PowerManager
@Mock private lateinit var viewUtil: ViewUtil
@Mock private lateinit var windowManager: WindowManager
private lateinit var chipbarCoordinator: ChipbarCoordinator
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeClock: FakeSystemClock
private lateinit var fakeExecutor: FakeExecutor
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var uiEventLogger: MediaTttSenderUiEventLogger
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(true)
whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(1000)
fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock)
uiEventLoggerFake = UiEventLoggerFake()
uiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake)
chipbarCoordinator =
FakeChipbarCoordinator(
context,
logger,
windowManager,
fakeExecutor,
accessibilityManager,
configurationController,
powerManager,
uiEventLogger,
falsingManager,
falsingCollector,
viewUtil,
)
chipbarCoordinator.start()
underTest =
MediaTttSenderCoordinator(
chipbarCoordinator,
commandQueue,
context,
logger,
mediaTttFlags,
uiEventLogger,
)
underTest.start()
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
verify(commandQueue).addCallback(callbackCaptor.capture())
commandQueueCallback = callbackCaptor.value!!
}
@Test
fun commandQueueCallback_flagOff_noCallbackAdded() {
reset(commandQueue)
whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(false)
underTest =
MediaTttSenderCoordinator(
chipbarCoordinator,
commandQueue,
context,
logger,
mediaTttFlags,
uiEventLogger,
)
underTest.start()
verify(commandQueue, never()).addCallback(any())
}
@Test
fun commandQueueCallback_almostCloseToStartCast_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(almostCloseToStartCast().state.getChipTextString(context, OTHER_DEVICE_NAME))
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST.id)
}
@Test
fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(almostCloseToEndCast().state.getChipTextString(context, OTHER_DEVICE_NAME))
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST.id)
}
@Test
fun commandQueueCallback_transferToReceiverTriggered_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(
transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED.id)
}
@Test
fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(
transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED.id)
}
@Test
fun commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(
transferToReceiverSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id)
}
@Test
fun commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(
transferToThisDeviceSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED.id)
}
@Test
fun commandQueueCallback_transferToReceiverFailed_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(
transferToReceiverFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED.id)
}
@Test
fun commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
routeInfo,
null
)
assertThat(getChipView().getChipText())
.isEqualTo(
transferToThisDeviceFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED.id)
}
@Test
fun commandQueueCallback_farFromReceiver_noChipShown() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
verify(windowManager, never()).addView(any(), any())
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER.id)
}
@Test
fun commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHidden() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
routeInfo,
null
)
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
verify(windowManager).removeView(viewCaptor.value)
}
@Test
fun commandQueueCallback_invalidStateParam_noChipShown() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(100, routeInfo, null)
verify(windowManager, never()).addView(any(), any())
}
@Test
fun receivesNewStateFromCommandQueue_isLogged() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
routeInfo,
null
)
verify(logger).logStateChange(any(), any(), any())
}
@Test
fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayed() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
routeInfo,
null
)
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
@Test
fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayed() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
routeInfo,
null
)
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
@Test
fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayed() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
routeInfo,
null
)
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
@Test
fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayed() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
routeInfo,
null
)
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
private fun getChipView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
return viewCaptor.value as ViewGroup
}
private fun ViewGroup.getChipText(): String =
(this.requireViewById<TextView>(R.id.text)).text as String
/** Helper method providing default parameters to not clutter up the tests. */
private fun almostCloseToStartCast() =
ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun almostCloseToEndCast() =
ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_END_CAST, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverTriggered() =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceTriggered() =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED, routeInfo, undoCallback)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED, routeInfo, undoCallback)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverFailed() =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceFailed() =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo)
}
private const val OTHER_DEVICE_NAME = "My Tablet"
private val routeInfo =
MediaRoute2Info.Builder("id", OTHER_DEVICE_NAME)
.addFeature("feature")
.setClientPackageName("com.android.systemui")
.build()

View File

@@ -253,7 +253,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
accessibilityManager, accessibilityManager,
configurationController, configurationController,
powerManager, powerManager,
R.layout.media_ttt_chip, R.layout.chipbar,
"Window Title", "Window Title",
"WAKE_REASON", "WAKE_REASON",
) { ) {

View File

@@ -14,10 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.systemui.media.taptotransfer.sender package com.android.systemui.temporarydisplay.chipbar
import android.app.StatusBarManager
import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
@@ -38,11 +36,11 @@ 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.classifier.FalsingCollector
import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger import com.android.systemui.media.taptotransfer.sender.ChipStateSender
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEventLogger
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEvents
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
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.DelayableExecutor
import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.eq
@@ -63,8 +61,8 @@ import org.mockito.MockitoAnnotations
@SmallTest @SmallTest
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper @TestableLooper.RunWithLooper
class MediaTttChipControllerSenderTest : SysuiTestCase() { class ChipbarCoordinatorTest : SysuiTestCase() {
private lateinit var controllerSender: TestMediaTttChipControllerSender private lateinit var underTest: FakeChipbarCoordinator
@Mock @Mock
private lateinit var packageManager: PackageManager private lateinit var packageManager: PackageManager
@@ -81,14 +79,11 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Mock @Mock
private lateinit var windowManager: WindowManager private lateinit var windowManager: WindowManager
@Mock @Mock
private lateinit var commandQueue: CommandQueue
@Mock
private lateinit var falsingManager: FalsingManager private lateinit var falsingManager: FalsingManager
@Mock @Mock
private lateinit var falsingCollector: FalsingCollector private lateinit var falsingCollector: FalsingCollector
@Mock @Mock
private lateinit var viewUtil: ViewUtil private lateinit var viewUtil: ViewUtil
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
private lateinit var fakeExecutor: FakeExecutor private lateinit var fakeExecutor: FakeExecutor
@@ -115,8 +110,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT) whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT)
controllerSender = TestMediaTttChipControllerSender( underTest = FakeChipbarCoordinator(
commandQueue,
context, context,
logger, logger,
windowManager, windowManager,
@@ -129,200 +123,13 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
falsingCollector, falsingCollector,
viewUtil, viewUtil,
) )
controllerSender.start() underTest.start()
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
verify(commandQueue).addCallback(callbackCaptor.capture())
commandQueueCallback = callbackCaptor.value!!
}
@Test
fun commandQueueCallback_almostCloseToStartCast_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
almostCloseToStartCast().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST.id
)
}
@Test
fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
almostCloseToEndCast().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST.id
)
}
@Test
fun commandQueueCallback_transferToReceiverTriggered_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED.id
)
}
@Test
fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED.id
)
}
@Test
fun commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
transferToReceiverSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id
)
}
@Test
fun commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
transferToThisDeviceSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED.id
)
}
@Test
fun commandQueueCallback_transferToReceiverFailed_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
transferToReceiverFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED.id
)
}
@Test
fun commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
routeInfo,
null
)
assertThat(getChipView().getChipText()).isEqualTo(
transferToThisDeviceFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED.id
)
}
@Test
fun commandQueueCallback_farFromReceiver_noChipShown() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
verify(windowManager, never()).addView(any(), any())
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER.id
)
}
@Test
fun commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHidden() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
routeInfo,
null
)
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
verify(windowManager).removeView(viewCaptor.value)
}
@Test
fun commandQueueCallback_invalidStateParam_noChipShown() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
100,
routeInfo,
null
)
verify(windowManager, never()).addView(any(), any())
}
@Test
fun receivesNewStateFromCommandQueue_isLogged() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
routeInfo,
null
)
verify(logger).logStateChange(any(), any(), any())
} }
@Test @Test
fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() { fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
val state = almostCloseToStartCast() val state = almostCloseToStartCast()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -338,7 +145,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() { fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
val state = almostCloseToEndCast() val state = almostCloseToEndCast()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -354,7 +161,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToReceiverTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() { fun transferToReceiverTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
val state = transferToReceiverTriggered() val state = transferToReceiverTriggered()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -370,7 +177,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToThisDeviceTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() { fun transferToThisDeviceTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
val state = transferToThisDeviceTriggered() val state = transferToThisDeviceTriggered()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -386,7 +193,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToReceiverSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() { fun transferToReceiverSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
val state = transferToReceiverSucceeded() val state = transferToReceiverSucceeded()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -400,7 +207,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToReceiverSucceeded_nullUndoRunnable_noUndo() { fun transferToReceiverSucceeded_nullUndoRunnable_noUndo() {
controllerSender.displayView(transferToReceiverSucceeded(undoCallback = null)) underTest.displayView(transferToReceiverSucceeded(undoCallback = null))
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -411,7 +218,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val undoCallback = object : IUndoMediaTransferCallback.Stub() { val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {} override fun onUndoTriggered() {}
} }
controllerSender.displayView(transferToReceiverSucceeded(undoCallback)) underTest.displayView(transferToReceiverSucceeded(undoCallback))
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -427,7 +234,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
} }
} }
controllerSender.displayView(transferToReceiverSucceeded(undoCallback)) underTest.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick() getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isTrue() assertThat(undoCallbackCalled).isTrue()
@@ -443,7 +250,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
} }
} }
controllerSender.displayView(transferToReceiverSucceeded(undoCallback)) underTest.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick() getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isFalse() assertThat(undoCallbackCalled).isFalse()
@@ -459,7 +266,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
} }
} }
controllerSender.displayView(transferToReceiverSucceeded(undoCallback)) underTest.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick() getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isTrue() assertThat(undoCallbackCalled).isTrue()
@@ -470,7 +277,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val undoCallback = object : IUndoMediaTransferCallback.Stub() { val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {} override fun onUndoTriggered() {}
} }
controllerSender.displayView(transferToReceiverSucceeded(undoCallback)) underTest.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick() getChipView().getUndoButton().performClick()
@@ -485,7 +292,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToThisDeviceSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() { fun transferToThisDeviceSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
val state = transferToThisDeviceSucceeded() val state = transferToThisDeviceSucceeded()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -499,7 +306,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToThisDeviceSucceeded_nullUndoRunnable_noUndo() { fun transferToThisDeviceSucceeded_nullUndoRunnable_noUndo() {
controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback = null)) underTest.displayView(transferToThisDeviceSucceeded(undoCallback = null))
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -510,7 +317,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val undoCallback = object : IUndoMediaTransferCallback.Stub() { val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {} override fun onUndoTriggered() {}
} }
controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback)) underTest.displayView(transferToThisDeviceSucceeded(undoCallback))
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -526,7 +333,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
} }
} }
controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback)) underTest.displayView(transferToThisDeviceSucceeded(undoCallback))
getChipView().getUndoButton().performClick() getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isTrue() assertThat(undoCallbackCalled).isTrue()
@@ -537,7 +344,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val undoCallback = object : IUndoMediaTransferCallback.Stub() { val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {} override fun onUndoTriggered() {}
} }
controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback)) underTest.displayView(transferToThisDeviceSucceeded(undoCallback))
getChipView().getUndoButton().performClick() getChipView().getUndoButton().performClick()
@@ -552,7 +359,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() { fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
val state = transferToReceiverFailed() val state = transferToReceiverFailed()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -568,7 +375,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() { fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
val state = transferToThisDeviceFailed() val state = transferToThisDeviceFailed()
controllerSender.displayView(state) underTest.displayView(state)
val chipView = getChipView() val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -583,24 +390,24 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() { fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() {
controllerSender.displayView(almostCloseToStartCast()) underTest.displayView(almostCloseToStartCast())
controllerSender.displayView(transferToReceiverTriggered()) underTest.displayView(transferToReceiverTriggered())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE) assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
} }
@Test @Test
fun changeFromTransferTriggeredToTransferSucceeded_loadingIconDisappears() { fun changeFromTransferTriggeredToTransferSucceeded_loadingIconDisappears() {
controllerSender.displayView(transferToReceiverTriggered()) underTest.displayView(transferToReceiverTriggered())
controllerSender.displayView(transferToReceiverSucceeded()) underTest.displayView(transferToReceiverSucceeded())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
} }
@Test @Test
fun changeFromTransferTriggeredToTransferSucceeded_undoButtonAppears() { fun changeFromTransferTriggeredToTransferSucceeded_undoButtonAppears() {
controllerSender.displayView(transferToReceiverTriggered()) underTest.displayView(transferToReceiverTriggered())
controllerSender.displayView( underTest.displayView(
transferToReceiverSucceeded( transferToReceiverSucceeded(
object : IUndoMediaTransferCallback.Stub() { object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {} override fun onUndoTriggered() {}
@@ -613,41 +420,26 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() { fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() {
controllerSender.displayView(transferToReceiverSucceeded()) underTest.displayView(transferToReceiverSucceeded())
controllerSender.displayView(almostCloseToStartCast()) underTest.displayView(almostCloseToStartCast())
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE) assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
} }
@Test @Test
fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() { fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
controllerSender.displayView(transferToReceiverTriggered()) underTest.displayView(transferToReceiverTriggered())
controllerSender.displayView(transferToReceiverFailed()) underTest.displayView(transferToReceiverFailed())
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE) assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
} }
@Test @Test
fun transferToReceiverTriggeredThenRemoveView_viewStillDisplayed() { fun transferToReceiverTriggeredThenRemoveView_viewStillDisplayed() {
controllerSender.displayView(transferToReceiverTriggered()) underTest.displayView(transferToReceiverTriggered())
fakeClock.advanceTime(1000L) fakeClock.advanceTime(1000L)
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
@Test
fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayed() {
controllerSender.displayView(transferToReceiverTriggered())
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady() fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
@@ -656,9 +448,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToReceiverTriggeredThenRemoveView_eventuallyTimesOut() { fun transferToReceiverTriggeredThenRemoveView_eventuallyTimesOut() {
controllerSender.displayView(transferToReceiverTriggered()) underTest.displayView(transferToReceiverTriggered())
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L) fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any()) verify(windowManager).removeView(any())
@@ -666,10 +458,10 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToThisDeviceTriggeredThenRemoveView_viewStillDisplayed() { fun transferToThisDeviceTriggeredThenRemoveView_viewStillDisplayed() {
controllerSender.displayView(transferToThisDeviceTriggered()) underTest.displayView(transferToThisDeviceTriggered())
fakeClock.advanceTime(1000L) fakeClock.advanceTime(1000L)
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeExecutor.runAllReady() fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
@@ -678,34 +470,19 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToThisDeviceTriggeredThenRemoveView_eventuallyTimesOut() { fun transferToThisDeviceTriggeredThenRemoveView_eventuallyTimesOut() {
controllerSender.displayView(transferToThisDeviceTriggered()) underTest.displayView(transferToThisDeviceTriggered())
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L) fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any()) verify(windowManager).removeView(any())
} }
@Test
fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayed() {
controllerSender.displayView(transferToThisDeviceTriggered())
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
@Test @Test
fun transferToReceiverSucceededThenRemoveView_viewStillDisplayed() { fun transferToReceiverSucceededThenRemoveView_viewStillDisplayed() {
controllerSender.displayView(transferToReceiverSucceeded()) underTest.displayView(transferToReceiverSucceeded())
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeExecutor.runAllReady() fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
@@ -714,34 +491,19 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToReceiverSucceededThenRemoveView_eventuallyTimesOut() { fun transferToReceiverSucceededThenRemoveView_eventuallyTimesOut() {
controllerSender.displayView(transferToReceiverSucceeded()) underTest.displayView(transferToReceiverSucceeded())
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L) fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any()) verify(windowManager).removeView(any())
} }
@Test
fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayed() {
controllerSender.displayView(transferToReceiverSucceeded())
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
@Test @Test
fun transferToThisDeviceSucceededThenRemoveView_viewStillDisplayed() { fun transferToThisDeviceSucceededThenRemoveView_viewStillDisplayed() {
controllerSender.displayView(transferToThisDeviceSucceeded()) underTest.displayView(transferToThisDeviceSucceeded())
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeExecutor.runAllReady() fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
@@ -750,29 +512,14 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test @Test
fun transferToThisDeviceSucceededThenRemoveView_eventuallyTimesOut() { fun transferToThisDeviceSucceededThenRemoveView_eventuallyTimesOut() {
controllerSender.displayView(transferToThisDeviceSucceeded()) underTest.displayView(transferToThisDeviceSucceeded())
controllerSender.removeView("fakeRemovalReason") underTest.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L) fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any()) verify(windowManager).removeView(any())
} }
@Test
fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayed() {
controllerSender.displayView(transferToThisDeviceSucceeded())
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
routeInfo,
null
)
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
}
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon) private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
private fun ViewGroup.getChipText(): String = private fun ViewGroup.getChipText(): String =
@@ -791,6 +538,10 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
return viewCaptor.value as ViewGroup return viewCaptor.value as ViewGroup
} }
// TODO(b/245610654): For now, the below methods are duplicated between this test and
// [MediaTttSenderCoordinatorTest]. Once we define a generic API for [ChipbarCoordinator],
// these will no longer be duplicated.
/** Helper method providing default parameters to not clutter up the tests. */ /** Helper method providing default parameters to not clutter up the tests. */
private fun almostCloseToStartCast() = private fun almostCloseToStartCast() =
ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST, routeInfo) ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST, routeInfo)
@@ -822,39 +573,6 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
/** Helper method providing default parameters to not clutter up the tests. */ /** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceFailed() = private fun transferToThisDeviceFailed() =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo) ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo)
private class TestMediaTttChipControllerSender(
commandQueue: CommandQueue,
context: Context,
@MediaTttReceiverLogger logger: MediaTttLogger,
windowManager: WindowManager,
mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
uiEventLogger: MediaTttSenderUiEventLogger,
falsingManager: FalsingManager,
falsingCollector: FalsingCollector,
viewUtil: ViewUtil,
) : MediaTttChipControllerSender(
commandQueue,
context,
logger,
windowManager,
mainExecutor,
accessibilityManager,
configurationController,
powerManager,
uiEventLogger,
falsingManager,
falsingCollector,
viewUtil,
) {
override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
// Just bypass the animation in tests
onAnimationEnd.run()
}
}
} }
private const val APP_NAME = "Fake app name" private const val APP_NAME = "Fake app name"

View File

@@ -0,0 +1,64 @@
/*
* 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.temporarydisplay.chipbar
import android.content.Context
import android.os.PowerManager
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEventLogger
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.view.ViewUtil
/** A fake implementation of [ChipbarCoordinator] for testing. */
class FakeChipbarCoordinator(
context: Context,
@MediaTttReceiverLogger logger: MediaTttLogger,
windowManager: WindowManager,
mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
uiEventLogger: MediaTttSenderUiEventLogger,
falsingManager: FalsingManager,
falsingCollector: FalsingCollector,
viewUtil: ViewUtil,
) :
ChipbarCoordinator(
context,
logger,
windowManager,
mainExecutor,
accessibilityManager,
configurationController,
powerManager,
uiEventLogger,
falsingManager,
falsingCollector,
viewUtil,
) {
override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
// Just bypass the animation in tests
onAnimationEnd.run()
}
}