Merge "Rename layout -> blueprint and add "sections"" into udc-qpr-dev
This commit is contained in:
@@ -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">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_width="@dimen/keyguard_settings_popup_menu_icon_height"
|
||||
android:layout_height="@dimen/keyguard_settings_popup_menu_icon_width"
|
||||
android:layout_marginEnd="@dimen/keyguard_settings_popup_menu_icon_end_margin"
|
||||
android:tint="?androidprv:attr/materialColorOnSecondaryFixed"
|
||||
android:importantForAccessibility="no"
|
||||
tools:ignore="UseAppTint" />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -417,7 +417,10 @@ public class LockIconViewController extends ViewController<LockIconView> 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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<String, KeyguardBlueprint> = blueprints.associateBy { it.id }
|
||||
private val _blueprint: MutableSharedFlow<KeyguardBlueprint> = MutableSharedFlow(replay = 1)
|
||||
val blueprint: Flow<KeyguardBlueprint> = _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)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<View>(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<View>(R.id.lock_icon_view) ?: return
|
||||
val lockIcon = lockIconView.findViewById<View>(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<View>(R.id.start_button) ?: return
|
||||
val rightShortcut = rootView.findViewById<View>(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<MarginLayoutParams> {
|
||||
marginStart = horizontalOffsetMargin
|
||||
bottomMargin = verticalOffsetMargin
|
||||
}
|
||||
setPadding(padding)
|
||||
}
|
||||
|
||||
rightShortcut.apply {
|
||||
updateLayoutParams<MarginLayoutParams> {
|
||||
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<View>(R.id.ambient_indication_container) ?: return
|
||||
val lockIconView = rootView.findViewById<View>(R.id.lock_icon_view) ?: return
|
||||
val indicationArea = rootView.findViewById<View>(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<LaunchableLinearLayout>(R.id.keyguard_settings_button) ?: return
|
||||
val icon = popupMenu.findViewById<ImageView>(R.id.icon) ?: return
|
||||
val textView = popupMenu.findViewById<TextView>(R.id.text) ?: return
|
||||
val horizontalOffsetMargin =
|
||||
context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset)
|
||||
|
||||
icon.updateLayoutParams<LinearLayout.LayoutParams> {
|
||||
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<LinearLayout.LayoutParams> {
|
||||
height = WRAP_CONTENT
|
||||
width = WRAP_CONTENT
|
||||
}
|
||||
|
||||
popupMenu.updateLayoutParams<MarginLayoutParams> {
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -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 <LayoutId> */
|
||||
class KeyguardLayoutManagerCommandListener
|
||||
/** Uses $ adb shell cmd statusbar blueprint <BlueprintId> */
|
||||
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 <layoutId>")
|
||||
pw.println("Existing Layout Ids: ")
|
||||
keyguardLayoutManager.layoutIdMap.forEach { entry -> pw.println("${entry.key}") }
|
||||
pw.println("Usage: $ adb shell cmd statusbar blueprint <blueprintId>")
|
||||
pw.println("Existing Blueprint Ids: ")
|
||||
keyguardBlueprintRepository.printBlueprints(pw)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val COMMAND = "layout"
|
||||
internal const val COMMAND = "blueprint"
|
||||
}
|
||||
}
|
||||
@@ -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<String, LockscreenLayout> = 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)
|
||||
}
|
||||
@@ -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<View>(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<View>(R.id.lock_icon_view) ?: return
|
||||
val lockIcon = lockIconView.findViewById<View>(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<View>(R.id.start_button) ?: return
|
||||
val rightShortcut = rootView.findViewById<View>(R.id.end_button) ?: return
|
||||
val lockIconView = rootView.findViewById<View>(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<ViewGroup.MarginLayoutParams> {
|
||||
marginStart = horizontalOffsetMargin
|
||||
bottomMargin = verticalOffsetMargin
|
||||
}
|
||||
setPadding(padding)
|
||||
}
|
||||
|
||||
rightShortcut.apply {
|
||||
updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
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<View>(R.id.ambient_indication_container) ?: return
|
||||
val lockIconView = rootView.findViewById<View>(R.id.lock_icon_view) ?: return
|
||||
val indicationArea = rootView.findViewById<View>(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<LaunchableLinearLayout>(R.id.keyguard_settings_button) ?: return
|
||||
val icon = popupMenu.findViewById<ImageView>(R.id.icon) ?: return
|
||||
val textView = popupMenu.findViewById<TextView>(R.id.text) ?: return
|
||||
val horizontalOffsetMargin =
|
||||
context.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset)
|
||||
|
||||
icon.updateLayoutParams<LinearLayout.LayoutParams> {
|
||||
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<LinearLayout.LayoutParams> {
|
||||
height = WRAP_CONTENT
|
||||
width = WRAP_CONTENT
|
||||
}
|
||||
|
||||
popupMenu.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<Unit>(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()
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user