diff --git a/packages/SystemUI/res/layout/new_status_bar_wifi_group.xml b/packages/SystemUI/res/layout/new_status_bar_wifi_group.xml index fc90c438b363b..753ba2f21faf4 100644 --- a/packages/SystemUI/res/layout/new_status_bar_wifi_group.xml +++ b/packages/SystemUI/res/layout/new_status_bar_wifi_group.xml @@ -16,7 +16,7 @@ ** limitations under the License. */ --> - - + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index b946be3018da3..c72eb054c62c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -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; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 3a7a6730e65fb..1a14a03637630 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -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; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt similarity index 60% rename from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarWifiView.kt rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt index e252e0c23a39e..cc0ec548716d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarWifiView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt @@ -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) - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt new file mode 100644 index 0000000000000..7a734862fe1b1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt @@ -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) } + } + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt new file mode 100644 index 0000000000000..3fe69837a7616 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt @@ -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" diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt index 3efa25e8f7b00..afd179987440e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt @@ -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))