Merge changes I6bb3f8db,I5b324867 into tm-qpr-dev am: cfca598a00

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20290225

Change-Id: I012938f9a86a418fb6fe681d145e3dd4d27a5bb4
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Caitlin Shkuratov
2022-10-27 19:33:00 +00:00
committed by Automerger Merge Worker
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.window.StatusBarWindowModule;
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.unfold.SysUIUnfoldModule;
import com.android.systemui.user.UserModule;
@@ -150,6 +151,7 @@ import dagger.Provides;
SysUIConcurrencyModule.class,
SysUIUnfoldModule.class,
TelephonyRepositoryModule.class,
TemporaryDisplayModule.class,
TunerModule.class,
UserModule.class,
UtilModule.class,

View File

@@ -27,10 +27,11 @@ import com.android.systemui.common.shared.model.Icon
/** Utility methods for media tap-to-transfer. */
class MediaTttUtils {
companion object {
// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
// UpdateMediaTapToTransferReceiverDisplayTest
const val WINDOW_TITLE = "Media Transfer Chip View"
const val WAKE_REASON = "MEDIA_TRANSFER_ACTIVATED"
const val WINDOW_TITLE_SENDER = "Media Transfer Chip View (Sender)"
const val WINDOW_TITLE_RECEIVER = "Media Transfer Chip View (Receiver)"
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.

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.statusbar.CommandQueue
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.TemporaryViewInfo
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
@@ -78,8 +77,6 @@ class MediaTttChipControllerReceiver @Inject constructor(
configurationController,
powerManager,
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
override val windowLayoutParams = commonWindowLayoutParams.apply {
@@ -231,7 +228,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
data class ChipReceiverInfo(
val routeInfo: MediaRoute2Info,
val appIconDrawableOverride: Drawable?,
val appNameOverride: CharSequence?
) : TemporaryViewInfo {
override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
}
val appNameOverride: CharSequence?,
override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER,
override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER,
) : TemporaryViewInfo()

View File

@@ -43,7 +43,7 @@ enum class ChipStateSender(
@StringRes val stringResId: Int?,
val transferStatus: TransferStatus,
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
@@ -223,6 +223,6 @@ sealed class SenderEndItem {
// Give the Transfer*Triggered states a longer timeout since those states represent an active
// process and we should keep the user informed about it as long as possible (but don't allow it to
// continue indefinitely).
private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000L
private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000
private const val TAG = "ChipStateSender"

View File

@@ -159,6 +159,9 @@ constructor(
}
},
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
* 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>(
internal val context: Context,
@@ -59,8 +54,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
private val configurationController: ConfigurationController,
private val powerManager: PowerManager,
@LayoutRes private val viewLayoutRes: Int,
private val windowTitle: String,
private val wakeReason: String,
) : CoreStartable {
/**
* 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
flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
title = windowTitle
format = PixelFormat.TRANSLUCENT
setTrustedOverlay()
}
@@ -100,29 +92,40 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
fun displayView(newInfo: T) {
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
updateView(currentDisplayInfo.info, currentDisplayInfo.view)
} 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)
// 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
// completely off.)
if (!powerManager.isScreenOn) {
powerManager.wakeUp(
SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION,
"com.android.systemui:$wakeReason",
SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION,
"com.android.systemui:${newInfo.wakeReason}",
)
}
logger.logChipAddition()
logger.logViewAddition(newInfo.windowTitle)
inflateAndUpdateView(newInfo)
}
// Cancel and re-set the view timeout each time we get a new state.
val timeout = accessibilityManager.getRecommendedTimeoutMillis(
newInfo.getTimeoutMs().toInt(),
newInfo.timeoutMs,
// Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
// include it just to be safe.
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)
displayInfo = newDisplayInfo
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)
}
@@ -177,7 +185,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
val currentView = currentDisplayInfo.view
animateViewOut(currentView) { windowManager.removeView(currentView) }
logger.logChipRemoval(removalReason)
logger.logViewRemoval(removalReason)
configurationController.removeCallback(displayScaleListener)
// 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

View File

@@ -19,12 +19,24 @@ package com.android.systemui.temporarydisplay
/**
* 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
* out and disappears.
* The title to use for the window that displays the temporary view. Should be normally cased,
* 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 tag: String,
) {
/** Logs that we added the chip to a new window. */
fun logChipAddition() {
buffer.log(tag, LogLevel.DEBUG, {}, { "Chip added" })
/** Logs that we added the view in a window titled [windowTitle]. */
fun logViewAddition(windowTitle: String) {
buffer.log(tag, LogLevel.DEBUG, { str1 = windowTitle }, { "View added. window=$str1" })
}
/** Logs that we removed the chip for the given [reason]. */
fun logChipRemoval(reason: String) {
buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "Chip removed due to $str1" })
fun logViewRemoval(reason: String) {
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.dagger.SysUISingleton
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.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -64,14 +61,11 @@ import javax.inject.Inject
* Only one chipbar may be shown at a time.
* TODO(b/245610654): Should we just display whichever chipbar was most recently requested, or do we
* need to maintain a priority ordering?
*
* TODO(b/245610654): Remove all media-related items from this class so it's just for generic
* chipbars.
*/
@SysUISingleton
open class ChipbarCoordinator @Inject constructor(
context: Context,
@MediaTttSenderLogger logger: MediaTttLogger,
logger: ChipbarLogger,
windowManager: WindowManager,
@Main mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
@@ -81,7 +75,7 @@ open class ChipbarCoordinator @Inject constructor(
private val falsingCollector: FalsingCollector,
private val viewUtil: ViewUtil,
private val vibratorHelper: VibratorHelper,
) : TemporaryViewDisplayController<ChipbarInfo, MediaTttLogger>(
) : TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>(
context,
logger,
windowManager,
@@ -90,8 +84,6 @@ open class ChipbarCoordinator @Inject constructor(
configurationController,
powerManager,
R.layout.chipbar,
MediaTttUtils.WINDOW_TITLE,
MediaTttUtils.WAKE_REASON,
) {
private lateinit var parent: ChipbarRootView
@@ -106,7 +98,16 @@ open class ChipbarCoordinator @Inject constructor(
newInfo: ChipbarInfo,
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.
parent = currentView.requireViewById(R.id.chipbar_root_view)

View File

@@ -37,7 +37,10 @@ data class ChipbarInfo(
val text: Text,
val endItem: ChipbarEndItem?,
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. */
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.policy.ConfigurationController
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.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -80,6 +81,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var chipbarLogger: ChipbarLogger
@Mock private lateinit var logger: MediaTttLogger
@Mock private lateinit var mediaTttFlags: MediaTttFlags
@Mock private lateinit var packageManager: PackageManager
@@ -122,7 +124,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
chipbarCoordinator =
FakeChipbarCoordinator(
context,
logger,
chipbarLogger,
windowManager,
fakeExecutor,
accessibilityManager,

View File

@@ -41,6 +41,7 @@ import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -85,10 +86,29 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
}
@Test
fun displayView_viewAdded() {
underTest.displayView(getState())
fun displayView_viewAddedWithCorrectTitle() {
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
@@ -110,7 +130,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
}
@Test
fun displayView_twice_viewNotAddedTwice() {
fun displayView_twiceWithSameWindowTitle_viewNotAddedTwice() {
underTest.displayView(getState())
reset(windowManager)
@@ -118,6 +138,32 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
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
fun displayView_viewDoesNotDisappearsBeforeTimeout() {
val state = getState()
@@ -197,7 +243,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
underTest.removeView(reason)
verify(windowManager).removeView(any())
verify(logger).logChipRemoval(reason)
verify(logger).logViewRemoval(reason)
}
@Test
@@ -232,8 +278,6 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
configurationController,
powerManager,
R.layout.chipbar,
"Window Title",
"WAKE_REASON",
) {
var mostRecentViewInfo: ViewInfo? = null
@@ -250,9 +294,12 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
}
}
inner class ViewInfo(val name: String) : TemporaryViewInfo {
override fun getTimeoutMs() = 1L
}
inner class ViewInfo(
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

View File

@@ -43,20 +43,21 @@ class TemporaryViewLoggerTest : SysuiTestCase() {
}
@Test
fun logChipAddition_bufferHasLog() {
logger.logChipAddition()
fun logViewAddition_bufferHasLog() {
logger.logViewAddition("Test Window Title")
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
val actualString = stringWriter.toString()
assertThat(actualString).contains(TAG)
assertThat(actualString).contains("Test Window Title")
}
@Test
fun logChipRemoval_bufferHasTagAndReason() {
fun logViewRemoval_bufferHasTagAndReason() {
val reason = "test reason"
logger.logChipRemoval(reason)
logger.logViewRemoval(reason)
val stringWriter = StringWriter()
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.Icon
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.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.FakeExecutor
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.view.ViewUtil
import com.google.common.truth.Truth.assertThat
@@ -60,7 +60,7 @@ import org.mockito.MockitoAnnotations
class ChipbarCoordinatorTest : SysuiTestCase() {
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 configurationController: ConfigurationController
@Mock private lateinit var powerManager: PowerManager
@@ -105,7 +105,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val drawable = context.getDrawable(R.drawable.ic_celebration)!!
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
Text.Loaded("text"),
endItem = null,
@@ -121,7 +121,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
fun displayView_resourceIcon_correctlyRendered() {
val contentDescription = ContentDescription.Resource(R.string.controls_error_timeout)
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.drawable.ic_cake, contentDescription),
Text.Loaded("text"),
endItem = null,
@@ -136,7 +136,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test
fun displayView_loadedText_correctlyRendered() {
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("display view text here"),
endItem = null,
@@ -149,7 +149,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test
fun displayView_resourceText_correctlyRendered() {
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Resource(R.string.screenrecord_start_error),
endItem = null,
@@ -163,7 +163,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test
fun displayView_endItemNull_correctlyRendered() {
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = null,
@@ -179,7 +179,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test
fun displayView_endItemLoading_correctlyRendered() {
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = ChipbarEndItem.Loading,
@@ -195,7 +195,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test
fun displayView_endItemError_correctlyRendered() {
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = ChipbarEndItem.Error,
@@ -211,7 +211,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test
fun displayView_endItemButton_correctlyRendered() {
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem =
@@ -237,7 +237,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val buttonClickListener = View.OnClickListener { isClicked = true }
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem =
@@ -260,7 +260,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val buttonClickListener = View.OnClickListener { isClicked = true }
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem =
@@ -279,7 +279,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
@Test
fun displayView_vibrationEffect_doubleClickEffect() {
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Resource(R.id.check_box, null),
Text.Loaded("text"),
endItem = null,
@@ -296,7 +296,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val drawable = context.getDrawable(R.drawable.ic_celebration)!!
underTest.displayView(
ChipbarInfo(
createChipbarInfo(
Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")),
Text.Loaded("title text"),
endItem = ChipbarEndItem.Loading,
@@ -314,7 +314,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
// WHEN the view is updated
val newDrawable = context.getDrawable(R.drawable.ic_cake)!!
underTest.updateView(
ChipbarInfo(
createChipbarInfo(
Icon.Loaded(newDrawable, ContentDescription.Loaded("new CD")),
Text.Loaded("new title text"),
endItem = ChipbarEndItem.Error,
@@ -331,6 +331,47 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
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.getChipText(): String =
@@ -350,3 +391,5 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
}
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.accessibility.AccessibilityManager
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper
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. */
class FakeChipbarCoordinator(
context: Context,
@MediaTttReceiverLogger logger: MediaTttLogger,
logger: ChipbarLogger,
windowManager: WindowManager,
mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,