From b13030249d120d1c3b9534a4d241f546e6de7069 Mon Sep 17 00:00:00 2001 From: Alejandro Nijamkin Date: Sun, 20 Aug 2023 15:17:31 -0700 Subject: [PATCH] Adds LongPressHandlingView to KeyguardRootView. - The settings popup was previously migrated to KeyguardRootView but the long-press handling view that handles the long-press to show the settings popup was not. - The reason is was working is by accident: the KeyguardRootView was rendering on top (z order) of the NotificationPanelView and the NotificaitonPanelView did contain the original LongPressHandlingView. Hence, long-press touches were passing through KeyguardRootView and did in fact work to show the settings popup menu. - This CL moves the LongPressHandlingView into KeyguardRootView and removes it from the NotificationPanelView based on the feature flag. In addition: - Adding the LongPressHandlingView to KeyguardRootView meant adding an additional ConstraintLayout "section": DefaultLongPressHandlingSection. - The interface for KeyguardSection was moved to the shared.model package because it was previously in the data layer but referenced from the UI layer, which breaks the Clean Architecture Dependnecy Rule. - The long-press handling view binder was updtes to also monitor for interactions on the same view that need to dismiss the settings popup menu, greatly simplifying what external invocations need to do to connect the long-press to the settings popup bindings. Fix: 278057014 Test: manually verified that long-pressing empty space on the lock screen brings up the settings popup with and without the "split bottom area" feature flag being enabled. Test: manually verified that tapping/touching outside the popup menu once it shows up, hides it. Again, with the flag on and off. Change-Id: I59bb4d54fb92c55266fed71dfa652c8025a6dd6c Merged-In: I59bb4d54fb92c55266fed71dfa652c8025a6dd6c --- .../common/ui/view/LongPressHandlingView.kt | 5 +- .../keyguard/KeyguardViewConfigurator.kt | 36 ++++++++++++-- .../repository/KeyguardBlueprintRepository.kt | 8 ---- .../keyguard/shared/model/KeyguardSection.kt | 27 +++++++++++ .../ui/binder/KeyguardBottomAreaViewBinder.kt | 47 +++++++------------ .../ui/binder/KeyguardLongPressViewBinder.kt | 37 +++++++++++++++ .../ui/binder/KeyguardSettingsViewBinder.kt | 7 +-- .../keyguard/ui/view/KeyguardRootView.kt | 13 +++++ .../blueprints/DefaultKeyguardBlueprint.kt | 3 ++ .../ShortcutsBesideUdfpsKeyguardBlueprint.kt | 3 ++ .../sections/AlignShortcutsToUdfpsSection.kt | 2 +- .../DefaultAmbientIndicationAreaSection.kt | 2 +- .../sections/DefaultIndicationAreaSection.kt | 2 +- .../layout/sections/DefaultLockIconSection.kt | 2 +- .../DefaultLongPressHandlingSection.kt | 47 +++++++++++++++++++ .../DefaultSettingsPopupMenuSection.kt | 2 +- .../sections/DefaultShortcutsSection.kt | 2 +- .../sections/DefaultStatusViewSection.kt | 14 +++--- .../layout/sections/SplitShadeGuidelines.kt | 16 ++----- .../viewmodel/KeyguardBottomAreaViewModel.kt | 8 ---- .../NotificationPanelViewController.java | 20 ++++---- .../DefaultKeyguardBlueprintTest.kt | 3 ++ .../notetask/NoteTaskControllerTest.kt | 3 +- ...tificationPanelViewControllerBaseTest.java | 3 ++ 24 files changed, 221 insertions(+), 91 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardSection.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLongPressHandlingSection.kt diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt index 323070a848633..03d787bc6c8fe 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt @@ -89,8 +89,9 @@ class LongPressHandlingView( } @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent?): Boolean { - return interactionHandler.onTouchEvent(event?.toModel()) + override fun onTouchEvent(event: MotionEvent): Boolean { + super.onTouchEvent(event) + return interactionHandler.onTouchEvent(event.toModel()) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index 8e323d8140d5b..a5f8bf704b8f5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -24,12 +24,15 @@ import com.android.keyguard.KeyguardStatusViewController import com.android.keyguard.dagger.KeyguardStatusViewComponent import com.android.systemui.CoreStartable import com.android.systemui.R +import com.android.systemui.animation.view.LaunchableLinearLayout +import com.android.systemui.common.ui.view.LongPressHandlingView 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.KeyguardLongPressViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardSettingsViewBinder @@ -38,6 +41,7 @@ import com.android.systemui.keyguard.ui.view.layout.KeyguardBlueprintCommandList import com.android.systemui.keyguard.ui.viewmodel.KeyguardAmbientIndicationViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel +import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel @@ -76,6 +80,7 @@ constructor( private val falsingManager: FalsingManager, private val vibratorHelper: VibratorHelper, private val keyguardStateController: KeyguardStateController, + private val keyguardLongPressViewModel: KeyguardLongPressViewModel, private val keyguardSettingsMenuViewModel: KeyguardSettingsMenuViewModel, private val activityStarter: ActivityStarter, private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, @@ -105,7 +110,7 @@ constructor( bindLeftShortcut() bindRightShortcut() bindAmbientIndicationArea() - bindSettingsPopupMenu() + bindSettingsPopupMenu(notificationPanel) KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) keyguardBlueprintCommandListener.start() @@ -194,12 +199,34 @@ constructor( } } - private fun bindSettingsPopupMenu() { + private fun bindSettingsPopupMenu(legacyParent: ViewGroup) { if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) { + // Remove the legacy long-press view from the NotificationPanelView where it used to be + // before this refactor such that we only have one long-press view at the bottom of + // KeyguardRootView. + val legacyLongPressView = legacyParent.requireViewById(R.id.keyguard_long_press) + legacyParent.removeView(legacyLongPressView) + + val longPressView: LongPressHandlingView = + keyguardRootView.requireViewById(R.id.keyguard_long_press) + val settingsMenuView: LaunchableLinearLayout = + keyguardRootView.requireViewById(R.id.keyguard_settings_button) + + // Bind the long-press view that (1) triggers the showing of the settings popup menu and + // (2) captures touch events outside of the shown settings popup menu to hide it. + KeyguardLongPressViewBinder.bind( + view = longPressView, + viewModel = keyguardLongPressViewModel, + onSingleTap = {}, + falsingManager = falsingManager, + settingsMenuView = settingsMenuView, + ) + + // Bind the settings popup menu. settingsPopupMenuHandle?.dispose() settingsPopupMenuHandle = KeyguardSettingsViewBinder.bind( - keyguardRootView, + settingsMenuView, keyguardSettingsMenuViewModel, vibratorHelper, activityStarter, @@ -208,6 +235,9 @@ constructor( keyguardRootView.findViewById(R.id.keyguard_settings_button)?.let { keyguardRootView.removeView(it) } + keyguardRootView.findViewById(R.id.keyguard_long_press)?.let { + keyguardRootView.removeView(it) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt index 059f72b9f708c..6e2fe1e3ba30e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt @@ -99,11 +99,3 @@ interface KeyguardBlueprint { fun apply(constraintSet: ConstraintSet) } - -/** - * Lower level modules that determine constraints for a particular section in the lockscreen root - * view. - */ -interface KeyguardSection { - fun apply(constraintSet: ConstraintSet) -} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardSection.kt new file mode 100644 index 0000000000000..405d75e3de7de --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardSection.kt @@ -0,0 +1,27 @@ +/* + * Copyright 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.shared.model + +import androidx.constraintlayout.widget.ConstraintSet + +/** + * Lower level modules that determine constraints for a particular section in the lockscreen root + * view. + */ +interface KeyguardSection { + fun apply(constraintSet: ConstraintSet) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index 44acf4f0fd2d0..1669f44604614 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.binder import android.annotation.SuppressLint import android.content.Intent -import android.graphics.Rect import android.graphics.drawable.Animatable2 import android.util.Size import android.view.View @@ -76,7 +75,7 @@ object KeyguardBottomAreaViewBinder { * Users of the [KeyguardBottomAreaViewBinder] class should use this to control the binder after * it is bound. */ - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] @Deprecated("Deprecated as part of b/278057014") interface Binding { /** @@ -119,17 +118,6 @@ object KeyguardBottomAreaViewBinder { view.clipChildren = false view.clipToPadding = false - view.setOnTouchListener { _, event -> - if (settingsMenu.isVisible) { - val hitRect = Rect() - settingsMenu.getHitRect(hitRect) - if (!hitRect.contains(event.x.toInt(), event.y.toInt())) { - viewModel.onTouchedOutsideLockScreenSettingsMenu() - } - } - - false - } val configurationBasedDimensions = MutableStateFlow(loadFromResources(view)) @@ -137,7 +125,7 @@ object KeyguardBottomAreaViewBinder { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] launch { viewModel.startButton.collect { buttonModel -> updateButton( @@ -150,7 +138,7 @@ object KeyguardBottomAreaViewBinder { } } - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] launch { viewModel.endButton.collect { buttonModel -> updateButton( @@ -188,7 +176,7 @@ object KeyguardBottomAreaViewBinder { } } - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] launch { updateButtonAlpha( view = startButton, @@ -197,7 +185,7 @@ object KeyguardBottomAreaViewBinder { ) } - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] launch { updateButtonAlpha( view = endButton, @@ -223,7 +211,7 @@ object KeyguardBottomAreaViewBinder { } } - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] launch { configurationBasedDimensions.collect { dimensions -> startButton.updateLayoutParams { @@ -385,13 +373,14 @@ object KeyguardBottomAreaViewBinder { view.isClickable = viewModel.isClickable if (viewModel.isClickable) { if (viewModel.useLongPress) { - val onTouchListener = KeyguardQuickAffordanceOnTouchListener( - view, - viewModel, - messageDisplayer, - vibratorHelper, - falsingManager, - ) + val onTouchListener = + KeyguardQuickAffordanceOnTouchListener( + view, + viewModel, + messageDisplayer, + vibratorHelper, + falsingManager, + ) view.setOnTouchListener(onTouchListener) view.onLongClickListener = OnLongClickListener(falsingManager, viewModel, vibratorHelper, onTouchListener) @@ -408,7 +397,7 @@ object KeyguardBottomAreaViewBinder { } @Deprecated("Deprecated as part of b/278057014") - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] private suspend fun updateButtonAlpha( view: View, viewModel: Flow, @@ -439,7 +428,7 @@ object KeyguardBottomAreaViewBinder { } @Deprecated("Deprecated as part of b/278057014") - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] private class OnLongClickListener( private val falsingManager: FalsingManager?, private val viewModel: KeyguardQuickAffordanceViewModel, @@ -476,7 +465,7 @@ object KeyguardBottomAreaViewBinder { } @Deprecated("Deprecated as part of b/278057014") - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] private class OnClickListener( private val viewModel: KeyguardQuickAffordanceViewModel, private val falsingManager: FalsingManager, @@ -532,7 +521,7 @@ object KeyguardBottomAreaViewBinder { } @Deprecated("Deprecated as part of b/278057014") - //If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] + // If updated, be sure to update [KeyguardQuickAffordanceViewBinder.kt] private data class ConfigurationBasedDimensions( val defaultBurnInPreventionYOffsetPx: Int, val buttonSizePx: Size, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt index 9cc503c079556..48fd24acdb34d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt @@ -17,7 +17,11 @@ package com.android.systemui.keyguard.ui.binder +import android.annotation.SuppressLint +import android.graphics.Rect +import android.view.MotionEvent import android.view.View +import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.common.ui.view.LongPressHandlingView @@ -35,6 +39,9 @@ object KeyguardLongPressViewBinder { * @param onSingleTap A callback to invoke when the system decides that there was a single tap. * @param falsingManager [FalsingManager] for making sure the long-press didn't just happen in * the user's pocket. + * @param settingsMenuView The [View] for the settings menu that shows up when the long-press is + * detected. The [view] will be monitored for all touch to know when to actually hide the + * settings menu after it had been shown due to an outside touch. */ @JvmStatic fun bind( @@ -42,6 +49,7 @@ object KeyguardLongPressViewBinder { viewModel: KeyguardLongPressViewModel, onSingleTap: () -> Unit, falsingManager: FalsingManager, + settingsMenuView: View, ) { view.listener = object : LongPressHandlingView.Listener { @@ -62,6 +70,12 @@ object KeyguardLongPressViewBinder { } } + listenForTouchOutsideDismissals( + outsideView = view, + settingsMenuView = settingsMenuView, + onTouchedOutsideSettingsMenu = viewModel::onTouchedOutside, + ) + view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { @@ -72,4 +86,27 @@ object KeyguardLongPressViewBinder { } } } + + /** Listens for and handles touches outside the settings menu view, to dismiss it. */ + @SuppressLint("ClickableViewAccessibility") + private fun listenForTouchOutsideDismissals( + outsideView: View, + settingsMenuView: View, + onTouchedOutsideSettingsMenu: () -> Unit, + ) { + outsideView.setOnTouchListener { _, event -> + if (event.actionMasked == MotionEvent.ACTION_DOWN && settingsMenuView.isVisible) { + val hitRect = Rect() + settingsMenuView.getHitRect(hitRect) + if (!hitRect.contains(event.x.toInt(), event.y.toInt())) { + onTouchedOutsideSettingsMenu() + true + } else { + false + } + } else { + false + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt index 82610e6ea59dd..95569f6ad4f24 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt @@ -38,13 +38,11 @@ import kotlinx.coroutines.launch object KeyguardSettingsViewBinder { fun bind( - parentView: View, + view: LaunchableLinearLayout, viewModel: KeyguardSettingsMenuViewModel, vibratorHelper: VibratorHelper, activityStarter: ActivityStarter ): DisposableHandle { - val view = parentView.requireViewById(R.id.keyguard_settings_button) - val disposableHandle = view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { @@ -127,5 +125,4 @@ object KeyguardSettingsViewBinder { } .start() } - -} \ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt index a94874176a346..a69a9d5d07b5e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.ui.view import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.widget.ImageView import androidx.constraintlayout.widget.ConstraintLayout @@ -28,6 +29,7 @@ import com.android.keyguard.KeyguardStatusView import com.android.keyguard.LockIconView import com.android.systemui.R import com.android.systemui.animation.view.LaunchableImageView +import com.android.systemui.common.ui.view.LongPressHandlingView /** Provides a container for all keyguard ui content. */ class KeyguardRootView( @@ -39,9 +41,11 @@ class KeyguardRootView( attrs, ) { + var motionEventSpy: ((MotionEvent) -> Unit)? = null private var statusView: KeyguardStatusView? = null init { + addLongPressHandlingView() addIndicationTextArea() addLockIconView() addAmbientIndicationArea() @@ -51,6 +55,15 @@ class KeyguardRootView( addStatusView() } + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { + motionEventSpy?.invoke(event) + return super.onInterceptTouchEvent(event) + } + + private fun addLongPressHandlingView() { + addView(LongPressHandlingView(context, attrs).apply { id = R.id.keyguard_long_press }) + } + private fun addIndicationTextArea() { val view = KeyguardIndicationArea(context, attrs) addView(view) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt index 518df0719aaa0..5ae30c1afc31c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt @@ -23,6 +23,7 @@ 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.DefaultLongPressHandlingSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection @@ -43,6 +44,7 @@ constructor( private val defaultLockIconSection: DefaultLockIconSection, private val defaultShortcutsSection: DefaultShortcutsSection, private val defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection, + private val defaultLongPressHandlingSection: DefaultLongPressHandlingSection, private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection, private val defaultStatusViewSection: DefaultStatusViewSection, private val splitShadeGuidelines: SplitShadeGuidelines, @@ -54,6 +56,7 @@ constructor( defaultLockIconSection.apply(constraintSet) defaultShortcutsSection.apply(constraintSet) defaultAmbientIndicationAreaSection.apply(constraintSet) + defaultLongPressHandlingSection.apply(constraintSet) defaultSettingsPopupMenuSection.apply(constraintSet) defaultStatusViewSection.apply(constraintSet) splitShadeGuidelines.apply(constraintSet) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt index 54c27960db3c9..7a1f030fa70a5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt @@ -25,6 +25,7 @@ import com.android.systemui.keyguard.ui.view.layout.sections.AlignShortcutsToUdf 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.DefaultLongPressHandlingSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection @@ -40,6 +41,7 @@ constructor( private val defaultIndicationAreaSection: DefaultIndicationAreaSection, private val defaultLockIconSection: DefaultLockIconSection, private val defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection, + private val defaultLongPressHandlingSection: DefaultLongPressHandlingSection, private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection, private val alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection, private val defaultShortcutsSection: DefaultShortcutsSection, @@ -52,6 +54,7 @@ constructor( defaultIndicationAreaSection.apply(constraintSet) defaultLockIconSection.apply(constraintSet) defaultAmbientIndicationAreaSection.apply(constraintSet) + defaultLongPressHandlingSection.apply(constraintSet) defaultSettingsPopupMenuSection.apply(constraintSet) if (keyguardUpdateMonitor.isUdfpsSupported) { alignShortcutsToUdfpsSection.apply(constraintSet) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt index 156b9f3e5f485..f7c27ffd936c6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt @@ -26,7 +26,7 @@ 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 com.android.systemui.keyguard.shared.model.KeyguardSection import javax.inject.Inject class AlignShortcutsToUdfpsSection @Inject constructor(@Main private val resources: Resources) : diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt index abf25a23439f1..937674e514218 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt @@ -28,7 +28,7 @@ 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 com.android.systemui.keyguard.shared.model.KeyguardSection import javax.inject.Inject class DefaultAmbientIndicationAreaSection diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt index dee7ed570b05f..93c1ef70466de 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt @@ -21,7 +21,7 @@ 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 com.android.systemui.keyguard.shared.model.KeyguardSection import javax.inject.Inject class DefaultIndicationAreaSection @Inject constructor(private val context: Context) : diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt index 461faec217ca7..f69f9c71141c9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt @@ -27,7 +27,7 @@ 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 com.android.systemui.keyguard.shared.model.KeyguardSection import javax.inject.Inject class DefaultLockIconSection diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLongPressHandlingSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLongPressHandlingSection.kt new file mode 100644 index 0000000000000..5470b4119b963 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLongPressHandlingSection.kt @@ -0,0 +1,47 @@ +/* + * Copyright 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 androidx.annotation.IdRes +import androidx.constraintlayout.widget.ConstraintSet +import com.android.systemui.R +import com.android.systemui.keyguard.shared.model.KeyguardSection +import javax.inject.Inject + +/** Positions the long-press handling view in the keyguard. */ +class DefaultLongPressHandlingSection @Inject constructor() : KeyguardSection { + override fun apply(constraintSet: ConstraintSet) { + constraintSet.fillMaxSize(R.id.keyguard_long_press) + } + + private fun ConstraintSet.fillMaxSize(@IdRes viewId: Int) { + listOf( + ConstraintSet.START, + ConstraintSet.TOP, + ConstraintSet.END, + ConstraintSet.BOTTOM, + ) + .forEach { side -> + connect( + viewId, + side, + ConstraintSet.PARENT_ID, + side, + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt index ad1e4f8b98b43..631d20db95ddc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt @@ -26,7 +26,7 @@ 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 com.android.systemui.keyguard.shared.model.KeyguardSection import javax.inject.Inject class DefaultSettingsPopupMenuSection @Inject constructor(@Main private val resources: Resources) : diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt index db4653defd34e..c349664c94afd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt @@ -25,7 +25,7 @@ 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 com.android.systemui.keyguard.shared.model.KeyguardSection import javax.inject.Inject class DefaultShortcutsSection @Inject constructor(@Main private val resources: Resources) : diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt index 3f319ba2d0e42..5e832f6cc89c2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt @@ -18,20 +18,18 @@ 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 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import androidx.constraintlayout.widget.ConstraintSet +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.END +import com.android.systemui.R +import com.android.systemui.keyguard.shared.model.KeyguardSection +import javax.inject.Inject -class DefaultStatusViewSection @Inject constructor(private val context: Context) : - KeyguardSection { +class DefaultStatusViewSection @Inject constructor(private val context: Context) : KeyguardSection { private val statusViewId = R.id.keyguard_status_view override fun apply(constraintSet: ConstraintSet) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt index 668b17ffeba06..92e37b75e53ac 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt @@ -18,21 +18,13 @@ 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 -import android.view.ViewGroup.LayoutParams.WRAP_CONTENT -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.END import androidx.constraintlayout.widget.ConstraintSet.VERTICAL +import com.android.systemui.R +import com.android.systemui.keyguard.shared.model.KeyguardSection +import javax.inject.Inject -class SplitShadeGuidelines @Inject constructor(private val context: Context) : - KeyguardSection { +class SplitShadeGuidelines @Inject constructor(private val context: Context) : KeyguardSection { override fun apply(constraintSet: ConstraintSet) { constraintSet.apply { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt index 3e6f8e68891a9..74eb856403413 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt @@ -157,14 +157,6 @@ constructor( selectedPreviewSlotId.value = slotId } - /** - * Notifies that some input gesture has started somewhere in the bottom area that's outside of - * the lock screen settings menu item pop-up. - */ - fun onTouchedOutsideLockScreenSettingsMenu() { - longPressViewModel.onTouchedOutside() - } - private fun button( position: KeyguardQuickAffordancePosition ): Flow { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 132cd6115bc7d..e86c6973fa98a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -546,6 +546,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final NPVCDownEventState.Buffer mLastDownEvents; private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel; private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; + private final KeyguardLongPressViewModel mKeyguardLongPressViewModel; private float mMinExpandHeight; private boolean mPanelUpdateWhenAnimatorEnds; private boolean mHasVibratedOnOpen = false; @@ -949,14 +950,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump updateUserSwitcherFlags(); mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel; mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor; - KeyguardLongPressViewBinder.bind( - mView.requireViewById(R.id.keyguard_long_press), - keyguardLongPressViewModel, - () -> { - onEmptySpaceClick(); - return Unit.INSTANCE; - }, - mFalsingManager); + mKeyguardLongPressViewModel = keyguardLongPressViewModel; mActivityStarter = activityStarter; onFinishInflate(); keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener( @@ -1492,6 +1486,16 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @Deprecated private void setKeyguardBottomArea(KeyguardBottomAreaView keyguardBottomArea) { mKeyguardBottomArea = keyguardBottomArea; + + KeyguardLongPressViewBinder.bind( + mView.requireViewById(R.id.keyguard_long_press), + mKeyguardLongPressViewModel, + () -> { + onEmptySpaceClick(); + return Unit.INSTANCE; + }, + mFalsingManager, + mKeyguardBottomArea.requireViewById(R.id.keyguard_settings_button)); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt index addb1815ceadb..d00fe9d309b8a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt @@ -26,6 +26,7 @@ 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.DefaultLongPressHandlingSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection @@ -48,6 +49,7 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { @Mock private lateinit var defaultShortcutsSection: DefaultShortcutsSection @Mock private lateinit var defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection + @Mock private lateinit var defaultLongPressHandlingSection: DefaultLongPressHandlingSection @Mock private lateinit var defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection @Mock private lateinit var defaultStatusViewSection: DefaultStatusViewSection @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines @@ -62,6 +64,7 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { defaultLockIconSection, defaultShortcutsSection, defaultAmbientIndicationAreaSection, + defaultLongPressHandlingSection, defaultSettingsPopupMenuSection, defaultStatusViewSection, splitShadeGuidelines, diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt index 1536c1737de60..c4a80bff29d76 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -69,7 +69,6 @@ import com.android.wm.shell.bubbles.Bubble import com.android.wm.shell.bubbles.Bubbles import com.google.common.truth.Truth.assertThat import java.util.Optional -import kotlin.test.assertNotNull import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -673,7 +672,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { extras().bool(EXTRA_USE_STYLUS_MODE).isTrue() } iconCaptor.value?.let { icon -> - assertNotNull(icon) + assertThat(icon).isNotNull() assertThat(icon.resId).isEqualTo(R.drawable.ic_note_task_shortcut_widget) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 981e44bea846c..270fa7a5c85dc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -80,6 +80,7 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.keyguard.logging.KeyguardLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.view.LaunchableLinearLayout; import com.android.systemui.biometrics.AuthController; import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.classifier.FalsingCollectorFake; @@ -411,6 +412,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea); when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); when(mKeyguardBottomArea.animate()).thenReturn(mViewPropertyAnimator); + when(mKeyguardBottomArea.requireViewById(R.id.keyguard_settings_button)) + .thenReturn(mock(LaunchableLinearLayout.class)); when(mView.animate()).thenReturn(mViewPropertyAnimator); when(mKeyguardStatusView.animate()).thenReturn(mViewPropertyAnimator); when(mViewPropertyAnimator.translationX(anyFloat())).thenReturn(mViewPropertyAnimator);