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