[SB Refactor] Remove the wifi-specific parts from ModernStatusBarView.

Bug: 238425913
Test: verify wifi icon still tints correctly
Test: atest ModernStatusBarViewTest ModernStatusBarWifiViewTest
Change-Id: I86a2ca1b7ddf05dc2942faf178e702abd1d5738f
This commit is contained in:
Caitlin Shkuratov
2022-12-27 16:56:54 +00:00
parent 8d921138b0
commit ed18e21dd9
7 changed files with 245 additions and 93 deletions

View File

@@ -16,7 +16,7 @@
** limitations under the License.
*/
-->
<com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarWifiView
<com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/wifi_combo"
android:layout_width="wrap_content"
@@ -25,4 +25,4 @@
<include layout="@layout/status_bar_wifi_group_inner" />
</com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarWifiView>
</com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView>

View File

@@ -42,7 +42,7 @@ import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconStat
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarWifiView;
import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel;
import java.util.ArrayList;

View File

@@ -55,7 +55,7 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinde
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter;
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarWifiView;
import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel;
import com.android.systemui.util.Assert;

View File

@@ -20,7 +20,6 @@ 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
@@ -28,17 +27,13 @@ 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
import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
/**
* A new and more modern implementation of [com.android.systemui.statusbar.StatusBarWifiView] that
* is updated by [WifiViewBinder].
* A new and more modern implementation of [BaseStatusBarFrameLayout] that gets updated by view
* binders communicating via [ModernStatusBarViewBinding].
*/
class ModernStatusBarWifiView(
context: Context,
attrs: AttributeSet?
) : BaseStatusBarFrameLayout(context, attrs) {
open class ModernStatusBarView(context: Context, attrs: AttributeSet?) :
BaseStatusBarFrameLayout(context, attrs) {
private lateinit var slot: String
private lateinit var binding: ModernStatusBarViewBinding
@@ -82,50 +77,39 @@ class ModernStatusBarWifiView(
return binding.getShouldIconBeVisible()
}
private fun initView(
slotName: String,
wifiViewModel: LocationBasedWifiViewModel,
) {
slot = slotName
/**
* 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()
binding = WifiViewBinder.bind(this, wifiViewModel)
this.binding = bindingCreator.invoke()
}
// Mostly duplicated from [com.android.systemui.statusbar.StatusBarWifiView].
/**
* 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
// 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
}
// 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)
}
companion object {
/**
* Inflates a new instance of [ModernStatusBarWifiView], binds it to a view model, and
* returns it.
*/
@JvmStatic
fun constructAndBind(
context: Context,
slot: String,
wifiViewModel: LocationBasedWifiViewModel,
): ModernStatusBarWifiView {
return (
LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
as ModernStatusBarWifiView
).also {
it.initView(slot, wifiViewModel)
}
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.wifi.ui.view
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import com.android.systemui.R
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
/**
* A new and more modern implementation of [com.android.systemui.statusbar.StatusBarWifiView] that
* is updated by [WifiViewBinder].
*/
class ModernStatusBarWifiView(
context: Context,
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,
slot: String,
wifiViewModel: LocationBasedWifiViewModel,
): ModernStatusBarWifiView {
return (
LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
as ModernStatusBarWifiView
).also {
it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) }
}
}
}
}

View File

@@ -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"

View File

@@ -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
@@ -40,7 +38,6 @@ import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneMod
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarWifiView
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
@@ -54,7 +51,6 @@ 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
@@ -71,7 +67,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
@@ -84,9 +81,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)
@@ -119,40 +113,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.
@@ -243,9 +203,8 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() {
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))