diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt new file mode 100644 index 0000000000000..d7d17006168ea --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt @@ -0,0 +1,22 @@ +/* + * 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.controls.controller + +interface ControlsTileResourceConfiguration { + fun getTileTitleId(): Int + fun getTileImageId(): Int +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt new file mode 100644 index 0000000000000..c96d3d4a26024 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt @@ -0,0 +1,36 @@ +/* + * 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.controls.controller + +import com.android.systemui.R +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +/** + * Default Instance for ControlsTileResourceConfiguration. + */ +@SysUISingleton +class ControlsTileResourceConfigurationImpl @Inject constructor() + : ControlsTileResourceConfiguration { + override fun getTileTitleId(): Int { + return R.string.quick_controls_title + } + + override fun getTileImageId(): Int { + return R.drawable.controls_icon + } +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt index 469e60a3852e7..b8e6d9f0f60a7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt @@ -29,6 +29,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.settings.SecureSettings import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT +import com.android.systemui.controls.controller.ControlsTileResourceConfiguration +import com.android.systemui.controls.controller.ControlsTileResourceConfigurationImpl import dagger.Lazy import java.util.Optional import javax.inject.Inject @@ -49,13 +51,20 @@ class ControlsComponent @Inject constructor( private val lockPatternUtils: LockPatternUtils, private val keyguardStateController: KeyguardStateController, private val userTracker: UserTracker, - private val secureSettings: SecureSettings + private val secureSettings: SecureSettings, + private val optionalControlsTileResourceConfiguration: + Optional ) { private val contentResolver: ContentResolver get() = context.contentResolver private var canShowWhileLockedSetting = false + private val controlsTileResourceConfiguration: ControlsTileResourceConfiguration = + optionalControlsTileResourceConfiguration.orElse( + ControlsTileResourceConfigurationImpl() + ) + val showWhileLockedObserver = object : ContentObserver(null) { override fun onChange(selfChange: Boolean) { updateShowWhileLocked() @@ -121,4 +130,12 @@ class ControlsComponent @Inject constructor( enum class Visibility { AVAILABLE, AVAILABLE_AFTER_UNLOCK, UNAVAILABLE } + + fun getTileTitleId(): Int { + return controlsTileResourceConfiguration.getTileTitleId() + } + + fun getTileImageId(): Int { + return controlsTileResourceConfiguration.getTileImageId() + } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index a165bb2c954fa..6f58abdeed565 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -25,6 +25,7 @@ import com.android.systemui.controls.controller.ControlsBindingControllerImpl import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper +import com.android.systemui.controls.controller.ControlsTileResourceConfiguration import com.android.systemui.controls.management.ControlsEditingActivity import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsListingController @@ -92,6 +93,9 @@ abstract class ControlsModule { @BindsOptionalOf abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper + @BindsOptionalOf + abstract fun provideControlsTileResourceConfiguration(): ControlsTileResourceConfiguration + @Binds @IntoMap @ClassKey(ControlsProviderSelectorActivity::class) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt index 80ec0adc21a96..05b342072974c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt @@ -22,6 +22,7 @@ import android.os.Handler import android.os.Looper import android.service.quicksettings.Tile import android.view.View +import androidx.annotation.VisibleForTesting import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.MetricsLogger import com.android.systemui.R @@ -69,7 +70,9 @@ class DeviceControlsTile @Inject constructor( private var hasControlsApps = AtomicBoolean(false) - private val icon = ResourceIcon.get(R.drawable.controls_icon) + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + val icon: QSTile.Icon + get() = ResourceIcon.get(controlsComponent.getTileImageId()) private val listingCallback = object : ControlsListingController.ControlsListingCallback { override fun onServicesUpdated(serviceInfos: List) { @@ -120,14 +123,14 @@ class DeviceControlsTile @Inject constructor( override fun handleUpdateState(state: QSTile.State, arg: Any?) { state.label = tileLabel - state.contentDescription = state.label state.icon = icon if (controlsComponent.isEnabled() && hasControlsApps.get()) { if (controlsComponent.getVisibility() == AVAILABLE) { + val structure = controlsComponent + .getControlsController().get().getPreferredStructure().structure state.state = Tile.STATE_ACTIVE - state.secondaryLabel = controlsComponent - .getControlsController().get().getPreferredStructure().structure + state.secondaryLabel = if (structure == tileLabel) null else structure } else { state.state = Tile.STATE_INACTIVE state.secondaryLabel = mContext.getText(R.string.controls_tile_locked) @@ -149,6 +152,6 @@ class DeviceControlsTile @Inject constructor( override fun handleLongClick(view: View?) {} override fun getTileLabel(): CharSequence { - return mContext.getText(R.string.quick_controls_title) + return mContext.getText(controlsComponent.getTileTitleId()) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 88fe1cae2d765..baee8dfe5a0b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -554,6 +554,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private void updateControlsVisibility() { if (mControlsComponent == null) return; + mControlsButton.setImageResource(mControlsComponent.getTileImageId()); + mControlsButton.setContentDescription(getContext() + .getString(mControlsComponent.getTileTitleId())); + boolean hasFavorites = mControlsComponent.getControlsController() .map(c -> c.getFavorites().size() > 0) .orElse(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt new file mode 100644 index 0000000000000..7fb088eb783f8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt @@ -0,0 +1,42 @@ +/* + * 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.controls.controller + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class ControlsTileResourceConfigurationImplTest : SysuiTestCase() { + @Test + fun getTileImageId() { + val instance = ControlsTileResourceConfigurationImpl() + assertEquals(instance.getTileImageId(), + R.drawable.controls_icon) + } + @Test + fun getTileTitleId() { + val instance = ControlsTileResourceConfigurationImpl() + assertEquals(instance.getTileTitleId(), + R.string.quick_controls_title) + } +} \ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt index ecefb5533c37a..c415c1fabdf3c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt @@ -24,12 +24,14 @@ import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUT import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT import com.android.systemui.SysuiTestCase import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.controls.controller.ControlsTileResourceConfiguration import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.settings.SecureSettings import dagger.Lazy +import java.util.Optional import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue @@ -41,6 +43,7 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.anyInt import org.mockito.Mockito.`when` +import org.mockito.Mockito.any import org.mockito.MockitoAnnotations @SmallTest @@ -61,6 +64,11 @@ class ControlsComponentTest : SysuiTestCase() { private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var secureSettings: SecureSettings + @Mock + private lateinit var optionalControlsTileResourceConfiguration: + Optional + @Mock + private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration companion object { fun eq(value: T): T = Mockito.eq(value) ?: value @@ -71,6 +79,8 @@ class ControlsComponentTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) `when`(userTracker.userHandle.identifier).thenReturn(0) + `when`(optionalControlsTileResourceConfiguration.orElse(any())) + .thenReturn(controlsTileResourceConfiguration) } @Test @@ -146,6 +156,26 @@ class ControlsComponentTest : SysuiTestCase() { assertEquals(ControlsComponent.Visibility.AVAILABLE, component.getVisibility()) } + @Test + fun testGetTileImageId() { + val tileImageId = 0 + + `when`(controlsTileResourceConfiguration.getTileImageId()) + .thenReturn(tileImageId) + val component = setupComponent(true) + assertEquals(component.getTileImageId(), tileImageId) + } + + @Test + fun testGetTileTitleId() { + val tileTitleId = 0 + + `when`(controlsTileResourceConfiguration.getTileTitleId()) + .thenReturn(tileTitleId) + val component = setupComponent(true) + assertEquals(component.getTileTitleId(), tileTitleId) + } + private fun setupComponent(enabled: Boolean): ControlsComponent { return ControlsComponent( enabled, @@ -156,7 +186,8 @@ class ControlsComponentTest : SysuiTestCase() { lockPatternUtils, keyguardStateController, userTracker, - secureSettings + secureSettings, + optionalControlsTileResourceConfiguration ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt index 98c7274aeba6c..ed988810fc83a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt @@ -28,6 +28,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger +import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.classifier.FalsingManagerFake @@ -41,6 +42,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture @@ -151,6 +153,9 @@ class DeviceControlsTileTest : SysuiTestCase() { Optional.empty() } } + + `when`(controlsComponent.getTileTitleId()).thenReturn(R.string.quick_controls_title) + `when`(controlsComponent.getTileTitleId()).thenReturn(R.drawable.controls_icon) } @Test @@ -316,6 +321,20 @@ class DeviceControlsTileTest : SysuiTestCase() { assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME) } + @Test + fun verifyTileEqualsResourceFromComponent() { + assertThat(tile.tileLabel) + .isEqualTo( + context.getText( + controlsComponent.getTileTitleId())) + } + + @Test + fun verifyTileImageEqualsResourceFromComponent() { + assertThat(tile.icon) + .isEqualTo(QSTileImpl.ResourceIcon.get(controlsComponent.getTileImageId())) + } + private fun createTile(): DeviceControlsTile { return DeviceControlsTile( qsHost,