Merge changes I6bb3f8db,I5b324867 into tm-qpr-dev

* changes:
  [Chipbar] Create a chipbar-specific logger and make some small updates to logging for both chipbar and temporary display.
  [Chipbar] Remove the media-specific wake reason and window title from the ChipbarCoordinator and instead pass them in each time we display a temporary view.
This commit is contained in:
Caitlin Shkuratov
2022-10-27 18:58:52 +00:00
committed by Android (Google) Code Review
18 changed files with 314 additions and 85 deletions

View File

@@ -84,6 +84,7 @@ import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule; import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
import com.android.systemui.statusbar.window.StatusBarWindowModule; import com.android.systemui.statusbar.window.StatusBarWindowModule;
import com.android.systemui.telephony.data.repository.TelephonyRepositoryModule; import com.android.systemui.telephony.data.repository.TelephonyRepositoryModule;
import com.android.systemui.temporarydisplay.dagger.TemporaryDisplayModule;
import com.android.systemui.tuner.dagger.TunerModule; import com.android.systemui.tuner.dagger.TunerModule;
import com.android.systemui.unfold.SysUIUnfoldModule; import com.android.systemui.unfold.SysUIUnfoldModule;
import com.android.systemui.user.UserModule; import com.android.systemui.user.UserModule;
@@ -150,6 +151,7 @@ import dagger.Provides;
SysUIConcurrencyModule.class, SysUIConcurrencyModule.class,
SysUIUnfoldModule.class, SysUIUnfoldModule.class,
TelephonyRepositoryModule.class, TelephonyRepositoryModule.class,
TemporaryDisplayModule.class,
TunerModule.class, TunerModule.class,
UserModule.class, UserModule.class,
UtilModule.class, UtilModule.class,

View File

@@ -27,10 +27,11 @@ import com.android.systemui.common.shared.model.Icon
/** Utility methods for media tap-to-transfer. */ /** Utility methods for media tap-to-transfer. */
class MediaTttUtils { class MediaTttUtils {
companion object { companion object {
// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and const val WINDOW_TITLE_SENDER = "Media Transfer Chip View (Sender)"
// UpdateMediaTapToTransferReceiverDisplayTest const val WINDOW_TITLE_RECEIVER = "Media Transfer Chip View (Receiver)"
const val WINDOW_TITLE = "Media Transfer Chip View"
const val WAKE_REASON = "MEDIA_TRANSFER_ACTIVATED" const val WAKE_REASON_SENDER = "MEDIA_TRANSFER_ACTIVATED_SENDER"
const val WAKE_REASON_RECEIVER = "MEDIA_TRANSFER_ACTIVATED_RECEIVER"
/** /**
* Returns the information needed to display the icon in [Icon] form. * Returns the information needed to display the icon in [Icon] form.

View File

@@ -40,7 +40,6 @@ import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.common.MediaTttUtils import com.android.systemui.media.taptotransfer.common.MediaTttUtils
import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.animation.AnimationUtil.Companion.frames import com.android.systemui.util.animation.AnimationUtil.Companion.frames
@@ -78,8 +77,6 @@ class MediaTttChipControllerReceiver @Inject constructor(
configurationController, configurationController,
powerManager, powerManager,
R.layout.media_ttt_chip_receiver, R.layout.media_ttt_chip_receiver,
MediaTttUtils.WINDOW_TITLE,
MediaTttUtils.WAKE_REASON,
) { ) {
@SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS @SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
override val windowLayoutParams = commonWindowLayoutParams.apply { override val windowLayoutParams = commonWindowLayoutParams.apply {
@@ -231,7 +228,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
data class ChipReceiverInfo( data class ChipReceiverInfo(
val routeInfo: MediaRoute2Info, val routeInfo: MediaRoute2Info,
val appIconDrawableOverride: Drawable?, val appIconDrawableOverride: Drawable?,
val appNameOverride: CharSequence? val appNameOverride: CharSequence?,
) : TemporaryViewInfo { override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER,
override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER,
} ) : TemporaryViewInfo()

View File

@@ -43,7 +43,7 @@ enum class ChipStateSender(
@StringRes val stringResId: Int?, @StringRes val stringResId: Int?,
val transferStatus: TransferStatus, val transferStatus: TransferStatus,
val endItem: SenderEndItem?, val endItem: SenderEndItem?,
val timeout: Long = DEFAULT_TIMEOUT_MILLIS val timeout: Int = DEFAULT_TIMEOUT_MILLIS,
) { ) {
/** /**
* A state representing that the two devices are close but not close enough to *start* a cast to * A state representing that the two devices are close but not close enough to *start* a cast to
@@ -223,6 +223,6 @@ sealed class SenderEndItem {
// 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 = 30000L private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000
private const val TAG = "ChipStateSender" private const val TAG = "ChipStateSender"

View File

@@ -159,6 +159,9 @@ constructor(
} }
}, },
vibrationEffect = chipStateSender.transferStatus.vibrationEffect, vibrationEffect = chipStateSender.transferStatus.vibrationEffect,
windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER,
wakeReason = MediaTttUtils.WAKE_REASON_SENDER,
timeoutMs = chipStateSender.timeout,
) )
} }

View File

@@ -44,11 +44,6 @@ import com.android.systemui.util.concurrency.DelayableExecutor
* *
* The generic type T is expected to contain all the information necessary for the subclasses to * The generic type T is expected to contain all the information necessary for the subclasses to
* display the view in a certain state, since they receive <T> in [updateView]. * display the view in a certain state, since they receive <T> in [updateView].
*
* @property windowTitle the title to use for the window that displays the temporary view. Should be
* normally cased, like "Window Title".
* @property wakeReason a string used for logging if we needed to wake the screen in order to
* display the temporary view. Should be screaming snake cased, like WAKE_REASON.
*/ */
abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : TemporaryViewLogger>( abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : TemporaryViewLogger>(
internal val context: Context, internal val context: Context,
@@ -59,8 +54,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
private val configurationController: ConfigurationController, private val configurationController: ConfigurationController,
private val powerManager: PowerManager, private val powerManager: PowerManager,
@LayoutRes private val viewLayoutRes: Int, @LayoutRes private val viewLayoutRes: Int,
private val windowTitle: String,
private val wakeReason: String,
) : CoreStartable { ) : CoreStartable {
/** /**
* Window layout params that will be used as a starting point for the [windowLayoutParams] of * Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -72,7 +65,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR
flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
title = windowTitle
format = PixelFormat.TRANSLUCENT format = PixelFormat.TRANSLUCENT
setTrustedOverlay() setTrustedOverlay()
} }
@@ -100,11 +92,22 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
fun displayView(newInfo: T) { fun displayView(newInfo: T) {
val currentDisplayInfo = displayInfo val currentDisplayInfo = displayInfo
if (currentDisplayInfo != null) { if (currentDisplayInfo != null &&
currentDisplayInfo.info.windowTitle == newInfo.windowTitle) {
// We're already displaying information in the correctly-titled window, so we just need
// to update the view.
currentDisplayInfo.info = newInfo currentDisplayInfo.info = newInfo
updateView(currentDisplayInfo.info, currentDisplayInfo.view) updateView(currentDisplayInfo.info, currentDisplayInfo.view)
} else { } else {
// The view is new, so set up all our callbacks and inflate the view if (currentDisplayInfo != null) {
// 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
// new window with the new title.
removeView(removalReason = "New info has new window title: ${newInfo.windowTitle}")
}
// At this point, we're guaranteed to no longer be displaying a view.
// So, set up all our callbacks and inflate the view.
configurationController.addCallback(displayScaleListener) configurationController.addCallback(displayScaleListener)
// Wake the screen if necessary so the user will see the view. (Per b/239426653, we want // Wake the screen if necessary so the user will see the view. (Per b/239426653, we want
// the view to show over the dream state, so we should only wake up if the screen is // the view to show over the dream state, so we should only wake up if the screen is
@@ -113,16 +116,16 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
powerManager.wakeUp( powerManager.wakeUp(
SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION, PowerManager.WAKE_REASON_APPLICATION,
"com.android.systemui:$wakeReason", "com.android.systemui:${newInfo.wakeReason}",
) )
} }
logger.logChipAddition() logger.logViewAddition(newInfo.windowTitle)
inflateAndUpdateView(newInfo) inflateAndUpdateView(newInfo)
} }
// Cancel and re-set the view timeout each time we get a new state. // Cancel and re-set the view timeout each time we get a new state.
val timeout = accessibilityManager.getRecommendedTimeoutMillis( val timeout = accessibilityManager.getRecommendedTimeoutMillis(
newInfo.getTimeoutMs().toInt(), newInfo.timeoutMs,
// Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but // Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
// 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
@@ -147,7 +150,12 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
val newDisplayInfo = DisplayInfo(newView, newInfo) val newDisplayInfo = DisplayInfo(newView, newInfo)
displayInfo = newDisplayInfo displayInfo = newDisplayInfo
updateView(newDisplayInfo.info, newDisplayInfo.view) updateView(newDisplayInfo.info, newDisplayInfo.view)
windowManager.addView(newView, windowLayoutParams)
val paramsWithTitle = WindowManager.LayoutParams().also {
it.copyFrom(windowLayoutParams)
it.title = newInfo.windowTitle
}
windowManager.addView(newView, paramsWithTitle)
animateViewIn(newView) animateViewIn(newView)
} }
@@ -177,7 +185,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
val currentView = currentDisplayInfo.view val currentView = currentDisplayInfo.view
animateViewOut(currentView) { windowManager.removeView(currentView) } animateViewOut(currentView) { windowManager.removeView(currentView) }
logger.logChipRemoval(removalReason) 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 the

View File

@@ -19,12 +19,24 @@ package com.android.systemui.temporarydisplay
/** /**
* A superclass view state used with [TemporaryViewDisplayController]. * A superclass view state used with [TemporaryViewDisplayController].
*/ */
interface TemporaryViewInfo { abstract class TemporaryViewInfo {
/** /**
* Returns the amount of time the given view state should display on the screen before it times * The title to use for the window that displays the temporary view. Should be normally cased,
* out and disappears. * like "Window Title".
*/ */
fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS abstract val windowTitle: String
/**
* A string used for logging if we needed to wake the screen in order to display the temporary
* view. Should be screaming snake cased, like WAKE_REASON.
*/
abstract val wakeReason: String
/**
* The amount of time the given view state should display on the screen before it times out and
* disappears.
*/
open val timeoutMs: Int = DEFAULT_TIMEOUT_MILLIS
} }
const val DEFAULT_TIMEOUT_MILLIS = 10000L const val DEFAULT_TIMEOUT_MILLIS = 10000

View File

@@ -24,13 +24,13 @@ open class TemporaryViewLogger(
internal val buffer: LogBuffer, internal val buffer: LogBuffer,
internal val tag: String, internal val tag: String,
) { ) {
/** Logs that we added the chip to a new window. */ /** Logs that we added the view in a window titled [windowTitle]. */
fun logChipAddition() { fun logViewAddition(windowTitle: String) {
buffer.log(tag, LogLevel.DEBUG, {}, { "Chip added" }) buffer.log(tag, LogLevel.DEBUG, { str1 = windowTitle }, { "View added. window=$str1" })
} }
/** Logs that we removed the chip for the given [reason]. */ /** Logs that we removed the chip for the given [reason]. */
fun logChipRemoval(reason: String) { fun logViewRemoval(reason: String) {
buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "Chip removed due to $str1" }) buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "View removed due to: $str1" })
} }
} }

View File

@@ -38,9 +38,6 @@ import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.common.ui.binder.TextViewBinder import com.android.systemui.common.ui.binder.TextViewBinder
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.common.MediaTttUtils
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
@@ -64,14 +61,11 @@ import javax.inject.Inject
* Only one chipbar may be shown at a time. * Only one chipbar may be shown at a time.
* TODO(b/245610654): Should we just display whichever chipbar was most recently requested, or do we * TODO(b/245610654): Should we just display whichever chipbar was most recently requested, or do we
* need to maintain a priority ordering? * need to maintain a priority ordering?
*
* TODO(b/245610654): Remove all media-related items from this class so it's just for generic
* chipbars.
*/ */
@SysUISingleton @SysUISingleton
open class ChipbarCoordinator @Inject constructor( open class ChipbarCoordinator @Inject constructor(
context: Context, context: Context,
@MediaTttSenderLogger logger: MediaTttLogger, logger: ChipbarLogger,
windowManager: WindowManager, windowManager: WindowManager,
@Main mainExecutor: DelayableExecutor, @Main mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager, accessibilityManager: AccessibilityManager,
@@ -81,7 +75,7 @@ open class ChipbarCoordinator @Inject constructor(
private val falsingCollector: FalsingCollector, private val falsingCollector: FalsingCollector,
private val viewUtil: ViewUtil, private val viewUtil: ViewUtil,
private val vibratorHelper: VibratorHelper, private val vibratorHelper: VibratorHelper,
) : TemporaryViewDisplayController<ChipbarInfo, MediaTttLogger>( ) : TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>(
context, context,
logger, logger,
windowManager, windowManager,
@@ -90,8 +84,6 @@ open class ChipbarCoordinator @Inject constructor(
configurationController, configurationController,
powerManager, powerManager,
R.layout.chipbar, R.layout.chipbar,
MediaTttUtils.WINDOW_TITLE,
MediaTttUtils.WAKE_REASON,
) { ) {
private lateinit var parent: ChipbarRootView private lateinit var parent: ChipbarRootView
@@ -106,7 +98,16 @@ open class ChipbarCoordinator @Inject constructor(
newInfo: ChipbarInfo, newInfo: ChipbarInfo,
currentView: ViewGroup currentView: ViewGroup
) { ) {
// TODO(b/245610654): Adding logging here. logger.logViewUpdate(
newInfo.windowTitle,
newInfo.text.loadText(context),
when (newInfo.endItem) {
null -> "null"
is ChipbarEndItem.Loading -> "loading"
is ChipbarEndItem.Error -> "error"
is ChipbarEndItem.Button -> "button(${newInfo.endItem.text.loadText(context)})"
}
)
// Detect falsing touches on the chip. // Detect falsing touches on the chip.
parent = currentView.requireViewById(R.id.chipbar_root_view) parent = currentView.requireViewById(R.id.chipbar_root_view)

View File

@@ -37,7 +37,10 @@ data class ChipbarInfo(
val text: Text, val text: Text,
val endItem: ChipbarEndItem?, val endItem: ChipbarEndItem?,
val vibrationEffect: VibrationEffect? = null, val vibrationEffect: VibrationEffect? = null,
) : TemporaryViewInfo override val windowTitle: String,
override val wakeReason: String,
override val timeoutMs: Int,
) : TemporaryViewInfo()
/** The possible items to display at the end of the chipbar. */ /** The possible items to display at the end of the chipbar. */
sealed class ChipbarEndItem { sealed class ChipbarEndItem {

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.temporarydisplay.chipbar
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.temporarydisplay.TemporaryViewLogger
import com.android.systemui.temporarydisplay.dagger.ChipbarLog
import javax.inject.Inject
/** A logger for the chipbar. */
@SysUISingleton
class ChipbarLogger
@Inject
constructor(
@ChipbarLog buffer: LogBuffer,
) : TemporaryViewLogger(buffer, "ChipbarLog") {
/**
* Logs that the chipbar was updated to display in a window named [windowTitle], with [text] and
* [endItemDesc].
*/
fun logViewUpdate(windowTitle: String, text: String?, endItemDesc: String) {
buffer.log(
tag,
LogLevel.DEBUG,
{
str1 = windowTitle
str2 = text
str3 = endItemDesc
},
{ "Chipbar updated. window=$str1 text=$str2 endItem=$str3" }
)
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.temporarydisplay.dagger
import javax.inject.Qualifier
/** Status bar connectivity logs in table format. */
@Qualifier
@MustBeDocumented
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
annotation class ChipbarLog

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.temporarydisplay.dagger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.plugins.log.LogBuffer
import dagger.Module
import dagger.Provides
@Module
interface TemporaryDisplayModule {
@Module
companion object {
@JvmStatic
@Provides
@SysUISingleton
@ChipbarLog
fun provideChipbarLogBuffer(factory: LogBufferFactory): LogBuffer {
return factory.create("ChipbarLog", 40)
}
}
}

View File

@@ -45,6 +45,7 @@ import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger
import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator
import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
@@ -80,6 +81,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var falsingCollector: FalsingCollector @Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var chipbarLogger: ChipbarLogger
@Mock private lateinit var logger: MediaTttLogger @Mock private lateinit var logger: MediaTttLogger
@Mock private lateinit var mediaTttFlags: MediaTttFlags @Mock private lateinit var mediaTttFlags: MediaTttFlags
@Mock private lateinit var packageManager: PackageManager @Mock private lateinit var packageManager: PackageManager
@@ -122,7 +124,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
chipbarCoordinator = chipbarCoordinator =
FakeChipbarCoordinator( FakeChipbarCoordinator(
context, context,
logger, chipbarLogger,
windowManager, windowManager,
fakeExecutor, fakeExecutor,
accessibilityManager, accessibilityManager,

View File

@@ -41,6 +41,7 @@ import org.junit.Test
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.never import org.mockito.Mockito.never
import org.mockito.Mockito.reset import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@@ -85,10 +86,29 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
} }
@Test @Test
fun displayView_viewAdded() { fun displayView_viewAddedWithCorrectTitle() {
underTest.displayView(getState()) underTest.displayView(
ViewInfo(
name = "name",
windowTitle = "Fake Window Title",
)
)
verify(windowManager).addView(any(), any()) val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>()
verify(windowManager).addView(any(), capture(windowParamsCaptor))
assertThat(windowParamsCaptor.value!!.title).isEqualTo("Fake Window Title")
}
@Test
fun displayView_logged() {
underTest.displayView(
ViewInfo(
name = "name",
windowTitle = "Fake Window Title",
)
)
verify(logger).logViewAddition("Fake Window Title")
} }
@Test @Test
@@ -110,7 +130,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
} }
@Test @Test
fun displayView_twice_viewNotAddedTwice() { fun displayView_twiceWithSameWindowTitle_viewNotAddedTwice() {
underTest.displayView(getState()) underTest.displayView(getState())
reset(windowManager) reset(windowManager)
@@ -118,6 +138,32 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager, never()).addView(any(), any()) verify(windowManager, never()).addView(any(), any())
} }
@Test
fun displayView_twiceWithDifferentWindowTitles_oldViewRemovedNewViewAdded() {
underTest.displayView(
ViewInfo(
name = "name",
windowTitle = "First Fake Window Title",
)
)
underTest.displayView(
ViewInfo(
name = "name",
windowTitle = "Second Fake Window Title",
)
)
val viewCaptor = argumentCaptor<View>()
val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>()
verify(windowManager, times(2)).addView(capture(viewCaptor), capture(windowParamsCaptor))
assertThat(windowParamsCaptor.allValues[0].title).isEqualTo("First Fake Window Title")
assertThat(windowParamsCaptor.allValues[1].title).isEqualTo("Second Fake Window Title")
verify(windowManager).removeView(viewCaptor.allValues[0])
}
@Test @Test
fun displayView_viewDoesNotDisappearsBeforeTimeout() { fun displayView_viewDoesNotDisappearsBeforeTimeout() {
val state = getState() val state = getState()
@@ -197,7 +243,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
underTest.removeView(reason) underTest.removeView(reason)
verify(windowManager).removeView(any()) verify(windowManager).removeView(any())
verify(logger).logChipRemoval(reason) verify(logger).logViewRemoval(reason)
} }
@Test @Test
@@ -232,8 +278,6 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
configurationController, configurationController,
powerManager, powerManager,
R.layout.chipbar, R.layout.chipbar,
"Window Title",
"WAKE_REASON",
) { ) {
var mostRecentViewInfo: ViewInfo? = null var mostRecentViewInfo: ViewInfo? = null
@@ -250,9 +294,12 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
} }
} }
inner class ViewInfo(val name: String) : TemporaryViewInfo { inner class ViewInfo(
override fun getTimeoutMs() = 1L val name: String,
} override val windowTitle: String = "Window Title",
override val wakeReason: String = "WAKE_REASON",
override val timeoutMs: Int = 1
) : TemporaryViewInfo()
} }
private const val TIMEOUT_MS = 10000L private const val TIMEOUT_MS = 10000L

View File

@@ -43,20 +43,21 @@ class TemporaryViewLoggerTest : SysuiTestCase() {
} }
@Test @Test
fun logChipAddition_bufferHasLog() { fun logViewAddition_bufferHasLog() {
logger.logChipAddition() logger.logViewAddition("Test Window Title")
val stringWriter = StringWriter() val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0) buffer.dump(PrintWriter(stringWriter), tailLength = 0)
val actualString = stringWriter.toString() val actualString = stringWriter.toString()
assertThat(actualString).contains(TAG) assertThat(actualString).contains(TAG)
assertThat(actualString).contains("Test Window Title")
} }
@Test @Test
fun logChipRemoval_bufferHasTagAndReason() { fun logViewRemoval_bufferHasTagAndReason() {
val reason = "test reason" val reason = "test reason"
logger.logChipRemoval(reason) logger.logViewRemoval(reason)
val stringWriter = StringWriter() val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0) buffer.dump(PrintWriter(stringWriter), tailLength = 0)

View File

@@ -35,12 +35,12 @@ import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.Text
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.view.ViewUtil import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -60,7 +60,7 @@ import org.mockito.MockitoAnnotations
class ChipbarCoordinatorTest : SysuiTestCase() { class ChipbarCoordinatorTest : SysuiTestCase() {
private lateinit var underTest: FakeChipbarCoordinator private lateinit var underTest: FakeChipbarCoordinator
@Mock private lateinit var logger: MediaTttLogger @Mock private lateinit var logger: ChipbarLogger
@Mock private lateinit var accessibilityManager: AccessibilityManager @Mock private lateinit var accessibilityManager: AccessibilityManager
@Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var powerManager: PowerManager @Mock private lateinit var powerManager: PowerManager
@@ -105,7 +105,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val drawable = context.getDrawable(R.drawable.ic_celebration)!! val drawable = context.getDrawable(R.drawable.ic_celebration)!!
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")), Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
Text.Loaded("text"), Text.Loaded("text"),
endItem = null, endItem = null,
@@ -121,7 +121,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
fun displayView_resourceIcon_correctlyRendered() { fun displayView_resourceIcon_correctlyRendered() {
val contentDescription = ContentDescription.Resource(R.string.controls_error_timeout) val contentDescription = ContentDescription.Resource(R.string.controls_error_timeout)
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.drawable.ic_cake, contentDescription), Icon.Resource(R.drawable.ic_cake, contentDescription),
Text.Loaded("text"), Text.Loaded("text"),
endItem = null, endItem = null,
@@ -136,7 +136,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test @Test
fun displayView_loadedText_correctlyRendered() { fun displayView_loadedText_correctlyRendered() {
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("display view text here"), Text.Loaded("display view text here"),
endItem = null, endItem = null,
@@ -149,7 +149,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test @Test
fun displayView_resourceText_correctlyRendered() { fun displayView_resourceText_correctlyRendered() {
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Resource(R.string.screenrecord_start_error), Text.Resource(R.string.screenrecord_start_error),
endItem = null, endItem = null,
@@ -163,7 +163,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test @Test
fun displayView_endItemNull_correctlyRendered() { fun displayView_endItemNull_correctlyRendered() {
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("text"), Text.Loaded("text"),
endItem = null, endItem = null,
@@ -179,7 +179,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test @Test
fun displayView_endItemLoading_correctlyRendered() { fun displayView_endItemLoading_correctlyRendered() {
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("text"), Text.Loaded("text"),
endItem = ChipbarEndItem.Loading, endItem = ChipbarEndItem.Loading,
@@ -195,7 +195,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test @Test
fun displayView_endItemError_correctlyRendered() { fun displayView_endItemError_correctlyRendered() {
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("text"), Text.Loaded("text"),
endItem = ChipbarEndItem.Error, endItem = ChipbarEndItem.Error,
@@ -211,7 +211,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test @Test
fun displayView_endItemButton_correctlyRendered() { fun displayView_endItemButton_correctlyRendered() {
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("text"), Text.Loaded("text"),
endItem = endItem =
@@ -237,7 +237,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val buttonClickListener = View.OnClickListener { isClicked = true } val buttonClickListener = View.OnClickListener { isClicked = true }
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("text"), Text.Loaded("text"),
endItem = endItem =
@@ -260,7 +260,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val buttonClickListener = View.OnClickListener { isClicked = true } val buttonClickListener = View.OnClickListener { isClicked = true }
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("text"), Text.Loaded("text"),
endItem = endItem =
@@ -279,7 +279,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test @Test
fun displayView_vibrationEffect_doubleClickEffect() { fun displayView_vibrationEffect_doubleClickEffect() {
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Resource(R.id.check_box, null), Icon.Resource(R.id.check_box, null),
Text.Loaded("text"), Text.Loaded("text"),
endItem = null, endItem = null,
@@ -296,7 +296,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val drawable = context.getDrawable(R.drawable.ic_celebration)!! val drawable = context.getDrawable(R.drawable.ic_celebration)!!
underTest.displayView( underTest.displayView(
ChipbarInfo( createChipbarInfo(
Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")), Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
Text.Loaded("title text"), Text.Loaded("title text"),
endItem = ChipbarEndItem.Loading, endItem = ChipbarEndItem.Loading,
@@ -314,7 +314,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
// WHEN the view is updated // WHEN the view is updated
val newDrawable = context.getDrawable(R.drawable.ic_cake)!! val newDrawable = context.getDrawable(R.drawable.ic_cake)!!
underTest.updateView( underTest.updateView(
ChipbarInfo( createChipbarInfo(
Icon.Loaded(newDrawable, ContentDescription.Loaded("new CD")), Icon.Loaded(newDrawable, ContentDescription.Loaded("new CD")),
Text.Loaded("new title text"), Text.Loaded("new title text"),
endItem = ChipbarEndItem.Error, endItem = ChipbarEndItem.Error,
@@ -331,6 +331,47 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
assertThat(chipbarView.getEndButton().visibility).isEqualTo(View.GONE) assertThat(chipbarView.getEndButton().visibility).isEqualTo(View.GONE)
} }
@Test
fun viewUpdates_logged() {
val drawable = context.getDrawable(R.drawable.ic_celebration)!!
underTest.displayView(
createChipbarInfo(
Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
Text.Loaded("title text"),
endItem = ChipbarEndItem.Loading,
)
)
verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("title text"), any())
underTest.displayView(
createChipbarInfo(
Icon.Loaded(drawable, ContentDescription.Loaded("new CD")),
Text.Loaded("new title text"),
endItem = ChipbarEndItem.Error,
)
)
verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("new title text"), any())
}
private fun createChipbarInfo(
startIcon: Icon,
text: Text,
endItem: ChipbarEndItem?,
vibrationEffect: VibrationEffect? = null,
): ChipbarInfo {
return ChipbarInfo(
startIcon,
text,
endItem,
vibrationEffect,
windowTitle = WINDOW_TITLE,
wakeReason = WAKE_REASON,
timeoutMs = TIMEOUT,
)
}
private fun ViewGroup.getStartIconView() = this.requireViewById<ImageView>(R.id.start_icon) private fun ViewGroup.getStartIconView() = this.requireViewById<ImageView>(R.id.start_icon)
private fun ViewGroup.getChipText(): String = private fun ViewGroup.getChipText(): String =
@@ -350,3 +391,5 @@ 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 WAKE_REASON = "TEST_CHIPBAR_WAKE_REASON"

View File

@@ -22,8 +22,6 @@ import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import android.view.accessibility.AccessibilityManager import android.view.accessibility.AccessibilityManager
import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
@@ -33,7 +31,7 @@ import com.android.systemui.util.view.ViewUtil
/** A fake implementation of [ChipbarCoordinator] for testing. */ /** A fake implementation of [ChipbarCoordinator] for testing. */
class FakeChipbarCoordinator( class FakeChipbarCoordinator(
context: Context, context: Context,
@MediaTttReceiverLogger logger: MediaTttLogger, logger: ChipbarLogger,
windowManager: WindowManager, windowManager: WindowManager,
mainExecutor: DelayableExecutor, mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager, accessibilityManager: AccessibilityManager,