Merge "UX polish for lock screen preview (1/3)." into tm-qpr-dev am: 9ddeac9025 am: b3fea560f2
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21077389
Change-Id: Ie0dc8b8233815bdc3a875224c0622ae7c55f5955
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt
index 18e8a96..bf922bc 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt
@@ -21,4 +21,5 @@
const val MESSAGE_ID_SLOT_SELECTED = 1337
const val KEY_SLOT_ID = "slot_id"
const val KEY_INITIALLY_SELECTED_SLOT_ID = "initially_selected_slot_id"
+ const val KEY_HIGHLIGHT_QUICK_AFFORDANCES = "highlight_quick_affordances"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index d020529..e9d7a5b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -66,6 +66,8 @@
object KeyguardBottomAreaViewBinder {
private const val EXIT_DOZE_BUTTON_REVEAL_ANIMATION_DURATION_MS = 250L
+ private const val SCALE_SELECTED_BUTTON = 1.23f
+ private const val DIM_ALPHA = 0.3f
/**
* Defines interface for an object that acts as the binding between the view and its view-model.
@@ -315,6 +317,12 @@
} else {
null
}
+ view
+ .animate()
+ .scaleX(if (viewModel.isSelected) SCALE_SELECTED_BUTTON else 1f)
+ .scaleY(if (viewModel.isSelected) SCALE_SELECTED_BUTTON else 1f)
+ .alpha(if (viewModel.isDimmed) DIM_ALPHA else 1f)
+ .start()
view.isClickable = viewModel.isClickable
if (viewModel.isClickable) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index a5ae8ba5..8808574 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -24,7 +24,6 @@
import android.hardware.display.DisplayManager
import android.os.Bundle
import android.os.IBinder
-import android.view.Gravity
import android.view.LayoutInflater
import android.view.SurfaceControlViewHost
import android.view.View
@@ -65,6 +64,11 @@
val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
private val height: Int = bundle.getInt(KEY_VIEW_HEIGHT)
+ private val shouldHighlightSelectedAffordance: Boolean =
+ bundle.getBoolean(
+ KeyguardQuickAffordancePreviewConstants.KEY_HIGHLIGHT_QUICK_AFFORDANCES,
+ false,
+ )
private var host: SurfaceControlViewHost
@@ -82,6 +86,7 @@
bundle.getString(
KeyguardQuickAffordancePreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID,
),
+ shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
)
runBlocking(mainDispatcher) {
host =
@@ -154,8 +159,7 @@
bottomAreaView,
FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.WRAP_CONTENT,
- Gravity.BOTTOM,
+ FrameLayout.LayoutParams.MATCH_PARENT,
),
)
}
@@ -195,7 +199,13 @@
?.events
?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
clockView?.let { parentView.removeView(it) }
- clockView = clockController.clock?.largeClock?.view?.apply { parentView.addView(this) }
+ clockView =
+ clockController.clock?.largeClock?.view?.apply {
+ if (shouldHighlightSelectedAffordance) {
+ alpha = DIM_ALPHA
+ }
+ parentView.addView(this)
+ }
}
companion object {
@@ -203,5 +213,7 @@
private const val KEY_VIEW_WIDTH = "width"
private const val KEY_VIEW_HEIGHT = "height"
private const val KEY_DISPLAY_ID = "display_id"
+
+ private const val DIM_ALPHA = 0.3f
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index 5d85680..1e3b60c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -45,12 +45,17 @@
private val bottomAreaInteractor: KeyguardBottomAreaInteractor,
private val burnInHelperWrapper: BurnInHelperWrapper,
) {
+ data class PreviewMode(
+ val isInPreviewMode: Boolean = false,
+ val shouldHighlightSelectedAffordance: Boolean = false,
+ )
+
/**
* Whether this view-model instance is powering the preview experience that renders exclusively
* in the wallpaper picker application. This should _always_ be `false` for the real lock screen
* experience.
*/
- private val isInPreviewMode = MutableStateFlow(false)
+ private val previewMode = MutableStateFlow(PreviewMode())
/**
* ID of the slot that's currently selected in the preview that renders exclusively in the
@@ -87,8 +92,8 @@
keyguardInteractor.isDozing.map { !it }.distinctUntilChanged()
/** An observable for the alpha level for the entire bottom area. */
val alpha: Flow<Float> =
- isInPreviewMode.flatMapLatest { isInPreviewMode ->
- if (isInPreviewMode) {
+ previewMode.flatMapLatest {
+ if (it.isInPreviewMode) {
flowOf(1f)
} else {
bottomAreaInteractor.alpha.distinctUntilChanged()
@@ -129,9 +134,18 @@
* lock screen.
*
* @param initiallySelectedSlotId The ID of the initial slot to render as the selected one.
+ * @param shouldHighlightSelectedAffordance Whether the selected quick affordance should be
+ * highlighted (while all others are dimmed to make the selected one stand out).
*/
- fun enablePreviewMode(initiallySelectedSlotId: String?) {
- isInPreviewMode.value = true
+ fun enablePreviewMode(
+ initiallySelectedSlotId: String?,
+ shouldHighlightSelectedAffordance: Boolean,
+ ) {
+ previewMode.value =
+ PreviewMode(
+ isInPreviewMode = true,
+ shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
+ )
onPreviewSlotSelected(
initiallySelectedSlotId ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
)
@@ -150,9 +164,9 @@
private fun button(
position: KeyguardQuickAffordancePosition
): Flow<KeyguardQuickAffordanceViewModel> {
- return isInPreviewMode.flatMapLatest { isInPreviewMode ->
+ return previewMode.flatMapLatest { previewMode ->
combine(
- if (isInPreviewMode) {
+ if (previewMode.isInPreviewMode) {
quickAffordanceInteractor.quickAffordanceAlwaysVisible(position = position)
} else {
quickAffordanceInteractor.quickAffordance(position = position)
@@ -161,11 +175,18 @@
areQuickAffordancesFullyOpaque,
selectedPreviewSlotId,
) { model, animateReveal, isFullyOpaque, selectedPreviewSlotId ->
+ val isSelected = selectedPreviewSlotId == position.toSlotId()
model.toViewModel(
- animateReveal = !isInPreviewMode && animateReveal,
- isClickable = isFullyOpaque && !isInPreviewMode,
+ animateReveal = !previewMode.isInPreviewMode && animateReveal,
+ isClickable = isFullyOpaque && !previewMode.isInPreviewMode,
isSelected =
- (isInPreviewMode && selectedPreviewSlotId == position.toSlotId()),
+ previewMode.isInPreviewMode &&
+ previewMode.shouldHighlightSelectedAffordance &&
+ isSelected,
+ isDimmed =
+ previewMode.isInPreviewMode &&
+ previewMode.shouldHighlightSelectedAffordance &&
+ !isSelected,
)
}
.distinctUntilChanged()
@@ -176,6 +197,7 @@
animateReveal: Boolean,
isClickable: Boolean,
isSelected: Boolean,
+ isDimmed: Boolean,
): KeyguardQuickAffordanceViewModel {
return when (this) {
is KeyguardQuickAffordanceModel.Visible ->
@@ -194,6 +216,7 @@
isActivated = activationState is ActivationState.Active,
isSelected = isSelected,
useLongPress = quickAffordanceInteractor.useLongPress,
+ isDimmed = isDimmed,
)
is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
index cf3a6da..cb68a82 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
@@ -31,6 +31,7 @@
val isActivated: Boolean = false,
val isSelected: Boolean = false,
val useLongPress: Boolean = false,
+ val isDimmed: Boolean = false,
) {
data class OnClickedParameters(
val configKey: String,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 022afdd..4b04b7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -234,7 +234,10 @@
@Test
fun `startButton - in preview mode - visible even when keyguard not showing`() =
testScope.runTest {
- underTest.enablePreviewMode(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START)
+ underTest.enablePreviewMode(
+ initiallySelectedSlotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+ shouldHighlightSelectedAffordance = true,
+ )
repository.setKeyguardShowing(false)
val latest = collectLastValue(underTest.startButton)
@@ -263,6 +266,7 @@
icon = icon,
canShowWhileLocked = false,
intent = Intent("action"),
+ isSelected = true,
),
configKey = configKey,
)
@@ -270,6 +274,60 @@
}
@Test
+ fun `endButton - in higlighted preview mode - dimmed when other is selected`() =
+ testScope.runTest {
+ underTest.enablePreviewMode(
+ initiallySelectedSlotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+ shouldHighlightSelectedAffordance = true,
+ )
+ repository.setKeyguardShowing(false)
+ val startButton = collectLastValue(underTest.startButton)
+ val endButton = collectLastValue(underTest.endButton)
+
+ val icon: Icon = mock()
+ setUpQuickAffordanceModel(
+ position = KeyguardQuickAffordancePosition.BOTTOM_START,
+ testConfig =
+ TestConfig(
+ isVisible = true,
+ isClickable = true,
+ isActivated = true,
+ icon = icon,
+ canShowWhileLocked = false,
+ intent = Intent("action"),
+ ),
+ )
+ val configKey =
+ setUpQuickAffordanceModel(
+ position = KeyguardQuickAffordancePosition.BOTTOM_END,
+ testConfig =
+ TestConfig(
+ isVisible = true,
+ isClickable = true,
+ isActivated = true,
+ icon = icon,
+ canShowWhileLocked = false,
+ intent = Intent("action"),
+ ),
+ )
+
+ assertQuickAffordanceViewModel(
+ viewModel = endButton(),
+ testConfig =
+ TestConfig(
+ isVisible = true,
+ isClickable = false,
+ isActivated = true,
+ icon = icon,
+ canShowWhileLocked = false,
+ intent = Intent("action"),
+ isDimmed = true,
+ ),
+ configKey = configKey,
+ )
+ }
+
+ @Test
fun `endButton - present - visible model - do nothing on click`() =
testScope.runTest {
repository.setKeyguardShowing(true)
@@ -377,7 +435,10 @@
@Test
fun `alpha - in preview mode - does not change`() =
testScope.runTest {
- underTest.enablePreviewMode(null)
+ underTest.enablePreviewMode(
+ initiallySelectedSlotId = null,
+ shouldHighlightSelectedAffordance = false,
+ )
val value = collectLastValue(underTest.alpha)
assertThat(value()).isEqualTo(1f)
@@ -639,6 +700,8 @@
assertThat(viewModel.isVisible).isEqualTo(testConfig.isVisible)
assertThat(viewModel.isClickable).isEqualTo(testConfig.isClickable)
assertThat(viewModel.isActivated).isEqualTo(testConfig.isActivated)
+ assertThat(viewModel.isSelected).isEqualTo(testConfig.isSelected)
+ assertThat(viewModel.isDimmed).isEqualTo(testConfig.isDimmed)
if (testConfig.isVisible) {
assertThat(viewModel.icon).isEqualTo(testConfig.icon)
viewModel.onClicked.invoke(
@@ -664,6 +727,8 @@
val icon: Icon? = null,
val canShowWhileLocked: Boolean = false,
val intent: Intent? = null,
+ val isSelected: Boolean = false,
+ val isDimmed: Boolean = false,
) {
init {
check(!isVisible || icon != null) { "Must supply non-null icon if visible!" }