Merge changes from topics "caitlinshk-wifi-screenshot-coloring", "caitlinshk-wifi-screenshot-shared", "caitlinshk-wifi-screenshot-wifi" into tm-qpr-dev am: 2e6bfea13b am: 7d279227df
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20814419 Change-Id: I05b8c71a07eb9adad5405f644ed724f821cf4a57 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -49,9 +49,9 @@ class StatusBarPipelineFlags @Inject constructor(private val featureFlags: Featu
|
||||
featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON_BACKEND) || useNewWifiIcon()
|
||||
|
||||
/**
|
||||
* Returns true if we should apply some coloring to the wifi icon that was rendered with the new
|
||||
* Returns true if we should apply some coloring to the icons that were rendered with the new
|
||||
* pipeline to help with debugging.
|
||||
*/
|
||||
fun useWifiDebugColoring(): Boolean =
|
||||
fun useDebugColoring(): Boolean =
|
||||
featureFlags.isEnabled(Flags.NEW_STATUS_BAR_ICONS_DEBUG_COLORING)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.binder
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
@@ -30,7 +31,13 @@ import com.android.settingslib.graph.SignalDrawable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.common.ui.binder.IconViewBinder
|
||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||
import com.android.systemui.statusbar.StatusBarIconView
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
|
||||
import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -40,7 +47,8 @@ object MobileIconBinder {
|
||||
fun bind(
|
||||
view: ViewGroup,
|
||||
viewModel: LocationBasedMobileViewModel,
|
||||
) {
|
||||
): ModernStatusBarViewBinding {
|
||||
val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group)
|
||||
val activityContainer = view.requireViewById<View>(R.id.inout_container)
|
||||
val activityIn = view.requireViewById<ImageView>(R.id.mobile_in)
|
||||
val activityOut = view.requireViewById<ImageView>(R.id.mobile_out)
|
||||
@@ -49,12 +57,39 @@ object MobileIconBinder {
|
||||
val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) }
|
||||
val roamingView = view.requireViewById<ImageView>(R.id.mobile_roaming)
|
||||
val roamingSpace = view.requireViewById<Space>(R.id.mobile_roaming_space)
|
||||
val dotView = view.requireViewById<StatusBarIconView>(R.id.status_bar_dot)
|
||||
|
||||
view.isVisible = true
|
||||
iconView.isVisible = true
|
||||
|
||||
// TODO(b/238425913): We should log this visibility state.
|
||||
@StatusBarIconView.VisibleState
|
||||
val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
|
||||
|
||||
val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
|
||||
val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
|
||||
|
||||
view.repeatWhenAttached {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
launch {
|
||||
visibilityState.collect { state ->
|
||||
when (state) {
|
||||
STATE_ICON -> {
|
||||
mobileGroupView.visibility = VISIBLE
|
||||
dotView.visibility = GONE
|
||||
}
|
||||
STATE_DOT -> {
|
||||
mobileGroupView.visibility = INVISIBLE
|
||||
dotView.visibility = VISIBLE
|
||||
}
|
||||
STATE_HIDDEN -> {
|
||||
mobileGroupView.visibility = INVISIBLE
|
||||
dotView.visibility = INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the icon for the triangle
|
||||
launch {
|
||||
viewModel.iconId.distinctUntilChanged().collect { iconId ->
|
||||
@@ -89,15 +124,43 @@ object MobileIconBinder {
|
||||
|
||||
// Set the tint
|
||||
launch {
|
||||
viewModel.tint.collect { tint ->
|
||||
iconTint.collect { tint ->
|
||||
val tintList = ColorStateList.valueOf(tint)
|
||||
iconView.imageTintList = tintList
|
||||
networkTypeView.imageTintList = tintList
|
||||
roamingView.imageTintList = tintList
|
||||
activityIn.imageTintList = tintList
|
||||
activityOut.imageTintList = tintList
|
||||
dotView.setDecorColor(tint)
|
||||
}
|
||||
}
|
||||
|
||||
launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
|
||||
}
|
||||
}
|
||||
|
||||
return object : ModernStatusBarViewBinding {
|
||||
override fun getShouldIconBeVisible(): Boolean {
|
||||
// If this view model exists, then the icon should be visible.
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int) {
|
||||
visibilityState.value = state
|
||||
}
|
||||
|
||||
override fun onIconTintChanged(newTint: Int) {
|
||||
if (viewModel.useDebugColoring) {
|
||||
return
|
||||
}
|
||||
iconTint.value = newTint
|
||||
}
|
||||
|
||||
override fun onDecorTintChanged(newTint: Int) {
|
||||
if (viewModel.useDebugColoring) {
|
||||
return
|
||||
}
|
||||
decorTint.value = newTint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,50 +17,20 @@
|
||||
package com.android.systemui.statusbar.pipeline.mobile.ui.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.BaseStatusBarFrameLayout
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
|
||||
import java.util.ArrayList
|
||||
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
|
||||
|
||||
class ModernStatusBarMobileView(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
) : BaseStatusBarFrameLayout(context, attrs) {
|
||||
) : ModernStatusBarView(context, attrs) {
|
||||
|
||||
var subId: Int = -1
|
||||
|
||||
private lateinit var slot: String
|
||||
override fun getSlot() = slot
|
||||
|
||||
override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun setStaticDrawableColor(color: Int) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun setDecorColor(color: Int) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun setVisibleState(state: Int, animate: Boolean) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun getVisibleState(): Int {
|
||||
return STATE_ICON
|
||||
}
|
||||
|
||||
override fun isIconVisible(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
@@ -77,9 +47,8 @@ class ModernStatusBarMobileView(
|
||||
.inflate(R.layout.status_bar_mobile_signal_group_new, null)
|
||||
as ModernStatusBarMobileView)
|
||||
.also {
|
||||
it.slot = slot
|
||||
it.subId = viewModel.subscriptionId
|
||||
MobileIconBinder.bind(it, viewModel)
|
||||
it.initView(slot) { MobileIconBinder.bind(it, viewModel) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||
|
||||
import android.graphics.Color
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||
|
||||
/**
|
||||
* A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
|
||||
@@ -33,50 +29,51 @@ import kotlinx.coroutines.flow.flowOf
|
||||
*/
|
||||
abstract class LocationBasedMobileViewModel(
|
||||
val commonImpl: MobileIconViewModelCommon,
|
||||
val logger: ConnectivityPipelineLogger,
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
debugTint: Int,
|
||||
) : MobileIconViewModelCommon by commonImpl {
|
||||
abstract val tint: Flow<Int>
|
||||
val useDebugColoring: Boolean = statusBarPipelineFlags.useDebugColoring()
|
||||
|
||||
val defaultColor: Int =
|
||||
if (useDebugColoring) {
|
||||
debugTint
|
||||
} else {
|
||||
Color.WHITE
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun viewModelForLocation(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
loc: StatusBarLocation,
|
||||
): LocationBasedMobileViewModel =
|
||||
when (loc) {
|
||||
StatusBarLocation.HOME -> HomeMobileIconViewModel(commonImpl, logger)
|
||||
StatusBarLocation.KEYGUARD -> KeyguardMobileIconViewModel(commonImpl, logger)
|
||||
StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl, logger)
|
||||
StatusBarLocation.HOME ->
|
||||
HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||
StatusBarLocation.KEYGUARD ->
|
||||
KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||
StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HomeMobileIconViewModel(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
) : MobileIconViewModelCommon, LocationBasedMobileViewModel(commonImpl, logger) {
|
||||
override val tint: Flow<Int> =
|
||||
flowOf(Color.CYAN)
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "HOME tint(${commonImpl.subscriptionId})")
|
||||
}
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
) :
|
||||
MobileIconViewModelCommon,
|
||||
LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.CYAN)
|
||||
|
||||
class QsMobileIconViewModel(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
) : MobileIconViewModelCommon, LocationBasedMobileViewModel(commonImpl, logger) {
|
||||
override val tint: Flow<Int> =
|
||||
flowOf(Color.GREEN)
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "QS tint(${commonImpl.subscriptionId})")
|
||||
}
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
) :
|
||||
MobileIconViewModelCommon,
|
||||
LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.GREEN)
|
||||
|
||||
class KeyguardMobileIconViewModel(
|
||||
commonImpl: MobileIconViewModelCommon,
|
||||
logger: ConnectivityPipelineLogger,
|
||||
) : MobileIconViewModelCommon, LocationBasedMobileViewModel(commonImpl, logger) {
|
||||
override val tint: Flow<Int> =
|
||||
flowOf(Color.MAGENTA)
|
||||
.distinctUntilChanged()
|
||||
.logOutputChange(logger, "KEYGUARD tint(${commonImpl.subscriptionId})")
|
||||
}
|
||||
statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
) :
|
||||
MobileIconViewModelCommon,
|
||||
LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.MAGENTA)
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||
@@ -41,6 +42,7 @@ constructor(
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val constants: ConnectivityConstants,
|
||||
@Application private val scope: CoroutineScope,
|
||||
private val statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
) {
|
||||
@VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
|
||||
|
||||
@@ -60,7 +62,11 @@ constructor(
|
||||
)
|
||||
.also { mobileIconSubIdCache[subId] = it }
|
||||
|
||||
return LocationBasedMobileViewModel.viewModelForLocation(common, logger, location)
|
||||
return LocationBasedMobileViewModel.viewModelForLocation(
|
||||
common,
|
||||
statusBarPipelineFlags,
|
||||
location,
|
||||
)
|
||||
}
|
||||
|
||||
private fun removeInvalidModelsFromCache(subIds: List<Int>) {
|
||||
@@ -75,6 +81,7 @@ constructor(
|
||||
private val logger: ConnectivityPipelineLogger,
|
||||
private val constants: ConnectivityConstants,
|
||||
@Application private val scope: CoroutineScope,
|
||||
private val statusBarPipelineFlags: StatusBarPipelineFlags,
|
||||
) {
|
||||
fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel {
|
||||
return MobileIconsViewModel(
|
||||
@@ -83,6 +90,7 @@ constructor(
|
||||
logger,
|
||||
constants,
|
||||
scope,
|
||||
statusBarPipelineFlags,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.statusbar.pipeline.shared.ui.binder
|
||||
|
||||
import com.android.systemui.statusbar.StatusBarIconView
|
||||
|
||||
/**
|
||||
* Defines interface for an object that acts as the binding between a modern status bar view and its
|
||||
* view-model.
|
||||
*
|
||||
* Users of the view binder classes in the modern status bar pipeline should use this to control the
|
||||
* binder after it is bound.
|
||||
*/
|
||||
interface ModernStatusBarViewBinding {
|
||||
/** Returns true if the icon should be visible and false otherwise. */
|
||||
fun getShouldIconBeVisible(): Boolean
|
||||
|
||||
/** Notifies that the visibility state has changed. */
|
||||
fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int)
|
||||
|
||||
/** Notifies that the icon tint has been updated. */
|
||||
fun onIconTintChanged(newTint: Int)
|
||||
|
||||
/** Notifies that the decor tint has been updated (used only for the dot). */
|
||||
fun onDecorTintChanged(newTint: Int)
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.statusbar.pipeline.shared.ui.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.plugins.DarkIconDispatcher
|
||||
import com.android.systemui.statusbar.BaseStatusBarFrameLayout
|
||||
import com.android.systemui.statusbar.StatusBarIconView
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
|
||||
import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
|
||||
|
||||
/**
|
||||
* A new and more modern implementation of [BaseStatusBarFrameLayout] that gets updated by view
|
||||
* binders communicating via [ModernStatusBarViewBinding].
|
||||
*/
|
||||
open class ModernStatusBarView(context: Context, attrs: AttributeSet?) :
|
||||
BaseStatusBarFrameLayout(context, attrs) {
|
||||
|
||||
private lateinit var slot: String
|
||||
private lateinit var binding: ModernStatusBarViewBinding
|
||||
|
||||
@StatusBarIconView.VisibleState
|
||||
private var iconVisibleState: Int = STATE_HIDDEN
|
||||
set(value) {
|
||||
if (field == value) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
binding.onVisibilityStateChanged(value)
|
||||
}
|
||||
|
||||
override fun getSlot() = slot
|
||||
|
||||
override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
|
||||
val newTint = DarkIconDispatcher.getTint(areas, this, tint)
|
||||
binding.onIconTintChanged(newTint)
|
||||
binding.onDecorTintChanged(newTint)
|
||||
}
|
||||
|
||||
override fun setStaticDrawableColor(color: Int) {
|
||||
binding.onIconTintChanged(color)
|
||||
}
|
||||
|
||||
override fun setDecorColor(color: Int) {
|
||||
binding.onDecorTintChanged(color)
|
||||
}
|
||||
|
||||
override fun setVisibleState(@StatusBarIconView.VisibleState state: Int, animate: Boolean) {
|
||||
iconVisibleState = state
|
||||
}
|
||||
|
||||
@StatusBarIconView.VisibleState
|
||||
override fun getVisibleState(): Int {
|
||||
return iconVisibleState
|
||||
}
|
||||
|
||||
override fun isIconVisible(): Boolean {
|
||||
return binding.getShouldIconBeVisible()
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this view.
|
||||
*
|
||||
* Creates a dot view, and uses [bindingCreator] to get and set the binding.
|
||||
*/
|
||||
fun initView(slot: String, bindingCreator: () -> ModernStatusBarViewBinding) {
|
||||
// The dot view requires [slot] to be set, and the [binding] may require an instantiated dot
|
||||
// view. So, this is the required order.
|
||||
this.slot = slot
|
||||
initDotView()
|
||||
this.binding = bindingCreator.invoke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [StatusBarIconView] that is always in DOT mode and adds it to this view.
|
||||
*
|
||||
* Mostly duplicated from [com.android.systemui.statusbar.StatusBarWifiView] and
|
||||
* [com.android.systemui.statusbar.StatusBarMobileView].
|
||||
*/
|
||||
private fun initDotView() {
|
||||
// TODO(b/238425913): Could we just have this dot view be part of the layout with a dot
|
||||
// drawable so we don't need to inflate it manually? Would that not work with animations?
|
||||
val dotView =
|
||||
StatusBarIconView(mContext, slot, null).also {
|
||||
it.id = R.id.status_bar_dot
|
||||
// Hard-code this view to always be in the DOT state so that whenever it's visible
|
||||
// it will show a dot
|
||||
it.visibleState = STATE_DOT
|
||||
}
|
||||
|
||||
val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size)
|
||||
val lp = LayoutParams(width, width)
|
||||
lp.gravity = Gravity.CENTER_VERTICAL or Gravity.START
|
||||
addView(dotView, lp)
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import com.android.systemui.statusbar.StatusBarIconView
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
|
||||
import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
|
||||
import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
|
||||
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
@@ -49,31 +50,12 @@ import kotlinx.coroutines.launch
|
||||
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
|
||||
object WifiViewBinder {
|
||||
|
||||
/**
|
||||
* Defines interface for an object that acts as the binding between the view and its view-model.
|
||||
*
|
||||
* Users of the [WifiViewBinder] class should use this to control the binder after it is bound.
|
||||
*/
|
||||
interface Binding {
|
||||
/** Returns true if the wifi icon should be visible and false otherwise. */
|
||||
fun getShouldIconBeVisible(): Boolean
|
||||
|
||||
/** Notifies that the visibility state has changed. */
|
||||
fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int)
|
||||
|
||||
/** Notifies that the icon tint has been updated. */
|
||||
fun onIconTintChanged(newTint: Int)
|
||||
|
||||
/** Notifies that the decor tint has been updated (used only for the dot). */
|
||||
fun onDecorTintChanged(newTint: Int)
|
||||
}
|
||||
|
||||
/** Binds the view to the view-model, continuing to update the former based on the latter. */
|
||||
@JvmStatic
|
||||
fun bind(
|
||||
view: ViewGroup,
|
||||
viewModel: LocationBasedWifiViewModel,
|
||||
): Binding {
|
||||
): ModernStatusBarViewBinding {
|
||||
val groupView = view.requireViewById<ViewGroup>(R.id.wifi_group)
|
||||
val iconView = view.requireViewById<ImageView>(R.id.wifi_signal)
|
||||
val dotView = view.requireViewById<StatusBarIconView>(R.id.status_bar_dot)
|
||||
@@ -148,7 +130,7 @@ object WifiViewBinder {
|
||||
}
|
||||
}
|
||||
|
||||
return object : Binding {
|
||||
return object : ModernStatusBarViewBinding {
|
||||
override fun getShouldIconBeVisible(): Boolean {
|
||||
return viewModel.wifiIcon.value is WifiIcon.Visible
|
||||
}
|
||||
|
||||
@@ -16,17 +16,12 @@
|
||||
|
||||
package com.android.systemui.statusbar.pipeline.wifi.ui.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.plugins.DarkIconDispatcher
|
||||
import com.android.systemui.statusbar.BaseStatusBarFrameLayout
|
||||
import com.android.systemui.statusbar.StatusBarIconView
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
|
||||
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
|
||||
import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder
|
||||
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
|
||||
|
||||
@@ -36,83 +31,14 @@ import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWi
|
||||
*/
|
||||
class ModernStatusBarWifiView(
|
||||
context: Context,
|
||||
attrs: AttributeSet?
|
||||
) : BaseStatusBarFrameLayout(context, attrs) {
|
||||
|
||||
private lateinit var slot: String
|
||||
private lateinit var binding: WifiViewBinder.Binding
|
||||
|
||||
@StatusBarIconView.VisibleState
|
||||
private var iconVisibleState: Int = STATE_HIDDEN
|
||||
set(value) {
|
||||
if (field == value) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
binding.onVisibilityStateChanged(value)
|
||||
}
|
||||
|
||||
override fun getSlot() = slot
|
||||
|
||||
override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
|
||||
val newTint = DarkIconDispatcher.getTint(areas, this, tint)
|
||||
binding.onIconTintChanged(newTint)
|
||||
binding.onDecorTintChanged(newTint)
|
||||
}
|
||||
|
||||
override fun setStaticDrawableColor(color: Int) {
|
||||
binding.onIconTintChanged(color)
|
||||
}
|
||||
|
||||
override fun setDecorColor(color: Int) {
|
||||
binding.onDecorTintChanged(color)
|
||||
}
|
||||
|
||||
override fun setVisibleState(@StatusBarIconView.VisibleState state: Int, animate: Boolean) {
|
||||
iconVisibleState = state
|
||||
}
|
||||
|
||||
@StatusBarIconView.VisibleState
|
||||
override fun getVisibleState(): Int {
|
||||
return iconVisibleState
|
||||
}
|
||||
|
||||
override fun isIconVisible(): Boolean {
|
||||
return binding.getShouldIconBeVisible()
|
||||
}
|
||||
|
||||
private fun initView(
|
||||
slotName: String,
|
||||
wifiViewModel: LocationBasedWifiViewModel,
|
||||
) {
|
||||
slot = slotName
|
||||
initDotView()
|
||||
binding = WifiViewBinder.bind(this, wifiViewModel)
|
||||
}
|
||||
|
||||
// Mostly duplicated from [com.android.systemui.statusbar.StatusBarWifiView].
|
||||
private fun initDotView() {
|
||||
// TODO(b/238425913): Could we just have this dot view be part of
|
||||
// R.layout.new_status_bar_wifi_group with a dot drawable so we don't need to inflate it
|
||||
// manually? Would that not work with animations?
|
||||
val dotView = StatusBarIconView(mContext, slot, null).also {
|
||||
it.id = R.id.status_bar_dot
|
||||
// Hard-code this view to always be in the DOT state so that whenever it's visible it
|
||||
// will show a dot
|
||||
it.visibleState = STATE_DOT
|
||||
}
|
||||
|
||||
val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size)
|
||||
val lp = LayoutParams(width, width)
|
||||
lp.gravity = Gravity.CENTER_VERTICAL or Gravity.START
|
||||
addView(dotView, lp)
|
||||
}
|
||||
|
||||
attrs: AttributeSet?,
|
||||
) : ModernStatusBarView(context, attrs) {
|
||||
companion object {
|
||||
/**
|
||||
* Inflates a new instance of [ModernStatusBarWifiView], binds it to a view model, and
|
||||
* returns it.
|
||||
*/
|
||||
@SuppressLint("InflateParams")
|
||||
@JvmStatic
|
||||
fun constructAndBind(
|
||||
context: Context,
|
||||
@@ -123,7 +49,7 @@ class ModernStatusBarWifiView(
|
||||
LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
|
||||
as ModernStatusBarWifiView
|
||||
).also {
|
||||
it.initView(slot, wifiViewModel)
|
||||
it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ abstract class LocationBasedWifiViewModel(
|
||||
/** True if the airplane spacer view should be visible. */
|
||||
val isAirplaneSpacerVisible: Flow<Boolean>,
|
||||
) {
|
||||
val useDebugColoring: Boolean = statusBarPipelineFlags.useWifiDebugColoring()
|
||||
val useDebugColoring: Boolean = statusBarPipelineFlags.useDebugColoring()
|
||||
|
||||
val defaultColor: Int =
|
||||
if (useDebugColoring) {
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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.statusbar.pipeline.mobile.ui.view
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import android.testing.ViewUtils
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.StatusBarIconView
|
||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper(setAsMainLooper = true)
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class ModernStatusBarMobileViewTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var testableLooper: TestableLooper
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
|
||||
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: ConnectivityConstants
|
||||
|
||||
private lateinit var viewModel: LocationBasedMobileViewModel
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
testableLooper = TestableLooper.get(this)
|
||||
|
||||
val interactor = FakeMobileIconInteractor(tableLogBuffer)
|
||||
|
||||
val viewModelCommon =
|
||||
MobileIconViewModel(
|
||||
subscriptionId = 1,
|
||||
interactor,
|
||||
logger,
|
||||
constants,
|
||||
testScope.backgroundScope,
|
||||
)
|
||||
viewModel = QsMobileIconViewModel(viewModelCommon, statusBarPipelineFlags)
|
||||
}
|
||||
|
||||
// Note: The following tests are more like integration tests, since they stand up a full
|
||||
// [WifiViewModel] and test the interactions between the view, view-binder, and view-model.
|
||||
|
||||
@Test
|
||||
fun setVisibleState_icon_iconShownDotHidden() {
|
||||
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
|
||||
view.setVisibleState(StatusBarIconView.STATE_ICON, /* animate= */ false)
|
||||
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.getGroupView().visibility).isEqualTo(View.VISIBLE)
|
||||
assertThat(view.getDotView().visibility).isEqualTo(View.GONE)
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setVisibleState_dot_iconHiddenDotShown() {
|
||||
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
|
||||
view.setVisibleState(StatusBarIconView.STATE_DOT, /* animate= */ false)
|
||||
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.getGroupView().visibility).isEqualTo(View.INVISIBLE)
|
||||
assertThat(view.getDotView().visibility).isEqualTo(View.VISIBLE)
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setVisibleState_hidden_iconAndDotHidden() {
|
||||
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
|
||||
view.setVisibleState(StatusBarIconView.STATE_HIDDEN, /* animate= */ false)
|
||||
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.getGroupView().visibility).isEqualTo(View.INVISIBLE)
|
||||
assertThat(view.getDotView().visibility).isEqualTo(View.INVISIBLE)
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isIconVisible_alwaysTrue() {
|
||||
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.isIconVisible).isTrue()
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDarkChanged_iconHasNewColor() {
|
||||
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
|
||||
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
val color = 0x12345678
|
||||
view.onDarkChanged(arrayListOf(), 1.0f, color)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.getIconView().imageTintList).isEqualTo(ColorStateList.valueOf(color))
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setStaticDrawableColor_iconHasNewColor() {
|
||||
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
|
||||
val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
val color = 0x23456789
|
||||
view.setStaticDrawableColor(color)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.getIconView().imageTintList).isEqualTo(ColorStateList.valueOf(color))
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
private fun View.getGroupView(): View {
|
||||
return this.requireViewById(R.id.mobile_group)
|
||||
}
|
||||
|
||||
private fun View.getIconView(): ImageView {
|
||||
return this.requireViewById(R.id.mobile_signal)
|
||||
}
|
||||
|
||||
private fun View.getDotView(): View {
|
||||
return this.requireViewById(R.id.status_bar_dot)
|
||||
}
|
||||
}
|
||||
|
||||
private const val SLOT_NAME = "TestSlotName"
|
||||
@@ -20,6 +20,7 @@ import androidx.test.filters.SmallTest
|
||||
import com.android.settingslib.mobile.TelephonyIcons
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal
|
||||
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
|
||||
@@ -45,6 +46,7 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
|
||||
private lateinit var qsIcon: QsMobileIconViewModel
|
||||
private lateinit var keyguardIcon: KeyguardMobileIconViewModel
|
||||
private lateinit var interactor: FakeMobileIconInteractor
|
||||
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: ConnectivityConstants
|
||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||
@@ -68,9 +70,9 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
|
||||
commonImpl =
|
||||
MobileIconViewModel(SUB_1_ID, interactor, logger, constants, testScope.backgroundScope)
|
||||
|
||||
homeIcon = HomeMobileIconViewModel(commonImpl, logger)
|
||||
qsIcon = QsMobileIconViewModel(commonImpl, logger)
|
||||
keyguardIcon = KeyguardMobileIconViewModel(commonImpl, logger)
|
||||
homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||
qsIcon = QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||
keyguardIcon = KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.phone.StatusBarLocation
|
||||
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
|
||||
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
|
||||
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
|
||||
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
|
||||
@@ -45,6 +46,7 @@ class MobileIconsViewModelTest : SysuiTestCase() {
|
||||
private lateinit var underTest: MobileIconsViewModel
|
||||
private val interactor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
|
||||
|
||||
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||
@Mock private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var constants: ConnectivityConstants
|
||||
|
||||
@@ -67,6 +69,7 @@ class MobileIconsViewModelTest : SysuiTestCase() {
|
||||
logger,
|
||||
constants,
|
||||
testScope.backgroundScope,
|
||||
statusBarPipelineFlags,
|
||||
)
|
||||
|
||||
interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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.statusbar.pipeline.shared.ui.view
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
|
||||
import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper(setAsMainLooper = true)
|
||||
class ModernStatusBarViewTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var binding: TestBinding
|
||||
|
||||
@Test
|
||||
fun initView_hasCorrectSlot() {
|
||||
val view = ModernStatusBarView(context, null)
|
||||
val binding = TestBinding()
|
||||
|
||||
view.initView("slotName") { binding }
|
||||
|
||||
assertThat(view.slot).isEqualTo("slotName")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getVisibleState_icon_returnsIcon() {
|
||||
val view = createAndInitView()
|
||||
|
||||
view.setVisibleState(STATE_ICON, /* animate= */ false)
|
||||
|
||||
assertThat(view.visibleState).isEqualTo(STATE_ICON)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getVisibleState_dot_returnsDot() {
|
||||
val view = createAndInitView()
|
||||
|
||||
view.setVisibleState(STATE_DOT, /* animate= */ false)
|
||||
|
||||
assertThat(view.visibleState).isEqualTo(STATE_DOT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getVisibleState_hidden_returnsHidden() {
|
||||
val view = createAndInitView()
|
||||
|
||||
view.setVisibleState(STATE_HIDDEN, /* animate= */ false)
|
||||
|
||||
assertThat(view.visibleState).isEqualTo(STATE_HIDDEN)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onDarkChanged_bindingReceivesIconAndDecorTint() {
|
||||
val view = createAndInitView()
|
||||
|
||||
view.onDarkChanged(arrayListOf(), 1.0f, 0x12345678)
|
||||
|
||||
assertThat(binding.iconTint).isEqualTo(0x12345678)
|
||||
assertThat(binding.decorTint).isEqualTo(0x12345678)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setStaticDrawableColor_bindingReceivesIconTint() {
|
||||
val view = createAndInitView()
|
||||
|
||||
view.setStaticDrawableColor(0x12345678)
|
||||
|
||||
assertThat(binding.iconTint).isEqualTo(0x12345678)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setDecorColor_bindingReceivesDecorColor() {
|
||||
val view = createAndInitView()
|
||||
|
||||
view.setDecorColor(0x23456789)
|
||||
|
||||
assertThat(binding.decorTint).isEqualTo(0x23456789)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isIconVisible_usesBinding_true() {
|
||||
val view = createAndInitView()
|
||||
|
||||
binding.shouldIconBeVisibleInternal = true
|
||||
|
||||
assertThat(view.isIconVisible).isEqualTo(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isIconVisible_usesBinding_false() {
|
||||
val view = createAndInitView()
|
||||
|
||||
binding.shouldIconBeVisibleInternal = false
|
||||
|
||||
assertThat(view.isIconVisible).isEqualTo(false)
|
||||
}
|
||||
|
||||
private fun createAndInitView(): ModernStatusBarView {
|
||||
val view = ModernStatusBarView(context, null)
|
||||
binding = TestBinding()
|
||||
view.initView(SLOT_NAME) { binding }
|
||||
return view
|
||||
}
|
||||
|
||||
inner class TestBinding : ModernStatusBarViewBinding {
|
||||
var iconTint: Int? = null
|
||||
var decorTint: Int? = null
|
||||
var onVisibilityStateChangedCalled: Boolean = false
|
||||
|
||||
var shouldIconBeVisibleInternal: Boolean = true
|
||||
|
||||
override fun onIconTintChanged(newTint: Int) {
|
||||
iconTint = newTint
|
||||
}
|
||||
|
||||
override fun onDecorTintChanged(newTint: Int) {
|
||||
decorTint = newTint
|
||||
}
|
||||
|
||||
override fun onVisibilityStateChanged(state: Int) {
|
||||
onVisibilityStateChangedCalled = true
|
||||
}
|
||||
|
||||
override fun getShouldIconBeVisible(): Boolean {
|
||||
return shouldIconBeVisibleInternal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val SLOT_NAME = "TestSlotName"
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.systemui.statusbar.pipeline.wifi.ui.view
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Rect
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
@@ -27,7 +26,6 @@ import android.widget.ImageView
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.lifecycle.InstantTaskExecutorRule
|
||||
import com.android.systemui.log.table.TableLogBuffer
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
|
||||
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
|
||||
@@ -52,8 +50,6 @@ import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
@@ -70,7 +66,8 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
|
||||
private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
|
||||
@Mock
|
||||
private lateinit var logger: ConnectivityPipelineLogger
|
||||
@Mock private lateinit var tableLogBuffer: TableLogBuffer
|
||||
@Mock
|
||||
private lateinit var tableLogBuffer: TableLogBuffer
|
||||
@Mock
|
||||
private lateinit var connectivityConstants: ConnectivityConstants
|
||||
@Mock
|
||||
@@ -83,9 +80,6 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
|
||||
private lateinit var scope: CoroutineScope
|
||||
private lateinit var airplaneModeViewModel: AirplaneModeViewModel
|
||||
|
||||
@JvmField @Rule
|
||||
val instantTaskExecutor = InstantTaskExecutorRule()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
@@ -118,40 +112,6 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
|
||||
).home
|
||||
}
|
||||
|
||||
@Test
|
||||
fun constructAndBind_hasCorrectSlot() {
|
||||
val view = ModernStatusBarWifiView.constructAndBind(context, "slotName", viewModel)
|
||||
|
||||
assertThat(view.slot).isEqualTo("slotName")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getVisibleState_icon_returnsIcon() {
|
||||
val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
|
||||
view.setVisibleState(STATE_ICON, /* animate= */ false)
|
||||
|
||||
assertThat(view.visibleState).isEqualTo(STATE_ICON)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getVisibleState_dot_returnsDot() {
|
||||
val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
|
||||
view.setVisibleState(STATE_DOT, /* animate= */ false)
|
||||
|
||||
assertThat(view.visibleState).isEqualTo(STATE_DOT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getVisibleState_hidden_returnsHidden() {
|
||||
val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
|
||||
view.setVisibleState(STATE_HIDDEN, /* animate= */ false)
|
||||
|
||||
assertThat(view.visibleState).isEqualTo(STATE_HIDDEN)
|
||||
}
|
||||
|
||||
// Note: The following tests are more like integration tests, since they stand up a full
|
||||
// [WifiViewModel] and test the interactions between the view, view-binder, and view-model.
|
||||
|
||||
@@ -235,24 +195,24 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("b/262660044")
|
||||
fun onDarkChanged_iconHasNewColor() {
|
||||
whenever(statusBarPipelineFlags.useWifiDebugColoring()).thenReturn(false)
|
||||
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
|
||||
val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
val areas = ArrayList(listOf(Rect(0, 0, 1000, 1000)))
|
||||
val color = 0x12345678
|
||||
view.onDarkChanged(areas, 1.0f, color)
|
||||
view.onDarkChanged(arrayListOf(), 1.0f, color)
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.getIconView().imageTintList).isEqualTo(ColorStateList.valueOf(color))
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setStaticDrawableColor_iconHasNewColor() {
|
||||
whenever(statusBarPipelineFlags.useWifiDebugColoring()).thenReturn(false)
|
||||
whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
|
||||
val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel)
|
||||
ViewUtils.attachView(view)
|
||||
testableLooper.processAllMessages()
|
||||
@@ -262,6 +222,8 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
|
||||
testableLooper.processAllMessages()
|
||||
|
||||
assertThat(view.getIconView().imageTintList).isEqualTo(ColorStateList.valueOf(color))
|
||||
|
||||
ViewUtils.detachView(view)
|
||||
}
|
||||
|
||||
private fun View.getIconGroupView(): View {
|
||||
|
||||
Reference in New Issue
Block a user