Home Controls: Update controls ui for sysui.

Added an interface that will serve to determine what icon and title to
show for the device controls tile.

Bug: 216104516
Test: Manual test on device.

Change-Id: I5694033f27cdff5a3dac2cc18b620292d7d042b3
This commit is contained in:
Aaron Liu
2022-01-26 20:05:24 +00:00
parent 4324a25dba
commit 8541605857
9 changed files with 185 additions and 7 deletions

View File

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

View File

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

View File

@@ -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<ControlsTileResourceConfiguration>
) {
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()
}
}

View File

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

View File

@@ -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<ControlsServiceInfo>) {
@@ -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())
}
}

View File

@@ -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);

View File

@@ -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)
}
}

View File

@@ -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<ControlsTileResourceConfiguration>
@Mock
private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration
companion object {
fun <T> 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
)
}
}

View File

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