Merge "[Media TTT] Handle multiple devices" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
473235f30b
@@ -61,7 +61,7 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
@SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE
|
@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])
|
val routeInfo = MediaRoute2Info.Builder(if (args.size >= 4) args[3] else "id", args[0])
|
||||||
.addFeature("feature")
|
.addFeature("feature")
|
||||||
val useAppIcon = !(args.size >= 3 && args[2] == "useAppIcon=false")
|
val useAppIcon = !(args.size >= 3 && args[2] == "useAppIcon=false")
|
||||||
if (useAppIcon) {
|
if (useAppIcon) {
|
||||||
@@ -107,7 +107,7 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
|
|
||||||
override fun help(pw: PrintWriter) {
|
override fun help(pw: PrintWriter) {
|
||||||
pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND " +
|
pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND " +
|
||||||
"<deviceName> <chipState> useAppIcon=[true|false]")
|
"<deviceName> <chipState> useAppIcon=[true|false] <id>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,8 +127,10 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
@SuppressLint("WrongConstant") // sysui is allowed to call STATUS_BAR_SERVICE
|
@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(
|
||||||
.addFeature("feature")
|
if (args.size >= 3) args[2] else "id",
|
||||||
|
"Test Name"
|
||||||
|
).addFeature("feature")
|
||||||
val useAppIcon = !(args.size >= 2 && args[1] == "useAppIcon=false")
|
val useAppIcon = !(args.size >= 2 && args[1] == "useAppIcon=false")
|
||||||
if (useAppIcon) {
|
if (useAppIcon) {
|
||||||
routeInfo.setClientPackageName(TEST_PACKAGE_NAME)
|
routeInfo.setClientPackageName(TEST_PACKAGE_NAME)
|
||||||
@@ -144,7 +146,7 @@ class MediaTttCommandLineHelper @Inject constructor(
|
|||||||
|
|
||||||
override fun help(pw: PrintWriter) {
|
override fun help(pw: PrintWriter) {
|
||||||
pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " +
|
pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " +
|
||||||
"<chipState> useAppIcon=[true|false]")
|
"<chipState> useAppIcon=[true|false] <id>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,18 +121,32 @@ class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
uiEventLogger.logReceiverStateChange(chipState)
|
uiEventLogger.logReceiverStateChange(chipState)
|
||||||
|
|
||||||
if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
|
if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
|
||||||
removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER.name)
|
removeView(routeInfo.id, removalReason = ChipStateReceiver.FAR_FROM_SENDER.name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (appIcon == null) {
|
if (appIcon == null) {
|
||||||
displayView(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
|
displayView(
|
||||||
|
ChipReceiverInfo(
|
||||||
|
routeInfo,
|
||||||
|
appIconDrawableOverride = null,
|
||||||
|
appName,
|
||||||
|
id = routeInfo.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
appIcon.loadDrawableAsync(
|
appIcon.loadDrawableAsync(
|
||||||
context,
|
context,
|
||||||
Icon.OnDrawableLoadedListener { drawable ->
|
Icon.OnDrawableLoadedListener { drawable ->
|
||||||
displayView(ChipReceiverInfo(routeInfo, drawable, appName))
|
displayView(
|
||||||
|
ChipReceiverInfo(
|
||||||
|
routeInfo,
|
||||||
|
drawable,
|
||||||
|
appName,
|
||||||
|
id = routeInfo.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
// Notify the listener on the main handler since the listener will update
|
// Notify the listener on the main handler since the listener will update
|
||||||
// the UI.
|
// the UI.
|
||||||
@@ -234,4 +248,5 @@ data class ChipReceiverInfo(
|
|||||||
val appNameOverride: CharSequence?,
|
val appNameOverride: CharSequence?,
|
||||||
override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER,
|
override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER,
|
||||||
override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER,
|
override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER,
|
||||||
|
override val id: String,
|
||||||
) : TemporaryViewInfo()
|
) : TemporaryViewInfo()
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
displayedState = null
|
displayedState = null
|
||||||
chipbarCoordinator.removeView(removalReason)
|
chipbarCoordinator.removeView(routeInfo.id, removalReason)
|
||||||
} else {
|
} else {
|
||||||
displayedState = chipState
|
displayedState = chipState
|
||||||
chipbarCoordinator.displayView(
|
chipbarCoordinator.displayView(
|
||||||
@@ -162,6 +162,7 @@ constructor(
|
|||||||
windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER,
|
windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER,
|
||||||
wakeReason = MediaTttUtils.WAKE_REASON_SENDER,
|
wakeReason = MediaTttUtils.WAKE_REASON_SENDER,
|
||||||
timeoutMs = chipStateSender.timeout,
|
timeoutMs = chipStateSender.timeout,
|
||||||
|
id = routeInfo.id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
|||||||
/** A string that keeps track of wakelock reason once it is acquired till it gets released */
|
/** A string that keeps track of wakelock reason once it is acquired till it gets released */
|
||||||
private var wakeReasonAcquired: String? = null
|
private var wakeReasonAcquired: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stack of pairs of device id and temporary view info. This is used when there may be
|
||||||
|
* multiple devices in range, and we want to always display the chip for the most recently
|
||||||
|
* active device.
|
||||||
|
*/
|
||||||
|
internal val activeViews: ArrayDeque<Pair<String, T>> = ArrayDeque()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the view with the provided [newInfo].
|
* Displays the view with the provided [newInfo].
|
||||||
*
|
*
|
||||||
@@ -102,6 +109,12 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
|||||||
fun displayView(newInfo: T) {
|
fun displayView(newInfo: T) {
|
||||||
val currentDisplayInfo = displayInfo
|
val currentDisplayInfo = displayInfo
|
||||||
|
|
||||||
|
// Update our list of active devices by removing it if necessary, then adding back at the
|
||||||
|
// front of the list
|
||||||
|
val id = newInfo.id
|
||||||
|
val position = findAndRemoveFromActiveViewsList(id)
|
||||||
|
activeViews.addFirst(Pair(id, newInfo))
|
||||||
|
|
||||||
if (currentDisplayInfo != null &&
|
if (currentDisplayInfo != null &&
|
||||||
currentDisplayInfo.info.windowTitle == newInfo.windowTitle) {
|
currentDisplayInfo.info.windowTitle == newInfo.windowTitle) {
|
||||||
// We're already displaying information in the correctly-titled window, so we just need
|
// We're already displaying information in the correctly-titled window, so we just need
|
||||||
@@ -113,7 +126,10 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
|||||||
// We're already displaying information but that information is under a different
|
// We're already displaying information but that information is under a different
|
||||||
// window title. So, we need to remove the old window with the old title and add a
|
// window title. So, we need to remove the old window with the old title and add a
|
||||||
// new window with the new title.
|
// new window with the new title.
|
||||||
removeView(removalReason = "New info has new window title: ${newInfo.windowTitle}")
|
removeView(
|
||||||
|
id,
|
||||||
|
removalReason = "New info has new window title: ${newInfo.windowTitle}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, we're guaranteed to no longer be displaying a view.
|
// At this point, we're guaranteed to no longer be displaying a view.
|
||||||
@@ -140,7 +156,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
|||||||
}
|
}
|
||||||
wakeLock?.acquire(newInfo.wakeReason)
|
wakeLock?.acquire(newInfo.wakeReason)
|
||||||
wakeReasonAcquired = newInfo.wakeReason
|
wakeReasonAcquired = newInfo.wakeReason
|
||||||
logger.logViewAddition(newInfo.windowTitle)
|
logger.logViewAddition(id, newInfo.windowTitle)
|
||||||
inflateAndUpdateView(newInfo)
|
inflateAndUpdateView(newInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,9 +167,13 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
|||||||
// include it just to be safe.
|
// include it just to be safe.
|
||||||
FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
|
FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
|
||||||
)
|
)
|
||||||
cancelViewTimeout?.run()
|
|
||||||
|
// Only cancel timeout of the most recent view displayed, as it will be reset.
|
||||||
|
if (position == 0) {
|
||||||
|
cancelViewTimeout?.run()
|
||||||
|
}
|
||||||
cancelViewTimeout = mainExecutor.executeDelayed(
|
cancelViewTimeout = mainExecutor.executeDelayed(
|
||||||
{ removeView(REMOVAL_REASON_TIMEOUT) },
|
{ removeView(id, REMOVAL_REASON_TIMEOUT) },
|
||||||
timeout.toLong()
|
timeout.toLong()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -196,28 +216,67 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides the view.
|
* Hides the view given its [id].
|
||||||
*
|
*
|
||||||
|
* @param id the id of the device responsible of displaying the temp view.
|
||||||
* @param removalReason a short string describing why the view was removed (timeout, state
|
* @param removalReason a short string describing why the view was removed (timeout, state
|
||||||
* change, etc.)
|
* change, etc.)
|
||||||
*/
|
*/
|
||||||
fun removeView(removalReason: String) {
|
fun removeView(id: String, removalReason: String) {
|
||||||
val currentDisplayInfo = displayInfo ?: return
|
val currentDisplayInfo = displayInfo ?: return
|
||||||
|
|
||||||
|
val removalPosition = findAndRemoveFromActiveViewsList(id)
|
||||||
|
if (removalPosition == null) {
|
||||||
|
logger.logViewRemovalIgnored(id, "view not found in the list")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (removalPosition != 0) {
|
||||||
|
logger.logViewRemovalIgnored(id, "most recent view is being displayed.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.logViewRemoval(id, removalReason)
|
||||||
|
|
||||||
|
val newViewToDisplay = if (activeViews.isEmpty()) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
activeViews[0].second
|
||||||
|
}
|
||||||
|
|
||||||
val currentView = currentDisplayInfo.view
|
val currentView = currentDisplayInfo.view
|
||||||
animateViewOut(currentView) {
|
animateViewOut(currentView) {
|
||||||
windowManager.removeView(currentView)
|
windowManager.removeView(currentView)
|
||||||
wakeLock?.release(wakeReasonAcquired)
|
wakeLock?.release(wakeReasonAcquired)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.logViewRemoval(removalReason)
|
|
||||||
configurationController.removeCallback(displayScaleListener)
|
configurationController.removeCallback(displayScaleListener)
|
||||||
// Re-set to null immediately (instead as part of the animation end runnable) so
|
// Re-set to null immediately (instead as part of the animation end runnable) so
|
||||||
// that if a new view event comes in while this view is animating out, we still display the
|
// that if a new view event comes in while this view is animating out, we still display
|
||||||
// new view appropriately.
|
// the new view appropriately.
|
||||||
displayInfo = null
|
displayInfo = null
|
||||||
// No need to time the view out since it's already gone
|
// No need to time the view out since it's already gone
|
||||||
cancelViewTimeout?.run()
|
cancelViewTimeout?.run()
|
||||||
|
|
||||||
|
if (newViewToDisplay != null) {
|
||||||
|
mainExecutor.executeDelayed({ displayView(newViewToDisplay)}, DISPLAY_VIEW_DELAY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and removes the active view with the given [id] from the stack, or null if there is no
|
||||||
|
* active view with that ID
|
||||||
|
*
|
||||||
|
* @param id that temporary view belonged to.
|
||||||
|
*
|
||||||
|
* @return index of the view in the stack , otherwise null.
|
||||||
|
*/
|
||||||
|
private fun findAndRemoveFromActiveViewsList(id: String): Int? {
|
||||||
|
for (i in 0 until activeViews.size) {
|
||||||
|
if (activeViews[i].first == id) {
|
||||||
|
activeViews.removeAt(i)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,6 +317,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
|||||||
}
|
}
|
||||||
|
|
||||||
private const val REMOVAL_REASON_TIMEOUT = "TIMEOUT"
|
private const val REMOVAL_REASON_TIMEOUT = "TIMEOUT"
|
||||||
|
const val DISPLAY_VIEW_DELAY = 50L
|
||||||
|
|
||||||
private data class IconInfo(
|
private data class IconInfo(
|
||||||
val iconName: String,
|
val iconName: String,
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ abstract class TemporaryViewInfo {
|
|||||||
* disappears.
|
* disappears.
|
||||||
*/
|
*/
|
||||||
open val timeoutMs: Int = DEFAULT_TIMEOUT_MILLIS
|
open val timeoutMs: Int = DEFAULT_TIMEOUT_MILLIS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the temporary view.
|
||||||
|
*/
|
||||||
|
abstract val id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
const val DEFAULT_TIMEOUT_MILLIS = 10000
|
const val DEFAULT_TIMEOUT_MILLIS = 10000
|
||||||
|
|||||||
@@ -24,13 +24,42 @@ open class TemporaryViewLogger(
|
|||||||
internal val buffer: LogBuffer,
|
internal val buffer: LogBuffer,
|
||||||
internal val tag: String,
|
internal val tag: String,
|
||||||
) {
|
) {
|
||||||
/** Logs that we added the view in a window titled [windowTitle]. */
|
/** Logs that we added the view with the given [id] in a window titled [windowTitle]. */
|
||||||
fun logViewAddition(windowTitle: String) {
|
fun logViewAddition(id: String, windowTitle: String) {
|
||||||
buffer.log(tag, LogLevel.DEBUG, { str1 = windowTitle }, { "View added. window=$str1" })
|
buffer.log(
|
||||||
|
tag,
|
||||||
|
LogLevel.DEBUG,
|
||||||
|
{
|
||||||
|
str1 = windowTitle
|
||||||
|
str2 = id
|
||||||
|
},
|
||||||
|
{ "View added. window=$str1 id=$str2" }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Logs that we removed the chip for the given [reason]. */
|
/** Logs that we removed the view with the given [id] for the given [reason]. */
|
||||||
fun logViewRemoval(reason: String) {
|
fun logViewRemoval(id: String, reason: String) {
|
||||||
buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "View removed due to: $str1" })
|
buffer.log(
|
||||||
|
tag,
|
||||||
|
LogLevel.DEBUG,
|
||||||
|
{
|
||||||
|
str1 = reason
|
||||||
|
str2 = id
|
||||||
|
},
|
||||||
|
{ "View with id=$str2 is removed due to: $str1" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Logs that we ignored removal of the view with the given [id]. */
|
||||||
|
fun logViewRemovalIgnored(id: String, reason: String) {
|
||||||
|
buffer.log(
|
||||||
|
tag,
|
||||||
|
LogLevel.DEBUG,
|
||||||
|
{
|
||||||
|
str1 = reason
|
||||||
|
str2 = id
|
||||||
|
},
|
||||||
|
{ "Removal of view with id=$str2 is ignored because $str1" }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ data class ChipbarInfo(
|
|||||||
override val windowTitle: String,
|
override val windowTitle: String,
|
||||||
override val wakeReason: String,
|
override val wakeReason: String,
|
||||||
override val timeoutMs: Int,
|
override val timeoutMs: Int,
|
||||||
|
override val id: String,
|
||||||
) : TemporaryViewInfo()
|
) : TemporaryViewInfo()
|
||||||
|
|
||||||
/** The possible items to display at the end of the chipbar. */
|
/** The possible items to display at the end of the chipbar. */
|
||||||
|
|||||||
@@ -261,7 +261,12 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun updateView_noOverrides_usesInfoFromAppIcon() {
|
fun updateView_noOverrides_usesInfoFromAppIcon() {
|
||||||
controllerReceiver.displayView(
|
controllerReceiver.displayView(
|
||||||
ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appNameOverride = null)
|
ChipReceiverInfo(
|
||||||
|
routeInfo,
|
||||||
|
appIconDrawableOverride = null,
|
||||||
|
appNameOverride = null,
|
||||||
|
id = "id",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val view = getChipView()
|
val view = getChipView()
|
||||||
@@ -274,7 +279,12 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
val drawableOverride = context.getDrawable(R.drawable.ic_celebration)!!
|
val drawableOverride = context.getDrawable(R.drawable.ic_celebration)!!
|
||||||
|
|
||||||
controllerReceiver.displayView(
|
controllerReceiver.displayView(
|
||||||
ChipReceiverInfo(routeInfo, drawableOverride, appNameOverride = null)
|
ChipReceiverInfo(
|
||||||
|
routeInfo,
|
||||||
|
drawableOverride,
|
||||||
|
appNameOverride = null,
|
||||||
|
id = "id",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val view = getChipView()
|
val view = getChipView()
|
||||||
@@ -286,7 +296,12 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
val appNameOverride = "Sweet New App"
|
val appNameOverride = "Sweet New App"
|
||||||
|
|
||||||
controllerReceiver.displayView(
|
controllerReceiver.displayView(
|
||||||
ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appNameOverride)
|
ChipReceiverInfo(
|
||||||
|
routeInfo,
|
||||||
|
appIconDrawableOverride = null,
|
||||||
|
appNameOverride,
|
||||||
|
id = "id",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val view = getChipView()
|
val view = getChipView()
|
||||||
@@ -340,7 +355,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
.addFeature("feature")
|
.addFeature("feature")
|
||||||
.setClientPackageName(packageName)
|
.setClientPackageName(packageName)
|
||||||
.build()
|
.build()
|
||||||
return ChipReceiverInfo(routeInfo, null, null)
|
return ChipReceiverInfo(routeInfo, null, null, id = "id")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
|
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
verify(logger).logViewAddition("Fake Window Title")
|
verify(logger).logViewAddition("id", "Fake Window Title")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -153,7 +153,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
|
|||||||
underTest.displayView(getState())
|
underTest.displayView(getState())
|
||||||
assertThat(fakeWakeLock.isHeld).isTrue()
|
assertThat(fakeWakeLock.isHeld).isTrue()
|
||||||
|
|
||||||
underTest.removeView("test reason")
|
underTest.removeView("id", "test reason")
|
||||||
|
|
||||||
assertThat(fakeWakeLock.isHeld).isFalse()
|
assertThat(fakeWakeLock.isHeld).isFalse()
|
||||||
}
|
}
|
||||||
@@ -262,6 +262,127 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
|
|||||||
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
|
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleViewsWithDifferentIds_recentActiveViewIsDisplayed() {
|
||||||
|
underTest.displayView(ViewInfo("First name", id = "id1"))
|
||||||
|
|
||||||
|
verify(windowManager).addView(any(), any())
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
underTest.displayView(ViewInfo("Second name", id = "id2"))
|
||||||
|
underTest.removeView("id2", "test reason")
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
|
||||||
|
fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1)
|
||||||
|
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1")
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name")
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
fakeClock.advanceTime(TIMEOUT_MS + 1)
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
assertThat(underTest.activeViews.size).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleViewsWithDifferentIds_oldViewRemoved_recentViewIsDisplayed() {
|
||||||
|
underTest.displayView(ViewInfo("First name", id = "id1"))
|
||||||
|
|
||||||
|
verify(windowManager).addView(any(), any())
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
underTest.displayView(ViewInfo("Second name", id = "id2"))
|
||||||
|
underTest.removeView("id1", "test reason")
|
||||||
|
|
||||||
|
verify(windowManager, never()).removeView(any())
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2")
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
|
||||||
|
|
||||||
|
fakeClock.advanceTime(TIMEOUT_MS + 1)
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
assertThat(underTest.activeViews.size).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleViewsWithDifferentIds_threeDifferentViews_recentActiveViewIsDisplayed() {
|
||||||
|
underTest.displayView(ViewInfo("First name", id = "id1"))
|
||||||
|
underTest.displayView(ViewInfo("Second name", id = "id2"))
|
||||||
|
underTest.displayView(ViewInfo("Third name", id = "id3"))
|
||||||
|
|
||||||
|
verify(windowManager).addView(any(), any())
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
underTest.removeView("id3", "test reason")
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
|
||||||
|
fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1)
|
||||||
|
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2")
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
underTest.removeView("id2", "test reason")
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
|
||||||
|
fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1)
|
||||||
|
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1")
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name")
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
fakeClock.advanceTime(TIMEOUT_MS + 1)
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
assertThat(underTest.activeViews.size).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleViewsWithDifferentIds_oneViewStateChanged_stackHasRecentState() {
|
||||||
|
underTest.displayView(ViewInfo("First name", id = "id1"))
|
||||||
|
underTest.displayView(ViewInfo("New name", id = "id1"))
|
||||||
|
|
||||||
|
verify(windowManager).addView(any(), any())
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
underTest.displayView(ViewInfo("Second name", id = "id2"))
|
||||||
|
underTest.removeView("id2", "test reason")
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
|
||||||
|
fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1)
|
||||||
|
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1")
|
||||||
|
assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("New name")
|
||||||
|
assertThat(underTest.activeViews[0].second.name).isEqualTo("New name")
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
fakeClock.advanceTime(TIMEOUT_MS + 1)
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
assertThat(underTest.activeViews.size).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleViewsWithDifferentIds_viewsTimeouts_noViewLeftToDisplay() {
|
||||||
|
underTest.displayView(ViewInfo("First name", id = "id1"))
|
||||||
|
fakeClock.advanceTime(TIMEOUT_MS / 3)
|
||||||
|
underTest.displayView(ViewInfo("Second name", id = "id2"))
|
||||||
|
fakeClock.advanceTime(TIMEOUT_MS / 3)
|
||||||
|
underTest.displayView(ViewInfo("Third name", id = "id3"))
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
fakeClock.advanceTime(TIMEOUT_MS + 1)
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
verify(windowManager, never()).addView(any(), any())
|
||||||
|
assertThat(underTest.activeViews.size).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun removeView_viewRemovedAndRemovalLogged() {
|
fun removeView_viewRemovedAndRemovalLogged() {
|
||||||
// First, add the view
|
// First, add the view
|
||||||
@@ -269,15 +390,16 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
// Then, remove it
|
// Then, remove it
|
||||||
val reason = "test reason"
|
val reason = "test reason"
|
||||||
underTest.removeView(reason)
|
val deviceId = "id"
|
||||||
|
underTest.removeView(deviceId, reason)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
verify(logger).logViewRemoval(reason)
|
verify(logger).logViewRemoval(deviceId, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun removeView_noAdd_viewNotRemoved() {
|
fun removeView_noAdd_viewNotRemoved() {
|
||||||
underTest.removeView("reason")
|
underTest.removeView("id", "reason")
|
||||||
|
|
||||||
verify(windowManager, never()).removeView(any())
|
verify(windowManager, never()).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -329,7 +451,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
|
|||||||
val name: String,
|
val name: String,
|
||||||
override val windowTitle: String = "Window Title",
|
override val windowTitle: String = "Window Title",
|
||||||
override val wakeReason: String = "WAKE_REASON",
|
override val wakeReason: String = "WAKE_REASON",
|
||||||
override val timeoutMs: Int = 1
|
override val timeoutMs: Int = 1,
|
||||||
|
override val id: String = "id",
|
||||||
) : TemporaryViewInfo()
|
) : TemporaryViewInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class TemporaryViewLoggerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun logViewAddition_bufferHasLog() {
|
fun logViewAddition_bufferHasLog() {
|
||||||
logger.logViewAddition("Test Window Title")
|
logger.logViewAddition("test id", "Test Window Title")
|
||||||
|
|
||||||
val stringWriter = StringWriter()
|
val stringWriter = StringWriter()
|
||||||
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
||||||
@@ -57,7 +57,8 @@ class TemporaryViewLoggerTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun logViewRemoval_bufferHasTagAndReason() {
|
fun logViewRemoval_bufferHasTagAndReason() {
|
||||||
val reason = "test reason"
|
val reason = "test reason"
|
||||||
logger.logViewRemoval(reason)
|
val deviceId = "test id"
|
||||||
|
logger.logViewRemoval(deviceId, reason)
|
||||||
|
|
||||||
val stringWriter = StringWriter()
|
val stringWriter = StringWriter()
|
||||||
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
||||||
@@ -65,6 +66,7 @@ class TemporaryViewLoggerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
assertThat(actualString).contains(TAG)
|
assertThat(actualString).contains(TAG)
|
||||||
assertThat(actualString).contains(reason)
|
assertThat(actualString).contains(reason)
|
||||||
|
assertThat(actualString).contains(deviceId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -377,6 +377,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
|
|||||||
windowTitle = WINDOW_TITLE,
|
windowTitle = WINDOW_TITLE,
|
||||||
wakeReason = WAKE_REASON,
|
wakeReason = WAKE_REASON,
|
||||||
timeoutMs = TIMEOUT,
|
timeoutMs = TIMEOUT,
|
||||||
|
id = DEVICE_ID,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,3 +402,4 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
|
|||||||
private const val TIMEOUT = 10000
|
private const val TIMEOUT = 10000
|
||||||
private const val WINDOW_TITLE = "Test Chipbar Window Title"
|
private const val WINDOW_TITLE = "Test Chipbar Window Title"
|
||||||
private const val WAKE_REASON = "TEST_CHIPBAR_WAKE_REASON"
|
private const val WAKE_REASON = "TEST_CHIPBAR_WAKE_REASON"
|
||||||
|
private const val DEVICE_ID = "id"
|
||||||
|
|||||||
Reference in New Issue
Block a user