diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt index 9dd8222ff6a19..3961f079748b4 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -16,6 +16,7 @@ package com.android.systemui.media.taptotransfer +import android.annotation.SuppressLint import android.app.StatusBarManager import android.content.Context import android.media.MediaRoute2Info @@ -23,16 +24,12 @@ import android.util.Log import androidx.annotation.VisibleForTesting import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast -import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast -import com.android.systemui.media.taptotransfer.sender.TransferFailed -import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered -import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded -import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered -import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded +import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver +import com.android.systemui.media.taptotransfer.sender.ChipStateSender import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import java.io.PrintWriter +import java.lang.IllegalArgumentException import java.util.concurrent.Executor import javax.inject.Inject @@ -46,28 +43,6 @@ class MediaTttCommandLineHelper @Inject constructor( private val context: Context, @Main private val mainExecutor: Executor ) { - /** - * A map from a display state string typed in the command line to the display int it represents. - */ - private val stateStringToStateInt: Map = mapOf( - AlmostCloseToStartCast::class.simpleName!! - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, - AlmostCloseToEndCast::class.simpleName!! - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, - TransferToReceiverTriggered::class.simpleName!! - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, - TransferToThisDeviceTriggered::class.simpleName!! - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, - TransferToReceiverSucceeded::class.simpleName!! - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, - TransferToThisDeviceSucceeded::class.simpleName!! - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, - TransferFailed::class.simpleName!! - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, - FAR_FROM_RECEIVER_STATE - to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER - ) - init { commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() } commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() } @@ -76,21 +51,23 @@ class MediaTttCommandLineHelper @Inject constructor( /** All commands for the sender device. */ inner class SenderCommand : Command { override fun execute(pw: PrintWriter, args: List) { - val routeInfo = MediaRoute2Info.Builder("id", args[0]) - .addFeature("feature") - .setPackageName(TEST_PACKAGE_NAME) - .build() - val commandName = args[1] @StatusBarManager.MediaTransferSenderState - val displayState = stateStringToStateInt[commandName] - if (displayState == null) { + val displayState: Int? + try { + displayState = ChipStateSender.getSenderStateIdFromName(commandName) + } catch (ex: IllegalArgumentException) { pw.println("Invalid command name $commandName") return } + @SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager + val routeInfo = MediaRoute2Info.Builder("id", args[0]) + .addFeature("feature") + .setPackageName(TEST_PACKAGE_NAME) + .build() statusBarManager.updateMediaTapToTransferSenderDisplay( displayState, routeInfo, @@ -136,6 +113,17 @@ class MediaTttCommandLineHelper @Inject constructor( /** All commands for the receiver device. */ inner class ReceiverCommand : Command { override fun execute(pw: PrintWriter, args: List) { + val commandName = args[0] + @StatusBarManager.MediaTransferReceiverState + val displayState: Int? + try { + displayState = ChipStateReceiver.getReceiverStateIdFromName(commandName) + } catch (ex: IllegalArgumentException) { + pw.println("Invalid command name $commandName") + return + } + + @SuppressLint("WrongConstant") // sysui is allowed to call STATUS_BAR_SERVICE val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager val routeInfo = MediaRoute2Info.Builder("id", "Test Name") @@ -143,24 +131,12 @@ class MediaTttCommandLineHelper @Inject constructor( .setPackageName(TEST_PACKAGE_NAME) .build() - when(val commandName = args[0]) { - CLOSE_TO_SENDER_STATE -> - statusBarManager.updateMediaTapToTransferReceiverDisplay( - StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, - routeInfo, - null, - null - ) - FAR_FROM_SENDER_STATE -> - statusBarManager.updateMediaTapToTransferReceiverDisplay( - StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, - routeInfo, - null, - null - ) - else -> - pw.println("Invalid command name $commandName") - } + statusBarManager.updateMediaTapToTransferReceiverDisplay( + displayState, + routeInfo, + null, + null + ) } override fun help(pw: PrintWriter) { @@ -173,11 +149,5 @@ class MediaTttCommandLineHelper @Inject constructor( const val SENDER_COMMAND = "media-ttt-chip-sender" @VisibleForTesting const val RECEIVER_COMMAND = "media-ttt-chip-receiver" -@VisibleForTesting -const val FAR_FROM_RECEIVER_STATE = "FarFromReceiver" -@VisibleForTesting -const val CLOSE_TO_SENDER_STATE = "CloseToSender" -@VisibleForTesting -const val FAR_FROM_SENDER_STATE = "FarFromSender" private const val CLI_TAG = "MediaTransferCli" private const val TEST_PACKAGE_NAME = "com.android.systemui" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt new file mode 100644 index 0000000000000..3cc99a8ef77e8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 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.common + +/** + * A superclass chip state that will be subclassed by the sender chip and receiver chip. + */ +interface ChipInfoCommon { + /** + * Returns the amount of time the given chip state should display on the screen before it times + * out and disappears. + */ + fun getTimeoutMs(): Long +} + +const val DEFAULT_TIMEOUT_MILLIS = 3000L diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt index 9c4b39d9cb771..81934a6b6a736 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt @@ -19,14 +19,16 @@ package com.android.systemui.media.taptotransfer.common import android.annotation.LayoutRes import android.annotation.SuppressLint import android.content.Context +import android.content.pm.PackageManager import android.graphics.PixelFormat +import android.graphics.drawable.Drawable +import android.util.Log import android.view.Gravity import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.WindowManager -import androidx.annotation.VisibleForTesting import com.android.internal.widget.CachingIconView import com.android.systemui.R import com.android.systemui.dagger.qualifiers.Main @@ -40,8 +42,11 @@ import com.android.systemui.util.view.ViewUtil * * Subclasses need to override and implement [updateChipView], which is where they can control what * gets displayed to the user. + * + * The generic type T is expected to contain all the information necessary for the subclasses to + * display the chip in a certain state, since they receive in [updateChipView]. */ -abstract class MediaTttChipControllerCommon( +abstract class MediaTttChipControllerCommon( internal val context: Context, internal val logger: MediaTttLogger, private val windowManager: WindowManager, @@ -64,10 +69,10 @@ abstract class MediaTttChipControllerCommon( } /** The chip view currently being displayed. Null if the chip is not being displayed. */ - var chipView: ViewGroup? = null + private var chipView: ViewGroup? = null /** A [Runnable] that, when run, will cancel the pending timeout of the chip. */ - var cancelChipViewTimeout: Runnable? = null + private var cancelChipViewTimeout: Runnable? = null /** * Displays the chip with the current state. @@ -75,7 +80,7 @@ abstract class MediaTttChipControllerCommon( * This method handles inflating and attaching the view, then delegates to [updateChipView] to * display the correct information in the chip. */ - fun displayChip(chipState: T) { + fun displayChip(chipInfo: T) { val oldChipView = chipView if (chipView == null) { chipView = LayoutInflater @@ -84,7 +89,7 @@ abstract class MediaTttChipControllerCommon( } val currentChipView = chipView!! - updateChipView(chipState, currentChipView) + updateChipView(chipInfo, currentChipView) // Add view if necessary if (oldChipView == null) { @@ -96,7 +101,7 @@ abstract class MediaTttChipControllerCommon( cancelChipViewTimeout?.run() cancelChipViewTimeout = mainExecutor.executeDelayed( { removeChip(MediaTttRemovalReason.REASON_TIMEOUT) }, - chipState.getTimeoutMs() + chipInfo.getTimeoutMs() ) } @@ -117,20 +122,28 @@ abstract class MediaTttChipControllerCommon( } /** - * A method implemented by subclasses to update [currentChipView] based on [chipState]. + * A method implemented by subclasses to update [currentChipView] based on [chipInfo]. */ - abstract fun updateChipView(chipState: T, currentChipView: ViewGroup) + abstract fun updateChipView(chipInfo: T, currentChipView: ViewGroup) /** * An internal method to set the icon on the view. * * This is in the common superclass since both the sender and the receiver show an icon. + * + * @param appPackageName the package name of the app playing the media. Will be used to fetch + * the app icon and app name if overrides aren't provided. */ - internal fun setIcon(chipState: T, currentChipView: ViewGroup) { + internal fun setIcon( + currentChipView: ViewGroup, + appPackageName: String?, + appIconDrawableOverride: Drawable? = null, + appNameOverride: CharSequence? = null, + ) { val appIconView = currentChipView.requireViewById(R.id.app_icon) - appIconView.contentDescription = chipState.getAppName(context) + appIconView.contentDescription = appNameOverride ?: getAppName(appPackageName) - val appIcon = chipState.getAppIcon(context) + val appIcon = appIconDrawableOverride ?: getAppIcon(appPackageName) val visibility = if (appIcon != null) { View.VISIBLE } else { @@ -140,6 +153,30 @@ abstract class MediaTttChipControllerCommon( appIconView.visibility = visibility } + /** Returns the icon of the app playing the media or null if we can't find it. */ + private fun getAppIcon(appPackageName: String?): Drawable? { + appPackageName ?: return null + return try { + context.packageManager.getApplicationIcon(appPackageName) + } catch (e: PackageManager.NameNotFoundException) { + Log.w(TAG, "Cannot find icon for package $appPackageName", e) + null + } + } + + /** Returns the name of the app playing the media or null if we can't find it. */ + private fun getAppName(appPackageName: String?): String? { + appPackageName ?: return null + return try { + context.packageManager.getApplicationInfo( + appPackageName, PackageManager.ApplicationInfoFlags.of(0) + ).loadLabel(context.packageManager).toString() + } catch (e: PackageManager.NameNotFoundException) { + Log.w(TAG, "Cannot find name for package $appPackageName", e) + null + } + } + private fun onScreenTapped(e: MotionEvent) { val view = chipView ?: return // If the tap is within the chip bounds, we shouldn't hide the chip (in case users think the @@ -159,4 +196,3 @@ object MediaTttRemovalReason { const val REASON_TIMEOUT = "TIMEOUT" const val REASON_SCREEN_TAP = "SCREEN_TAP" } - diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt deleted file mode 100644 index 6f6018170f986..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2021 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.common - -import android.content.Context -import android.content.pm.PackageManager -import android.graphics.drawable.Drawable -import android.util.Log - -/** - * A superclass chip state that will be subclassed by the sender chip and receiver chip. - * - * @property appPackageName the package name of the app playing the media. Will be used to fetch the - * app icon and app name. - */ -open class MediaTttChipState( - internal val appPackageName: String?, -) { - open fun getAppIcon(context: Context): Drawable? { - appPackageName ?: return null - return try { - context.packageManager.getApplicationIcon(appPackageName) - } catch (e: PackageManager.NameNotFoundException) { - Log.w(TAG, "Cannot find icon for package $appPackageName", e) - null - } - } - - /** Returns the name of the app playing the media or null if we can't find it. */ - open fun getAppName(context: Context): String? { - appPackageName ?: return null - return try { - context.packageManager.getApplicationInfo( - appPackageName, PackageManager.ApplicationInfoFlags.of(0) - ).loadLabel(context.packageManager).toString() - } catch (e: PackageManager.NameNotFoundException) { - Log.w(TAG, "Cannot find name for package $appPackageName", e) - null - } - } - - /** - * Returns the amount of time this chip should display on the screen before it times out and - * disappears. [MediaTttChipControllerCommon] will ensure that the timeout resets each time we - * receive a new state. - */ - open fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS -} - -private const val DEFAULT_TIMEOUT_MILLIS = 3000L -private val TAG = MediaTttChipState::class.simpleName!! diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt index 6a4b62a8c1aeb..a3f8ebf0b46d1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt @@ -16,35 +16,41 @@ package com.android.systemui.media.taptotransfer.receiver -import android.content.Context -import android.graphics.drawable.Drawable -import com.android.systemui.media.taptotransfer.common.MediaTttChipState +import android.app.StatusBarManager +import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS +import com.android.systemui.media.taptotransfer.common.ChipInfoCommon /** * A class that stores all the information necessary to display the media tap-to-transfer chip on * the receiver device. - * - * @property appIconDrawable a drawable representing the icon of the app playing the media. If - * present, this will be used in [this.getAppIcon] instead of [appPackageName]. - * @property appName a name for the app playing the media. If present, this will be used in - * [this.getAppName] instead of [appPackageName]. */ -class ChipStateReceiver( - appPackageName: String?, - private val appIconDrawable: Drawable?, - private val appName: CharSequence? -) : MediaTttChipState(appPackageName) { - override fun getAppIcon(context: Context): Drawable? { - if (appIconDrawable != null) { - return appIconDrawable - } - return super.getAppIcon(context) - } +enum class ChipStateReceiver( + @StatusBarManager.MediaTransferSenderState val stateInt: Int, +) { + CLOSE_TO_SENDER( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + ), + FAR_FROM_SENDER( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, + ); - override fun getAppName(context: Context): String? { - if (appName != null) { - return appName.toString() - } - return super.getAppName(context) + companion object { + /** + * Returns the receiver state enum associated with the given [displayState] from + * [StatusBarManager]. + */ + fun getReceiverStateFromId( + @StatusBarManager.MediaTransferReceiverState displayState: Int + ) : ChipStateReceiver = values().first { it.stateInt == displayState } + + + /** + * Returns the state int from [StatusBarManager] associated with the given sender state + * name. + * + * @param name the name of one of the [ChipStateReceiver] enums. + */ + @StatusBarManager.MediaTransferReceiverState + fun getReceiverStateIdFromName(name: String): Int = valueOf(name).stateInt } } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index 1a96ddf69b284..969b388797ffe 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -18,6 +18,7 @@ package com.android.systemui.media.taptotransfer.receiver import android.app.StatusBarManager import android.content.Context +import android.graphics.drawable.Drawable import android.graphics.drawable.Icon import android.media.MediaRoute2Info import android.os.Handler @@ -27,6 +28,8 @@ import android.view.WindowManager import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.media.taptotransfer.common.ChipInfoCommon +import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.statusbar.CommandQueue @@ -50,7 +53,7 @@ class MediaTttChipControllerReceiver @Inject constructor( mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, @Main private val mainHandler: Handler, -) : MediaTttChipControllerCommon( +) : MediaTttChipControllerCommon( context, logger, windowManager, @@ -82,45 +85,50 @@ class MediaTttChipControllerReceiver @Inject constructor( appIcon: Icon?, appName: CharSequence? ) { - logger.logStateChange(stateIntToString(displayState), routeInfo.id) - when(displayState) { - StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> { - val packageName = routeInfo.packageName - if (appIcon == null) { - displayChip(ChipStateReceiver(packageName, null, appName)) - } else { - appIcon.loadDrawableAsync( - context, - Icon.OnDrawableLoadedListener { drawable -> - displayChip( - ChipStateReceiver(packageName, drawable, appName) - )}, - // Notify the listener on the main handler since the listener will update - // the UI. - mainHandler - ) - } - } - StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> - removeChip(removalReason = FAR_FROM_SENDER) - else -> - Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState") + val chipState: ChipStateReceiver? = ChipStateReceiver.getReceiverStateFromId(displayState) + val stateName = chipState?.name ?: "Invalid" + logger.logStateChange(stateName, routeInfo.id) + + if (chipState == null) { + Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState") + return } + if (chipState == ChipStateReceiver.FAR_FROM_SENDER) { + removeChip(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!) + return + } + if (appIcon == null) { + displayChip(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName)) + return + } + + appIcon.loadDrawableAsync( + context, + Icon.OnDrawableLoadedListener { drawable -> + displayChip(ChipReceiverInfo(routeInfo, drawable, appName)) + }, + // Notify the listener on the main handler since the listener will update + // the UI. + mainHandler + ) } - override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) { - setIcon(chipState, currentChipView) - } - - private fun stateIntToString(@StatusBarManager.MediaTransferReceiverState state: Int): String { - return when (state) { - StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> CLOSE_TO_SENDER - StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> FAR_FROM_SENDER - else -> "INVALID: $state" - } + override fun updateChipView(chipInfo: ChipReceiverInfo, currentChipView: ViewGroup) { + setIcon( + currentChipView, + chipInfo.routeInfo.packageName, + chipInfo.appIconDrawableOverride, + chipInfo.appNameOverride + ) } } +data class ChipReceiverInfo( + val routeInfo: MediaRoute2Info, + val appIconDrawableOverride: Drawable?, + val appNameOverride: CharSequence? +) : ChipInfoCommon { + override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS +} + private const val RECEIVER_TAG = "MediaTapToTransferRcvr" -private const val CLOSE_TO_SENDER = "CLOSE_TO_SENDER" -private const val FAR_FROM_SENDER = "FAR_FROM_SENDER" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt index 22424a4e9c74f..b598335038dcb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt @@ -16,27 +16,168 @@ package com.android.systemui.media.taptotransfer.sender +import android.app.StatusBarManager import android.content.Context +import android.media.MediaRoute2Info import android.view.View +import androidx.annotation.StringRes import com.android.internal.statusbar.IUndoMediaTransferCallback import com.android.systemui.R -import com.android.systemui.media.taptotransfer.common.MediaTttChipState +import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS /** - * A class that stores all the information necessary to display the media tap-to-transfer chip on - * the sender device. + * A class enumerating all the possible states of the media tap-to-transfer chip on the sender + * device. * - * This is a sealed class where each subclass represents a specific chip state. Each subclass can - * contain additional information that is necessary for only that state. + * @property stateInt the integer from [StatusBarManager] corresponding with this state. + * @property stringResId the res ID of the string that should be displayed in the chip. Null if the + * state should not have the chip be displayed. + * @property isMidTransfer true if the state represents that a transfer is currently ongoing. + * @property isTransferFailure true if the state represents that the transfer has failed. + * @property timeout the amount of time this chip should display on the screen before it times out + * and disappears. */ -sealed class ChipStateSender( - appPackageName: String? -) : MediaTttChipState(appPackageName) { - /** Returns a fully-formed string with the text that the chip should display. */ - abstract fun getChipTextString(context: Context): String +enum class ChipStateSender( + @StatusBarManager.MediaTransferSenderState val stateInt: Int, + @StringRes val stringResId: Int?, + val isMidTransfer: Boolean = false, + val isTransferFailure: Boolean = false, + val timeout: Long = DEFAULT_TIMEOUT_MILLIS +) { + /** + * A state representing that the two devices are close but not close enough to *start* a cast to + * the receiver device. The chip will instruct the user to move closer in order to initiate the + * transfer to the receiver. + */ + ALMOST_CLOSE_TO_START_CAST( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, + R.string.media_move_closer_to_start_cast, + ), - /** Returns true if the loading icon should be displayed and false otherwise. */ - open fun showLoading(): Boolean = false + /** + * A state representing that the two devices are close but not close enough to *end* a cast + * that's currently occurring the receiver device. The chip will instruct the user to move + * closer in order to initiate the transfer from the receiver and back onto this device (the + * original sender). + */ + ALMOST_CLOSE_TO_END_CAST( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, + R.string.media_move_closer_to_end_cast, + ), + + /** + * A state representing that a transfer to the receiver device has been initiated (but not + * completed). + */ + TRANSFER_TO_RECEIVER_TRIGGERED( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, + R.string.media_transfer_playing_different_device, + isMidTransfer = true, + timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS + ), + + /** + * A state representing that a transfer from the receiver device and back to this device (the + * sender) has been initiated (but not completed). + */ + TRANSFER_TO_THIS_DEVICE_TRIGGERED( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, + R.string.media_transfer_playing_this_device, + isMidTransfer = true, + timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS + ), + + /** + * A state representing that a transfer to the receiver device has been successfully completed. + */ + TRANSFER_TO_RECEIVER_SUCCEEDED( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, + R.string.media_transfer_playing_different_device + ) { + override fun undoClickListener( + controllerSender: MediaTttChipControllerSender, + routeInfo: MediaRoute2Info, + undoCallback: IUndoMediaTransferCallback?, + ): View.OnClickListener? { + if (undoCallback == null) { + return null + } + return View.OnClickListener { + undoCallback.onUndoTriggered() + // The external service should eventually send us a TransferToThisDeviceTriggered + // state, but that may take too long to go through the binder and the user may be + // confused ast o why the UI hasn't changed yet. So, we immediately change the UI + // here. + controllerSender.displayChip( + ChipSenderInfo( + TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback + ) + ) + } + } + }, + + /** + * A state representing that a transfer back to this device has been successfully completed. + */ + TRANSFER_TO_THIS_DEVICE_SUCCEEDED( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, + R.string.media_transfer_playing_this_device + ) { + override fun undoClickListener( + controllerSender: MediaTttChipControllerSender, + routeInfo: MediaRoute2Info, + undoCallback: IUndoMediaTransferCallback?, + ): View.OnClickListener? { + if (undoCallback == null) { + return null + } + return View.OnClickListener { + undoCallback.onUndoTriggered() + // The external service should eventually send us a TransferToReceiverTriggered + // 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 + // here. + controllerSender.displayChip( + ChipSenderInfo( + TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback + ) + ) + } + } + }, + + /** A state representing that a transfer to the receiver device has failed. */ + TRANSFER_TO_RECEIVER_FAILED( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, + R.string.media_transfer_failed, + isTransferFailure = true + ), + + /** A state representing that a transfer back to this device has failed. */ + TRANSFER_TO_THIS_DEVICE_FAILED( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED, + R.string.media_transfer_failed, + isTransferFailure = true + ), + + /** A state representing that this device is far away from any receiver device. */ + FAR_FROM_RECEIVER( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + stringResId = null + ); + + /** + * Returns a fully-formed string with the text that the chip should display. + * + * @param otherDeviceName the name of the other device involved in the transfer. + */ + fun getChipTextString(context: Context, otherDeviceName: String): String? { + if (stringResId == null) { + return null + } + return context.getString(stringResId, otherDeviceName) + } /** * Returns a click listener for the undo button on the chip. Returns null if this chip state @@ -44,160 +185,36 @@ sealed class ChipStateSender( * * @param controllerSender passed as a parameter in case we want to display a new chip state * when undo is clicked. + * @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. */ open fun undoClickListener( - controllerSender: MediaTttChipControllerSender + controllerSender: MediaTttChipControllerSender, + routeInfo: MediaRoute2Info, + undoCallback: IUndoMediaTransferCallback? ): View.OnClickListener? = null -} -/** - * A state representing that the two devices are close but not close enough to *start* a cast to - * the receiver device. The chip will instruct the user to move closer in order to initiate the - * transfer to the receiver. - * - * @property otherDeviceName the name of the other device involved in the transfer. - */ -class AlmostCloseToStartCast( - appPackageName: String?, - private val otherDeviceName: String, -) : ChipStateSender(appPackageName) { - override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_move_closer_to_start_cast, otherDeviceName) - } -} + companion object { + /** + * Returns the sender state enum associated with the given [displayState] from + * [StatusBarManager]. + */ + fun getSenderStateFromId( + @StatusBarManager.MediaTransferSenderState displayState: Int, + ): ChipStateSender = values().first { it.stateInt == displayState } -/** - * A state representing that the two devices are close but not close enough to *end* a cast that's - * currently occurring the receiver device. The chip will instruct the user to move closer in order - * to initiate the transfer from the receiver and back onto this device (the original sender). - * - * @property otherDeviceName the name of the other device involved in the transfer. - */ -class AlmostCloseToEndCast( - appPackageName: String?, - private val otherDeviceName: String, -) : ChipStateSender(appPackageName) { - override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_move_closer_to_end_cast, otherDeviceName) - } -} - -/** - * A state representing that a transfer to the receiver device has been initiated (but not - * completed). - * - * @property otherDeviceName the name of the other device involved in the transfer. - */ -class TransferToReceiverTriggered( - appPackageName: String?, - private val otherDeviceName: String -) : ChipStateSender(appPackageName) { - override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName) - } - - override fun showLoading() = true - override fun getTimeoutMs() = TRANSFER_TRIGGERED_TIMEOUT_MILLIS -} - -/** - * A state representing that a transfer from the receiver device and back to this device (the - * sender) has been initiated (but not completed). - */ -class TransferToThisDeviceTriggered( - appPackageName: String?, -) : ChipStateSender(appPackageName) { - override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_transfer_playing_this_device) - } - - override fun showLoading() = true - override fun getTimeoutMs() = TRANSFER_TRIGGERED_TIMEOUT_MILLIS -} - -/** - * A state representing that a transfer to the receiver device has been successfully completed. - * - * @property otherDeviceName the name of the other device involved in the transfer. - * @property 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. - */ -class TransferToReceiverSucceeded( - appPackageName: String?, - private val otherDeviceName: String, - val undoCallback: IUndoMediaTransferCallback? = null -) : ChipStateSender(appPackageName) { - override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName) - } - - override fun undoClickListener( - controllerSender: MediaTttChipControllerSender - ): View.OnClickListener? { - if (undoCallback == null) { - return null - } - - return View.OnClickListener { - this.undoCallback.onUndoTriggered() - // The external service should eventually send us a TransferToThisDeviceTriggered 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 here. - controllerSender.displayChip( - TransferToThisDeviceTriggered(this.appPackageName) - ) - } - } -} - -/** - * A state representing that a transfer back to this device has been successfully completed. - * - * @property otherDeviceName the name of the other device involved in the transfer. - * @property 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. - */ -class TransferToThisDeviceSucceeded( - appPackageName: String?, - private val otherDeviceName: String, - val undoCallback: IUndoMediaTransferCallback? = null -) : ChipStateSender(appPackageName) { - override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_transfer_playing_this_device) - } - - override fun undoClickListener( - controllerSender: MediaTttChipControllerSender - ): View.OnClickListener? { - if (undoCallback == null) { - return null - } - - return View.OnClickListener { - this.undoCallback.onUndoTriggered() - // The external service should eventually send us a TransferToReceiverTriggered 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 here. - controllerSender.displayChip( - TransferToReceiverTriggered( - this.appPackageName, - this.otherDeviceName - ) - ) - } - } -} - -/** A state representing that a transfer has failed. */ -class TransferFailed( - appPackageName: String?, -) : ChipStateSender(appPackageName) { - override fun getChipTextString(context: Context): String { - return context.getString(R.string.media_transfer_failed) + /** + * Returns the state int from [StatusBarManager] associated with the given sender state + * name. + * + * @param name the name of one of the [ChipStateSender] enums. + */ + @StatusBarManager.MediaTransferSenderState + fun getSenderStateIdFromName(name: String): Int = valueOf(name).stateInt } } // Give the Transfer*Triggered states a longer timeout since those states represent an active // process and we should keep the user informed about it as long as possible (but don't allow it to // continue indefinitely). -private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 15000L \ No newline at end of file +private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 15000L diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index da2aac4d5ad7a..3b38946f64832 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -28,6 +28,7 @@ import com.android.internal.statusbar.IUndoMediaTransferCallback import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.media.taptotransfer.common.ChipInfoCommon import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason @@ -50,7 +51,7 @@ class MediaTttChipControllerSender @Inject constructor( viewUtil: ViewUtil, @Main mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, -) : MediaTttChipControllerCommon( +) : MediaTttChipControllerCommon( context, logger, windowManager, @@ -82,104 +83,82 @@ class MediaTttChipControllerSender @Inject constructor( routeInfo: MediaRoute2Info, undoCallback: IUndoMediaTransferCallback? ) { - logger.logStateChange(stateIntToString(displayState), routeInfo.id) - val appPackageName = routeInfo.packageName - val otherDeviceName = routeInfo.name.toString() - val chipState = when(displayState) { - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST -> - AlmostCloseToStartCast(appPackageName, otherDeviceName) - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST -> - AlmostCloseToEndCast(appPackageName, otherDeviceName) - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED -> - TransferToReceiverTriggered(appPackageName, otherDeviceName) - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED -> - TransferToThisDeviceTriggered(appPackageName) - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED -> - TransferToReceiverSucceeded(appPackageName, otherDeviceName, undoCallback) - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED -> - TransferToThisDeviceSucceeded(appPackageName, otherDeviceName, undoCallback) - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED -> - TransferFailed(appPackageName) - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> { - removeChip(removalReason = FAR_FROM_RECEIVER) - null - } - else -> { - Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState") - null - } + val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState) + val stateName = chipState?.name ?: "Invalid" + logger.logStateChange(stateName, routeInfo.id) + + if (chipState == null) { + Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState") + return } - chipState?.let { - displayChip(it) + if (chipState == ChipStateSender.FAR_FROM_RECEIVER) { + removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!) + } else { + displayChip(ChipSenderInfo(chipState, routeInfo, undoCallback)) } } /** Displays the chip view for the given state. */ - override fun updateChipView(chipState: ChipStateSender, currentChipView: ViewGroup) { + override fun updateChipView( + chipInfo: ChipSenderInfo, + currentChipView: ViewGroup) { + val chipState = chipInfo.state currentlyDisplayedChipState = chipState // App icon - setIcon(chipState, currentChipView) + setIcon(currentChipView, chipInfo.routeInfo.packageName) // Text + val otherDeviceName = chipInfo.routeInfo.name.toString() currentChipView.requireViewById(R.id.text).apply { - text = chipState.getChipTextString(context) + text = chipState.getChipTextString(context, otherDeviceName) } // Loading currentChipView.requireViewById(R.id.loading).visibility = - if (chipState.showLoading()) { View.VISIBLE } else { View.GONE } + chipState.isMidTransfer.visibleIfTrue() + // Undo val undoView = currentChipView.requireViewById(R.id.undo) - val undoClickListener = chipState.undoClickListener(this) + val undoClickListener = chipState.undoClickListener( + this, chipInfo.routeInfo, chipInfo.undoCallback + ) undoView.setOnClickListener(undoClickListener) - undoView.visibility = if (undoClickListener != null) { View.VISIBLE } else { View.GONE } + undoView.visibility = (undoClickListener != null).visibleIfTrue() // Failure - val showFailure = chipState is TransferFailed currentChipView.requireViewById(R.id.failure_icon).visibility = - if (showFailure) { View.VISIBLE } else { View.GONE } + chipState.isTransferFailure.visibleIfTrue() } override fun removeChip(removalReason: String) { // Don't remove the chip if we're mid-transfer since the user should still be able to // see the status of the transfer. (But do remove it if it's finally timed out.) - if ((currentlyDisplayedChipState is TransferToReceiverTriggered || - currentlyDisplayedChipState is TransferToThisDeviceTriggered) - && removalReason != MediaTttRemovalReason.REASON_TIMEOUT) { + if (currentlyDisplayedChipState?.isMidTransfer == true + && removalReason != MediaTttRemovalReason.REASON_TIMEOUT) { return } super.removeChip(removalReason) currentlyDisplayedChipState = null } - private fun stateIntToString(@StatusBarManager.MediaTransferSenderState state: Int): String { - return when(state) { - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST -> - "ALMOST_CLOSE_TO_START_CAST" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST -> - "ALMOST_CLOSE_TO_END_CAST" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED -> - "TRANSFER_TO_RECEIVER_TRIGGERED" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED -> - "TRANSFER_TO_THIS_DEVICE_TRIGGERED" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED -> - "TRANSFER_TO_RECEIVER_SUCCEEDED" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED -> - "TRANSFER_TO_THIS_DEVICE_SUCCEEDED" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED -> - "TRANSFER_TO_RECEIVER_FAILED" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED -> - "TRANSFER_TO_THIS_DEVICE_FAILED" - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> - FAR_FROM_RECEIVER - else -> "INVALID: $state" + private fun Boolean.visibleIfTrue(): Int { + return if (this) { + View.VISIBLE + } else { + View.GONE } } } +data class ChipSenderInfo( + val state: ChipStateSender, + val routeInfo: MediaRoute2Info, + val undoCallback: IUndoMediaTransferCallback? = null +) : ChipInfoCommon { + override fun getTimeoutMs() = state.timeout +} + const val SENDER_TAG = "MediaTapToTransferSender" -private const val FAR_FROM_RECEIVER = "FAR_FROM_RECEIVER" diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt index 794bc09715af3..2a130535c6571 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt @@ -21,13 +21,8 @@ import android.content.Context import android.media.MediaRoute2Info import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast -import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast -import com.android.systemui.media.taptotransfer.sender.TransferFailed -import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered -import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded -import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered -import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded +import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver +import com.android.systemui.media.taptotransfer.sender.ChipStateSender import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.util.concurrency.FakeExecutor @@ -88,7 +83,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun sender_almostCloseToStartCast_serviceCallbackCalled() { commandRegistry.onShellCommand( - pw, getSenderCommand(AlmostCloseToStartCast::class.simpleName!!) + pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.name) ) val routeInfoCaptor = argumentCaptor() @@ -103,7 +98,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun sender_almostCloseToEndCast_serviceCallbackCalled() { commandRegistry.onShellCommand( - pw, getSenderCommand(AlmostCloseToEndCast::class.simpleName!!) + pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_END_CAST.name) ) val routeInfoCaptor = argumentCaptor() @@ -118,7 +113,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun sender_transferToReceiverTriggered_chipDisplayWithCorrectState() { commandRegistry.onShellCommand( - pw, getSenderCommand(TransferToReceiverTriggered::class.simpleName!!) + pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.name) ) val routeInfoCaptor = argumentCaptor() @@ -133,7 +128,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() { commandRegistry.onShellCommand( - pw, getSenderCommand(TransferToThisDeviceTriggered::class.simpleName!!) + pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.name) ) verify(statusBarManager).updateMediaTapToTransferSenderDisplay( @@ -146,7 +141,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() { commandRegistry.onShellCommand( - pw, getSenderCommand(TransferToReceiverSucceeded::class.simpleName!!) + pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.name) ) val routeInfoCaptor = argumentCaptor() @@ -161,7 +156,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() { commandRegistry.onShellCommand( - pw, getSenderCommand(TransferToThisDeviceSucceeded::class.simpleName!!) + pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.name) ) val routeInfoCaptor = argumentCaptor() @@ -174,8 +169,10 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { } @Test - fun sender_transferFailed_serviceCallbackCalled() { - commandRegistry.onShellCommand(pw, getSenderCommand(TransferFailed::class.simpleName!!)) + fun sender_transferToReceiverFailed_serviceCallbackCalled() { + commandRegistry.onShellCommand( + pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED.name) + ) verify(statusBarManager).updateMediaTapToTransferSenderDisplay( eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED), @@ -184,9 +181,24 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { nullable()) } + @Test + fun sender_transferToThisDeviceFailed_serviceCallbackCalled() { + commandRegistry.onShellCommand( + pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_FAILED.name) + ) + + verify(statusBarManager).updateMediaTapToTransferSenderDisplay( + eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED), + any(), + nullable(), + nullable()) + } + @Test fun sender_farFromReceiver_serviceCallbackCalled() { - commandRegistry.onShellCommand(pw, getSenderCommand(FAR_FROM_RECEIVER_STATE)) + commandRegistry.onShellCommand( + pw, getSenderCommand(ChipStateSender.FAR_FROM_RECEIVER.name) + ) verify(statusBarManager).updateMediaTapToTransferSenderDisplay( eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER), @@ -197,7 +209,9 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun receiver_closeToSender_serviceCallbackCalled() { - commandRegistry.onShellCommand(pw, getReceiverCommand(CLOSE_TO_SENDER_STATE)) + commandRegistry.onShellCommand( + pw, getReceiverCommand(ChipStateReceiver.CLOSE_TO_SENDER.name) + ) verify(statusBarManager).updateMediaTapToTransferReceiverDisplay( eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER), @@ -209,7 +223,9 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { @Test fun receiver_farFromSender_serviceCallbackCalled() { - commandRegistry.onShellCommand(pw, getReceiverCommand(FAR_FROM_SENDER_STATE)) + commandRegistry.onShellCommand( + pw, getReceiverCommand(ChipStateReceiver.FAR_FROM_SENDER.name) + ) verify(statusBarManager).updateMediaTapToTransferReceiverDisplay( eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER), diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt index adb59eca1e083..f99efe25c6eb2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt @@ -17,7 +17,10 @@ package com.android.systemui.media.taptotransfer.common import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager import android.graphics.drawable.Drawable +import android.media.MediaRoute2Info import android.view.MotionEvent import android.view.View import android.view.ViewGroup @@ -27,6 +30,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.media.taptotransfer.receiver.ChipReceiverInfo import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.FakeExecutor @@ -40,6 +44,7 @@ import org.junit.Before import org.junit.Test import org.mockito.ArgumentCaptor import org.mockito.Mock +import org.mockito.Mockito.eq import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify @@ -48,12 +53,16 @@ import org.mockito.MockitoAnnotations @SmallTest class MediaTttChipControllerCommonTest : SysuiTestCase() { - private lateinit var controllerCommon: MediaTttChipControllerCommon + private lateinit var controllerCommon: MediaTttChipControllerCommon private lateinit var fakeClock: FakeSystemClock private lateinit var fakeExecutor: FakeExecutor - private lateinit var appIconDrawable: Drawable + private lateinit var appIconFromPackageName: Drawable + @Mock + private lateinit var packageManager: PackageManager + @Mock + private lateinit var applicationInfo: ApplicationInfo @Mock private lateinit var logger: MediaTttLogger @Mock @@ -66,7 +75,15 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) - appIconDrawable = context.getDrawable(R.drawable.ic_cake)!! + + appIconFromPackageName = context.getDrawable(R.drawable.ic_cake)!! + whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(appIconFromPackageName) + whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME) + whenever(packageManager.getApplicationInfo( + eq(PACKAGE_NAME), any() + )).thenReturn(applicationInfo) + context.setMockPackageManager(packageManager) + fakeClock = FakeSystemClock() fakeExecutor = FakeExecutor(fakeClock) @@ -100,7 +117,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { controllerCommon.displayChip(state) reset(windowManager) - fakeClock.advanceTime(state.getTimeoutMs() - 1) + fakeClock.advanceTime(TIMEOUT_MS - 1) verify(windowManager, never()).removeView(any()) } @@ -111,7 +128,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { controllerCommon.displayChip(state) reset(windowManager) - fakeClock.advanceTime(state.getTimeoutMs() + 1) + fakeClock.advanceTime(TIMEOUT_MS + 1) verify(windowManager).removeView(any()) } @@ -128,7 +145,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { controllerCommon.displayChip(getState()) // Wait until the timeout for the first display would've happened - fakeClock.advanceTime(state.getTimeoutMs() - waitTime + 1) + fakeClock.advanceTime(TIMEOUT_MS - waitTime + 1) // Verify we didn't hide the chip verify(windowManager, never()).removeView(any()) @@ -145,7 +162,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { controllerCommon.displayChip(getState()) // Ensure we still hide the chip eventually - fakeClock.advanceTime(state.getTimeoutMs() + 1) + fakeClock.advanceTime(TIMEOUT_MS + 1) verify(windowManager).removeView(any()) } @@ -172,16 +189,45 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { } @Test - fun setIcon_viewHasIconAndContentDescription() { + fun setIcon_nullAppIconDrawable_iconIsFromPackageName() { controllerCommon.displayChip(getState()) val chipView = getChipView() - val state = TestChipState(PACKAGE_NAME) - controllerCommon.setIcon(state, chipView) + controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null) - assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) - assertThat(chipView.getAppIconView().contentDescription) - .isEqualTo(state.getAppName(context)) + assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName) + } + + @Test + fun displayChip_hasAppIconDrawable_iconIsDrawable() { + controllerCommon.displayChip(getState()) + val chipView = getChipView() + + val drawable = context.getDrawable(R.drawable.ic_alarm)!! + controllerCommon.setIcon(chipView, PACKAGE_NAME, drawable, null) + + assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable) + } + + @Test + fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() { + controllerCommon.displayChip(getState()) + val chipView = getChipView() + + controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appNameOverride = null) + + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) + } + + @Test + fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() { + controllerCommon.displayChip(getState()) + val chipView = getChipView() + + val appName = "Override App Name" + controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appName) + + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName) } @Test @@ -218,7 +264,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { verify(windowManager, never()).removeView(any()) } - private fun getState() = MediaTttChipState(PACKAGE_NAME) + private fun getState() = ChipInfo() private fun getChipView(): ViewGroup { val viewCaptor = ArgumentCaptor.forClass(View::class.java) @@ -235,7 +281,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { viewUtil: ViewUtil, @Main mainExecutor: DelayableExecutor, tapGestureDetector: TapGestureDetector, - ) : MediaTttChipControllerCommon( + ) : MediaTttChipControllerCommon( context, logger, windowManager, @@ -244,13 +290,16 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { tapGestureDetector, R.layout.media_ttt_chip ) { - override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) { + override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) { + } } - inner class TestChipState(appPackageName: String?) : MediaTttChipState(appPackageName) { - override fun getAppIcon(context: Context) = appIconDrawable + inner class ChipInfo : ChipInfoCommon { + override fun getTimeoutMs() = TIMEOUT_MS } } private const val PACKAGE_NAME = "com.android.systemui" +private const val APP_NAME = "Fake App Name" +private const val TIMEOUT_MS = 10000L diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt index 56f45896436c5..a5a1a26acbd5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt @@ -157,44 +157,6 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { verify(logger).logStateChange(any(), any()) } - @Test - fun displayChip_nullAppIconDrawable_iconIsFromPackageName() { - val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, "appName") - - controllerReceiver.displayChip(state) - - assertThat(getChipView().getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) - } - - @Test - fun displayChip_hasAppIconDrawable_iconIsDrawable() { - val drawable = context.getDrawable(R.drawable.ic_alarm)!! - val state = ChipStateReceiver(PACKAGE_NAME, drawable, "appName") - - controllerReceiver.displayChip(state) - - assertThat(getChipView().getAppIconView().drawable).isEqualTo(drawable) - } - - @Test - fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() { - val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, appName = null) - - controllerReceiver.displayChip(state) - - assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(APP_NAME) - } - - @Test - fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() { - val appName = "Override App Name" - val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, appName) - - controllerReceiver.displayChip(state) - - assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(appName) - } - private fun getChipView(): ViewGroup { val viewCaptor = ArgumentCaptor.forClass(View::class.java) verify(windowManager).addView(viewCaptor.capture(), any()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index fd1d76a5d02d3..9a4aa63ca496d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -113,8 +113,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(almostCloseToStartCast().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + almostCloseToStartCast().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -125,8 +126,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(almostCloseToEndCast().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + almostCloseToEndCast().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -137,8 +139,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(transferToReceiverTriggered().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -149,8 +152,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(transferToThisDeviceTriggered().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -161,8 +165,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(transferToReceiverSucceeded().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToReceiverSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -173,8 +178,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(transferToThisDeviceSucceeded().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToThisDeviceSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -185,8 +191,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(transferFailed().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToReceiverFailed().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -197,8 +204,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { null ) - assertThat(getChipView().getChipText()) - .isEqualTo(transferFailed().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToThisDeviceFailed().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -250,7 +258,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) - assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(chipView.getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) @@ -264,7 +274,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) - assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(chipView.getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) @@ -278,7 +290,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) - assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(chipView.getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) @@ -292,7 +306,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) - assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(chipView.getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) @@ -306,7 +322,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) - assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(chipView.getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) } @@ -355,8 +373,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { getChipView().getUndoButton().performClick() - assertThat(getChipView().getChipText()) - .isEqualTo(transferToThisDeviceTriggered().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test @@ -367,7 +386,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) - assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(chipView.getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE) } @@ -416,19 +437,38 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { getChipView().getUndoButton().performClick() - assertThat(getChipView().getChipText()) - .isEqualTo(transferToReceiverTriggered().getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) } @Test - fun transferFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() { - val state = transferFailed() + fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() { + val state = transferToReceiverFailed() controllerSender.displayChip(state) val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) - assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context)) + assertThat(getChipView().getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) + assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) + assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) + assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE) + } + + @Test + fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() { + val state = transferToThisDeviceFailed() + controllerSender.displayChip(state) + + val chipView = getChipView() + assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME) + assertThat(getChipView().getChipText()).isEqualTo( + state.state.getChipTextString(context, OTHER_DEVICE_NAME) + ) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE) @@ -475,7 +515,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { @Test fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() { controllerSender.displayChip(transferToReceiverTriggered()) - controllerSender.displayChip(transferFailed()) + controllerSender.displayChip(transferToReceiverFailed()) assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE) } @@ -498,7 +538,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { fakeClock.advanceTime(1000L) controllerSender.removeChip("fakeRemovalReason") - fakeClock.advanceTime(state.getTimeoutMs() + 1) + fakeClock.advanceTime(state.state.timeout + 1) verify(windowManager).removeView(any()) } @@ -521,7 +561,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { fakeClock.advanceTime(1000L) controllerSender.removeChip("fakeRemovalReason") - fakeClock.advanceTime(state.getTimeoutMs() + 1) + fakeClock.advanceTime(state.state.timeout + 1) verify(windowManager).removeView(any()) } @@ -546,34 +586,35 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { /** Helper method providing default parameters to not clutter up the tests. */ private fun almostCloseToStartCast() = - AlmostCloseToStartCast(PACKAGE_NAME, OTHER_DEVICE_NAME) + ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST, routeInfo) /** Helper method providing default parameters to not clutter up the tests. */ private fun almostCloseToEndCast() = - AlmostCloseToEndCast(PACKAGE_NAME, OTHER_DEVICE_NAME) + ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_END_CAST, routeInfo) /** Helper method providing default parameters to not clutter up the tests. */ private fun transferToReceiverTriggered() = - TransferToReceiverTriggered(PACKAGE_NAME, OTHER_DEVICE_NAME) + ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo) /** Helper method providing default parameters to not clutter up the tests. */ private fun transferToThisDeviceTriggered() = - TransferToThisDeviceTriggered(PACKAGE_NAME) + 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) = - TransferToReceiverSucceeded( - PACKAGE_NAME, OTHER_DEVICE_NAME, undoCallback - ) + 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) = - TransferToThisDeviceSucceeded( - PACKAGE_NAME, OTHER_DEVICE_NAME, undoCallback - ) + ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED, routeInfo, undoCallback) /** Helper method providing default parameters to not clutter up the tests. */ - private fun transferFailed() = TransferFailed(PACKAGE_NAME) + 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 APP_NAME = "Fake app name"