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:
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -159,6 +159,9 @@ constructor(
|
||||
}
|
||||
},
|
||||
vibrationEffect = chipStateSender.transferStatus.vibrationEffect,
|
||||
windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER,
|
||||
wakeReason = MediaTttUtils.WAKE_REASON_SENDER,
|
||||
timeoutMs = chipStateSender.timeout,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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" }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user