From a30c678eb4f6623b79a1dd5732d2fc910f74d8d4 Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Wed, 19 Jul 2023 13:01:41 -0700 Subject: [PATCH] Rename layout -> blueprint and add "sections" Rename from layout to blueprint because layout is an overloaded word. Items will not be components that we can use to determine our layout constraints. Also refactor blueprints to use multiple data layers for scalability. Flag: MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA Bug: 288464307 Test: Adjust tests and see that views in the rootview are properly constrained. Change-Id: I8369360614e100a37964cb869faa1a3acd694acb --- .../layout/keyguard_settings_popup_menu.xml | 8 +- .../com/android/keyguard/LockIconView.java | 4 + .../keyguard/LockIconViewController.java | 5 +- .../systemui/dagger/SystemUIModule.java | 4 +- .../keyguard/KeyguardViewConfigurator.kt | 39 +-- .../repository/KeyguardBlueprintRepository.kt | 109 +++++++ .../interactor/KeyguardBlueprintInteractor.kt | 44 +++ .../ui/binder/KeyguardBlueprintViewBinder.kt | 55 ++++ .../ui/preview/KeyguardPreviewRenderer.kt | 24 +- .../keyguard/ui/view/KeyguardRootView.kt | 30 +- .../ui/view/layout/DefaultLockscreenLayout.kt | 286 ---------------- ...kt => KeyguardBlueprintCommandListener.kt} | 23 +- .../ui/view/layout/KeyguardLayoutManager.kt | 97 ------ .../ShortcutsBesideUdfpsLockscreenLayout.kt | 305 ------------------ .../blueprints/DefaultKeyguardBlueprint.kt | 59 ++++ .../KeyguardBlueprintModule.kt} | 17 +- .../ShortcutsBesideUdfpsKeyguardBlueprint.kt | 62 ++++ .../sections/AlignShortcutsToUdfpsSection.kt | 54 ++++ .../DefaultAmbientIndicationAreaSection.kt | 62 ++++ .../sections/DefaultIndicationAreaSection.kt | 56 ++++ .../layout/sections/DefaultLockIconSection.kt | 116 +++++++ .../DefaultSettingsPopupMenuSection.kt | 56 ++++ .../sections/DefaultShortcutsSection.kt | 53 +++ .../viewmodel/KeyguardBlueprintViewModel.kt | 29 ++ .../KeyguardBlueprintRepositoryTest.kt | 104 ++++++ .../KeyguardBlueprintInteractorTest.kt | 55 ++++ ...> KeyguardBlueprintCommandListenerTest.kt} | 34 +- .../view/layout/KeyguardLayoutManagerTest.kt | 69 ---- .../DefaultKeyguardBlueprintTest.kt | 73 +++++ .../DefaultIndicationAreaSectionTest.kt | 48 +++ .../DefaultLockIconSectionTest.kt} | 50 +-- .../KeyguardBlueprintViewModelTest.kt | 48 +++ 32 files changed, 1199 insertions(+), 879 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/DefaultLockscreenLayout.kt rename packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/{KeyguardLayoutManagerCommandListener.kt => KeyguardBlueprintCommandListener.kt} (63%) delete mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManager.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/ShortcutsBesideUdfpsLockscreenLayout.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt rename packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/{LockscreenLayoutModule.kt => blueprints/KeyguardBlueprintModule.kt} (61%) create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt rename packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/{KeyguardLayoutManagerCommandListenerTest.kt => KeyguardBlueprintCommandListenerTest.kt} (66%) delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt rename packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/{DefaultLockscreenLayoutTest.kt => sections/DefaultLockIconSectionTest.kt} (54%) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt diff --git a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml index 65ee8b370f9b5..636f479e5778c 100644 --- a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml +++ b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml @@ -25,13 +25,13 @@ android:orientation="horizontal" android:gravity="center_vertical" android:background="@drawable/keyguard_settings_popup_menu_background" - android:padding="12dp"> + android:padding="@dimen/keyguard_settings_popup_menu_padding"> diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index 76b073ef73afe..1a0c7f97e146e 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -181,6 +181,10 @@ public class LockIconView extends FrameLayout implements Dumpable { mLockIcon.setImageState(getLockIconState(mIconType, mAod), true); } + public ImageView getLockIcon() { + return mLockIcon; + } + private void addLockIconImageView(Context context, AttributeSet attrs) { mLockIcon = new ImageView(context, attrs); mLockIcon.setId(R.id.lock_icon); diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 54597185f8556..4845a6173be97 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -417,7 +417,10 @@ public class LockIconViewController extends ViewController impleme private void updateLockIconLocation() { final float scaleFactor = mAuthController.getScaleFactor(); final int scaledPadding = (int) (mDefaultPaddingPx * scaleFactor); - if (!mFeatureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) { + if (mFeatureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) { + mView.getLockIcon().setPadding(scaledPadding, scaledPadding, scaledPadding, + scaledPadding); + } else { if (mUdfpsSupported) { mView.setCenterLocation(mAuthController.getUdfpsLocation(), mAuthController.getUdfpsRadius(), scaledPadding); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 3c42a29451cab..f73a602bda63a 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -54,7 +54,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FlagsModule; import com.android.systemui.keyboard.KeyboardModule; -import com.android.systemui.keyguard.ui.view.layout.LockscreenLayoutModule; +import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule; import com.android.systemui.log.dagger.LogModule; import com.android.systemui.log.dagger.MonitorLog; import com.android.systemui.log.table.TableLogBuffer; @@ -179,7 +179,7 @@ import javax.inject.Named; GarbageMonitorModule.class, KeyboardModule.class, LetterboxModule.class, - LockscreenLayoutModule.class, + KeyguardBlueprintModule.class, LogModule.class, MediaProjectionModule.class, MediaProjectionTaskSwitcherModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index 4495943c72c91..6213265cb66ef 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -26,27 +26,28 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.ui.binder.KeyguardAmbientIndicationAreaViewBinder +import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardSettingsViewBinder import com.android.systemui.keyguard.ui.view.KeyguardRootView +import com.android.systemui.keyguard.ui.view.layout.KeyguardBlueprintCommandListener import com.android.systemui.keyguard.ui.viewmodel.KeyguardAmbientIndicationViewModel -import com.android.systemui.keyguard.ui.view.layout.KeyguardLayoutManager -import com.android.systemui.keyguard.ui.view.layout.KeyguardLayoutManagerCommandListener +import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel +import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager -import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.statusbar.KeyguardIndicationController +import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel -import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import javax.inject.Inject @@ -68,9 +69,8 @@ constructor( private val notificationShadeWindowView: NotificationShadeWindowView, private val featureFlags: FeatureFlags, private val indicationController: KeyguardIndicationController, - private val keyguardLayoutManager: KeyguardLayoutManager, - private val keyguardLayoutManagerCommandListener: KeyguardLayoutManagerCommandListener, - private val keyguardQuickAffordancesCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel, + private val keyguardQuickAffordancesCombinedViewModel: + KeyguardQuickAffordancesCombinedViewModel, private val falsingManager: FalsingManager, private val vibratorHelper: VibratorHelper, private val keyguardStateController: KeyguardStateController, @@ -78,6 +78,8 @@ constructor( private val activityStarter: ActivityStarter, private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, private val chipbarCoordinator: ChipbarCoordinator, + private val keyguardBlueprintCommandListener: KeyguardBlueprintCommandListener, + private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel, ) : CoreStartable { private var rootViewHandle: DisposableHandle? = null @@ -100,8 +102,8 @@ constructor( bindAmbientIndicationArea() bindSettingsPopupMenu() - keyguardLayoutManager.layoutViews() - keyguardLayoutManagerCommandListener.start() + KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) + keyguardBlueprintCommandListener.start() } fun setupNotificationStackScrollLayout(legacyParent: ViewGroup) { @@ -125,8 +127,6 @@ constructor( leftShortcutHandle?.onConfigurationChanged() rightShortcutHandle?.onConfigurationChanged() ambientIndicationAreaHandle?.onConfigurationChanged() - - keyguardLayoutManager.layoutViews() } fun bindIndicationArea() { @@ -152,14 +152,15 @@ constructor( private fun bindKeyguardRootView() { rootViewHandle?.dispose() - rootViewHandle = KeyguardRootViewBinder.bind( - keyguardRootView, - keyguardRootViewModel, - featureFlags, - occludingAppDeviceEntryMessageViewModel, - chipbarCoordinator, - keyguardStateController, - ) + rootViewHandle = + KeyguardRootViewBinder.bind( + keyguardRootView, + keyguardRootViewModel, + featureFlags, + occludingAppDeviceEntryMessageViewModel, + chipbarCoordinator, + keyguardStateController, + ) } private fun bindLockIconView(legacyParent: ViewGroup) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt new file mode 100644 index 0000000000000..059f72b9f708c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2023 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.keyguard.data.repository + +import androidx.constraintlayout.widget.ConstraintSet +import com.android.systemui.common.ui.data.repository.ConfigurationRepository +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT +import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule +import java.io.PrintWriter +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch + +/** + * Manages blueprint changes for the lockscreen. + * + * To add a blueprint, create a class that implements LockscreenBlueprint and bind it to the map in + * the dagger module: + * + * A Blueprint determines how the layout should be constrained on a high level. + * + * A Section is a modular piece of code that implements the constraints. The blueprint uses the + * sections to define the constraints. + * + * @see KeyguardBlueprintModule + */ +@SysUISingleton +class KeyguardBlueprintRepository +@Inject +constructor( + configurationRepository: ConfigurationRepository, + blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>, + @Application private val applicationScope: CoroutineScope, +) { + private val blueprintIdMap: Map = blueprints.associateBy { it.id } + private val _blueprint: MutableSharedFlow = MutableSharedFlow(replay = 1) + val blueprint: Flow = _blueprint.asSharedFlow() + + init { + applyBlueprint(blueprintIdMap[DEFAULT]!!) + applicationScope.launch { + configurationRepository.onAnyConfigurationChange.collect { refreshBlueprint() } + } + } + + /** + * Emits the blueprint value to the collectors. + * + * @param blueprintId + * @return whether the transition has succeeded. + */ + fun applyBlueprint(blueprintId: String?): Boolean { + val blueprint = blueprintIdMap[blueprintId] ?: return false + applyBlueprint(blueprint) + return true + } + + /** Emits the blueprint value to the collectors. */ + fun applyBlueprint(blueprint: KeyguardBlueprint?) { + blueprint?.let { _blueprint.tryEmit(it) } + } + + /** Re-emits the last emitted blueprint value if possible. */ + fun refreshBlueprint() { + if (_blueprint.replayCache.isNotEmpty()) { + _blueprint.tryEmit(_blueprint.replayCache.last()) + } + } + + /** Prints all available blueprints to the PrintWriter. */ + fun printBlueprints(pw: PrintWriter) { + blueprintIdMap.forEach { entry -> pw.println("${entry.key}") } + } +} + +/** Determines the constraints for the ConstraintSet in the lockscreen root view. */ +interface KeyguardBlueprint { + val id: String + + fun apply(constraintSet: ConstraintSet) +} + +/** + * Lower level modules that determine constraints for a particular section in the lockscreen root + * view. + */ +interface KeyguardSection { + fun apply(constraintSet: ConstraintSet) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt new file mode 100644 index 0000000000000..390ad7ef892bf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 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.keyguard.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository +import javax.inject.Inject + +@SysUISingleton +class KeyguardBlueprintInteractor +@Inject +constructor(private val keyguardBlueprintRepository: KeyguardBlueprintRepository) { + val blueprint = keyguardBlueprintRepository.blueprint + + /** + * Transitions to a blueprint. + * + * @param blueprintId + * @return whether the transition has succeeded. + */ + fun transitionToBlueprint(blueprintId: String): Boolean { + return keyguardBlueprintRepository.applyBlueprint(blueprintId) + } + + /** Re-emits the blueprint value to the collectors. */ + fun refreshBlueprint() { + keyguardBlueprintRepository.refreshBlueprint() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt new file mode 100644 index 0000000000000..23b80b05a7858 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.binder + +import android.os.Trace +import android.util.Log +import androidx.constraintlayout.widget.ConstraintSet +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.keyguard.ui.view.KeyguardRootView +import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel +import com.android.systemui.lifecycle.repeatWhenAttached +import kotlinx.coroutines.launch + +class KeyguardBlueprintViewBinder { + companion object { + private const val TAG = "KeyguardBlueprintViewBinder" + + fun bind(keyguardRootView: KeyguardRootView, viewModel: KeyguardBlueprintViewModel) { + keyguardRootView.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.CREATED) { + launch { + viewModel.blueprint.collect { blueprint -> + Trace.beginSection("KeyguardBlueprintController#applyBlueprint") + Log.d(TAG, "applying blueprint: $blueprint") + ConstraintSet().apply { + clone(keyguardRootView) + val emptyLayout = ConstraintSet.Layout() + knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) } + blueprint?.apply(this) + applyTo(keyguardRootView) + } + Trace.endSection() + } + } + } + } + } + } +} 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 3e6e1585ca6d3..58bc552ad4ef5 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 @@ -44,11 +44,13 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor +import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder import com.android.systemui.keyguard.ui.view.KeyguardRootView -import com.android.systemui.keyguard.ui.view.layout.KeyguardLayoutManager +import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel @@ -90,12 +92,13 @@ constructor( private val lockscreenSmartspaceController: LockscreenSmartspaceController, private val udfpsOverlayInteractor: UdfpsOverlayInteractor, private val featureFlags: FeatureFlags, - private val keyguardLayoutManager: KeyguardLayoutManager, private val falsingManager: FalsingManager, private val vibratorHelper: VibratorHelper, private val indicationController: KeyguardIndicationController, private val keyguardRootViewModel: KeyguardRootViewModel, @Assisted bundle: Bundle, + private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel, + private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor, ) { val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN) @@ -129,17 +132,17 @@ constructor( if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { keyguardRootViewModel.enablePreviewMode( initiallySelectedSlotId = - bundle.getString( - KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID, - ), + bundle.getString( + KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID, + ), shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance, ) } else { bottomAreaViewModel.enablePreviewMode( initiallySelectedSlotId = - bundle.getString( - KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID, - ), + bundle.getString( + KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID, + ), shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance, ) } @@ -169,7 +172,8 @@ constructor( ), ) setupShortcuts(keyguardRootView) - keyguardLayoutManager.layoutViews(keyguardRootView) + KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) + keyguardBlueprintInteractor.refreshBlueprint() } else { setUpBottomArea(rootView) } @@ -309,7 +313,7 @@ constructor( false, ) as KeyguardBottomAreaView bottomAreaView.init( - viewModel = bottomAreaViewModel, + viewModel = bottomAreaViewModel, ) parentView.addView( bottomAreaView, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt index 65fe990453875..e60901f922c32 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt @@ -19,10 +19,10 @@ package com.android.systemui.keyguard.ui.view import android.content.Context import android.util.AttributeSet -import androidx.constraintlayout.widget.ConstraintLayout import android.view.LayoutInflater import android.view.View import android.widget.ImageView +import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.res.ResourcesCompat import com.android.keyguard.LockIconView import com.android.systemui.R @@ -62,8 +62,9 @@ class KeyguardRootView( } private fun addLeftShortcut() { - val view = LaunchableImageView(context, attrs) - .apply { + val padding = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_padding) + val view = + LaunchableImageView(context, attrs).apply { id = R.id.start_button scaleType = ImageView.ScaleType.FIT_CENTER background = @@ -79,13 +80,15 @@ class KeyguardRootView( context.theme ) visibility = View.INVISIBLE + setPadding(padding, padding, padding, padding) } addView(view) } private fun addRightShortcut() { - val view = LaunchableImageView(context, attrs) - .apply { + val padding = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_padding) + val view = + LaunchableImageView(context, attrs).apply { id = R.id.end_button scaleType = ImageView.ScaleType.FIT_CENTER background = @@ -101,20 +104,19 @@ class KeyguardRootView( context.theme ) visibility = View.INVISIBLE + setPadding(padding, padding, padding, padding) } addView(view) } private fun addSettingsPopupMenu() { - val view = LayoutInflater.from(context).inflate( - R.layout.keyguard_settings_popup_menu, - this, - false - ) - .apply { - id = R.id.keyguard_settings_button - visibility = GONE - } + val view = + LayoutInflater.from(context) + .inflate(R.layout.keyguard_settings_popup_menu, this, false) + .apply { + id = R.id.keyguard_settings_button + visibility = GONE + } addView(view) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/DefaultLockscreenLayout.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/DefaultLockscreenLayout.kt deleted file mode 100644 index 6be45c79e37e6..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/DefaultLockscreenLayout.kt +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2023 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.keyguard.ui.view.layout - -import android.content.Context -import android.graphics.Point -import android.graphics.Rect -import android.util.DisplayMetrics -import android.view.View -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.view.ViewGroup.LayoutParams.WRAP_CONTENT -import android.view.ViewGroup.MarginLayoutParams -import android.view.WindowManager -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView -import androidx.annotation.VisibleForTesting -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.constraintlayout.widget.ConstraintSet -import androidx.constraintlayout.widget.ConstraintSet.BOTTOM -import androidx.constraintlayout.widget.ConstraintSet.END -import androidx.constraintlayout.widget.ConstraintSet.LEFT -import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT -import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID -import androidx.constraintlayout.widget.ConstraintSet.RIGHT -import androidx.constraintlayout.widget.ConstraintSet.START -import androidx.constraintlayout.widget.ConstraintSet.TOP -import androidx.core.view.setPadding -import androidx.core.view.updateLayoutParams -import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.R -import com.android.systemui.animation.view.LaunchableLinearLayout -import com.android.systemui.biometrics.AuthController -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.ui.view.KeyguardRootView -import javax.inject.Inject - -/** - * Positions elements of the lockscreen to the default position. - * - * This will be the most common use case for phones in portrait mode. - */ -@SysUISingleton -class DefaultLockscreenLayout -@Inject -constructor( - private val authController: AuthController, - private val keyguardUpdateMonitor: KeyguardUpdateMonitor, - private val windowManager: WindowManager, - private val context: Context, -) : LockscreenLayout { - override val id: String = DEFAULT - - override fun layoutIndicationArea(rootView: KeyguardRootView) { - val indicationArea = rootView.findViewById(R.id.keyguard_indication_area) ?: return - - rootView.getConstraintSet().apply { - constrainWidth(indicationArea.id, MATCH_PARENT) - constrainHeight(indicationArea.id, WRAP_CONTENT) - connect( - indicationArea.id, - BOTTOM, - PARENT_ID, - BOTTOM, - R.dimen.keyguard_indication_margin_bottom.dp() - ) - connect(indicationArea.id, START, PARENT_ID, START) - connect(indicationArea.id, END, PARENT_ID, END) - applyTo(rootView) - } - } - - override fun layoutLockIcon(rootView: KeyguardRootView) { - val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported - val scaleFactor: Float = authController.scaleFactor - val mBottomPaddingPx = R.dimen.lock_icon_margin_bottom.dp() - val mDefaultPaddingPx = R.dimen.lock_icon_padding.dp() - val scaledPadding: Int = (mDefaultPaddingPx * scaleFactor).toInt() - val bounds = windowManager.currentWindowMetrics.bounds - val widthPixels = bounds.right.toFloat() - val heightPixels = bounds.bottom.toFloat() - val defaultDensity = - DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() / - DisplayMetrics.DENSITY_DEFAULT.toFloat() - val lockIconRadiusPx = (defaultDensity * 36).toInt() - - if (isUdfpsSupported) { - authController.udfpsLocation?.let { udfpsLocation -> - centerLockIcon(udfpsLocation, authController.udfpsRadius, scaledPadding, rootView) - } - } else { - centerLockIcon( - Point( - (widthPixels / 2).toInt(), - (heightPixels - ((mBottomPaddingPx + lockIconRadiusPx) * scaleFactor)).toInt() - ), - lockIconRadiusPx * scaleFactor, - scaledPadding, - rootView - ) - } - } - - @VisibleForTesting - internal fun centerLockIcon( - center: Point, - radius: Float, - drawablePadding: Int, - rootView: KeyguardRootView, - ) { - val lockIconView = rootView.findViewById(R.id.lock_icon_view) ?: return - val lockIcon = lockIconView.findViewById(R.id.lock_icon) ?: return - lockIcon.setPadding(drawablePadding, drawablePadding, drawablePadding, drawablePadding) - - val sensorRect = - Rect().apply { - set( - center.x - radius.toInt(), - center.y - radius.toInt(), - center.x + radius.toInt(), - center.y + radius.toInt(), - ) - } - - rootView.getConstraintSet().apply { - constrainWidth(lockIconView.id, sensorRect.right - sensorRect.left) - constrainHeight(lockIconView.id, sensorRect.bottom - sensorRect.top) - connect(lockIconView.id, TOP, PARENT_ID, TOP, sensorRect.top) - connect(lockIconView.id, START, PARENT_ID, START, sensorRect.left) - applyTo(rootView) - } - } - - override fun layoutShortcuts(rootView: KeyguardRootView) { - val leftShortcut = rootView.findViewById(R.id.start_button) ?: return - val rightShortcut = rootView.findViewById(R.id.end_button) ?: return - val width = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width) - val height = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height) - val horizontalOffsetMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset) - val verticalOffsetMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset) - val padding = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_padding) - - leftShortcut.apply { - updateLayoutParams { - marginStart = horizontalOffsetMargin - bottomMargin = verticalOffsetMargin - } - setPadding(padding) - } - - rightShortcut.apply { - updateLayoutParams { - marginEnd = horizontalOffsetMargin - bottomMargin = verticalOffsetMargin - } - setPadding(padding) - } - - rootView.getConstraintSet().apply { - constrainWidth(leftShortcut.id, width) - constrainHeight(leftShortcut.id, height) - connect(leftShortcut.id, LEFT, PARENT_ID, LEFT) - connect(leftShortcut.id, BOTTOM, PARENT_ID, BOTTOM) - - constrainWidth(rightShortcut.id, width) - constrainHeight(rightShortcut.id, height) - connect(rightShortcut.id, RIGHT, PARENT_ID, RIGHT) - connect(rightShortcut.id, BOTTOM, PARENT_ID, BOTTOM) - applyTo(rootView) - } - } - - override fun layoutAmbientIndicationArea(rootView: KeyguardRootView) { - val ambientIndicationContainer = - rootView.findViewById(R.id.ambient_indication_container) ?: return - val lockIconView = rootView.findViewById(R.id.lock_icon_view) ?: return - val indicationArea = rootView.findViewById(R.id.keyguard_indication_area) ?: return - - rootView.getConstraintSet().apply { - constrainWidth(ambientIndicationContainer.id, MATCH_PARENT) - - if (keyguardUpdateMonitor.isUdfpsSupported) { - //constrain below udfps and above indication area - constrainHeight(ambientIndicationContainer.id, MATCH_CONSTRAINT) - connect(ambientIndicationContainer.id, TOP, lockIconView.id, BOTTOM) - connect(ambientIndicationContainer.id, BOTTOM, indicationArea.id, TOP) - connect(ambientIndicationContainer.id, LEFT, PARENT_ID, LEFT) - connect(ambientIndicationContainer.id, RIGHT, PARENT_ID, RIGHT) - } else { - //constrain above lock icon - constrainHeight(ambientIndicationContainer.id, WRAP_CONTENT) - connect(ambientIndicationContainer.id, BOTTOM, lockIconView.id, TOP) - connect(ambientIndicationContainer.id, LEFT, PARENT_ID, LEFT) - connect(ambientIndicationContainer.id, RIGHT, PARENT_ID, RIGHT) - } - - applyTo(rootView) - } - } - - override fun layoutSettingsPopupMenu(rootView: KeyguardRootView) { - val popupMenu = - rootView.findViewById(R.id.keyguard_settings_button) ?: return - val icon = popupMenu.findViewById(R.id.icon) ?: return - val textView = popupMenu.findViewById(R.id.text) ?: return - val horizontalOffsetMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset) - - icon.updateLayoutParams { - height = - context - .resources - .getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_icon_height) - width = - context - .resources - .getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_icon_width) - marginEnd = - context - .resources - .getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_icon_end_margin) - } - - textView.updateLayoutParams { - height = WRAP_CONTENT - width = WRAP_CONTENT - } - - popupMenu.updateLayoutParams { - bottomMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset) - marginStart = horizontalOffsetMargin - marginEnd = horizontalOffsetMargin - } - popupMenu.setPadding( - context.resources.getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_padding) - ) - - rootView.getConstraintSet().apply { - constrainWidth(popupMenu.id, WRAP_CONTENT) - constrainHeight(popupMenu.id, WRAP_CONTENT) - constrainMinHeight( - popupMenu.id, - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height) - ) - connect(popupMenu.id, LEFT, PARENT_ID, LEFT) - connect(popupMenu.id, RIGHT, PARENT_ID, RIGHT) - connect(popupMenu.id, BOTTOM, PARENT_ID, BOTTOM) - - applyTo(rootView) - } - } - - private fun Int.dp(): Int { - return context.resources.getDimensionPixelSize(this) - } - - private fun ConstraintLayout.getConstraintSet(): ConstraintSet = - ConstraintSet().also { - it.clone(this) - } - - companion object { - const val DEFAULT = "default" - } -} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerCommandListener.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt similarity index 63% rename from packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerCommandListener.kt rename to packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt index b351ea8923f63..36d21f1babe22 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerCommandListener.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt @@ -16,17 +16,20 @@ package com.android.systemui.keyguard.ui.view.layout +import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import java.io.PrintWriter import javax.inject.Inject -/** Uses $ adb shell cmd statusbar layout */ -class KeyguardLayoutManagerCommandListener +/** Uses $ adb shell cmd statusbar blueprint */ +class KeyguardBlueprintCommandListener @Inject constructor( private val commandRegistry: CommandRegistry, - private val keyguardLayoutManager: KeyguardLayoutManager + private val keyguardBlueprintRepository: KeyguardBlueprintRepository, + private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor, ) { private val layoutCommand = KeyguardLayoutManagerCommand() @@ -42,22 +45,22 @@ constructor( return } - if (keyguardLayoutManager.transitionToLayout(arg)) { + if (keyguardBlueprintInteractor.transitionToBlueprint(arg)) { pw.println("Transition succeeded!") } else { - pw.println("Invalid argument! To see available layout ids, run:") - pw.println("$ adb shell cmd statusbar layout help") + pw.println("Invalid argument! To see available blueprint ids, run:") + pw.println("$ adb shell cmd statusbar blueprint help") } } override fun help(pw: PrintWriter) { - pw.println("Usage: $ adb shell cmd statusbar layout ") - pw.println("Existing Layout Ids: ") - keyguardLayoutManager.layoutIdMap.forEach { entry -> pw.println("${entry.key}") } + pw.println("Usage: $ adb shell cmd statusbar blueprint ") + pw.println("Existing Blueprint Ids: ") + keyguardBlueprintRepository.printBlueprints(pw) } } companion object { - internal const val COMMAND = "layout" + internal const val COMMAND = "blueprint" } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManager.kt deleted file mode 100644 index 6973cd914aade..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManager.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2023 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.keyguard.ui.view.layout - -import android.content.res.Configuration -import androidx.constraintlayout.widget.ConstraintSet -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.ui.view.KeyguardRootView -import com.android.systemui.keyguard.ui.view.layout.DefaultLockscreenLayout.Companion.DEFAULT -import com.android.systemui.statusbar.policy.ConfigurationController -import javax.inject.Inject - -/** - * Manages layout changes for the lockscreen. - * - * To add a layout, add an entry to the map with a unique id and call #transitionToLayout(string). - */ -@SysUISingleton -class KeyguardLayoutManager -@Inject -constructor( - configurationController: ConfigurationController, - layouts: Set<@JvmSuppressWildcards LockscreenLayout>, - private val keyguardRootView: KeyguardRootView, -) { - internal val layoutIdMap: Map = layouts.associateBy { it.id } - private var layout: LockscreenLayout? = layoutIdMap[DEFAULT] - - init { - configurationController.addCallback( - object : ConfigurationController.ConfigurationListener { - override fun onConfigChanged(newConfig: Configuration?) { - layoutViews() - } - } - ) - } - - /** - * Transitions to a layout. - * - * @param layoutId - * @return whether the transition has succeeded. - */ - fun transitionToLayout(layoutId: String): Boolean { - layout = layoutIdMap[layoutId] ?: return false - layoutViews() - return true - } - - fun layoutViews(rootView: KeyguardRootView = keyguardRootView) { - layout?.layoutViews(rootView) - } - - companion object { - const val TAG = "KeyguardLayoutManager" - } -} - -interface LockscreenLayout { - val id: String - - fun layoutViews(rootView: KeyguardRootView) { - // Clear constraints. - ConstraintSet() - .apply { - clone(rootView) - knownIds.forEach { getConstraint(it).layout.copyFrom(ConstraintSet.Layout()) } - } - .applyTo(rootView) - layoutIndicationArea(rootView) - layoutLockIcon(rootView) - layoutShortcuts(rootView) - layoutAmbientIndicationArea(rootView) - layoutSettingsPopupMenu(rootView) - } - fun layoutIndicationArea(rootView: KeyguardRootView) - fun layoutLockIcon(rootView: KeyguardRootView) - fun layoutShortcuts(rootView: KeyguardRootView) - fun layoutAmbientIndicationArea(rootView: KeyguardRootView) - fun layoutSettingsPopupMenu(rootView: KeyguardRootView) -} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/ShortcutsBesideUdfpsLockscreenLayout.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/ShortcutsBesideUdfpsLockscreenLayout.kt deleted file mode 100644 index 569762d67c5fd..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/ShortcutsBesideUdfpsLockscreenLayout.kt +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2023 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.keyguard.ui.view.layout - -import android.content.Context -import android.graphics.Point -import android.graphics.Rect -import android.util.DisplayMetrics -import android.view.View -import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.view.ViewGroup.LayoutParams.WRAP_CONTENT -import android.view.WindowManager -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView -import androidx.annotation.VisibleForTesting -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.constraintlayout.widget.ConstraintSet -import androidx.constraintlayout.widget.ConstraintSet.BOTTOM -import androidx.constraintlayout.widget.ConstraintSet.END -import androidx.constraintlayout.widget.ConstraintSet.LEFT -import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT -import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID -import androidx.constraintlayout.widget.ConstraintSet.RIGHT -import androidx.constraintlayout.widget.ConstraintSet.START -import androidx.constraintlayout.widget.ConstraintSet.TOP -import androidx.core.view.setPadding -import androidx.core.view.updateLayoutParams -import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.R -import com.android.systemui.animation.view.LaunchableLinearLayout -import com.android.systemui.biometrics.AuthController -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.ui.view.KeyguardRootView -import javax.inject.Inject - -/** - * Positions elements of the lockscreen to the default position. - * - * This will be the most common use case for phones in portrait mode. - */ -@SysUISingleton -class ShortcutsBesideUdfpsLockscreenLayout -@Inject -constructor( - private val authController: AuthController, - private val keyguardUpdateMonitor: KeyguardUpdateMonitor, - private val windowManager: WindowManager, - private val context: Context, -) : LockscreenLayout { - override val id: String = SHORTCUTS_BESIDE_UDFPS - - override fun layoutIndicationArea(rootView: KeyguardRootView) { - val indicationArea = rootView.findViewById(R.id.keyguard_indication_area) ?: return - - rootView.getConstraintSet().apply { - constrainWidth(indicationArea.id, MATCH_PARENT) - constrainHeight(indicationArea.id, WRAP_CONTENT) - connect( - indicationArea.id, - BOTTOM, - PARENT_ID, - BOTTOM, - R.dimen.keyguard_indication_margin_bottom.dp() - ) - connect(indicationArea.id, START, PARENT_ID, START) - connect(indicationArea.id, END, PARENT_ID, END) - applyTo(rootView) - } - } - - override fun layoutLockIcon(rootView: KeyguardRootView) { - val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported - val scaleFactor: Float = authController.scaleFactor - val mBottomPaddingPx = R.dimen.lock_icon_margin_bottom.dp() - val mDefaultPaddingPx = R.dimen.lock_icon_padding.dp() - val scaledPadding: Int = (mDefaultPaddingPx * scaleFactor).toInt() - val bounds = windowManager.currentWindowMetrics.bounds - val widthPixels = bounds.right.toFloat() - val heightPixels = bounds.bottom.toFloat() - val defaultDensity = - DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() / - DisplayMetrics.DENSITY_DEFAULT.toFloat() - val lockIconRadiusPx = (defaultDensity * 36).toInt() - - if (isUdfpsSupported) { - authController.udfpsLocation?.let { udfpsLocation -> - centerLockIcon(udfpsLocation, authController.udfpsRadius, scaledPadding, rootView) - } - } else { - centerLockIcon( - Point( - (widthPixels / 2).toInt(), - (heightPixels - ((mBottomPaddingPx + lockIconRadiusPx) * scaleFactor)).toInt() - ), - lockIconRadiusPx * scaleFactor, - scaledPadding, - rootView - ) - } - } - - @VisibleForTesting - internal fun centerLockIcon( - center: Point, - radius: Float, - drawablePadding: Int, - rootView: KeyguardRootView, - ) { - val lockIconView = rootView.findViewById(R.id.lock_icon_view) ?: return - val lockIcon = lockIconView.findViewById(R.id.lock_icon) ?: return - lockIcon.setPadding(drawablePadding, drawablePadding, drawablePadding, drawablePadding) - - val sensorRect = - Rect().apply { - set( - center.x - radius.toInt(), - center.y - radius.toInt(), - center.x + radius.toInt(), - center.y + radius.toInt(), - ) - } - - rootView.getConstraintSet().apply { - constrainWidth(lockIconView.id, sensorRect.right - sensorRect.left) - constrainHeight(lockIconView.id, sensorRect.bottom - sensorRect.top) - connect(lockIconView.id, TOP, PARENT_ID, TOP, sensorRect.top) - connect(lockIconView.id, START, PARENT_ID, START, sensorRect.left) - applyTo(rootView) - } - } - - override fun layoutShortcuts(rootView: KeyguardRootView) { - val leftShortcut = rootView.findViewById(R.id.start_button) ?: return - val rightShortcut = rootView.findViewById(R.id.end_button) ?: return - val lockIconView = rootView.findViewById(R.id.lock_icon_view) ?: return - val udfpsSupported = keyguardUpdateMonitor.isUdfpsSupported - val width = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width) - val height = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height) - val horizontalOffsetMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset) - val verticalOffsetMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset) - val padding = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_padding) - - if (!udfpsSupported) { - leftShortcut.apply { - updateLayoutParams { - marginStart = horizontalOffsetMargin - bottomMargin = verticalOffsetMargin - } - setPadding(padding) - } - - rightShortcut.apply { - updateLayoutParams { - marginEnd = horizontalOffsetMargin - bottomMargin = verticalOffsetMargin - } - setPadding(padding) - } - } - - rootView.getConstraintSet().apply { - if (udfpsSupported) { - constrainWidth(leftShortcut.id, width) - constrainHeight(leftShortcut.id, height) - connect(leftShortcut.id, LEFT, PARENT_ID, LEFT) - connect(leftShortcut.id, RIGHT, lockIconView.id, LEFT) - connect(leftShortcut.id, TOP, lockIconView.id, TOP) - connect(leftShortcut.id, BOTTOM, lockIconView.id, BOTTOM) - - constrainWidth(rightShortcut.id, width) - constrainHeight(rightShortcut.id, height) - connect(rightShortcut.id, RIGHT, PARENT_ID, RIGHT) - connect(rightShortcut.id, LEFT, lockIconView.id, RIGHT) - connect(rightShortcut.id, TOP, lockIconView.id, TOP) - connect(rightShortcut.id, BOTTOM, lockIconView.id, BOTTOM) - } else { - constrainWidth(leftShortcut.id, width) - constrainHeight(leftShortcut.id, height) - connect(leftShortcut.id, LEFT, PARENT_ID, LEFT) - connect(leftShortcut.id, BOTTOM, PARENT_ID, BOTTOM) - - constrainWidth(rightShortcut.id, width) - constrainHeight(rightShortcut.id, height) - connect(rightShortcut.id, RIGHT, PARENT_ID, RIGHT) - connect(rightShortcut.id, BOTTOM, PARENT_ID, BOTTOM) - } - applyTo(rootView) - } - } - - override fun layoutAmbientIndicationArea(rootView: KeyguardRootView) { - val ambientIndicationContainer = - rootView.findViewById(R.id.ambient_indication_container) ?: return - val lockIconView = rootView.findViewById(R.id.lock_icon_view) ?: return - val indicationArea = rootView.findViewById(R.id.keyguard_indication_area) ?: return - - rootView.getConstraintSet().apply { - constrainWidth(ambientIndicationContainer.id, MATCH_PARENT) - - if (keyguardUpdateMonitor.isUdfpsSupported) { - //constrain below udfps and above indication area - constrainHeight(ambientIndicationContainer.id, MATCH_CONSTRAINT) - connect(ambientIndicationContainer.id, TOP, lockIconView.id, BOTTOM) - connect(ambientIndicationContainer.id, BOTTOM, indicationArea.id, TOP) - connect(ambientIndicationContainer.id, LEFT, PARENT_ID, LEFT) - connect(ambientIndicationContainer.id, RIGHT, PARENT_ID, RIGHT) - } else { - //constrain above lock icon - constrainHeight(ambientIndicationContainer.id, WRAP_CONTENT) - connect(ambientIndicationContainer.id, BOTTOM, lockIconView.id, TOP) - connect(ambientIndicationContainer.id, LEFT, PARENT_ID, LEFT) - connect(ambientIndicationContainer.id, RIGHT, PARENT_ID, RIGHT) - } - applyTo(rootView) - } - } - - override fun layoutSettingsPopupMenu(rootView: KeyguardRootView) { - val popupMenu = - rootView.findViewById(R.id.keyguard_settings_button) ?: return - val icon = popupMenu.findViewById(R.id.icon) ?: return - val textView = popupMenu.findViewById(R.id.text) ?: return - val horizontalOffsetMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset) - - icon.updateLayoutParams { - height = - context - .resources - .getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_icon_height) - width = - context - .resources - .getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_icon_width) - marginEnd = - context - .resources - .getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_icon_end_margin) - } - - textView.updateLayoutParams { - height = WRAP_CONTENT - width = WRAP_CONTENT - } - - popupMenu.updateLayoutParams { - bottomMargin = - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset) - marginStart = horizontalOffsetMargin - marginEnd = horizontalOffsetMargin - } - popupMenu.setPadding( - context.resources.getDimensionPixelSize(R.dimen.keyguard_settings_popup_menu_padding) - ) - - rootView.getConstraintSet().apply { - constrainWidth(popupMenu.id, WRAP_CONTENT) - constrainHeight(popupMenu.id, WRAP_CONTENT) - constrainMinHeight( - popupMenu.id, - context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height) - ) - connect(popupMenu.id, LEFT, PARENT_ID, LEFT) - connect(popupMenu.id, RIGHT, PARENT_ID, RIGHT) - connect(popupMenu.id, BOTTOM, PARENT_ID, BOTTOM) - - applyTo(rootView) - } - } - - private fun Int.dp(): Int { - return context.resources.getDimensionPixelSize(this) - } - - private fun ConstraintLayout.getConstraintSet(): ConstraintSet = - ConstraintSet().also { - it.clone(this) - } - - companion object { - const val SHORTCUTS_BESIDE_UDFPS = "shortcutsBesideUdfps" - } -} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt new file mode 100644 index 0000000000000..5538fe7e70068 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.blueprints + +import androidx.constraintlayout.widget.ConstraintSet +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.data.repository.KeyguardBlueprint +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection +import javax.inject.Inject + +/** + * Positions elements of the lockscreen to the default position. + * + * This will be the most common use case for phones in portrait mode. + */ +@SysUISingleton +@JvmSuppressWildcards +class DefaultKeyguardBlueprint +@Inject +constructor( + private val defaultIndicationAreaSection: DefaultIndicationAreaSection, + private val defaultLockIconSection: DefaultLockIconSection, + private val defaultShortcutsSection: DefaultShortcutsSection, + private val defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection, + private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection, +) : KeyguardBlueprint { + override val id: String = DEFAULT + + override fun apply(constraintSet: ConstraintSet) { + defaultIndicationAreaSection.apply(constraintSet) + defaultLockIconSection.apply(constraintSet) + defaultShortcutsSection.apply(constraintSet) + defaultAmbientIndicationAreaSection.apply(constraintSet) + defaultSettingsPopupMenuSection.apply(constraintSet) + } + + companion object { + const val DEFAULT = "default" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/LockscreenLayoutModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt similarity index 61% rename from packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/LockscreenLayoutModule.kt rename to packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt index c0447af0590da..fefe6792036f6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/LockscreenLayoutModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt @@ -15,23 +15,24 @@ * */ -package com.android.systemui.keyguard.ui.view.layout +package com.android.systemui.keyguard.ui.view.layout.blueprints +import com.android.systemui.keyguard.data.repository.KeyguardBlueprint import dagger.Binds import dagger.Module import dagger.multibindings.IntoSet @Module -abstract class LockscreenLayoutModule { +abstract class KeyguardBlueprintModule { @Binds @IntoSet - abstract fun bindDefaultLayout( - defaultLockscreenLayout: DefaultLockscreenLayout - ): LockscreenLayout + abstract fun bindDefaultBlueprint( + defaultLockscreenBlueprint: DefaultKeyguardBlueprint + ): KeyguardBlueprint @Binds @IntoSet - abstract fun bindShortcutsBesideUdfpsLockscreenLayout( - shortcutsBesideUdfpsLockscreenLayout: ShortcutsBesideUdfpsLockscreenLayout - ): LockscreenLayout + abstract fun bindShortcutsBesideUdfpsLockscreenBlueprint( + shortcutsBesideUdfpsLockscreenBlueprint: ShortcutsBesideUdfpsKeyguardBlueprint + ): KeyguardBlueprint } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt new file mode 100644 index 0000000000000..19410e4ba89d0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.blueprints + +import androidx.constraintlayout.widget.ConstraintSet +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.data.repository.KeyguardBlueprint +import com.android.systemui.keyguard.ui.view.layout.sections.AlignShortcutsToUdfpsSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection +import javax.inject.Inject + +/** Vertically aligns the shortcuts with the udfps. */ +@SysUISingleton +class ShortcutsBesideUdfpsKeyguardBlueprint +@Inject +constructor( + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val defaultIndicationAreaSection: DefaultIndicationAreaSection, + private val defaultLockIconSection: DefaultLockIconSection, + private val defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection, + private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection, + private val alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection, + private val defaultShortcutsSection: DefaultShortcutsSection, +) : KeyguardBlueprint { + override val id: String = SHORTCUTS_BESIDE_UDFPS + + override fun apply(constraintSet: ConstraintSet) { + defaultIndicationAreaSection.apply(constraintSet) + defaultLockIconSection.apply(constraintSet) + defaultAmbientIndicationAreaSection.apply(constraintSet) + defaultSettingsPopupMenuSection.apply(constraintSet) + if (keyguardUpdateMonitor.isUdfpsSupported) { + alignShortcutsToUdfpsSection.apply(constraintSet) + } else { + defaultShortcutsSection.apply(constraintSet) + } + } + + companion object { + const val SHORTCUTS_BESIDE_UDFPS = "shortcutsBesideUdfps" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt new file mode 100644 index 0000000000000..156b9f3e5f485 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.sections + +import android.content.res.Resources +import androidx.constraintlayout.widget.ConstraintSet +import androidx.constraintlayout.widget.ConstraintSet.BOTTOM +import androidx.constraintlayout.widget.ConstraintSet.LEFT +import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID +import androidx.constraintlayout.widget.ConstraintSet.RIGHT +import androidx.constraintlayout.widget.ConstraintSet.TOP +import com.android.systemui.R +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.data.repository.KeyguardSection +import javax.inject.Inject + +class AlignShortcutsToUdfpsSection @Inject constructor(@Main private val resources: Resources) : + KeyguardSection { + override fun apply(constraintSet: ConstraintSet) { + val width = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width) + val height = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height) + + constraintSet.apply { + constrainWidth(R.id.start_button, width) + constrainHeight(R.id.start_button, height) + connect(R.id.start_button, LEFT, PARENT_ID, LEFT) + connect(R.id.start_button, RIGHT, R.id.lock_icon_view, LEFT) + connect(R.id.start_button, TOP, R.id.lock_icon_view, TOP) + connect(R.id.start_button, BOTTOM, R.id.lock_icon_view, BOTTOM) + + constrainWidth(R.id.end_button, width) + constrainHeight(R.id.end_button, height) + connect(R.id.end_button, RIGHT, PARENT_ID, RIGHT) + connect(R.id.end_button, LEFT, R.id.lock_icon_view, RIGHT) + connect(R.id.end_button, TOP, R.id.lock_icon_view, TOP) + connect(R.id.end_button, BOTTOM, R.id.lock_icon_view, BOTTOM) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt new file mode 100644 index 0000000000000..abf25a23439f1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.sections + +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import androidx.constraintlayout.widget.ConstraintSet +import androidx.constraintlayout.widget.ConstraintSet.BOTTOM +import androidx.constraintlayout.widget.ConstraintSet.END +import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT +import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID +import androidx.constraintlayout.widget.ConstraintSet.START +import androidx.constraintlayout.widget.ConstraintSet.TOP +import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.R +import com.android.systemui.keyguard.data.repository.KeyguardSection +import javax.inject.Inject + +class DefaultAmbientIndicationAreaSection +@Inject +constructor(private val keyguardUpdateMonitor: KeyguardUpdateMonitor) : KeyguardSection { + override fun apply(constraintSet: ConstraintSet) { + constraintSet.apply { + constrainWidth(R.id.ambient_indication_container, MATCH_PARENT) + + if (keyguardUpdateMonitor.isUdfpsSupported) { + // constrain below udfps and above indication area + constrainHeight(R.id.ambient_indication_container, MATCH_CONSTRAINT) + connect(R.id.ambient_indication_container, TOP, R.id.lock_icon_view, BOTTOM) + connect( + R.id.ambient_indication_container, + BOTTOM, + R.id.keyguard_indication_area, + TOP + ) + connect(R.id.ambient_indication_container, START, PARENT_ID, START) + connect(R.id.ambient_indication_container, END, PARENT_ID, END) + } else { + // constrain above lock icon + constrainHeight(R.id.ambient_indication_container, WRAP_CONTENT) + connect(R.id.ambient_indication_container, BOTTOM, R.id.lock_icon_view, TOP) + connect(R.id.ambient_indication_container, START, PARENT_ID, START) + connect(R.id.ambient_indication_container, END, PARENT_ID, END) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt new file mode 100644 index 0000000000000..dee7ed570b05f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.sections + +import android.content.Context +import android.view.ViewGroup +import androidx.constraintlayout.widget.ConstraintSet +import com.android.systemui.R +import com.android.systemui.keyguard.data.repository.KeyguardSection +import javax.inject.Inject + +class DefaultIndicationAreaSection @Inject constructor(private val context: Context) : + KeyguardSection { + private val indicationAreaViewId = R.id.keyguard_indication_area + + override fun apply(constraintSet: ConstraintSet) { + constraintSet.apply { + constrainWidth(indicationAreaViewId, ViewGroup.LayoutParams.MATCH_PARENT) + constrainHeight(indicationAreaViewId, ViewGroup.LayoutParams.WRAP_CONTENT) + connect( + indicationAreaViewId, + ConstraintSet.BOTTOM, + ConstraintSet.PARENT_ID, + ConstraintSet.BOTTOM, + context.resources.getDimensionPixelSize(R.dimen.keyguard_indication_margin_bottom) + ) + connect( + indicationAreaViewId, + ConstraintSet.START, + ConstraintSet.PARENT_ID, + ConstraintSet.START + ) + connect( + indicationAreaViewId, + ConstraintSet.END, + ConstraintSet.PARENT_ID, + ConstraintSet.END + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt new file mode 100644 index 0000000000000..461faec217ca7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.sections + +import android.content.Context +import android.graphics.Point +import android.graphics.Rect +import android.util.DisplayMetrics +import android.view.WindowManager +import androidx.annotation.VisibleForTesting +import androidx.constraintlayout.widget.ConstraintSet +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.R +import com.android.systemui.biometrics.AuthController +import com.android.systemui.keyguard.data.repository.KeyguardSection +import javax.inject.Inject + +class DefaultLockIconSection +@Inject +constructor( + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val authController: AuthController, + private val windowManager: WindowManager, + private val context: Context, +) : KeyguardSection { + private val lockIconViewId = R.id.lock_icon_view + + override fun apply(constraintSet: ConstraintSet) { + val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported + val scaleFactor: Float = authController.scaleFactor + val mBottomPaddingPx = + context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom) + val mDefaultPaddingPx = context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding) + val scaledPadding: Int = (mDefaultPaddingPx * scaleFactor).toInt() + val bounds = windowManager.currentWindowMetrics.bounds + val widthPixels = bounds.right.toFloat() + val heightPixels = bounds.bottom.toFloat() + val defaultDensity = + DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() / + DisplayMetrics.DENSITY_DEFAULT.toFloat() + val lockIconRadiusPx = (defaultDensity * 36).toInt() + + if (isUdfpsSupported) { + authController.udfpsLocation?.let { udfpsLocation -> + centerLockIcon( + udfpsLocation, + authController.udfpsRadius, + scaledPadding, + constraintSet + ) + } + } else { + centerLockIcon( + Point( + (widthPixels / 2).toInt(), + (heightPixels - ((mBottomPaddingPx + lockIconRadiusPx) * scaleFactor)).toInt() + ), + lockIconRadiusPx * scaleFactor, + scaledPadding, + constraintSet, + ) + } + } + + @VisibleForTesting + internal fun centerLockIcon( + center: Point, + radius: Float, + drawablePadding: Int, + constraintSet: ConstraintSet + ) { + val sensorRect = + Rect().apply { + set( + center.x - radius.toInt(), + center.y - radius.toInt(), + center.x + radius.toInt(), + center.y + radius.toInt(), + ) + } + + constraintSet.apply { + constrainWidth(lockIconViewId, sensorRect.right - sensorRect.left) + constrainHeight(lockIconViewId, sensorRect.bottom - sensorRect.top) + connect( + lockIconViewId, + ConstraintSet.TOP, + ConstraintSet.PARENT_ID, + ConstraintSet.TOP, + sensorRect.top + ) + connect( + lockIconViewId, + ConstraintSet.START, + ConstraintSet.PARENT_ID, + ConstraintSet.START, + sensorRect.left + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt new file mode 100644 index 0000000000000..ad1e4f8b98b43 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.sections + +import android.content.res.Resources +import androidx.constraintlayout.widget.ConstraintSet +import androidx.constraintlayout.widget.ConstraintSet.BOTTOM +import androidx.constraintlayout.widget.ConstraintSet.END +import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID +import androidx.constraintlayout.widget.ConstraintSet.START +import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT +import com.android.systemui.R +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.data.repository.KeyguardSection +import javax.inject.Inject + +class DefaultSettingsPopupMenuSection @Inject constructor(@Main private val resources: Resources) : + KeyguardSection { + override fun apply(constraintSet: ConstraintSet) { + val horizontalOffsetMargin = + resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset) + + constraintSet.apply { + constrainWidth(R.id.keyguard_settings_button, WRAP_CONTENT) + constrainHeight(R.id.keyguard_settings_button, WRAP_CONTENT) + constrainMinHeight( + R.id.keyguard_settings_button, + resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height) + ) + connect(R.id.keyguard_settings_button, START, PARENT_ID, START, horizontalOffsetMargin) + connect(R.id.keyguard_settings_button, END, PARENT_ID, END, horizontalOffsetMargin) + connect( + R.id.keyguard_settings_button, + BOTTOM, + PARENT_ID, + BOTTOM, + resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset) + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt new file mode 100644 index 0000000000000..db4653defd34e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.sections + +import android.content.res.Resources +import androidx.constraintlayout.widget.ConstraintSet +import androidx.constraintlayout.widget.ConstraintSet.BOTTOM +import androidx.constraintlayout.widget.ConstraintSet.LEFT +import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID +import androidx.constraintlayout.widget.ConstraintSet.RIGHT +import com.android.systemui.R +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.data.repository.KeyguardSection +import javax.inject.Inject + +class DefaultShortcutsSection @Inject constructor(@Main private val resources: Resources) : + KeyguardSection { + override fun apply(constraintSet: ConstraintSet) { + val width = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width) + val height = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height) + val horizontalOffsetMargin = + resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset) + val verticalOffsetMargin = + resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset) + + constraintSet.apply { + constrainWidth(R.id.start_button, width) + constrainHeight(R.id.start_button, height) + connect(R.id.start_button, LEFT, PARENT_ID, LEFT, horizontalOffsetMargin) + connect(R.id.start_button, BOTTOM, PARENT_ID, BOTTOM, verticalOffsetMargin) + + constrainWidth(R.id.end_button, width) + constrainHeight(R.id.end_button, height) + connect(R.id.end_button, RIGHT, PARENT_ID, RIGHT, horizontalOffsetMargin) + connect(R.id.end_button, BOTTOM, PARENT_ID, BOTTOM, verticalOffsetMargin) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt new file mode 100644 index 0000000000000..5e9e553616dca --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor +import javax.inject.Inject + +@SysUISingleton +class KeyguardBlueprintViewModel +@Inject +constructor(keyguardBlueprintInteractor: KeyguardBlueprintInteractor) { + val blueprint = keyguardBlueprintInteractor.blueprint +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt new file mode 100644 index 0000000000000..66ead14d3d4c4 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2023 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.keyguard.data.repository + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.ConfigurationRepository +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint +import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@RunWith(JUnit4::class) +@SmallTest +class KeyguardBlueprintRepositoryTest : SysuiTestCase() { + private lateinit var underTest: KeyguardBlueprintRepository + @Mock lateinit var configurationRepository: ConfigurationRepository + @Mock lateinit var defaultLockscreenBlueprint: DefaultKeyguardBlueprint + private val testDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testDispatcher) + private val configurationFlow = MutableSharedFlow(extraBufferCapacity = 1) + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + whenever(defaultLockscreenBlueprint.id).thenReturn(DEFAULT) + whenever(configurationRepository.onAnyConfigurationChange).thenReturn(configurationFlow) + underTest = + KeyguardBlueprintRepository( + configurationRepository, + setOf(defaultLockscreenBlueprint), + testScope.backgroundScope, + ) + } + + @Test + fun testApplyBlueprint_DefaultLayout() { + testScope.runTest { + val blueprint by collectLastValue(underTest.blueprint) + runCurrent() + underTest.applyBlueprint(defaultLockscreenBlueprint) + runCurrent() + assertThat(blueprint).isEqualTo(defaultLockscreenBlueprint) + } + } + + @Test + fun testConfigurationChange() { + testScope.runTest { + val blueprint by collectLastValue(underTest.blueprint) + runCurrent() + configurationFlow.tryEmit(Unit) + runCurrent() + assertThat(blueprint).isEqualTo(defaultLockscreenBlueprint) + } + } + + @Test + fun testRefreshBlueprint() { + testScope.runTest { + val blueprint by collectLastValue(underTest.blueprint) + runCurrent() + underTest.refreshBlueprint() + runCurrent() + assertThat(blueprint).isEqualTo(defaultLockscreenBlueprint) + } + } + + @Test + fun testTransitionToLayout_validId() { + assertThat(underTest.applyBlueprint(DEFAULT)).isTrue() + } + @Test + fun testTransitionToLayout_invalidId() { + assertThat(underTest.applyBlueprint("abc")).isFalse() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt new file mode 100644 index 0000000000000..b8a2e9d4afc75 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023 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.keyguard.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class KeyguardBlueprintInteractorTest : SysuiTestCase() { + private lateinit var underTest: KeyguardBlueprintInteractor + + @Mock private lateinit var keyguardBlueprintRepository: KeyguardBlueprintRepository + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + underTest = KeyguardBlueprintInteractor(keyguardBlueprintRepository) + } + + @Test + fun testRefreshBlueprint() { + underTest.refreshBlueprint() + verify(keyguardBlueprintRepository).refreshBlueprint() + } + + @Test + fun testTransitionToBlueprint() { + underTest.transitionToBlueprint("abc") + verify(keyguardBlueprintRepository).applyBlueprint("abc") + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerCommandListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt similarity index 66% rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerCommandListenerTest.kt rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt index 145b2fdb000f4..bb73dc699d37f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerCommandListenerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt @@ -18,10 +18,11 @@ package com.android.systemui.keyguard.ui.view.layout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import java.io.PrintWriter import org.junit.Before @@ -31,32 +32,33 @@ import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito.atLeastOnce -import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @RunWith(JUnit4::class) @SmallTest -class KeyguardLayoutManagerCommandListenerTest : SysuiTestCase() { - private lateinit var keyguardLayoutManagerCommandListener: KeyguardLayoutManagerCommandListener +class KeyguardBlueprintCommandListenerTest : SysuiTestCase() { + private lateinit var keyguardBlueprintCommandListener: KeyguardBlueprintCommandListener @Mock private lateinit var commandRegistry: CommandRegistry - @Mock private lateinit var keyguardLayoutManager: KeyguardLayoutManager + @Mock private lateinit var keyguardBlueprintRepository: KeyguardBlueprintRepository + @Mock private lateinit var keyguardBlueprintInteractor: KeyguardBlueprintInteractor @Mock private lateinit var pw: PrintWriter private lateinit var command: () -> Command @Before fun setup() { MockitoAnnotations.initMocks(this) - keyguardLayoutManagerCommandListener = - KeyguardLayoutManagerCommandListener( + keyguardBlueprintCommandListener = + KeyguardBlueprintCommandListener( commandRegistry, - keyguardLayoutManager, + keyguardBlueprintRepository, + keyguardBlueprintInteractor, ) - keyguardLayoutManagerCommandListener.start() + keyguardBlueprintCommandListener.start() command = withArgCaptor<() -> Command> { - verify(commandRegistry).registerCommand(eq("layout"), capture()) + verify(commandRegistry).registerCommand(eq("blueprint"), capture()) } } @@ -64,25 +66,19 @@ class KeyguardLayoutManagerCommandListenerTest : SysuiTestCase() { fun testHelp() { command().execute(pw, listOf("help")) verify(pw, atLeastOnce()).println(anyString()) - verify(keyguardLayoutManager, never()).transitionToLayout(anyString()) + verify(keyguardBlueprintInteractor, never()).transitionToBlueprint(anyString()) } @Test fun testBlank() { command().execute(pw, listOf()) verify(pw, atLeastOnce()).println(anyString()) - verify(keyguardLayoutManager, never()).transitionToLayout(anyString()) + verify(keyguardBlueprintInteractor, never()).transitionToBlueprint(anyString()) } @Test fun testValidArg() { - bindFakeIdMapToLayoutManager() command().execute(pw, listOf("fake")) - verify(keyguardLayoutManager).transitionToLayout("fake") - } - - private fun bindFakeIdMapToLayoutManager() { - val map = mapOf("fake" to mock(LockscreenLayout::class.java)) - whenever(keyguardLayoutManager.layoutIdMap).thenReturn(map) + verify(keyguardBlueprintInteractor).transitionToBlueprint("fake") } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerTest.kt deleted file mode 100644 index 95b2030de923c..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardLayoutManagerTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2023 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.keyguard.ui.view.layout - -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.keyguard.ui.view.KeyguardRootView -import com.android.systemui.keyguard.ui.view.layout.DefaultLockscreenLayout.Companion.DEFAULT -import com.android.systemui.statusbar.policy.ConfigurationController -import com.android.systemui.util.mockito.whenever -import com.google.common.truth.Truth.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 -import org.mockito.Mock -import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations - -@RunWith(JUnit4::class) -@SmallTest -class KeyguardLayoutManagerTest : SysuiTestCase() { - private lateinit var keyguardLayoutManager: KeyguardLayoutManager - @Mock lateinit var configurationController: ConfigurationController - @Mock lateinit var defaultLockscreenLayout: DefaultLockscreenLayout - @Mock lateinit var keyguardRootView: KeyguardRootView - - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - whenever(defaultLockscreenLayout.id).thenReturn(DEFAULT) - keyguardLayoutManager = - KeyguardLayoutManager( - configurationController, - setOf(defaultLockscreenLayout), - keyguardRootView - ) - } - - @Test - fun testDefaultLayout() { - keyguardLayoutManager.transitionToLayout(DEFAULT) - verify(defaultLockscreenLayout).layoutViews(keyguardRootView) - } - - @Test - fun testTransitionToLayout_validId() { - assertThat(keyguardLayoutManager.transitionToLayout(DEFAULT)).isTrue() - } - @Test - fun testTransitionToLayout_invalidId() { - assertThat(keyguardLayoutManager.transitionToLayout("abc")).isFalse() - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt new file mode 100644 index 0000000000000..66631dc9977ba --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.blueprints + +import androidx.constraintlayout.widget.ConstraintSet +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.ui.view.KeyguardRootView +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection +import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(JUnit4::class) +@SmallTest +class DefaultKeyguardBlueprintTest : SysuiTestCase() { + private lateinit var underTest: DefaultKeyguardBlueprint + private lateinit var rootView: KeyguardRootView + @Mock private lateinit var defaultIndicationAreaSection: DefaultIndicationAreaSection + @Mock private lateinit var defaultLockIconSection: DefaultLockIconSection + @Mock private lateinit var defaultShortcutsSection: DefaultShortcutsSection + @Mock + private lateinit var defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection + @Mock private lateinit var defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + rootView = KeyguardRootView(context, null) + underTest = + DefaultKeyguardBlueprint( + defaultIndicationAreaSection, + defaultLockIconSection, + defaultShortcutsSection, + defaultAmbientIndicationAreaSection, + defaultSettingsPopupMenuSection, + ) + } + + @Test + fun apply() { + val cs = ConstraintSet() + underTest.apply(cs) + verify(defaultIndicationAreaSection).apply(cs) + verify(defaultLockIconSection).apply(cs) + verify(defaultShortcutsSection).apply(cs) + verify(defaultAmbientIndicationAreaSection).apply(cs) + verify(defaultSettingsPopupMenuSection).apply(cs) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt new file mode 100644 index 0000000000000..3dcc03d61fd7b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.view.layout.sections + +import android.view.ViewGroup +import androidx.constraintlayout.widget.ConstraintSet +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +@SmallTest +class DefaultIndicationAreaSectionTest : SysuiTestCase() { + private val underTest = DefaultIndicationAreaSection(context) + + @Test + fun apply() { + val cs = ConstraintSet() + underTest.apply(cs) + + val constraint = cs.getConstraint(R.id.keyguard_indication_area) + + assertThat(constraint.layout.bottomToBottom).isEqualTo(ConstraintSet.PARENT_ID) + assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID) + assertThat(constraint.layout.endToEnd).isEqualTo(ConstraintSet.PARENT_ID) + assertThat(constraint.layout.mWidth).isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT) + assertThat(constraint.layout.mHeight).isEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/DefaultLockscreenLayoutTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt similarity index 54% rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/DefaultLockscreenLayoutTest.kt rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt index c771356a741e0..1444f8df4e4cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/DefaultLockscreenLayoutTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt @@ -15,10 +15,9 @@ * */ -package com.android.systemui.keyguard.ui.view.layout +package com.android.systemui.keyguard.ui.view.layout.sections import android.graphics.Point -import android.view.ViewGroup import android.view.WindowManager import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest @@ -26,9 +25,6 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.AuthController -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.KeyguardRepository -import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -40,45 +36,36 @@ import org.mockito.MockitoAnnotations @RunWith(JUnit4::class) @SmallTest -class DefaultLockscreenLayoutTest : SysuiTestCase() { - private lateinit var defaultLockscreenLayout: DefaultLockscreenLayout - private lateinit var rootView: KeyguardRootView +class DefaultLockIconSectionTest : SysuiTestCase() { + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var authController: AuthController @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager - - @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + private lateinit var underTest: DefaultLockIconSection @Before fun setup() { MockitoAnnotations.initMocks(this) - rootView = KeyguardRootView(context, null) - defaultLockscreenLayout = - DefaultLockscreenLayout(authController, keyguardUpdateMonitor, windowManager, context) + underTest = + DefaultLockIconSection(keyguardUpdateMonitor, authController, windowManager, context) } @Test - fun testLayoutViews_KeyguardIndicationArea() { - defaultLockscreenLayout.layoutViews(rootView) - val constraint = getViewConstraint(R.id.keyguard_indication_area) - assertThat(constraint.layout.bottomToBottom).isEqualTo(ConstraintSet.PARENT_ID) - assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID) - assertThat(constraint.layout.endToEnd).isEqualTo(ConstraintSet.PARENT_ID) - assertThat(constraint.layout.mWidth).isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT) - assertThat(constraint.layout.mHeight).isEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT) - } + fun apply() { + val cs = ConstraintSet() + underTest.apply(cs) + + val constraint = cs.getConstraint(R.id.lock_icon_view) - @Test - fun testLayoutViews_lockIconView() { - defaultLockscreenLayout.layoutViews(rootView) - val constraint = getViewConstraint(R.id.lock_icon_view) assertThat(constraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID) assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID) } @Test fun testCenterLockIcon() { - defaultLockscreenLayout.centerLockIcon(Point(5, 6), 1F, 5, rootView) - val constraint = getViewConstraint(R.id.lock_icon_view) + val cs = ConstraintSet() + underTest.centerLockIcon(Point(5, 6), 1F, 5, cs) + + val constraint = cs.getConstraint(R.id.lock_icon_view) assertThat(constraint.layout.mWidth).isEqualTo(2) assertThat(constraint.layout.mHeight).isEqualTo(2) @@ -87,11 +74,4 @@ class DefaultLockscreenLayoutTest : SysuiTestCase() { assertThat(constraint.layout.topMargin).isEqualTo(5) assertThat(constraint.layout.startMargin).isEqualTo(4) } - - /** Get the ConstraintLayout constraint of the view. */ - private fun getViewConstraint(viewId: Int): ConstraintSet.Constraint { - val constraintSet = ConstraintSet() - constraintSet.clone(rootView) - return constraintSet.getConstraint(viewId) - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt new file mode 100644 index 0000000000000..a18b0330d48f0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 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.keyguard.ui.viewmodel + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(JUnit4::class) +@SmallTest +class KeyguardBlueprintViewModelTest : SysuiTestCase() { + @Mock private lateinit var keyguardBlueprintInteractor: KeyguardBlueprintInteractor + private lateinit var undertest: KeyguardBlueprintViewModel + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + undertest = + KeyguardBlueprintViewModel(keyguardBlueprintInteractor = keyguardBlueprintInteractor) + } + + @Test + fun testBlueprintFlow() { + verify(keyguardBlueprintInteractor).blueprint + } +}