Merge "[Media TTT] Refactor media states to use an enum instead of sealed classes." into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
bb1a04a502
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.systemui.media.taptotransfer
|
package com.android.systemui.media.taptotransfer
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.StatusBarManager
|
import android.app.StatusBarManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.MediaRoute2Info
|
import android.media.MediaRoute2Info
|
||||||
@@ -23,16 +24,12 @@ import android.util.Log
|
|||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
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.sender.AlmostCloseToEndCast
|
import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
|
||||||
import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
|
import com.android.systemui.media.taptotransfer.sender.ChipStateSender
|
||||||
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.statusbar.commandline.Command
|
import com.android.systemui.statusbar.commandline.Command
|
||||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -46,28 +43,6 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
private val context: Context,
|
private val context: Context,
|
||||||
@Main private val mainExecutor: Executor
|
@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<String, Int> = 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 {
|
init {
|
||||||
commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
|
commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
|
||||||
commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() }
|
commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() }
|
||||||
@@ -76,21 +51,23 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
/** All commands for the sender device. */
|
/** All commands for the sender device. */
|
||||||
inner class SenderCommand : Command {
|
inner class SenderCommand : Command {
|
||||||
override fun execute(pw: PrintWriter, args: List<String>) {
|
override fun execute(pw: PrintWriter, args: List<String>) {
|
||||||
val routeInfo = MediaRoute2Info.Builder("id", args[0])
|
|
||||||
.addFeature("feature")
|
|
||||||
.setPackageName(TEST_PACKAGE_NAME)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val commandName = args[1]
|
val commandName = args[1]
|
||||||
@StatusBarManager.MediaTransferSenderState
|
@StatusBarManager.MediaTransferSenderState
|
||||||
val displayState = stateStringToStateInt[commandName]
|
val displayState: Int?
|
||||||
if (displayState == null) {
|
try {
|
||||||
|
displayState = ChipStateSender.getSenderStateIdFromName(commandName)
|
||||||
|
} catch (ex: IllegalArgumentException) {
|
||||||
pw.println("Invalid command name $commandName")
|
pw.println("Invalid command name $commandName")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE
|
||||||
val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
|
val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
|
||||||
as StatusBarManager
|
as StatusBarManager
|
||||||
|
val routeInfo = MediaRoute2Info.Builder("id", args[0])
|
||||||
|
.addFeature("feature")
|
||||||
|
.setPackageName(TEST_PACKAGE_NAME)
|
||||||
|
.build()
|
||||||
statusBarManager.updateMediaTapToTransferSenderDisplay(
|
statusBarManager.updateMediaTapToTransferSenderDisplay(
|
||||||
displayState,
|
displayState,
|
||||||
routeInfo,
|
routeInfo,
|
||||||
@@ -136,6 +113,17 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
/** All commands for the receiver device. */
|
/** All commands for the receiver device. */
|
||||||
inner class ReceiverCommand : Command {
|
inner class ReceiverCommand : Command {
|
||||||
override fun execute(pw: PrintWriter, args: List<String>) {
|
override fun execute(pw: PrintWriter, args: List<String>) {
|
||||||
|
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)
|
val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
|
||||||
as StatusBarManager
|
as StatusBarManager
|
||||||
val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
|
val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
|
||||||
@@ -143,24 +131,12 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
.setPackageName(TEST_PACKAGE_NAME)
|
.setPackageName(TEST_PACKAGE_NAME)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
when(val commandName = args[0]) {
|
statusBarManager.updateMediaTapToTransferReceiverDisplay(
|
||||||
CLOSE_TO_SENDER_STATE ->
|
displayState,
|
||||||
statusBarManager.updateMediaTapToTransferReceiverDisplay(
|
routeInfo,
|
||||||
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
|
null,
|
||||||
routeInfo,
|
null
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun help(pw: PrintWriter) {
|
override fun help(pw: PrintWriter) {
|
||||||
@@ -173,11 +149,5 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
const val SENDER_COMMAND = "media-ttt-chip-sender"
|
const val SENDER_COMMAND = "media-ttt-chip-sender"
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
const val RECEIVER_COMMAND = "media-ttt-chip-receiver"
|
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 CLI_TAG = "MediaTransferCli"
|
||||||
private const val TEST_PACKAGE_NAME = "com.android.systemui"
|
private const val TEST_PACKAGE_NAME = "com.android.systemui"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -19,14 +19,16 @@ package com.android.systemui.media.taptotransfer.common
|
|||||||
import android.annotation.LayoutRes
|
import android.annotation.LayoutRes
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.PixelFormat
|
import android.graphics.PixelFormat
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.util.Log
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.annotation.VisibleForTesting
|
|
||||||
import com.android.internal.widget.CachingIconView
|
import com.android.internal.widget.CachingIconView
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
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
|
* Subclasses need to override and implement [updateChipView], which is where they can control what
|
||||||
* gets displayed to the user.
|
* 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 <T> in [updateChipView].
|
||||||
*/
|
*/
|
||||||
abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
|
||||||
internal val context: Context,
|
internal val context: Context,
|
||||||
internal val logger: MediaTttLogger,
|
internal val logger: MediaTttLogger,
|
||||||
private val windowManager: WindowManager,
|
private val windowManager: WindowManager,
|
||||||
@@ -64,10 +69,10 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The chip view currently being displayed. Null if the chip is not being displayed. */
|
/** 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. */
|
/** 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.
|
* Displays the chip with the current state.
|
||||||
@@ -75,7 +80,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
* This method handles inflating and attaching the view, then delegates to [updateChipView] to
|
* This method handles inflating and attaching the view, then delegates to [updateChipView] to
|
||||||
* display the correct information in the chip.
|
* display the correct information in the chip.
|
||||||
*/
|
*/
|
||||||
fun displayChip(chipState: T) {
|
fun displayChip(chipInfo: T) {
|
||||||
val oldChipView = chipView
|
val oldChipView = chipView
|
||||||
if (chipView == null) {
|
if (chipView == null) {
|
||||||
chipView = LayoutInflater
|
chipView = LayoutInflater
|
||||||
@@ -84,7 +89,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
}
|
}
|
||||||
val currentChipView = chipView!!
|
val currentChipView = chipView!!
|
||||||
|
|
||||||
updateChipView(chipState, currentChipView)
|
updateChipView(chipInfo, currentChipView)
|
||||||
|
|
||||||
// Add view if necessary
|
// Add view if necessary
|
||||||
if (oldChipView == null) {
|
if (oldChipView == null) {
|
||||||
@@ -96,7 +101,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
cancelChipViewTimeout?.run()
|
cancelChipViewTimeout?.run()
|
||||||
cancelChipViewTimeout = mainExecutor.executeDelayed(
|
cancelChipViewTimeout = mainExecutor.executeDelayed(
|
||||||
{ removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
|
{ removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
|
||||||
chipState.getTimeoutMs()
|
chipInfo.getTimeoutMs()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,20 +122,28 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
* 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.
|
* 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<CachingIconView>(R.id.app_icon)
|
val appIconView = currentChipView.requireViewById<CachingIconView>(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) {
|
val visibility = if (appIcon != null) {
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
@@ -140,6 +153,30 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
appIconView.visibility = visibility
|
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) {
|
private fun onScreenTapped(e: MotionEvent) {
|
||||||
val view = chipView ?: return
|
val view = chipView ?: return
|
||||||
// If the tap is within the chip bounds, we shouldn't hide the chip (in case users think the
|
// 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_TIMEOUT = "TIMEOUT"
|
||||||
const val REASON_SCREEN_TAP = "SCREEN_TAP"
|
const val REASON_SCREEN_TAP = "SCREEN_TAP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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!!
|
|
||||||
@@ -16,35 +16,41 @@
|
|||||||
|
|
||||||
package com.android.systemui.media.taptotransfer.receiver
|
package com.android.systemui.media.taptotransfer.receiver
|
||||||
|
|
||||||
import android.content.Context
|
import android.app.StatusBarManager
|
||||||
import android.graphics.drawable.Drawable
|
import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
|
||||||
import com.android.systemui.media.taptotransfer.common.MediaTttChipState
|
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
|
* A class that stores all the information necessary to display the media tap-to-transfer chip on
|
||||||
* the receiver device.
|
* 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(
|
enum class ChipStateReceiver(
|
||||||
appPackageName: String?,
|
@StatusBarManager.MediaTransferSenderState val stateInt: Int,
|
||||||
private val appIconDrawable: Drawable?,
|
) {
|
||||||
private val appName: CharSequence?
|
CLOSE_TO_SENDER(
|
||||||
) : MediaTttChipState(appPackageName) {
|
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
|
||||||
override fun getAppIcon(context: Context): Drawable? {
|
),
|
||||||
if (appIconDrawable != null) {
|
FAR_FROM_SENDER(
|
||||||
return appIconDrawable
|
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
|
||||||
}
|
);
|
||||||
return super.getAppIcon(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAppName(context: Context): String? {
|
companion object {
|
||||||
if (appName != null) {
|
/**
|
||||||
return appName.toString()
|
* Returns the receiver state enum associated with the given [displayState] from
|
||||||
}
|
* [StatusBarManager].
|
||||||
return super.getAppName(context)
|
*/
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.systemui.media.taptotransfer.receiver
|
|||||||
|
|
||||||
import android.app.StatusBarManager
|
import android.app.StatusBarManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.Icon
|
import android.graphics.drawable.Icon
|
||||||
import android.media.MediaRoute2Info
|
import android.media.MediaRoute2Info
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
@@ -27,6 +28,8 @@ import android.view.WindowManager
|
|||||||
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.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.MediaTttChipControllerCommon
|
||||||
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
|
||||||
@@ -50,7 +53,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
mainExecutor: DelayableExecutor,
|
mainExecutor: DelayableExecutor,
|
||||||
tapGestureDetector: TapGestureDetector,
|
tapGestureDetector: TapGestureDetector,
|
||||||
@Main private val mainHandler: Handler,
|
@Main private val mainHandler: Handler,
|
||||||
) : MediaTttChipControllerCommon<ChipStateReceiver>(
|
) : MediaTttChipControllerCommon<ChipReceiverInfo>(
|
||||||
context,
|
context,
|
||||||
logger,
|
logger,
|
||||||
windowManager,
|
windowManager,
|
||||||
@@ -82,45 +85,50 @@ class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
appIcon: Icon?,
|
appIcon: Icon?,
|
||||||
appName: CharSequence?
|
appName: CharSequence?
|
||||||
) {
|
) {
|
||||||
logger.logStateChange(stateIntToString(displayState), routeInfo.id)
|
val chipState: ChipStateReceiver? = ChipStateReceiver.getReceiverStateFromId(displayState)
|
||||||
when(displayState) {
|
val stateName = chipState?.name ?: "Invalid"
|
||||||
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> {
|
logger.logStateChange(stateName, routeInfo.id)
|
||||||
val packageName = routeInfo.packageName
|
|
||||||
if (appIcon == null) {
|
if (chipState == null) {
|
||||||
displayChip(ChipStateReceiver(packageName, null, appName))
|
Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
|
||||||
} else {
|
return
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
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) {
|
override fun updateChipView(chipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
|
||||||
setIcon(chipState, currentChipView)
|
setIcon(
|
||||||
}
|
currentChipView,
|
||||||
|
chipInfo.routeInfo.packageName,
|
||||||
private fun stateIntToString(@StatusBarManager.MediaTransferReceiverState state: Int): String {
|
chipInfo.appIconDrawableOverride,
|
||||||
return when (state) {
|
chipInfo.appNameOverride
|
||||||
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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 RECEIVER_TAG = "MediaTapToTransferRcvr"
|
||||||
private const val CLOSE_TO_SENDER = "CLOSE_TO_SENDER"
|
|
||||||
private const val FAR_FROM_SENDER = "FAR_FROM_SENDER"
|
|
||||||
|
|||||||
@@ -16,27 +16,168 @@
|
|||||||
|
|
||||||
package com.android.systemui.media.taptotransfer.sender
|
package com.android.systemui.media.taptotransfer.sender
|
||||||
|
|
||||||
|
import android.app.StatusBarManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.media.MediaRoute2Info
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import com.android.internal.statusbar.IUndoMediaTransferCallback
|
import com.android.internal.statusbar.IUndoMediaTransferCallback
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.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
|
* A class enumerating all the possible states of the media tap-to-transfer chip on the sender
|
||||||
* the sender device.
|
* device.
|
||||||
*
|
*
|
||||||
* This is a sealed class where each subclass represents a specific chip state. Each subclass can
|
* @property stateInt the integer from [StatusBarManager] corresponding with this state.
|
||||||
* contain additional information that is necessary for only that 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(
|
enum class ChipStateSender(
|
||||||
appPackageName: String?
|
@StatusBarManager.MediaTransferSenderState val stateInt: Int,
|
||||||
) : MediaTttChipState(appPackageName) {
|
@StringRes val stringResId: Int?,
|
||||||
/** Returns a fully-formed string with the text that the chip should display. */
|
val isMidTransfer: Boolean = false,
|
||||||
abstract fun getChipTextString(context: Context): String
|
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
|
* 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
|
* @param controllerSender passed as a parameter in case we want to display a new chip state
|
||||||
* when undo is clicked.
|
* 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(
|
open fun undoClickListener(
|
||||||
controllerSender: MediaTttChipControllerSender
|
controllerSender: MediaTttChipControllerSender,
|
||||||
|
routeInfo: MediaRoute2Info,
|
||||||
|
undoCallback: IUndoMediaTransferCallback?
|
||||||
): View.OnClickListener? = null
|
): View.OnClickListener? = null
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
companion object {
|
||||||
* 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
|
* Returns the sender state enum associated with the given [displayState] from
|
||||||
* transfer to the receiver.
|
* [StatusBarManager].
|
||||||
*
|
*/
|
||||||
* @property otherDeviceName the name of the other device involved in the transfer.
|
fun getSenderStateFromId(
|
||||||
*/
|
@StatusBarManager.MediaTransferSenderState displayState: Int,
|
||||||
class AlmostCloseToStartCast(
|
): ChipStateSender = values().first { it.stateInt == displayState }
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A state representing that the two devices are close but not close enough to *end* a cast that's
|
* Returns the state int from [StatusBarManager] associated with the given sender state
|
||||||
* currently occurring the receiver device. The chip will instruct the user to move closer in order
|
* name.
|
||||||
* to initiate the transfer from the receiver and back onto this device (the original sender).
|
*
|
||||||
*
|
* @param name the name of one of the [ChipStateSender] enums.
|
||||||
* @property otherDeviceName the name of the other device involved in the transfer.
|
*/
|
||||||
*/
|
@StatusBarManager.MediaTransferSenderState
|
||||||
class AlmostCloseToEndCast(
|
fun getSenderStateIdFromName(name: String): Int = valueOf(name).stateInt
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give the Transfer*Triggered states a longer timeout since those states represent an active
|
// 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
|
// process and we should keep the user informed about it as long as possible (but don't allow it to
|
||||||
// continue indefinitely).
|
// continue indefinitely).
|
||||||
private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 15000L
|
private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 15000L
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.android.internal.statusbar.IUndoMediaTransferCallback
|
|||||||
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.common.ChipInfoCommon
|
||||||
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
|
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
|
||||||
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
|
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
|
||||||
import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
|
import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
|
||||||
@@ -50,7 +51,7 @@ class MediaTttChipControllerSender @Inject constructor(
|
|||||||
viewUtil: ViewUtil,
|
viewUtil: ViewUtil,
|
||||||
@Main mainExecutor: DelayableExecutor,
|
@Main mainExecutor: DelayableExecutor,
|
||||||
tapGestureDetector: TapGestureDetector,
|
tapGestureDetector: TapGestureDetector,
|
||||||
) : MediaTttChipControllerCommon<ChipStateSender>(
|
) : MediaTttChipControllerCommon<ChipSenderInfo>(
|
||||||
context,
|
context,
|
||||||
logger,
|
logger,
|
||||||
windowManager,
|
windowManager,
|
||||||
@@ -82,104 +83,82 @@ class MediaTttChipControllerSender @Inject constructor(
|
|||||||
routeInfo: MediaRoute2Info,
|
routeInfo: MediaRoute2Info,
|
||||||
undoCallback: IUndoMediaTransferCallback?
|
undoCallback: IUndoMediaTransferCallback?
|
||||||
) {
|
) {
|
||||||
logger.logStateChange(stateIntToString(displayState), routeInfo.id)
|
val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState)
|
||||||
val appPackageName = routeInfo.packageName
|
val stateName = chipState?.name ?: "Invalid"
|
||||||
val otherDeviceName = routeInfo.name.toString()
|
logger.logStateChange(stateName, routeInfo.id)
|
||||||
val chipState = when(displayState) {
|
|
||||||
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
|
if (chipState == null) {
|
||||||
AlmostCloseToStartCast(appPackageName, otherDeviceName)
|
Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
|
||||||
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
|
return
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chipState?.let {
|
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
|
||||||
displayChip(it)
|
removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
|
||||||
|
} else {
|
||||||
|
displayChip(ChipSenderInfo(chipState, routeInfo, undoCallback))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Displays the chip view for the given state. */
|
/** 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
|
currentlyDisplayedChipState = chipState
|
||||||
|
|
||||||
// App icon
|
// App icon
|
||||||
setIcon(chipState, currentChipView)
|
setIcon(currentChipView, chipInfo.routeInfo.packageName)
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
|
val otherDeviceName = chipInfo.routeInfo.name.toString()
|
||||||
currentChipView.requireViewById<TextView>(R.id.text).apply {
|
currentChipView.requireViewById<TextView>(R.id.text).apply {
|
||||||
text = chipState.getChipTextString(context)
|
text = chipState.getChipTextString(context, otherDeviceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loading
|
// Loading
|
||||||
currentChipView.requireViewById<View>(R.id.loading).visibility =
|
currentChipView.requireViewById<View>(R.id.loading).visibility =
|
||||||
if (chipState.showLoading()) { View.VISIBLE } else { View.GONE }
|
chipState.isMidTransfer.visibleIfTrue()
|
||||||
|
|
||||||
|
|
||||||
// Undo
|
// Undo
|
||||||
val undoView = currentChipView.requireViewById<View>(R.id.undo)
|
val undoView = currentChipView.requireViewById<View>(R.id.undo)
|
||||||
val undoClickListener = chipState.undoClickListener(this)
|
val undoClickListener = chipState.undoClickListener(
|
||||||
|
this, chipInfo.routeInfo, chipInfo.undoCallback
|
||||||
|
)
|
||||||
undoView.setOnClickListener(undoClickListener)
|
undoView.setOnClickListener(undoClickListener)
|
||||||
undoView.visibility = if (undoClickListener != null) { View.VISIBLE } else { View.GONE }
|
undoView.visibility = (undoClickListener != null).visibleIfTrue()
|
||||||
|
|
||||||
// Failure
|
// Failure
|
||||||
val showFailure = chipState is TransferFailed
|
|
||||||
currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
|
currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
|
||||||
if (showFailure) { View.VISIBLE } else { View.GONE }
|
chipState.isTransferFailure.visibleIfTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeChip(removalReason: String) {
|
override fun removeChip(removalReason: String) {
|
||||||
// Don't remove the chip if we're mid-transfer since the user should still be able to
|
// 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.)
|
// see the status of the transfer. (But do remove it if it's finally timed out.)
|
||||||
if ((currentlyDisplayedChipState is TransferToReceiverTriggered ||
|
if (currentlyDisplayedChipState?.isMidTransfer == true
|
||||||
currentlyDisplayedChipState is TransferToThisDeviceTriggered)
|
&& removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
|
||||||
&& removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
super.removeChip(removalReason)
|
super.removeChip(removalReason)
|
||||||
currentlyDisplayedChipState = null
|
currentlyDisplayedChipState = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stateIntToString(@StatusBarManager.MediaTransferSenderState state: Int): String {
|
private fun Boolean.visibleIfTrue(): Int {
|
||||||
return when(state) {
|
return if (this) {
|
||||||
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
|
View.VISIBLE
|
||||||
"ALMOST_CLOSE_TO_START_CAST"
|
} else {
|
||||||
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
|
View.GONE
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ChipSenderInfo(
|
||||||
|
val state: ChipStateSender,
|
||||||
|
val routeInfo: MediaRoute2Info,
|
||||||
|
val undoCallback: IUndoMediaTransferCallback? = null
|
||||||
|
) : ChipInfoCommon {
|
||||||
|
override fun getTimeoutMs() = state.timeout
|
||||||
|
}
|
||||||
|
|
||||||
const val SENDER_TAG = "MediaTapToTransferSender"
|
const val SENDER_TAG = "MediaTapToTransferSender"
|
||||||
private const val FAR_FROM_RECEIVER = "FAR_FROM_RECEIVER"
|
|
||||||
|
|||||||
@@ -21,13 +21,8 @@ import android.content.Context
|
|||||||
import android.media.MediaRoute2Info
|
import android.media.MediaRoute2Info
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast
|
import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
|
||||||
import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
|
import com.android.systemui.media.taptotransfer.sender.ChipStateSender
|
||||||
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.statusbar.commandline.Command
|
import com.android.systemui.statusbar.commandline.Command
|
||||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
@@ -88,7 +83,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun sender_almostCloseToStartCast_serviceCallbackCalled() {
|
fun sender_almostCloseToStartCast_serviceCallbackCalled() {
|
||||||
commandRegistry.onShellCommand(
|
commandRegistry.onShellCommand(
|
||||||
pw, getSenderCommand(AlmostCloseToStartCast::class.simpleName!!)
|
pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
||||||
@@ -103,7 +98,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun sender_almostCloseToEndCast_serviceCallbackCalled() {
|
fun sender_almostCloseToEndCast_serviceCallbackCalled() {
|
||||||
commandRegistry.onShellCommand(
|
commandRegistry.onShellCommand(
|
||||||
pw, getSenderCommand(AlmostCloseToEndCast::class.simpleName!!)
|
pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_END_CAST.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
||||||
@@ -118,7 +113,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun sender_transferToReceiverTriggered_chipDisplayWithCorrectState() {
|
fun sender_transferToReceiverTriggered_chipDisplayWithCorrectState() {
|
||||||
commandRegistry.onShellCommand(
|
commandRegistry.onShellCommand(
|
||||||
pw, getSenderCommand(TransferToReceiverTriggered::class.simpleName!!)
|
pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
||||||
@@ -133,7 +128,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() {
|
fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() {
|
||||||
commandRegistry.onShellCommand(
|
commandRegistry.onShellCommand(
|
||||||
pw, getSenderCommand(TransferToThisDeviceTriggered::class.simpleName!!)
|
pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
|
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
|
||||||
@@ -146,7 +141,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() {
|
fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() {
|
||||||
commandRegistry.onShellCommand(
|
commandRegistry.onShellCommand(
|
||||||
pw, getSenderCommand(TransferToReceiverSucceeded::class.simpleName!!)
|
pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
||||||
@@ -161,7 +156,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() {
|
fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() {
|
||||||
commandRegistry.onShellCommand(
|
commandRegistry.onShellCommand(
|
||||||
pw, getSenderCommand(TransferToThisDeviceSucceeded::class.simpleName!!)
|
pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
|
||||||
@@ -174,8 +169,10 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun sender_transferFailed_serviceCallbackCalled() {
|
fun sender_transferToReceiverFailed_serviceCallbackCalled() {
|
||||||
commandRegistry.onShellCommand(pw, getSenderCommand(TransferFailed::class.simpleName!!))
|
commandRegistry.onShellCommand(
|
||||||
|
pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED.name)
|
||||||
|
)
|
||||||
|
|
||||||
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
|
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
|
||||||
eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED),
|
eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED),
|
||||||
@@ -184,9 +181,24 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
nullable())
|
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
|
@Test
|
||||||
fun sender_farFromReceiver_serviceCallbackCalled() {
|
fun sender_farFromReceiver_serviceCallbackCalled() {
|
||||||
commandRegistry.onShellCommand(pw, getSenderCommand(FAR_FROM_RECEIVER_STATE))
|
commandRegistry.onShellCommand(
|
||||||
|
pw, getSenderCommand(ChipStateSender.FAR_FROM_RECEIVER.name)
|
||||||
|
)
|
||||||
|
|
||||||
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
|
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
|
||||||
eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER),
|
eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER),
|
||||||
@@ -197,7 +209,9 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun receiver_closeToSender_serviceCallbackCalled() {
|
fun receiver_closeToSender_serviceCallbackCalled() {
|
||||||
commandRegistry.onShellCommand(pw, getReceiverCommand(CLOSE_TO_SENDER_STATE))
|
commandRegistry.onShellCommand(
|
||||||
|
pw, getReceiverCommand(ChipStateReceiver.CLOSE_TO_SENDER.name)
|
||||||
|
)
|
||||||
|
|
||||||
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
|
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
|
||||||
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER),
|
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER),
|
||||||
@@ -209,7 +223,9 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun receiver_farFromSender_serviceCallbackCalled() {
|
fun receiver_farFromSender_serviceCallbackCalled() {
|
||||||
commandRegistry.onShellCommand(pw, getReceiverCommand(FAR_FROM_SENDER_STATE))
|
commandRegistry.onShellCommand(
|
||||||
|
pw, getReceiverCommand(ChipStateReceiver.FAR_FROM_SENDER.name)
|
||||||
|
)
|
||||||
|
|
||||||
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
|
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
|
||||||
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER),
|
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER),
|
||||||
|
|||||||
@@ -17,7 +17,10 @@
|
|||||||
package com.android.systemui.media.taptotransfer.common
|
package com.android.systemui.media.taptotransfer.common
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.media.MediaRoute2Info
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -27,6 +30,7 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
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.statusbar.gesture.TapGestureDetector
|
||||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
@@ -40,6 +44,7 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.ArgumentCaptor
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.eq
|
||||||
import org.mockito.Mockito.never
|
import org.mockito.Mockito.never
|
||||||
import org.mockito.Mockito.reset
|
import org.mockito.Mockito.reset
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
@@ -48,12 +53,16 @@ import org.mockito.MockitoAnnotations
|
|||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
||||||
private lateinit var controllerCommon: MediaTttChipControllerCommon<MediaTttChipState>
|
private lateinit var controllerCommon: MediaTttChipControllerCommon<ChipInfo>
|
||||||
|
|
||||||
private lateinit var fakeClock: FakeSystemClock
|
private lateinit var fakeClock: FakeSystemClock
|
||||||
private lateinit var fakeExecutor: FakeExecutor
|
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
|
@Mock
|
||||||
private lateinit var logger: MediaTttLogger
|
private lateinit var logger: MediaTttLogger
|
||||||
@Mock
|
@Mock
|
||||||
@@ -66,7 +75,15 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
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<PackageManager.ApplicationInfoFlags>()
|
||||||
|
)).thenReturn(applicationInfo)
|
||||||
|
context.setMockPackageManager(packageManager)
|
||||||
|
|
||||||
fakeClock = FakeSystemClock()
|
fakeClock = FakeSystemClock()
|
||||||
fakeExecutor = FakeExecutor(fakeClock)
|
fakeExecutor = FakeExecutor(fakeClock)
|
||||||
|
|
||||||
@@ -100,7 +117,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
controllerCommon.displayChip(state)
|
controllerCommon.displayChip(state)
|
||||||
reset(windowManager)
|
reset(windowManager)
|
||||||
|
|
||||||
fakeClock.advanceTime(state.getTimeoutMs() - 1)
|
fakeClock.advanceTime(TIMEOUT_MS - 1)
|
||||||
|
|
||||||
verify(windowManager, never()).removeView(any())
|
verify(windowManager, never()).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -111,7 +128,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
controllerCommon.displayChip(state)
|
controllerCommon.displayChip(state)
|
||||||
reset(windowManager)
|
reset(windowManager)
|
||||||
|
|
||||||
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
fakeClock.advanceTime(TIMEOUT_MS + 1)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -128,7 +145,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
controllerCommon.displayChip(getState())
|
controllerCommon.displayChip(getState())
|
||||||
|
|
||||||
// Wait until the timeout for the first display would've happened
|
// 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 we didn't hide the chip
|
||||||
verify(windowManager, never()).removeView(any())
|
verify(windowManager, never()).removeView(any())
|
||||||
@@ -145,7 +162,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
controllerCommon.displayChip(getState())
|
controllerCommon.displayChip(getState())
|
||||||
|
|
||||||
// Ensure we still hide the chip eventually
|
// Ensure we still hide the chip eventually
|
||||||
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
fakeClock.advanceTime(TIMEOUT_MS + 1)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -172,16 +189,45 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setIcon_viewHasIconAndContentDescription() {
|
fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
|
||||||
controllerCommon.displayChip(getState())
|
controllerCommon.displayChip(getState())
|
||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
|
|
||||||
val state = TestChipState(PACKAGE_NAME)
|
controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null)
|
||||||
controllerCommon.setIcon(state, chipView)
|
|
||||||
|
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
|
||||||
assertThat(chipView.getAppIconView().contentDescription)
|
}
|
||||||
.isEqualTo(state.getAppName(context))
|
|
||||||
|
@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
|
@Test
|
||||||
@@ -218,7 +264,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
verify(windowManager, never()).removeView(any())
|
verify(windowManager, never()).removeView(any())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getState() = MediaTttChipState(PACKAGE_NAME)
|
private fun getState() = ChipInfo()
|
||||||
|
|
||||||
private fun getChipView(): ViewGroup {
|
private fun getChipView(): ViewGroup {
|
||||||
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
|
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
|
||||||
@@ -235,7 +281,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
viewUtil: ViewUtil,
|
viewUtil: ViewUtil,
|
||||||
@Main mainExecutor: DelayableExecutor,
|
@Main mainExecutor: DelayableExecutor,
|
||||||
tapGestureDetector: TapGestureDetector,
|
tapGestureDetector: TapGestureDetector,
|
||||||
) : MediaTttChipControllerCommon<MediaTttChipState>(
|
) : MediaTttChipControllerCommon<ChipInfo>(
|
||||||
context,
|
context,
|
||||||
logger,
|
logger,
|
||||||
windowManager,
|
windowManager,
|
||||||
@@ -244,13 +290,16 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
tapGestureDetector,
|
tapGestureDetector,
|
||||||
R.layout.media_ttt_chip
|
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) {
|
inner class ChipInfo : ChipInfoCommon {
|
||||||
override fun getAppIcon(context: Context) = appIconDrawable
|
override fun getTimeoutMs() = TIMEOUT_MS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val PACKAGE_NAME = "com.android.systemui"
|
private const val PACKAGE_NAME = "com.android.systemui"
|
||||||
|
private const val APP_NAME = "Fake App Name"
|
||||||
|
private const val TIMEOUT_MS = 10000L
|
||||||
|
|||||||
@@ -157,44 +157,6 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
verify(logger).logStateChange(any(), any())
|
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 {
|
private fun getChipView(): ViewGroup {
|
||||||
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
|
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
|
||||||
verify(windowManager).addView(viewCaptor.capture(), any())
|
verify(windowManager).addView(viewCaptor.capture(), any())
|
||||||
|
|||||||
@@ -113,8 +113,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(almostCloseToStartCast().getChipTextString(context))
|
almostCloseToStartCast().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -125,8 +126,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(almostCloseToEndCast().getChipTextString(context))
|
almostCloseToEndCast().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -137,8 +139,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferToReceiverTriggered().getChipTextString(context))
|
transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -149,8 +152,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferToThisDeviceTriggered().getChipTextString(context))
|
transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -161,8 +165,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferToReceiverSucceeded().getChipTextString(context))
|
transferToReceiverSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -173,8 +178,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferToThisDeviceSucceeded().getChipTextString(context))
|
transferToThisDeviceSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -185,8 +191,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferFailed().getChipTextString(context))
|
transferToReceiverFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -197,8 +204,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferFailed().getChipTextString(context))
|
transferToThisDeviceFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -250,7 +258,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
||||||
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
|
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.getLoadingIconVisibility()).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
||||||
@@ -264,7 +274,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
||||||
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
|
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.getLoadingIconVisibility()).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
||||||
@@ -278,7 +290,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
||||||
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
|
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.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
|
||||||
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
||||||
@@ -292,7 +306,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
||||||
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
|
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.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
|
||||||
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
||||||
@@ -306,7 +322,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
||||||
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
|
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.getLoadingIconVisibility()).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
||||||
}
|
}
|
||||||
@@ -355,8 +373,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
getChipView().getUndoButton().performClick()
|
getChipView().getUndoButton().performClick()
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferToThisDeviceTriggered().getChipTextString(context))
|
transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -367,7 +386,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
||||||
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
|
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.getLoadingIconVisibility()).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
|
||||||
}
|
}
|
||||||
@@ -416,19 +437,38 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
getChipView().getUndoButton().performClick()
|
getChipView().getUndoButton().performClick()
|
||||||
|
|
||||||
assertThat(getChipView().getChipText())
|
assertThat(getChipView().getChipText()).isEqualTo(
|
||||||
.isEqualTo(transferToReceiverTriggered().getChipTextString(context))
|
transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun transferFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
|
fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
|
||||||
val state = transferFailed()
|
val state = transferToReceiverFailed()
|
||||||
controllerSender.displayChip(state)
|
controllerSender.displayChip(state)
|
||||||
|
|
||||||
val chipView = getChipView()
|
val chipView = getChipView()
|
||||||
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
|
||||||
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
|
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.getLoadingIconVisibility()).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
|
||||||
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE)
|
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE)
|
||||||
@@ -475,7 +515,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
|
fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
|
||||||
controllerSender.displayChip(transferToReceiverTriggered())
|
controllerSender.displayChip(transferToReceiverTriggered())
|
||||||
controllerSender.displayChip(transferFailed())
|
controllerSender.displayChip(transferToReceiverFailed())
|
||||||
|
|
||||||
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
|
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
|
||||||
}
|
}
|
||||||
@@ -498,7 +538,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
fakeClock.advanceTime(1000L)
|
fakeClock.advanceTime(1000L)
|
||||||
controllerSender.removeChip("fakeRemovalReason")
|
controllerSender.removeChip("fakeRemovalReason")
|
||||||
|
|
||||||
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
fakeClock.advanceTime(state.state.timeout + 1)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -521,7 +561,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
fakeClock.advanceTime(1000L)
|
fakeClock.advanceTime(1000L)
|
||||||
controllerSender.removeChip("fakeRemovalReason")
|
controllerSender.removeChip("fakeRemovalReason")
|
||||||
|
|
||||||
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
fakeClock.advanceTime(state.state.timeout + 1)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -546,34 +586,35 @@ 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 almostCloseToStartCast() =
|
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. */
|
/** Helper method providing default parameters to not clutter up the tests. */
|
||||||
private fun almostCloseToEndCast() =
|
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. */
|
/** Helper method providing default parameters to not clutter up the tests. */
|
||||||
private fun transferToReceiverTriggered() =
|
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. */
|
/** Helper method providing default parameters to not clutter up the tests. */
|
||||||
private fun transferToThisDeviceTriggered() =
|
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. */
|
/** Helper method providing default parameters to not clutter up the tests. */
|
||||||
private fun transferToReceiverSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
|
private fun transferToReceiverSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
|
||||||
TransferToReceiverSucceeded(
|
ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED, routeInfo, undoCallback)
|
||||||
PACKAGE_NAME, OTHER_DEVICE_NAME, undoCallback
|
|
||||||
)
|
|
||||||
|
|
||||||
/** Helper method providing default parameters to not clutter up the tests. */
|
/** Helper method providing default parameters to not clutter up the tests. */
|
||||||
private fun transferToThisDeviceSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
|
private fun transferToThisDeviceSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
|
||||||
TransferToThisDeviceSucceeded(
|
ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED, routeInfo, undoCallback)
|
||||||
PACKAGE_NAME, OTHER_DEVICE_NAME, undoCallback
|
|
||||||
)
|
|
||||||
|
|
||||||
/** Helper method providing default parameters to not clutter up the tests. */
|
/** 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"
|
private const val APP_NAME = "Fake app name"
|
||||||
|
|||||||
Reference in New Issue
Block a user