Device Control metrics
Log user events related to controls, such as when controls are refreshed as well as user interactions with all controls (touch, long press, drag) Bug: 162066455 Test: manual Change-Id: I32e0b560dcfb119f8a9eecd1dc7bc74de9253ca4
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls
|
||||
|
||||
import android.service.controls.DeviceTypes.DeviceType
|
||||
|
||||
import com.android.internal.logging.UiEvent
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.controls.ui.ControlViewHolder
|
||||
|
||||
/**
|
||||
* Interface for logging UI events related to controls
|
||||
*/
|
||||
interface ControlsMetricsLogger {
|
||||
|
||||
/**
|
||||
* Assign a new instance id for this controls session, defined as when the controls area is
|
||||
* made visible to when it is closed.
|
||||
*/
|
||||
fun assignInstanceId()
|
||||
|
||||
fun touch(cvh: ControlViewHolder, isLocked: Boolean) {
|
||||
log(ControlsEvents.CONTROL_TOUCH.id, cvh.deviceType, cvh.uid, isLocked)
|
||||
}
|
||||
|
||||
fun drag(cvh: ControlViewHolder, isLocked: Boolean) {
|
||||
log(ControlsEvents.CONTROL_DRAG.id, cvh.deviceType, cvh.uid, isLocked)
|
||||
}
|
||||
|
||||
fun longPress(cvh: ControlViewHolder, isLocked: Boolean) {
|
||||
log(ControlsEvents.CONTROL_LONG_PRESS.id, cvh.deviceType, cvh.uid, isLocked)
|
||||
}
|
||||
|
||||
fun refreshBegin(uid: Int, isLocked: Boolean) {
|
||||
assignInstanceId()
|
||||
log(ControlsEvents.CONTROL_REFRESH_BEGIN.id, 0, uid, isLocked)
|
||||
}
|
||||
|
||||
fun refreshEnd(cvh: ControlViewHolder, isLocked: Boolean) {
|
||||
log(ControlsEvents.CONTROL_REFRESH_END.id, cvh.deviceType, cvh.uid, isLocked)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a controls-related event
|
||||
*
|
||||
* @param eventId Main UIEvent to capture
|
||||
* @param deviceType One of {@link android.service.controls.DeviceTypes}
|
||||
* @param packageName Package name of the service that receives the request
|
||||
* @param isLocked Is the device locked at the start of the action?
|
||||
*/
|
||||
fun log(
|
||||
eventId: Int,
|
||||
@DeviceType deviceType: Int,
|
||||
uid: Int,
|
||||
isLocked: Boolean
|
||||
)
|
||||
|
||||
private enum class ControlsEvents(val metricId: Int) : UiEventLogger.UiEventEnum {
|
||||
@UiEvent(doc = "User touched a control")
|
||||
CONTROL_TOUCH(714),
|
||||
|
||||
@UiEvent(doc = "User dragged a control")
|
||||
CONTROL_DRAG(713),
|
||||
|
||||
@UiEvent(doc = "User long-pressed a control")
|
||||
CONTROL_LONG_PRESS(715),
|
||||
|
||||
@UiEvent(doc = "User has opened controls, and a state refresh has begun")
|
||||
CONTROL_REFRESH_BEGIN(716),
|
||||
|
||||
@UiEvent(doc = "User has opened controls, and a state refresh has ended")
|
||||
CONTROL_REFRESH_END(717);
|
||||
|
||||
override fun getId() = metricId
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.controls
|
||||
|
||||
import android.service.controls.DeviceTypes.DeviceType
|
||||
|
||||
import com.android.internal.logging.InstanceIdSequence
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.shared.system.SysUiStatsLog
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Implementation for logging UI events related to controls
|
||||
*/
|
||||
@SysUISingleton
|
||||
class ControlsMetricsLoggerImpl @Inject constructor() : ControlsMetricsLogger {
|
||||
|
||||
companion object {
|
||||
private const val INSTANCE_ID_MAX = 1 shl 13
|
||||
}
|
||||
|
||||
private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
|
||||
private var instanceId = 0
|
||||
|
||||
override fun assignInstanceId() {
|
||||
instanceId = instanceIdSequence.newInstanceId().id
|
||||
}
|
||||
|
||||
/**
|
||||
* {@see ControlsMetricsLogger#log}
|
||||
*/
|
||||
override fun log(
|
||||
eventId: Int,
|
||||
@DeviceType deviceType: Int,
|
||||
uid: Int,
|
||||
isLocked: Boolean
|
||||
) {
|
||||
SysUiStatsLog.write(
|
||||
SysUiStatsLog.DEVICE_CONTROL_CHANGED,
|
||||
eventId,
|
||||
instanceId,
|
||||
deviceType,
|
||||
uid,
|
||||
isLocked
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.controls.dagger
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.pm.PackageManager
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.ControlsMetricsLoggerImpl
|
||||
import com.android.systemui.controls.controller.ControlsBindingController
|
||||
import com.android.systemui.controls.controller.ControlsBindingControllerImpl
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
@@ -79,6 +81,9 @@ abstract class ControlsModule {
|
||||
@Binds
|
||||
abstract fun provideUiController(controller: ControlsUiControllerImpl): ControlsUiController
|
||||
|
||||
@Binds
|
||||
abstract fun provideMetricsLogger(logger: ControlsMetricsLoggerImpl): ControlsMetricsLogger
|
||||
|
||||
@Binds
|
||||
abstract fun provideControlActionCoordinator(
|
||||
coordinator: ControlActionCoordinatorImpl
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.systemui.controls.ui
|
||||
|
||||
import android.annotation.MainThread
|
||||
import android.app.Dialog
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
@@ -33,6 +32,7 @@ import android.util.Log
|
||||
import android.view.HapticFeedbackConstants
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.globalactions.GlobalActionsComponent
|
||||
@@ -54,13 +54,15 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
private val globalActionsComponent: GlobalActionsComponent,
|
||||
private val taskViewFactory: Optional<TaskViewFactory>,
|
||||
private val broadcastDispatcher: BroadcastDispatcher,
|
||||
private val lazyUiController: Lazy<ControlsUiController>
|
||||
private val lazyUiController: Lazy<ControlsUiController>,
|
||||
private val controlsMetricsLogger: ControlsMetricsLogger
|
||||
) : ControlActionCoordinator {
|
||||
private var dialog: Dialog? = null
|
||||
private val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
private var pendingAction: Action? = null
|
||||
private var actionsInProgress = mutableSetOf<String>()
|
||||
|
||||
private val isLocked: Boolean
|
||||
get() = !keyguardStateController.isUnlocked()
|
||||
override var activityContext: Context? = null
|
||||
|
||||
companion object {
|
||||
@@ -73,6 +75,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
|
||||
controlsMetricsLogger.touch(cvh, isLocked)
|
||||
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
|
||||
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
|
||||
cvh.action(BooleanAction(templateId, !isChecked))
|
||||
@@ -80,6 +83,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
|
||||
controlsMetricsLogger.touch(cvh, isLocked)
|
||||
val blockable = cvh.usePanel()
|
||||
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
|
||||
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
|
||||
@@ -100,12 +104,14 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) {
|
||||
controlsMetricsLogger.drag(cvh, isLocked)
|
||||
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
|
||||
cvh.action(FloatAction(templateId, newValue))
|
||||
}, false /* blockable */))
|
||||
}
|
||||
|
||||
override fun longPress(cvh: ControlViewHolder) {
|
||||
controlsMetricsLogger.longPress(cvh, isLocked)
|
||||
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
|
||||
// Long press snould only be called when there is valid control state, otherwise ignore
|
||||
cvh.cws.control?.let {
|
||||
@@ -116,7 +122,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override fun runPendingAction(controlId: String) {
|
||||
if (!keyguardStateController.isUnlocked()) return
|
||||
if (isLocked) return
|
||||
if (pendingAction?.controlId == controlId) {
|
||||
pendingAction?.invoke()
|
||||
pendingAction = null
|
||||
@@ -141,28 +147,17 @@ class ControlActionCoordinatorImpl @Inject constructor(
|
||||
@VisibleForTesting
|
||||
fun bouncerOrRun(action: Action) {
|
||||
if (keyguardStateController.isShowing()) {
|
||||
var closeDialog = !keyguardStateController.isUnlocked()
|
||||
if (closeDialog) {
|
||||
if (isLocked) {
|
||||
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||
|
||||
// pending actions will only run after the control state has been refreshed
|
||||
pendingAction = action
|
||||
}
|
||||
|
||||
val wasLocked = isLocked
|
||||
activityStarter.dismissKeyguardThenExecute({
|
||||
Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action")
|
||||
if (closeDialog) {
|
||||
activityContext?.let {
|
||||
val i = Intent().apply {
|
||||
component = ComponentName(context, ControlsActivity::class.java)
|
||||
addFlags(
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
putExtra(ControlsUiController.BACK_TO_GLOBAL_ACTIONS, false)
|
||||
}
|
||||
it.startActivity(i)
|
||||
} ?: run {
|
||||
globalActionsComponent.handleShowGlobalActionsMenu()
|
||||
}
|
||||
if (wasLocked && activityContext == null) {
|
||||
globalActionsComponent.handleShowGlobalActionsMenu()
|
||||
} else {
|
||||
action.invoke()
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import android.widget.TextView
|
||||
import com.android.internal.graphics.ColorUtils
|
||||
import com.android.systemui.Interpolators
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||
import kotlin.reflect.KClass
|
||||
@@ -63,7 +64,9 @@ class ControlViewHolder(
|
||||
val controlsController: ControlsController,
|
||||
val uiExecutor: DelayableExecutor,
|
||||
val bgExecutor: DelayableExecutor,
|
||||
val controlActionCoordinator: ControlActionCoordinator
|
||||
val controlActionCoordinator: ControlActionCoordinator,
|
||||
val controlsMetricsLogger: ControlsMetricsLogger,
|
||||
val uid: Int
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -141,7 +144,7 @@ class ControlViewHolder(
|
||||
status.setSelected(true)
|
||||
}
|
||||
|
||||
fun bindData(cws: ControlWithState) {
|
||||
fun bindData(cws: ControlWithState, isLocked: Boolean) {
|
||||
// If an interaction is in progress, the update may visually interfere with the action the
|
||||
// action the user wants to make. Don't apply the update, and instead assume a new update
|
||||
// will coming from when the user interaction is complete.
|
||||
@@ -171,10 +174,16 @@ class ControlViewHolder(
|
||||
controlActionCoordinator.runPendingAction(cws.ci.controlId)
|
||||
}
|
||||
|
||||
val wasLoading = isLoading
|
||||
isLoading = false
|
||||
behavior = bindBehavior(behavior,
|
||||
findBehaviorClass(controlStatus, controlTemplate, deviceType))
|
||||
updateContentDescription()
|
||||
|
||||
// Only log one event per control, at the moment we have determined that the control
|
||||
// switched from the loading to done state
|
||||
val doneLoading = wasLoading && !isLoading
|
||||
if (doneLoading) controlsMetricsLogger.refreshEnd(this, isLocked)
|
||||
}
|
||||
|
||||
fun actionResponse(@ControlAction.ResponseResult response: Int) {
|
||||
|
||||
@@ -43,6 +43,7 @@ import android.widget.ListPopupWindow
|
||||
import android.widget.Space
|
||||
import android.widget.TextView
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.ControlsServiceInfo
|
||||
import com.android.systemui.controls.CustomIconCache
|
||||
import com.android.systemui.controls.controller.ControlInfo
|
||||
@@ -58,6 +59,7 @@ import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.globalactions.GlobalActionsPopupMenu
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.statusbar.phone.ShadeController
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||
import dagger.Lazy
|
||||
import java.text.Collator
|
||||
@@ -77,7 +79,9 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
val controlActionCoordinator: ControlActionCoordinator,
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val shadeController: ShadeController,
|
||||
private val iconCache: CustomIconCache
|
||||
private val iconCache: CustomIconCache,
|
||||
private val controlsMetricsLogger: ControlsMetricsLogger,
|
||||
private val keyguardStateController: KeyguardStateController
|
||||
) : ControlsUiController {
|
||||
|
||||
companion object {
|
||||
@@ -133,7 +137,8 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
return object : ControlsListingController.ControlsListingCallback {
|
||||
override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
|
||||
val lastItems = serviceInfos.map {
|
||||
SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName)
|
||||
val uid = it.serviceInfo.applicationInfo.uid
|
||||
SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName, uid)
|
||||
}
|
||||
uiExecutor.execute {
|
||||
parent.removeAllViews()
|
||||
@@ -282,8 +287,19 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
private fun showControlsView(items: List<SelectionItem>) {
|
||||
controlViewsById.clear()
|
||||
|
||||
createListView()
|
||||
createDropDown(items)
|
||||
val itemsByComponent = items.associateBy { it.componentName }
|
||||
val itemsWithStructure = mutableListOf<SelectionItem>()
|
||||
allStructures.mapNotNullTo(itemsWithStructure) {
|
||||
itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
|
||||
}
|
||||
itemsWithStructure.sortWith(localeComparator)
|
||||
|
||||
val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0]
|
||||
|
||||
controlsMetricsLogger.refreshBegin(selectionItem.uid, !keyguardStateController.isUnlocked())
|
||||
|
||||
createListView(selectionItem)
|
||||
createDropDown(itemsWithStructure, selectionItem)
|
||||
createMenu()
|
||||
}
|
||||
|
||||
@@ -325,22 +341,13 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
})
|
||||
}
|
||||
|
||||
private fun createDropDown(items: List<SelectionItem>) {
|
||||
private fun createDropDown(items: List<SelectionItem>, selected: SelectionItem) {
|
||||
items.forEach {
|
||||
RenderInfo.registerComponentIcon(it.componentName, it.icon)
|
||||
}
|
||||
|
||||
val itemsByComponent = items.associateBy { it.componentName }
|
||||
val itemsWithStructure = mutableListOf<SelectionItem>()
|
||||
allStructures.mapNotNullTo(itemsWithStructure) {
|
||||
itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
|
||||
}
|
||||
itemsWithStructure.sortWith(localeComparator)
|
||||
|
||||
val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0]
|
||||
|
||||
var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
|
||||
addAll(itemsWithStructure)
|
||||
addAll(items)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -349,13 +356,13 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
* a similar effect
|
||||
*/
|
||||
val spinner = parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply {
|
||||
setText(selectionItem.getTitle())
|
||||
setText(selected.getTitle())
|
||||
// override the default color on the dropdown drawable
|
||||
(getBackground() as LayerDrawable).getDrawable(0)
|
||||
.setTint(context.resources.getColor(R.color.control_spinner_dropdown, null))
|
||||
}
|
||||
|
||||
if (itemsWithStructure.size == 1) {
|
||||
if (items.size == 1) {
|
||||
spinner.setBackground(null)
|
||||
return
|
||||
}
|
||||
@@ -388,7 +395,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
})
|
||||
}
|
||||
|
||||
private fun createListView() {
|
||||
private fun createListView(selected: SelectionItem) {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
inflater.inflate(R.layout.controls_with_favorites, parent, true)
|
||||
|
||||
@@ -421,9 +428,11 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
controlsController.get(),
|
||||
uiExecutor,
|
||||
bgExecutor,
|
||||
controlActionCoordinator
|
||||
controlActionCoordinator,
|
||||
controlsMetricsLogger,
|
||||
selected.uid
|
||||
)
|
||||
cvh.bindData(it)
|
||||
cvh.bindData(it, false /* isLocked, will be ignored on initial load */)
|
||||
controlViewsById.put(key, cvh)
|
||||
}
|
||||
}
|
||||
@@ -528,6 +537,7 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
}
|
||||
|
||||
override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
|
||||
val isLocked = !keyguardStateController.isUnlocked()
|
||||
controls.forEach { c ->
|
||||
controlsById.get(ControlKey(componentName, c.getControlId()))?.let {
|
||||
Log.d(ControlsUiController.TAG, "onRefreshState() for id: " + c.getControlId())
|
||||
@@ -536,8 +546,8 @@ class ControlsUiControllerImpl @Inject constructor (
|
||||
val key = ControlKey(componentName, c.getControlId())
|
||||
controlsById.put(key, cws)
|
||||
|
||||
uiExecutor.execute {
|
||||
controlViewsById.get(key)?.bindData(cws)
|
||||
controlViewsById.get(key)?.let {
|
||||
uiExecutor.execute { it.bindData(cws, isLocked) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -566,7 +576,8 @@ private data class SelectionItem(
|
||||
val appName: CharSequence,
|
||||
val structure: CharSequence,
|
||||
val icon: Drawable,
|
||||
val componentName: ComponentName
|
||||
val componentName: ComponentName,
|
||||
val uid: Int
|
||||
) {
|
||||
fun getTitle() = if (structure.isEmpty()) { appName } else { structure }
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.controls.ui
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.globalactions.GlobalActionsComponent
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
@@ -63,6 +64,8 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
private lateinit var taskViewFactory: Optional<TaskViewFactory>
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private lateinit var cvh: ControlViewHolder
|
||||
@Mock
|
||||
private lateinit var metricsLogger: ControlsMetricsLogger
|
||||
|
||||
companion object {
|
||||
fun <T> any(): T = Mockito.any<T>()
|
||||
@@ -86,7 +89,8 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
globalActionsComponent,
|
||||
taskViewFactory,
|
||||
getFakeBroadcastDispatcher(),
|
||||
lazyUiController
|
||||
lazyUiController,
|
||||
metricsLogger
|
||||
))
|
||||
|
||||
`when`(cvh.cws.ci.controlId).thenReturn(ID)
|
||||
|
||||
Reference in New Issue
Block a user