diff options
24 files changed, 1470 insertions, 143 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index 6d4dbf632d76..33c7c117dc95 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -102,6 +102,33 @@ public interface ActivityStarter { void dismissKeyguardThenExecute(OnDismissAction action, @Nullable Runnable cancel, boolean afterKeyguardGone, @Nullable String customMessage); + /** Starts an activity and dismisses keyguard. */ + void startActivityDismissingKeyguard(Intent intent, + boolean onlyProvisioned, + boolean dismissShade, + boolean disallowEnterPictureInPictureWhileLaunching, + Callback callback, + int flags, + @Nullable ActivityLaunchAnimator.Controller animationController, + UserHandle userHandle); + + /** Execute a runnable after dismissing keyguard. */ + void executeRunnableDismissingKeyguard(Runnable runnable, + Runnable cancelAction, + boolean dismissShade, + boolean afterKeyguardGone, + boolean deferred); + + /** Execute a runnable after dismissing keyguard. */ + void executeRunnableDismissingKeyguard( + Runnable runnable, + Runnable cancelAction, + boolean dismissShade, + boolean afterKeyguardGone, + boolean deferred, + boolean willAnimateOnKeyguard, + @Nullable String customMessage); + interface Callback { void onActivityStarted(int resultCode); } diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java index 401f6c9c747d..bf84f8af02fe 100644 --- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java @@ -35,6 +35,8 @@ import javax.inject.Inject; /** * Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but * delegates to an actual implementation (CentralSurfaces). + * + * @deprecated Migrating to ActivityStarterImpl */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @SysUISingleton @@ -92,6 +94,14 @@ public class ActivityStarterDelegate implements ActivityStarter { } @Override + public void startActivity(Intent intent, + boolean dismissShade, + @Nullable ActivityLaunchAnimator.Controller animationController) { + mActualStarterOptionalLazy.get().ifPresent( + starter -> starter.startActivity(intent, dismissShade, animationController)); + } + + @Override public void startActivity(Intent intent, boolean dismissShade, @Nullable ActivityLaunchAnimator.Controller animationController, boolean showOverLockscreenWhenLocked) { @@ -177,4 +187,35 @@ public class ActivityStarterDelegate implements ActivityStarter { starter -> starter.dismissKeyguardThenExecute(action, cancel, afterKeyguardGone, customMessage)); } + + @Override + public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, + boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching, + Callback callback, int flags, + @Nullable ActivityLaunchAnimator.Controller animationController, + UserHandle userHandle) { + mActualStarterOptionalLazy.get().ifPresent( + starter -> starter.startActivityDismissingKeyguard(intent, onlyProvisioned, + dismissShade, disallowEnterPictureInPictureWhileLaunching, callback, + flags, animationController, userHandle)); + } + + @Override + public void executeRunnableDismissingKeyguard(Runnable runnable, + Runnable cancelAction, boolean dismissShade, + boolean afterKeyguardGone, boolean deferred) { + mActualStarterOptionalLazy.get().ifPresent( + starter -> starter.executeRunnableDismissingKeyguard(runnable, cancelAction, + dismissShade, afterKeyguardGone, deferred)); + } + + @Override + public void executeRunnableDismissingKeyguard(Runnable runnable, Runnable cancelAction, + boolean dismissShade, boolean afterKeyguardGone, boolean deferred, + boolean willAnimateOnKeyguard, @Nullable String customMessage) { + mActualStarterOptionalLazy.get().ifPresent( + starter -> starter.executeRunnableDismissingKeyguard(runnable, cancelAction, + dismissShade, afterKeyguardGone, deferred, willAnimateOnKeyguard, + customMessage)); + } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java index 67ad3db74f8a..8764297c1b5d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/PluginModule.java @@ -18,6 +18,8 @@ package com.android.systemui.dagger; import com.android.systemui.ActivityStarterDelegate; import com.android.systemui.classifier.FalsingManagerProxy; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.globalactions.GlobalActionsImpl; import com.android.systemui.plugins.ActivityStarter; @@ -28,6 +30,7 @@ import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.phone.ActivityStarterImpl; import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl; import com.android.systemui.volume.VolumeDialogControllerImpl; @@ -46,7 +49,11 @@ public abstract class PluginModule { /** */ @Provides static ActivityStarter provideActivityStarter(ActivityStarterDelegate delegate, - PluginDependencyProvider dependencyProvider) { + PluginDependencyProvider dependencyProvider, ActivityStarterImpl activityStarterImpl, + FeatureFlags featureFlags) { + if (featureFlags.isEnabled(Flags.USE_NEW_ACTIVITY_STARTER)) { + return activityStarterImpl; + } dependencyProvider.allowPluginDependency(ActivityStarter.class, delegate); return delegate; } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 2ecb0a0043a2..17e66a74927b 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -675,4 +675,8 @@ object Flags { @JvmField val ADVANCED_VPN_ENABLED = unreleasedFlag(2800, name = "AdvancedVpn__enable_feature", namespace = "vpn", teamfood = true) + + // TODO(b/278761837): Tracking Bug + @JvmField + val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter") } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java index 5ea1c0b4ce85..4b22edcc29ad 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java @@ -23,15 +23,16 @@ import android.os.RemoteException; import android.util.Log; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.statusbar.phone.CentralSurfaces; +import dagger.Lazy; + import java.util.Optional; import javax.inject.Inject; -import dagger.Lazy; - /** * An implementation of the Recents interface which proxies to the OverviewProxyService. */ @@ -44,13 +45,15 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation { private Handler mHandler; private final OverviewProxyService mOverviewProxyService; + private final ActivityStarter mActivityStarter; @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject public OverviewProxyRecentsImpl(Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, - OverviewProxyService overviewProxyService) { + OverviewProxyService overviewProxyService, ActivityStarter activityStarter) { mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mOverviewProxyService = overviewProxyService; + mActivityStarter = activityStarter; } @Override @@ -101,7 +104,7 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation { final Optional<CentralSurfaces> centralSurfacesOptional = mCentralSurfacesOptionalLazy.get(); if (centralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing).orElse(false)) { - centralSurfacesOptional.get().executeRunnableDismissingKeyguard( + mActivityStarter.executeRunnableDismissingKeyguard( () -> mHandler.post(toggleRecents), null, true /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java index 4f5cb72438bc..3aefcb3d2976 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java @@ -33,11 +33,9 @@ import android.util.Log; import android.view.RemoteAnimationAdapter; import android.view.WindowManagerGlobal; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.statusbar.phone.CentralSurfaces; - -import java.util.Optional; import javax.inject.Inject; @@ -48,20 +46,20 @@ import javax.inject.Inject; public class ActionProxyReceiver extends BroadcastReceiver { private static final String TAG = "ActionProxyReceiver"; - private final CentralSurfaces mCentralSurfaces; private final ActivityManagerWrapper mActivityManagerWrapper; private final ScreenshotSmartActions mScreenshotSmartActions; private final DisplayTracker mDisplayTracker; + private final ActivityStarter mActivityStarter; @Inject - public ActionProxyReceiver(Optional<CentralSurfaces> centralSurfacesOptional, - ActivityManagerWrapper activityManagerWrapper, + public ActionProxyReceiver(ActivityManagerWrapper activityManagerWrapper, ScreenshotSmartActions screenshotSmartActions, - DisplayTracker displayTracker) { - mCentralSurfaces = centralSurfacesOptional.orElse(null); + DisplayTracker displayTracker, + ActivityStarter activityStarter) { mActivityManagerWrapper = activityManagerWrapper; mScreenshotSmartActions = screenshotSmartActions; mDisplayTracker = displayTracker; + mActivityStarter = activityStarter; } @Override @@ -92,13 +90,9 @@ public class ActionProxyReceiver extends BroadcastReceiver { }; - if (mCentralSurfaces != null) { - mCentralSurfaces.executeRunnableDismissingKeyguard(startActivityRunnable, null, - true /* dismissShade */, true /* afterKeyguardGone */, - true /* deferred */); - } else { - startActivityRunnable.run(); - } + mActivityStarter.executeRunnableDismissingKeyguard(startActivityRunnable, null, + true /* dismissShade */, true /* afterKeyguardGone */, + true /* deferred */); if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { String actionType = Intent.ACTION_EDIT.equals(intent.getAction()) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt index 4cb91e134003..14e875d28f8f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt @@ -21,53 +21,44 @@ import android.util.Log import androidx.lifecycle.LifecycleService import androidx.lifecycle.lifecycleScope import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.shade.ShadeExpansionStateManager -import com.android.systemui.statusbar.phone.CentralSurfaces +import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.util.Optional -import javax.inject.Inject -/** - * Provides state from the main SystemUI process on behalf of the Screenshot process. - */ -internal class ScreenshotProxyService @Inject constructor( +/** Provides state from the main SystemUI process on behalf of the Screenshot process. */ +internal class ScreenshotProxyService +@Inject +constructor( private val mExpansionMgr: ShadeExpansionStateManager, - private val mCentralSurfacesOptional: Optional<CentralSurfaces>, @Main private val mMainDispatcher: CoroutineDispatcher, + private val activityStarter: ActivityStarter, ) : LifecycleService() { - private val mBinder: IBinder = object : IScreenshotProxy.Stub() { - /** - * @return true when the notification shade is partially or fully expanded. - */ - override fun isNotificationShadeExpanded(): Boolean { - val expanded = !mExpansionMgr.isClosed() - Log.d(TAG, "isNotificationShadeExpanded(): $expanded") - return expanded - } + private val mBinder: IBinder = + object : IScreenshotProxy.Stub() { + /** @return true when the notification shade is partially or fully expanded. */ + override fun isNotificationShadeExpanded(): Boolean { + val expanded = !mExpansionMgr.isClosed() + Log.d(TAG, "isNotificationShadeExpanded(): $expanded") + return expanded + } - override fun dismissKeyguard(callback: IOnDoneCallback) { - lifecycleScope.launch { - executeAfterDismissing(callback) + override fun dismissKeyguard(callback: IOnDoneCallback) { + lifecycleScope.launch { executeAfterDismissing(callback) } } } - } private suspend fun executeAfterDismissing(callback: IOnDoneCallback) = withContext(mMainDispatcher) { - mCentralSurfacesOptional.ifPresentOrElse( - { - it.executeRunnableDismissingKeyguard( - Runnable { - callback.onDone(true) - }, null, - true /* dismissShade */, true /* afterKeyguardGone */, - true /* deferred */ - ) - }, - { callback.onDone(false) } + activityStarter.executeRunnableDismissingKeyguard( + Runnable { callback.onDone(true) }, + null, + true /* dismissShade */, + true /* afterKeyguardGone */, + true /* deferred */ ) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index be92bd48a619..dfc9bcf593f0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -4086,7 +4086,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump if (!mFalsingManager.isUnlockingDisabled() && qsFullyExpanded && mFalsingCollector.shouldEnforceBouncer()) { - mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, + mActivityStarter.executeRunnableDismissingKeyguard(null, null, false, true, false); } if (DEBUG_DRAWABLE) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 22589686520b..88d9d8fb14a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -26,6 +26,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.media.controls.ui.MediaHierarchyManager +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter.OnDismissAction import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QS @@ -62,11 +63,12 @@ class LockscreenShadeTransitionController @Inject constructor( private val mediaHierarchyManager: MediaHierarchyManager, private val scrimTransitionController: LockscreenShadeScrimTransitionController, private val keyguardTransitionControllerFactory: - LockscreenShadeKeyguardTransitionController.Factory, + LockscreenShadeKeyguardTransitionController.Factory, private val depthController: NotificationShadeDepthController, private val context: Context, private val splitShadeOverScrollerFactory: SplitShadeLockScreenOverScroller.Factory, private val singleShadeOverScrollerFactory: SingleShadeLockScreenOverScroller.Factory, + private val activityStarter: ActivityStarter, wakefulnessLifecycle: WakefulnessLifecycle, configurationController: ConfigurationController, falsingManager: FalsingManager, @@ -305,7 +307,7 @@ class LockscreenShadeTransitionController @Inject constructor( if (nsslController.isInLockedDownShade()) { logger.logDraggedDownLockDownShade(startingChild) statusBarStateController.setLeaveOpenOnKeyguardHide(true) - centralSurfaces.dismissKeyguardThenExecute(OnDismissAction { + activityStarter.dismissKeyguardThenExecute(OnDismissAction { nextHideKeyguardNeedsNoAnimation = true false }, cancelRunnable, false /* afterKeyguardGone */) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index e6e6b9950d40..0c4b0927a906 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -49,6 +49,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.settings.UserContextProvider; @@ -73,8 +74,6 @@ import java.util.Optional; import javax.inject.Inject; -import dagger.Lazy; - /** * Handles various NotificationGuts related tasks, such as binding guts to a row, opening and * closing guts, and keeping track of the currently exposed notification guts. @@ -107,7 +106,6 @@ public class NotificationGutsManager implements NotifGutsViewManager { private NotificationListContainer mListContainer; private OnSettingsClickListener mOnSettingsClickListener; - private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; private final Handler mMainHandler; private final Handler mBgHandler; private final Optional<BubblesManager> mBubblesManagerOptional; @@ -121,10 +119,10 @@ public class NotificationGutsManager implements NotifGutsViewManager { private final ShadeController mShadeController; private NotifGutsViewListener mGutsListener; private final HeadsUpManagerPhone mHeadsUpManagerPhone; + private final ActivityStarter mActivityStarter; @Inject public NotificationGutsManager(Context context, - Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, @Main Handler mainHandler, @Background Handler bgHandler, AccessibilityManager accessibilityManager, @@ -144,9 +142,9 @@ public class NotificationGutsManager implements NotifGutsViewManager { StatusBarStateController statusBarStateController, DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger, - HeadsUpManagerPhone headsUpManagerPhone) { + HeadsUpManagerPhone headsUpManagerPhone, + ActivityStarter activityStarter) { mContext = context; - mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mMainHandler = mainHandler; mBgHandler = bgHandler; mAccessibilityManager = accessibilityManager; @@ -167,6 +165,7 @@ public class NotificationGutsManager implements NotifGutsViewManager { mDeviceProvisionedController = deviceProvisionedController; mMetricsLogger = metricsLogger; mHeadsUpManagerPhone = headsUpManagerPhone; + mActivityStarter = activityStarter; } public void setUpWithPresenter(NotificationPresenter presenter, @@ -551,19 +550,15 @@ public class NotificationGutsManager implements NotifGutsViewManager { .setLeaveOpenOnKeyguardHide(true); } - Optional<CentralSurfaces> centralSurfacesOptional = - mCentralSurfacesOptionalLazy.get(); - if (centralSurfacesOptional.isPresent()) { - Runnable r = () -> mMainHandler.post( - () -> openGutsInternal(view, x, y, menuItem)); - centralSurfacesOptional.get().executeRunnableDismissingKeyguard( - r, - null /* cancelAction */, - false /* dismissShade */, - true /* afterKeyguardGone */, - true /* deferred */); - return true; - } + Runnable r = () -> mMainHandler.post( + () -> openGutsInternal(view, x, y, menuItem)); + mActivityStarter.executeRunnableDismissingKeyguard( + r, + null /* cancelAction */, + false /* dismissShade */, + true /* afterKeyguardGone */, + true /* deferred */); + return true; /** * When {@link CentralSurfaces} doesn't exist, falling through to call * {@link #openGutsInternal(View,int,int,NotificationMenuRowPlugin.MenuItem)}. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 82608b1b1c7d..4a9bf4eb91ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -89,6 +89,7 @@ import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.shade.ShadeController; import com.android.systemui.statusbar.CommandQueue; @@ -319,6 +320,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable }; private NotificationStackScrollLogger mLogger; private CentralSurfaces mCentralSurfaces; + private ActivityStarter mActivityStarter; private final int[] mTempInt2 = new int[2]; private boolean mGenerateChildOrderChangedEvent; private final HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>(); @@ -4814,6 +4816,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable this.mCentralSurfaces = centralSurfaces; } + public void setActivityStarter(ActivityStarter activityStarter) { + mActivityStarter = activityStarter; + } + @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) void requestAnimateEverything() { if (mIsExpanded && mAnimationsEnabled) { @@ -5579,7 +5585,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable Intent intent = showHistory ? new Intent(Settings.ACTION_NOTIFICATION_HISTORY) : new Intent(Settings.ACTION_NOTIFICATION_SETTINGS); - mCentralSurfaces.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP); + mActivityStarter.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP); }); setEmptyShadeView(view); updateEmptyShadeView( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index b69ce3861342..4751fb68697b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -63,6 +63,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.media.controls.ui.KeyguardMediaController; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener; @@ -198,6 +199,7 @@ public class NotificationStackScrollLayoutController { private final NotificationTargetsHelper mNotificationTargetsHelper; private final SecureSettings mSecureSettings; private final NotificationDismissibilityProvider mDismissibilityProvider; + private final ActivityStarter mActivityStarter; private View mLongPressedView; @@ -487,7 +489,7 @@ public class NotificationStackScrollLayoutController { mView.addSwipedOutView(view); mFalsingCollector.onNotificationDismissed(); if (mFalsingCollector.shouldEnforceBouncer()) { - mCentralSurfaces.executeRunnableDismissingKeyguard( + mActivityStarter.executeRunnableDismissingKeyguard( null, null /* cancelAction */, false /* dismissShade */, @@ -678,7 +680,8 @@ public class NotificationStackScrollLayoutController { FeatureFlags featureFlags, NotificationTargetsHelper notificationTargetsHelper, SecureSettings secureSettings, - NotificationDismissibilityProvider dismissibilityProvider) { + NotificationDismissibilityProvider dismissibilityProvider, + ActivityStarter activityStarter) { mView = view; mStackStateLogger = stackLogger; mLogger = logger; @@ -724,6 +727,7 @@ public class NotificationStackScrollLayoutController { mNotificationTargetsHelper = notificationTargetsHelper; mSecureSettings = secureSettings; mDismissibilityProvider = dismissibilityProvider; + mActivityStarter = activityStarter; updateResources(); setUpView(); } @@ -734,6 +738,7 @@ public class NotificationStackScrollLayoutController { mView.setLogger(mLogger); mView.setTouchHandler(new TouchHandler()); mView.setCentralSurfaces(mCentralSurfaces); + mView.setActivityStarter(mActivityStarter); mView.setClearAllAnimationListener(this::onAnimationEnd); mView.setClearAllListener((selection) -> mUiEventLogger.log( NotificationPanelEvent.fromSelection(selection))); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt new file mode 100644 index 000000000000..d9dc8878fa61 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt @@ -0,0 +1,867 @@ +/* + * 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.statusbar.phone + +import android.app.ActivityManager +import android.app.ActivityOptions +import android.app.ActivityTaskManager +import android.app.PendingIntent +import android.app.TaskStackBuilder +import android.content.Context +import android.content.Intent +import android.os.RemoteException +import android.os.UserHandle +import android.provider.Settings +import android.util.Log +import android.view.RemoteAnimationAdapter +import android.view.View +import android.view.WindowManager +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.ActivityIntentHelper +import com.android.systemui.R +import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.animation.ActivityLaunchAnimator.PendingIntentStarter +import com.android.systemui.animation.DelegateLaunchAnimatorController +import com.android.systemui.assist.AssistManager +import com.android.systemui.camera.CameraIntents.Companion.isInsecureCameraIntent +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.KeyguardViewMediator +import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.ActivityStarter.OnDismissAction +import com.android.systemui.settings.UserTracker +import com.android.systemui.shade.ShadeController +import com.android.systemui.statusbar.NotificationLockscreenUserManager +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.window.StatusBarWindowController +import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.kotlin.getOrNull +import dagger.Lazy +import java.util.Optional +import javax.inject.Inject + +/** Handles start activity logic in SystemUI. */ +@SysUISingleton +class ActivityStarterImpl +@Inject +constructor( + private val centralSurfacesOptLazy: Lazy<Optional<CentralSurfaces>>, + private val assistManagerLazy: Lazy<AssistManager>, + private val dozeServiceHostLazy: Lazy<DozeServiceHost>, + private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>, + private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>, + private val shadeControllerLazy: Lazy<ShadeController>, + private val statusBarKeyguardViewManagerLazy: Lazy<StatusBarKeyguardViewManager>, + private val activityLaunchAnimator: ActivityLaunchAnimator, + private val context: Context, + private val lockScreenUserManager: NotificationLockscreenUserManager, + private val statusBarWindowController: StatusBarWindowController, + private val wakefulnessLifecycle: WakefulnessLifecycle, + private val keyguardStateController: KeyguardStateController, + private val statusBarStateController: SysuiStatusBarStateController, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val deviceProvisionedController: DeviceProvisionedController, + private val userTracker: UserTracker, + private val activityIntentHelper: ActivityIntentHelper, + @Main private val mainExecutor: DelayableExecutor, +) : ActivityStarter { + companion object { + const val TAG = "ActivityStarterImpl" + } + + private val centralSurfaces: CentralSurfaces? + get() = centralSurfacesOptLazy.get().getOrNull() + + private val activityStarterInternal = ActivityStarterInternal() + + override fun startPendingIntentDismissingKeyguard(intent: PendingIntent) { + activityStarterInternal.startPendingIntentDismissingKeyguard(intent = intent) + } + + override fun startPendingIntentDismissingKeyguard( + intent: PendingIntent, + intentSentUiThreadCallback: Runnable?, + ) { + activityStarterInternal.startPendingIntentDismissingKeyguard( + intent = intent, + intentSentUiThreadCallback = intentSentUiThreadCallback, + ) + } + + override fun startPendingIntentDismissingKeyguard( + intent: PendingIntent, + intentSentUiThreadCallback: Runnable?, + associatedView: View?, + ) { + activityStarterInternal.startPendingIntentDismissingKeyguard( + intent = intent, + intentSentUiThreadCallback = intentSentUiThreadCallback, + associatedView = associatedView, + ) + } + + override fun startPendingIntentDismissingKeyguard( + intent: PendingIntent, + intentSentUiThreadCallback: Runnable?, + animationController: ActivityLaunchAnimator.Controller?, + ) { + activityStarterInternal.startPendingIntentDismissingKeyguard( + intent = intent, + intentSentUiThreadCallback = intentSentUiThreadCallback, + animationController = animationController, + ) + } + + /** + * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate + * this. + */ + override fun startActivity(intent: Intent, dismissShade: Boolean) { + activityStarterInternal.startActivityDismissingKeyguard( + intent = intent, + dismissShade = dismissShade, + ) + } + + /** + * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate + * this. + */ + override fun startActivity(intent: Intent, onlyProvisioned: Boolean, dismissShade: Boolean) { + activityStarterInternal.startActivityDismissingKeyguard( + intent = intent, + onlyProvisioned = onlyProvisioned, + dismissShade = dismissShade, + ) + } + + /** + * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate + * this. + */ + override fun startActivity( + intent: Intent, + dismissShade: Boolean, + callback: ActivityStarter.Callback?, + ) { + activityStarterInternal.startActivityDismissingKeyguard( + intent = intent, + dismissShade = dismissShade, + callback = callback, + ) + } + + /** + * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate + * this. + */ + override fun startActivity( + intent: Intent, + onlyProvisioned: Boolean, + dismissShade: Boolean, + flags: Int, + ) { + activityStarterInternal.startActivityDismissingKeyguard( + intent = intent, + onlyProvisioned = onlyProvisioned, + dismissShade = dismissShade, + flags = flags, + ) + } + + override fun startActivity( + intent: Intent, + dismissShade: Boolean, + animationController: ActivityLaunchAnimator.Controller?, + showOverLockscreenWhenLocked: Boolean, + ) { + activityStarterInternal.startActivity( + intent = intent, + dismissShade = dismissShade, + animationController = animationController, + showOverLockscreenWhenLocked = showOverLockscreenWhenLocked, + ) + } + override fun startActivity( + intent: Intent, + dismissShade: Boolean, + animationController: ActivityLaunchAnimator.Controller?, + showOverLockscreenWhenLocked: Boolean, + userHandle: UserHandle?, + ) { + activityStarterInternal.startActivity( + intent = intent, + dismissShade = dismissShade, + animationController = animationController, + showOverLockscreenWhenLocked = showOverLockscreenWhenLocked, + userHandle = userHandle, + ) + } + + override fun postStartActivityDismissingKeyguard(intent: PendingIntent) { + postOnUiThread { + activityStarterInternal.startPendingIntentDismissingKeyguard( + intent = intent, + ) + } + } + + override fun postStartActivityDismissingKeyguard( + intent: PendingIntent, + animationController: ActivityLaunchAnimator.Controller? + ) { + postOnUiThread { + activityStarterInternal.startPendingIntentDismissingKeyguard( + intent = intent, + animationController = animationController, + ) + } + } + + override fun postStartActivityDismissingKeyguard(intent: Intent, delay: Int) { + postOnUiThread(delay) { + activityStarterInternal.startActivityDismissingKeyguard(intent = intent) + } + } + + override fun postStartActivityDismissingKeyguard( + intent: Intent, + delay: Int, + animationController: ActivityLaunchAnimator.Controller?, + ) { + postOnUiThread(delay) { + activityStarterInternal.startActivityDismissingKeyguard( + intent = intent, + animationController = animationController, + ) + } + } + + override fun postStartActivityDismissingKeyguard( + intent: Intent, + delay: Int, + animationController: ActivityLaunchAnimator.Controller?, + customMessage: String?, + ) { + postOnUiThread(delay) { + activityStarterInternal.startActivityDismissingKeyguard( + intent = intent, + animationController = animationController, + customMessage = customMessage, + ) + } + } + + override fun dismissKeyguardThenExecute( + action: OnDismissAction, + cancel: Runnable?, + afterKeyguardGone: Boolean, + ) { + activityStarterInternal.dismissKeyguardThenExecute( + action = action, + cancel = cancel, + afterKeyguardGone = afterKeyguardGone, + ) + } + + override fun dismissKeyguardThenExecute( + action: OnDismissAction, + cancel: Runnable?, + afterKeyguardGone: Boolean, + customMessage: String?, + ) { + activityStarterInternal.dismissKeyguardThenExecute( + action = action, + cancel = cancel, + afterKeyguardGone = afterKeyguardGone, + customMessage = customMessage, + ) + } + + override fun startActivityDismissingKeyguard( + intent: Intent, + onlyProvisioned: Boolean, + dismissShade: Boolean, + disallowEnterPictureInPictureWhileLaunching: Boolean, + callback: ActivityStarter.Callback?, + flags: Int, + animationController: ActivityLaunchAnimator.Controller?, + userHandle: UserHandle?, + ) { + activityStarterInternal.startActivityDismissingKeyguard( + intent = intent, + onlyProvisioned = onlyProvisioned, + dismissShade = dismissShade, + disallowEnterPictureInPictureWhileLaunching = + disallowEnterPictureInPictureWhileLaunching, + callback = callback, + flags = flags, + animationController = animationController, + userHandle = userHandle, + ) + } + + override fun executeRunnableDismissingKeyguard( + runnable: Runnable?, + cancelAction: Runnable?, + dismissShade: Boolean, + afterKeyguardGone: Boolean, + deferred: Boolean, + ) { + activityStarterInternal.executeRunnableDismissingKeyguard( + runnable = runnable, + cancelAction = cancelAction, + dismissShade = dismissShade, + afterKeyguardGone = afterKeyguardGone, + deferred = deferred, + ) + } + + override fun executeRunnableDismissingKeyguard( + runnable: Runnable?, + cancelAction: Runnable?, + dismissShade: Boolean, + afterKeyguardGone: Boolean, + deferred: Boolean, + willAnimateOnKeyguard: Boolean, + customMessage: String?, + ) { + activityStarterInternal.executeRunnableDismissingKeyguard( + runnable = runnable, + cancelAction = cancelAction, + dismissShade = dismissShade, + afterKeyguardGone = afterKeyguardGone, + deferred = deferred, + willAnimateOnKeyguard = willAnimateOnKeyguard, + customMessage = customMessage, + ) + } + + override fun postQSRunnableDismissingKeyguard(runnable: Runnable?) { + postOnUiThread { + statusBarStateController.setLeaveOpenOnKeyguardHide(true) + activityStarterInternal.executeRunnableDismissingKeyguard( + runnable = { runnable?.let { postOnUiThread(runnable = it) } }, + ) + } + } + + private fun postOnUiThread(delay: Int = 0, runnable: Runnable) { + mainExecutor.executeDelayed(runnable, delay.toLong()) + } + + /** + * Encapsulates the activity logic for activity starter. + * + * Logic is duplicated in {@link CentralSurfacesImpl} + */ + private inner class ActivityStarterInternal { + /** Starts an activity after dismissing keyguard. */ + fun startActivityDismissingKeyguard( + intent: Intent, + onlyProvisioned: Boolean = false, + dismissShade: Boolean = false, + disallowEnterPictureInPictureWhileLaunching: Boolean = false, + callback: ActivityStarter.Callback? = null, + flags: Int = 0, + animationController: ActivityLaunchAnimator.Controller? = null, + userHandle: UserHandle? = null, + customMessage: String? = null, + ) { + val userHandle: UserHandle = userHandle ?: getActivityUserHandle(intent) + + if (onlyProvisioned && !deviceProvisionedController.isDeviceProvisioned) return + + val willLaunchResolverActivity: Boolean = + activityIntentHelper.wouldLaunchResolverActivity( + intent, + lockScreenUserManager.currentUserId + ) + + val animate = + animationController != null && + !willLaunchResolverActivity && + centralSurfaces?.shouldAnimateLaunch(true /* isActivityIntent */) == true + val animController = + wrapAnimationController( + animationController = animationController, + dismissShade = dismissShade, + isLaunchForActivity = true, + ) + + // If we animate, we will dismiss the shade only once the animation is done. This is + // taken care of by the StatusBarLaunchAnimationController. + val dismissShadeDirectly = dismissShade && animController == null + + val runnable = Runnable { + assistManagerLazy.get().hideAssist() + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + intent.addFlags(flags) + val result = intArrayOf(ActivityManager.START_CANCELED) + activityLaunchAnimator.startIntentWithAnimation( + animController, + animate, + intent.getPackage() + ) { adapter: RemoteAnimationAdapter? -> + val options = + ActivityOptions( + CentralSurfaces.getActivityOptions(centralSurfaces!!.displayId, adapter) + ) + + // We know that the intent of the caller is to dismiss the keyguard and + // this runnable is called right after the keyguard is solved, so we tell + // WM that we should dismiss it to avoid flickers when opening an activity + // that can also be shown over the keyguard. + options.setDismissKeyguard() + options.setDisallowEnterPictureInPictureWhileLaunching( + disallowEnterPictureInPictureWhileLaunching + ) + if (isInsecureCameraIntent(intent)) { + // Normally an activity will set it's requested rotation + // animation on its window. However when launching an activity + // causes the orientation to change this is too late. In these cases + // the default animation is used. This doesn't look good for + // the camera (as it rotates the camera contents out of sync + // with physical reality). So, we ask the WindowManager to + // force the cross fade animation if an orientation change + // happens to occur during the launch. + options.rotationAnimationHint = + WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS + } + if (Settings.Panel.ACTION_VOLUME == intent.action) { + // Settings Panel is implemented as activity(not a dialog), so + // underlying app is paused and may enter picture-in-picture mode + // as a result. + // So we need to disable picture-in-picture mode here + // if it is volume panel. + options.setDisallowEnterPictureInPictureWhileLaunching(true) + } + try { + result[0] = + ActivityTaskManager.getService() + .startActivityAsUser( + null, + context.basePackageName, + context.attributionTag, + intent, + intent.resolveTypeIfNeeded(context.contentResolver), + null, + null, + 0, + Intent.FLAG_ACTIVITY_NEW_TASK, + null, + options.toBundle(), + userHandle.identifier, + ) + } catch (e: RemoteException) { + Log.w(TAG, "Unable to start activity", e) + } + result[0] + } + callback?.onActivityStarted(result[0]) + } + val cancelRunnable = Runnable { + callback?.onActivityStarted(ActivityManager.START_CANCELED) + } + // Do not deferKeyguard when occluded because, when keyguard is occluded, + // we do not launch the activity until keyguard is done. + val occluded = (keyguardStateController.isShowing && keyguardStateController.isOccluded) + val deferred = !occluded + executeRunnableDismissingKeyguard( + runnable, + cancelRunnable, + dismissShadeDirectly, + willLaunchResolverActivity, + deferred, + animate, + customMessage, + ) + } + + /** Starts a pending intent after dismissing keyguard. */ + fun startPendingIntentDismissingKeyguard( + intent: PendingIntent, + intentSentUiThreadCallback: Runnable? = null, + associatedView: View? = null, + animationController: ActivityLaunchAnimator.Controller? = null, + ) { + val animationController = + if (associatedView is ExpandableNotificationRow) { + centralSurfaces?.getAnimatorControllerFromNotification(associatedView) + } else animationController + + val willLaunchResolverActivity = + (intent.isActivity && + activityIntentHelper.wouldPendingLaunchResolverActivity( + intent, + lockScreenUserManager.currentUserId, + )) + + val animate = + !willLaunchResolverActivity && + animationController != null && + centralSurfaces?.shouldAnimateLaunch(intent.isActivity) == true + + // If we animate, don't collapse the shade and defer the keyguard dismiss (in case we + // run the animation on the keyguard). The animation will take care of (instantly) + // collapsing the shade and hiding the keyguard once it is done. + val collapse = !animate + executeRunnableDismissingKeyguard( + runnable = { + try { + // We wrap animationCallback with a StatusBarLaunchAnimatorController so + // that the shade is collapsed after the animation (or when it is cancelled, + // aborted, etc). + val controller: ActivityLaunchAnimator.Controller? = + wrapAnimationController( + animationController = animationController, + dismissShade = true, + isLaunchForActivity = intent.isActivity, + ) + activityLaunchAnimator.startPendingIntentWithAnimation( + controller, + animate, + intent.creatorPackage, + object : PendingIntentStarter { + override fun startPendingIntent( + animationAdapter: RemoteAnimationAdapter? + ): Int { + val options = + ActivityOptions( + CentralSurfaces.getActivityOptions( + centralSurfaces!!.displayId, + animationAdapter + ) + ) + // TODO b/221255671: restrict this to only be set for + // notifications + options.isEligibleForLegacyPermissionPrompt = true + return intent.sendAndReturnResult( + null, + 0, + null, + null, + null, + null, + options.toBundle() + ) + } + }, + ) + } catch (e: PendingIntent.CanceledException) { + // the stack trace isn't very helpful here. + // Just log the exception message. + Log.w(TAG, "Sending intent failed: $e") + if (!collapse) { + // executeRunnableDismissingKeyguard did not collapse for us already. + centralSurfaces?.collapsePanelOnMainThread() + } + // TODO: Dismiss Keyguard. + } + if (intent.isActivity) { + assistManagerLazy.get().hideAssist() + } + intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) } + }, + afterKeyguardGone = willLaunchResolverActivity, + dismissShade = collapse, + willAnimateOnKeyguard = animate, + ) + } + + /** Starts an Activity. */ + fun startActivity( + intent: Intent, + dismissShade: Boolean = false, + animationController: ActivityLaunchAnimator.Controller? = null, + showOverLockscreenWhenLocked: Boolean = false, + userHandle: UserHandle? = null, + ) { + val userHandle = userHandle ?: getActivityUserHandle(intent) + // Make sure that we dismiss the keyguard if it is directly dismissible or when we don't + // want to show the activity above it. + if (keyguardStateController.isUnlocked || !showOverLockscreenWhenLocked) { + startActivityDismissingKeyguard( + intent = intent, + onlyProvisioned = false, + dismissShade = dismissShade, + disallowEnterPictureInPictureWhileLaunching = false, + callback = null, + flags = 0, + animationController = animationController, + userHandle = userHandle, + ) + return + } + + val animate = + animationController != null && + centralSurfaces?.shouldAnimateLaunch( + /* isActivityIntent= */ true, + showOverLockscreenWhenLocked + ) == true + + var controller: ActivityLaunchAnimator.Controller? = null + if (animate) { + // Wrap the animation controller to dismiss the shade and set + // mIsLaunchingActivityOverLockscreen during the animation. + val delegate = + wrapAnimationController( + animationController = animationController, + dismissShade = dismissShade, + isLaunchForActivity = true, + ) + delegate?.let { + controller = + object : DelegateLaunchAnimatorController(delegate) { + override fun onIntentStarted(willAnimate: Boolean) { + delegate?.onIntentStarted(willAnimate) + if (willAnimate) { + centralSurfaces?.setIsLaunchingActivityOverLockscreen(true) + } + } + + override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { + super.onLaunchAnimationStart(isExpandingFullyAbove) + + // Double check that the keyguard is still showing and not going + // away, but if so set the keyguard occluded. Typically, WM will let + // KeyguardViewMediator know directly, but we're overriding that to + // play the custom launch animation, so we need to take care of that + // here. The unocclude animation is not overridden, so WM will call + // KeyguardViewMediator's unocclude animation runner when the + // activity is exited. + if ( + keyguardStateController.isShowing && + !keyguardStateController.isKeyguardGoingAway + ) { + Log.d(TAG, "Setting occluded = true in #startActivity.") + keyguardViewMediatorLazy + .get() + .setOccluded(true /* isOccluded */, true /* animate */) + } + } + + override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { + // Set mIsLaunchingActivityOverLockscreen to false before actually + // finishing the animation so that we can assume that + // mIsLaunchingActivityOverLockscreen being true means that we will + // collapse the shade (or at least run the post collapse runnables) + // later on. + centralSurfaces?.setIsLaunchingActivityOverLockscreen(false) + delegate?.onLaunchAnimationEnd(isExpandingFullyAbove) + } + + override fun onLaunchAnimationCancelled( + newKeyguardOccludedState: Boolean? + ) { + if (newKeyguardOccludedState != null) { + keyguardViewMediatorLazy + .get() + .setOccluded(newKeyguardOccludedState, false /* animate */) + } + + // Set mIsLaunchingActivityOverLockscreen to false before actually + // finishing the animation so that we can assume that + // mIsLaunchingActivityOverLockscreen being true means that we will + // collapse the shade (or at least run the // post collapse + // runnables) later on. + centralSurfaces?.setIsLaunchingActivityOverLockscreen(false) + delegate.onLaunchAnimationCancelled(newKeyguardOccludedState) + } + } + } + } else if (dismissShade) { + // The animation will take care of dismissing the shade at the end of the animation. + // If we don't animate, collapse it directly. + centralSurfaces?.collapseShade() + } + + // We should exit the dream to prevent the activity from starting below the + // dream. + if (keyguardUpdateMonitor.isDreaming) { + centralSurfaces?.awakenDreams() + } + + activityLaunchAnimator.startIntentWithAnimation( + controller, + animate, + intent.getPackage(), + showOverLockscreenWhenLocked + ) { adapter: RemoteAnimationAdapter? -> + TaskStackBuilder.create(context) + .addNextIntent(intent) + .startActivities( + CentralSurfaces.getActivityOptions(centralSurfaces!!.displayId, adapter), + userHandle + ) + } + } + + /** Executes an action after dismissing keyguard. */ + fun dismissKeyguardThenExecute( + action: OnDismissAction, + cancel: Runnable? = null, + afterKeyguardGone: Boolean = false, + customMessage: String? = null, + ) { + if ( + !action.willRunAnimationOnKeyguard() && + wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP && + keyguardStateController.canDismissLockScreen() && + !statusBarStateController.leaveOpenOnKeyguardHide() && + dozeServiceHostLazy.get().isPulsing + ) { + // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a + // pulse. + // TODO: Factor this transition out of BiometricUnlockController. + biometricUnlockControllerLazy + .get() + .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) + } + if (keyguardStateController.isShowing) { + statusBarKeyguardViewManagerLazy + .get() + .dismissWithAction(action, cancel, afterKeyguardGone, customMessage) + } else { + // If the keyguard isn't showing but the device is dreaming, we should exit the + // dream. + if (keyguardUpdateMonitor.isDreaming) { + centralSurfaces?.awakenDreams() + } + action.onDismiss() + } + } + + /** Executes an action after dismissing keyguard. */ + fun executeRunnableDismissingKeyguard( + runnable: Runnable? = null, + cancelAction: Runnable? = null, + dismissShade: Boolean = false, + afterKeyguardGone: Boolean = false, + deferred: Boolean = false, + willAnimateOnKeyguard: Boolean = false, + customMessage: String? = null, + ) { + val onDismissAction: OnDismissAction = + object : OnDismissAction { + override fun onDismiss(): Boolean { + if (runnable != null) { + if ( + keyguardStateController.isShowing && + keyguardStateController.isOccluded + ) { + statusBarKeyguardViewManagerLazy + .get() + .addAfterKeyguardGoneRunnable(runnable) + } else { + mainExecutor.execute(runnable) + } + } + if (dismissShade) { + if ( + shadeControllerLazy.get().isExpandedVisible && + !statusBarKeyguardViewManagerLazy.get().isBouncerShowing + ) { + shadeControllerLazy.get().animateCollapseShadeDelayed() + } else { + // Do it after DismissAction has been processed to conserve the + // needed ordering. + postOnUiThread { + shadeControllerLazy.get().runPostCollapseRunnables() + } + } + } + return deferred + } + + override fun willRunAnimationOnKeyguard(): Boolean { + return willAnimateOnKeyguard + } + } + dismissKeyguardThenExecute( + onDismissAction, + cancelAction, + afterKeyguardGone, + customMessage, + ) + } + + /** + * Return a [ActivityLaunchAnimator.Controller] wrapping `animationController` so that: + * - if it launches in the notification shade window and `dismissShade` is true, then the + * shade will be instantly dismissed at the end of the animation. + * - if it launches in status bar window, it will make the status bar window match the + * device size during the animation (that way, the animation won't be clipped by the + * status bar size). + * + * @param animationController the controller that is wrapped and will drive the main + * animation. + * @param dismissShade whether the notification shade will be dismissed at the end of the + * animation. This is ignored if `animationController` is not animating in the shade + * window. + * @param isLaunchForActivity whether the launch is for an activity. + */ + private fun wrapAnimationController( + animationController: ActivityLaunchAnimator.Controller?, + dismissShade: Boolean, + isLaunchForActivity: Boolean, + ): ActivityLaunchAnimator.Controller? { + if (animationController == null) { + return null + } + val rootView = animationController.launchContainer.rootView + val controllerFromStatusBar: Optional<ActivityLaunchAnimator.Controller> = + statusBarWindowController.wrapAnimationControllerIfInStatusBar( + rootView, + animationController + ) + if (controllerFromStatusBar.isPresent) { + return controllerFromStatusBar.get() + } + + centralSurfaces?.let { + // If the view is not in the status bar, then we are animating a view in the shade. + // We have to make sure that we collapse it when the animation ends or is cancelled. + if (dismissShade) { + return StatusBarLaunchAnimatorController( + animationController, + it, + isLaunchForActivity + ) + } + } + + return animationController + } + + /** Retrieves the current user handle to start the Activity. */ + private fun getActivityUserHandle(intent: Intent): UserHandle { + val packages: Array<String> = + context.resources.getStringArray(R.array.system_ui_packages) + for (pkg in packages) { + if (intent.component == null) break + if (pkg == intent.component.packageName) { + return UserHandle(UserHandle.myUserId()) + } + } + return userTracker.userHandle + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index f579d304b268..4e690696b5d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -45,7 +45,8 @@ import com.android.systemui.Dumpable; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.RemoteTransitionAdapter; import com.android.systemui.navigationbar.NavigationBarView; -import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.ActivityStarter.Callback; +import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.qs.QSPanelController; import com.android.systemui.shade.NotificationShadeWindowView; @@ -53,11 +54,13 @@ import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.LightRevealScrim; import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.util.Compile; import java.io.PrintWriter; -public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwner { +/** */ +public interface CentralSurfaces extends Dumpable, LifecycleOwner { boolean MULTIUSER_DEBUG = false; // Should match the values in PhoneWindowManager String SYSTEM_DIALOG_REASON_KEY = "reason"; @@ -230,29 +233,33 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn boolean isShadeDisabled(); - @Override + /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */ void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags); - @Override + /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */ void startActivity(Intent intent, boolean dismissShade); - @Override + /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */ + void startActivity(Intent intent, boolean dismissShade, + @Nullable ActivityLaunchAnimator.Controller animationController); + + /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */ void startActivity(Intent intent, boolean dismissShade, @Nullable ActivityLaunchAnimator.Controller animationController, boolean showOverLockscreenWhenLocked); - @Override + /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */ void startActivity(Intent intent, boolean dismissShade, @Nullable ActivityLaunchAnimator.Controller animationController, boolean showOverLockscreenWhenLocked, UserHandle userHandle); boolean isLaunchingActivityOverLockscreen(); - @Override + /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */ void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade); - @Override + /** Starts an activity. Please use ActivityStarter instead of using these methods directly. */ void startActivity(Intent intent, boolean dismissShade, Callback callback); boolean isWakeUpComingFromTouch(); @@ -315,19 +322,34 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn float getDisplayHeight(); + /** Starts an activity intent that dismisses keyguard. + * + * Please use ActivityStarter instead of using these methods directly. + */ void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags); + /** Starts an activity intent that dismisses keyguard. + * + * Please use ActivityStarter instead of using these methods directly. + */ void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, boolean dismissShade); + /** Starts an activity intent that dismisses keyguard. + * + * Please use ActivityStarter instead of using these methods directly. + */ void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching, Callback callback, int flags, @Nullable ActivityLaunchAnimator.Controller animationController, UserHandle userHandle); - /** Starts an activity intent that dismisses keyguard. */ + /** Starts an activity intent that dismisses keyguard. + * + * Please use ActivityStarter instead of using these methods directly. + */ void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching, Callback callback, int flags, @@ -352,29 +374,70 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void resetUserExpandedStates(); - @Override + /** + * Dismisses Keyguard and executes an action afterwards. + * + * Please use ActivityStarter instead of using these methods directly. + */ void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone); + /** + * Dismisses Keyguard and executes an action afterwards. + * + * Please use ActivityStarter instead of using these methods directly. + */ + void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, + boolean afterKeyguardGone, @Nullable String customMessage); + void setLockscreenUser(int newUserId); - @Override + /** + * Starts a QS runnable on the main thread and dismisses keyguard. + * + * Please use ActivityStarter instead of using these methods directly. + */ void postQSRunnableDismissingKeyguard(Runnable runnable); - @Override + /** + * Starts an activity on the main thread with a delay. + * + * Please use ActivityStarter instead of using these methods directly. + */ void postStartActivityDismissingKeyguard(PendingIntent intent); - @Override + /** + * Starts an activity on the main thread with a delay. + * + * Please use ActivityStarter instead of using these methods directly. + */ void postStartActivityDismissingKeyguard(PendingIntent intent, @Nullable ActivityLaunchAnimator.Controller animationController); - @Override + /** + * Starts an activity on the main thread with a delay. + * + * Please use ActivityStarter instead of using these methods directly. + */ void postStartActivityDismissingKeyguard(Intent intent, int delay); - @Override + /** + * Starts an activity on the main thread with a delay. + * + * Please use ActivityStarter instead of using these methods directly. + */ void postStartActivityDismissingKeyguard(Intent intent, int delay, @Nullable ActivityLaunchAnimator.Controller animationController); + /** + * Starts an activity on the main thread with a delay. + * + * Please use ActivityStarter instead of using these methods directly. + */ + void postStartActivityDismissingKeyguard(Intent intent, int delay, + @Nullable ActivityLaunchAnimator.Controller animationController, + @Nullable String customMessage); + void showKeyguard(); boolean hideKeyguard(); @@ -468,18 +531,14 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void awakenDreams(); - @Override void startPendingIntentDismissingKeyguard(PendingIntent intent); - @Override void startPendingIntentDismissingKeyguard( PendingIntent intent, @Nullable Runnable intentSentUiThreadCallback); - @Override void startPendingIntentDismissingKeyguard(PendingIntent intent, Runnable intentSentUiThreadCallback, View associatedView); - @Override void startPendingIntentDismissingKeyguard( PendingIntent intent, @Nullable Runnable intentSentUiThreadCallback, @Nullable ActivityLaunchAnimator.Controller animationController); @@ -554,4 +613,15 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn mDeviceId = deviceId; } } + + /** + * Sets launching activity over LS state in central surfaces. + */ + void setIsLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen); + + /** + * Gets an animation controller from a notification row. + */ + ActivityLaunchAnimator.Controller getAnimatorControllerFromNotification( + ExpandableNotificationRow associatedView); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index c0a7a34a3a1e..37e77766c889 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -50,6 +50,7 @@ import com.android.systemui.camera.CameraIntents; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QSPanelController; import com.android.systemui.settings.UserTracker; @@ -102,6 +103,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba private final boolean mVibrateOnOpening; private final VibrationEffect mCameraLaunchGestureVibrationEffect; private final SystemBarAttributesListener mSystemBarAttributesListener; + private final ActivityStarter mActivityStarter; private final Lazy<CameraLauncher> mCameraLauncherLazy; private final QuickSettingsController mQsController; private final QSHost mQSHost; @@ -138,7 +140,8 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba SystemBarAttributesListener systemBarAttributesListener, Lazy<CameraLauncher> cameraLauncherLazy, UserTracker userTracker, - QSHost qsHost) { + QSHost qsHost, + ActivityStarter activityStarter) { mCentralSurfaces = centralSurfaces; mQsController = quickSettingsController; mContext = context; @@ -170,6 +173,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect( mVibratorOptional, resources); mSystemBarAttributesListener = systemBarAttributesListener; + mActivityStarter = activityStarter; } @Override @@ -375,7 +379,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba if (!mKeyguardStateController.isShowing()) { final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext); cameraIntent.putExtra(CameraIntents.EXTRA_LAUNCH_SOURCE, source); - mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent, + mActivityStarter.startActivityDismissingKeyguard(cameraIntent, false /* onlyProvisioned */, true /* dismissShade */, true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, null /* animationController */, mUserTracker.getUserHandle()); @@ -432,7 +436,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba // app-side haptic experimentation. if (!mKeyguardStateController.isShowing()) { - mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent, + mActivityStarter.startActivityDismissingKeyguard(emergencyIntent, false /* onlyProvisioned */, true /* dismissShade */, true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, null /* animationController */, mUserTracker.getUserHandle()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index e1c806401ea4..aa5aed7451f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -168,6 +168,8 @@ import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.notetask.NoteTaskController; +import com.android.systemui.plugins.ActivityStarter.Callback; +import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.OverlayPlugin; @@ -281,6 +283,9 @@ import javax.inject.Provider; * <b>If at all possible, please avoid adding additional code to this monstrous class! Our goal is * to break up this class into many small classes, and any code added here will slow down that goal. * </b> + * + * Note that ActivityStarter logic here is deprecated and should be added here as well as + * {@link ActivityStarterImpl} */ @SysUISingleton public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @@ -1790,17 +1795,27 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags) { startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivity(Intent intent, boolean dismissShade) { startActivityDismissingKeyguard(intent, false /* onlyProvisioned */, dismissShade); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ + @Override + public void startActivity(Intent intent, boolean dismissShade, + @androidx.annotation.Nullable ActivityLaunchAnimator.Controller animationController) { + startActivity(intent, dismissShade, animationController, false); + } + + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivity(Intent intent, boolean dismissShade, @Nullable ActivityLaunchAnimator.Controller animationController, @@ -1809,6 +1824,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { getActivityUserHandle(intent)); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivity(Intent intent, boolean dismissShade, @Nullable ActivityLaunchAnimator.Controller animationController, @@ -2406,6 +2422,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return mDisplayId; } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags) { @@ -2414,12 +2431,14 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { flags, null /* animationController */, getActivityUserHandle(intent)); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, boolean dismissShade) { startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned, boolean dismissShade, boolean disallowEnterPictureInPictureWhileLaunching, @@ -2431,6 +2450,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { userHandle, null /* customMessage */); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned, final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching, @@ -2541,6 +2561,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { * animation. This is ignored if {@code animationController} is not * animating in the shade window. * @param isLaunchForActivity whether the launch is for an activity. + * + * Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Nullable private ActivityLaunchAnimator.Controller wrapAnimationController( @@ -2570,6 +2592,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mStatusBarKeyguardViewManager.readyForKeyguardDone(); } + + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void executeRunnableDismissingKeyguard(final Runnable runnable, final Runnable cancelAction, @@ -2580,6 +2604,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { deferred, false /* willAnimateOnKeyguard */, null /* customMessage */); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void executeRunnableDismissingKeyguard(final Runnable runnable, final Runnable cancelAction, @@ -2690,16 +2715,19 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { afterKeyguardGone /* afterKeyguardGone */); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) { dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone) { dismissKeyguardThenExecute(action, cancelAction, afterKeyguardGone, null); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone, String customMessage) { @@ -2901,6 +2929,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { | ((currentlyInsecure ? 1 : 0) << 12); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void postQSRunnableDismissingKeyguard(final Runnable runnable) { mMainExecutor.execute(() -> { @@ -2910,11 +2939,13 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { }); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void postStartActivityDismissingKeyguard(PendingIntent intent) { postStartActivityDismissingKeyguard(intent, null /* animationController */); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void postStartActivityDismissingKeyguard(final PendingIntent intent, @Nullable ActivityLaunchAnimator.Controller animationController) { @@ -2922,11 +2953,13 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { null /* intentSentUiThreadCallback */, animationController)); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void postStartActivityDismissingKeyguard(final Intent intent, int delay) { postStartActivityDismissingKeyguard(intent, delay, null /* animationController */); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void postStartActivityDismissingKeyguard(Intent intent, int delay, @Nullable ActivityLaunchAnimator.Controller animationController) { @@ -2934,6 +2967,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { null /* customMessage */); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void postStartActivityDismissingKeyguard(Intent intent, int delay, @Nullable ActivityLaunchAnimator.Controller animationController, @@ -4081,11 +4115,13 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { dismissKeyguardThenExecute(onDismissAction, afterKeyguardGone); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startPendingIntentDismissingKeyguard(final PendingIntent intent) { startPendingIntentDismissingKeyguard(intent, null); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startPendingIntentDismissingKeyguard( final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) { @@ -4093,6 +4129,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { (ActivityLaunchAnimator.Controller) null); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startPendingIntentDismissingKeyguard(PendingIntent intent, Runnable intentSentUiThreadCallback, View associatedView) { @@ -4106,6 +4143,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { animationController); } + /** Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ @Override public void startPendingIntentDismissingKeyguard( final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback, @@ -4529,6 +4567,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { * launched as user of the current process. * @param intent * @return UserHandle + * + * Logic is duplicated in {@link ActivityStarterImpl}. Please add it there too. */ private UserHandle getActivityUserHandle(Intent intent) { String[] packages = mContext.getResources().getStringArray(R.array.system_ui_packages); @@ -4551,4 +4591,15 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { && mBiometricUnlockController.getMode() != BiometricUnlockController.MODE_WAKE_AND_UNLOCK; } + + @Override + public void setIsLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) { + mIsLaunchingActivityOverLockscreen = isLaunchingActivityOverLockscreen; + } + + @Override + public ActivityLaunchAnimator.Controller getAnimatorControllerFromNotification( + ExpandableNotificationRow associatedView) { + return mNotificationAnimationProvider.getAnimatorController(associatedView); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index f7646d718dc6..89dddbf1f573 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -68,6 +68,7 @@ import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.TaskbarDelegate; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeExpansionChangeEvent; @@ -284,6 +285,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mIsBackAnimationEnabled; private final boolean mUdfpsNewTouchDetectionEnabled; private final UdfpsOverlayInteractor mUdfpsOverlayInteractor; + private final ActivityStarter mActivityStarter; private OnDismissAction mAfterKeyguardGoneAction; private Runnable mKeyguardGoneCancelAction; @@ -339,7 +341,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb PrimaryBouncerInteractor primaryBouncerInteractor, BouncerView primaryBouncerView, AlternateBouncerInteractor alternateBouncerInteractor, - UdfpsOverlayInteractor udfpsOverlayInteractor + UdfpsOverlayInteractor udfpsOverlayInteractor, + ActivityStarter activityStarter ) { mContext = context; mViewMediatorCallback = callback; @@ -367,6 +370,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM); mUdfpsNewTouchDetectionEnabled = featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION); mUdfpsOverlayInteractor = udfpsOverlayInteractor; + mActivityStarter = activityStarter; } @Override @@ -1006,7 +1010,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void dismissAndCollapse() { - mCentralSurfaces.executeRunnableDismissingKeyguard(null, null, true, false, true); + mActivityStarter.executeRunnableDismissingKeyguard( + /* runnable= */ null, + /* cancelAction= */ null, + /* dismissShade= */ true, + /* afterKeyguardGone= */ false, + /* deferred= */ true + ); } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java index 7d583258e4e5..9ea30d676dc5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java @@ -39,9 +39,9 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.FakeDisplayTracker; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.statusbar.phone.CentralSurfaces; import org.junit.Before; import org.junit.Test; @@ -50,22 +50,20 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; -import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @RunWith(AndroidTestingRunner.class) @SmallTest public class ActionProxyReceiverTest extends SysuiTestCase { - - @Mock - private CentralSurfaces mMockCentralSurfaces; @Mock private ActivityManagerWrapper mMockActivityManagerWrapper; @Mock private ScreenshotSmartActions mMockScreenshotSmartActions; @Mock private PendingIntent mMockPendingIntent; + @Mock + private ActivityStarter mActivityStarter; private Intent mIntent; private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext); @@ -78,32 +76,19 @@ public class ActionProxyReceiverTest extends SysuiTestCase { } @Test - public void testPendingIntentSentWithoutStatusBar() throws PendingIntent.CanceledException { - ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(false); - - actionProxyReceiver.onReceive(mContext, mIntent); - - verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT); - verify(mMockCentralSurfaces, never()).executeRunnableDismissingKeyguard( - any(Runnable.class), any(Runnable.class), anyBoolean(), anyBoolean(), anyBoolean()); - verify(mMockPendingIntent).send( - eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); - } - - @Test public void testPendingIntentSentWithStatusBar() throws PendingIntent.CanceledException { - ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true); + ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(); // ensure that the pending intent call is passed through doAnswer((Answer<Object>) invocation -> { ((Runnable) invocation.getArgument(0)).run(); return null; - }).when(mMockCentralSurfaces).executeRunnableDismissingKeyguard( + }).when(mActivityStarter).executeRunnableDismissingKeyguard( any(Runnable.class), isNull(), anyBoolean(), anyBoolean(), anyBoolean()); actionProxyReceiver.onReceive(mContext, mIntent); verify(mMockActivityManagerWrapper).closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT); - verify(mMockCentralSurfaces).executeRunnableDismissingKeyguard( + verify(mActivityStarter).executeRunnableDismissingKeyguard( any(Runnable.class), isNull(), eq(true), eq(true), eq(true)); verify(mMockPendingIntent).send( eq(mContext), anyInt(), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); @@ -111,7 +96,7 @@ public class ActionProxyReceiverTest extends SysuiTestCase { @Test public void testSmartActionsNotNotifiedByDefault() { - ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true); + ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(); actionProxyReceiver.onReceive(mContext, mIntent); @@ -122,7 +107,7 @@ public class ActionProxyReceiverTest extends SysuiTestCase { @Test public void testSmartActionsNotifiedIfEnabled() { - ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(true); + ActionProxyReceiver actionProxyReceiver = constructActionProxyReceiver(); mIntent.putExtra(EXTRA_SMART_ACTIONS_ENABLED, true); String testId = "testID"; mIntent.putExtra(EXTRA_ID, testId); @@ -133,15 +118,12 @@ public class ActionProxyReceiverTest extends SysuiTestCase { testId, ACTION_TYPE_SHARE, false, null); } - private ActionProxyReceiver constructActionProxyReceiver(boolean withStatusBar) { - if (withStatusBar) { - return new ActionProxyReceiver( - Optional.of(mMockCentralSurfaces), mMockActivityManagerWrapper, - mMockScreenshotSmartActions, mDisplayTracker); - } else { - return new ActionProxyReceiver( - Optional.empty(), mMockActivityManagerWrapper, mMockScreenshotSmartActions, - mDisplayTracker); - } + private ActionProxyReceiver constructActionProxyReceiver() { + return new ActionProxyReceiver( + mMockActivityManagerWrapper, + mMockScreenshotSmartActions, + mDisplayTracker, + mActivityStarter + ); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index d017ffd08a4b..2106da887b44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -11,6 +11,7 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.media.controls.ui.MediaHierarchyManager +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QS import com.android.systemui.shade.ShadeViewController @@ -79,6 +80,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController + @Mock lateinit var activityStarter: ActivityStarter @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback @JvmField @Rule val mockito = MockitoJUnit.rule() @@ -124,6 +126,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { dumpManager) }, qsTransitionControllerFactory = { qsTransitionController }, + activityStarter = activityStarter, ) transitionController.addCallback(transitionControllerCallback) whenever(nsslController.view).thenReturn(stackscroller) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 4bb2c8740d44..3cefc9973d09 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -67,6 +67,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.SysuiTestCase; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.settings.UserContextProvider; @@ -80,7 +81,6 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.wmshell.BubblesManager; @@ -120,7 +120,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private NotificationListContainer mNotificationListContainer; @Mock private OnSettingsClickListener mOnSettingsClickListener; @Mock private DeviceProvisionedController mDeviceProvisionedController; - @Mock private CentralSurfaces mCentralSurfaces; @Mock private AccessibilityManager mAccessibilityManager; @Mock private HighPriorityProvider mHighPriorityProvider; @Mock private INotificationManager mINotificationManager; @@ -136,6 +135,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager; @Mock private StatusBarStateController mStatusBarStateController; @Mock private HeadsUpManagerPhone mHeadsUpManagerPhone; + @Mock private ActivityStarter mActivityStarter; @Before public void setUp() { @@ -145,8 +145,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this)); when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); - mGutsManager = new NotificationGutsManager(mContext, - () -> Optional.of(mCentralSurfaces), mHandler, mHandler, mAccessibilityManager, + mGutsManager = new NotificationGutsManager(mContext, mHandler, mHandler, + mAccessibilityManager, mHighPriorityProvider, mINotificationManager, mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager, mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController, @@ -156,7 +156,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mStatusBarStateController, mDeviceProvisionedController, mMetricsLogger, - mHeadsUpManagerPhone); + mHeadsUpManagerPhone, mActivityStarter); mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 420c7ae3d2ec..6a0e3c6d51eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -48,6 +48,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.media.controls.ui.KeyguardMediaController; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -143,6 +144,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private NotificationTargetsHelper mNotificationTargetsHelper; @Mock private SecureSettings mSecureSettings; @Mock private NotificationIconAreaController mIconAreaController; + @Mock private ActivityStarter mActivityStarter; @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor; @@ -491,7 +493,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mFeatureFlags, mNotificationTargetsHelper, mSecureSettings, - mock(NotificationDismissibilityProvider.class) + mock(NotificationDismissibilityProvider.class), + mActivityStarter ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt new file mode 100644 index 000000000000..b6b28c9e4527 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt @@ -0,0 +1,255 @@ +/* + * 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.statusbar.phone + +import android.app.PendingIntent +import android.content.Intent +import android.os.RemoteException +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.ActivityIntentHelper +import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.assist.AssistManager +import com.android.systemui.keyguard.KeyguardViewMediator +import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.plugins.ActivityStarter.OnDismissAction +import com.android.systemui.settings.UserTracker +import com.android.systemui.shade.ShadeController +import com.android.systemui.statusbar.NotificationLockscreenUserManager +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.window.StatusBarWindowController +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import dagger.Lazy +import java.util.Optional +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.anyBoolean +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class ActivityStarterImplTest : SysuiTestCase() { + @Mock private lateinit var centralSurfaces: CentralSurfaces + @Mock private lateinit var assistManager: AssistManager + @Mock private lateinit var dozeServiceHost: DozeServiceHost + @Mock private lateinit var biometricUnlockController: BiometricUnlockController + @Mock private lateinit var keyguardViewMediator: KeyguardViewMediator + @Mock private lateinit var shadeController: ShadeController + @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager + @Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator + @Mock private lateinit var lockScreenUserManager: NotificationLockscreenUserManager + @Mock private lateinit var statusBarWindowController: StatusBarWindowController + @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle + @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var activityIntentHelper: ActivityIntentHelper + private lateinit var underTest: ActivityStarterImpl + private val mainExecutor = FakeExecutor(FakeSystemClock()) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + underTest = + ActivityStarterImpl( + Lazy { Optional.of(centralSurfaces) }, + Lazy { assistManager }, + Lazy { dozeServiceHost }, + Lazy { biometricUnlockController }, + Lazy { keyguardViewMediator }, + Lazy { shadeController }, + Lazy { statusBarKeyguardViewManager }, + activityLaunchAnimator, + context, + lockScreenUserManager, + statusBarWindowController, + wakefulnessLifecycle, + keyguardStateController, + statusBarStateController, + keyguardUpdateMonitor, + deviceProvisionedController, + userTracker, + activityIntentHelper, + mainExecutor, + ) + } + + @Test + fun startPendingIntentDismissingKeyguard_keyguardShowing_dismissWithAction() { + val pendingIntent = mock(PendingIntent::class.java) + whenever(keyguardStateController.isShowing).thenReturn(true) + whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) + + underTest.startPendingIntentDismissingKeyguard(pendingIntent) + + verify(statusBarKeyguardViewManager) + .dismissWithAction(any(OnDismissAction::class.java), eq(null), anyBoolean(), eq(null)) + } + + @Test + fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() { + val pendingIntent = mock(PendingIntent::class.java) + val associatedView = mock(ExpandableNotificationRow::class.java) + + underTest.startPendingIntentDismissingKeyguard( + intent = pendingIntent, + intentSentUiThreadCallback = null, + associatedView = associatedView, + ) + + verify(centralSurfaces).getAnimatorControllerFromNotification(associatedView) + } + + @Test + fun startActivity_noUserHandleProvided_getUserHandle() { + val intent = mock(Intent::class.java) + + underTest.startActivity(intent, false) + + verify(userTracker).userHandle + } + + @Test + fun postStartActivityDismissingKeyguard_pendingIntent_postsOnMain() { + val intent = mock(PendingIntent::class.java) + + underTest.postStartActivityDismissingKeyguard(intent) + + assertThat(mainExecutor.numPending()).isEqualTo(1) + } + + @Test + fun postStartActivityDismissingKeyguard_intent_postsOnMain() { + val intent = mock(Intent::class.java) + + underTest.postStartActivityDismissingKeyguard(intent, 0) + + assertThat(mainExecutor.numPending()).isEqualTo(1) + } + + @Test + fun dismissKeyguardThenExecute_startWakeAndUnlock() { + whenever(wakefulnessLifecycle.wakefulness) + .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP) + whenever(keyguardStateController.canDismissLockScreen()).thenReturn(true) + whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) + whenever(dozeServiceHost.isPulsing).thenReturn(true) + + underTest.dismissKeyguardThenExecute({ true }, {}, false) + + verify(biometricUnlockController) + .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) + } + + @Test + fun dismissKeyguardThenExecute_keyguardIsShowing_dismissWithAction() { + val customMessage = "Enter your pin." + whenever(keyguardStateController.isShowing).thenReturn(true) + + underTest.dismissKeyguardThenExecute({ true }, {}, false, customMessage) + + verify(statusBarKeyguardViewManager) + .dismissWithAction( + any(OnDismissAction::class.java), + any(Runnable::class.java), + eq(false), + eq(customMessage) + ) + } + + @Test + fun dismissKeyguardThenExecute_awakeDreams() { + val customMessage = "Enter your pin." + var dismissActionExecuted = false + whenever(keyguardStateController.isShowing).thenReturn(false) + whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true) + + underTest.dismissKeyguardThenExecute( + { + dismissActionExecuted = true + true + }, + {}, + false, + customMessage + ) + + verify(centralSurfaces).awakenDreams() + assertThat(dismissActionExecuted).isTrue() + } + + @Test + @Throws(RemoteException::class) + fun executeRunnableDismissingKeyguard_dreaming_notShowing_awakenDreams() { + whenever(keyguardStateController.isShowing).thenReturn(false) + whenever(keyguardStateController.isOccluded).thenReturn(false) + whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true) + + underTest.executeRunnableDismissingKeyguard( + runnable = {}, + cancelAction = null, + dismissShade = false, + afterKeyguardGone = false, + deferred = false + ) + + verify(centralSurfaces, times(1)).awakenDreams() + } + + @Test + @Throws(RemoteException::class) + fun executeRunnableDismissingKeyguard_notDreaming_notShowing_doNotAwakenDreams() { + whenever(keyguardStateController.isShowing).thenReturn(false) + whenever(keyguardStateController.isOccluded).thenReturn(false) + whenever(keyguardUpdateMonitor.isDreaming).thenReturn(false) + + underTest.executeRunnableDismissingKeyguard( + runnable = {}, + cancelAction = null, + dismissShade = false, + afterKeyguardGone = false, + deferred = false + ) + + verify(centralSurfaces, never()).awakenDreams() + } + + @Test + fun postQSRunnableDismissingKeyguard_leaveOpenStatusBarState() { + underTest.postQSRunnableDismissingKeyguard {} + + assertThat(mainExecutor.numPending()).isEqualTo(1) + mainExecutor.runAllReady() + verify(statusBarStateController).setLeaveOpenOnKeyguardHide(true) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java index 872c5603b7a5..3870d996d2ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java @@ -43,6 +43,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.qs.QSHost; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.CameraLauncher; @@ -96,6 +97,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { @Mock private Lazy<CameraLauncher> mCameraLauncherLazy; @Mock private UserTracker mUserTracker; @Mock private QSHost mQSHost; + @Mock private ActivityStarter mActivityStarter; CentralSurfacesCommandQueueCallbacks mSbcqCallbacks; @@ -131,7 +133,8 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { mSystemBarAttributesListener, mCameraLauncherLazy, mUserTracker, - mQSHost); + mQSHost, + mActivityStarter); when(mUserTracker.getUserHandle()).thenReturn( UserHandle.of(ActivityManager.getCurrentUser())); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 4ff225cc7f3f..6be0e2deaf35 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -72,6 +72,7 @@ import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInt import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.TaskbarDelegate; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.ShadeController; @@ -129,6 +130,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor; @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor; @Mock private UdfpsOverlayInteractor mUdfpsOverlayInteractor; + @Mock private ActivityStarter mActivityStarter; @Mock private BouncerView mBouncerView; @Mock private BouncerViewDelegate mBouncerViewDelegate; @Mock private OnBackAnimationCallback mBouncerViewDelegateBackCallback; @@ -192,7 +194,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mPrimaryBouncerInteractor, mBouncerView, mAlternateBouncerInteractor, - mUdfpsOverlayInteractor) { + mUdfpsOverlayInteractor, + mActivityStarter) { @Override public ViewRootImpl getViewRootImpl() { return mViewRootImpl; @@ -680,7 +683,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mPrimaryBouncerInteractor, mBouncerView, mAlternateBouncerInteractor, - mUdfpsOverlayInteractor) { + mUdfpsOverlayInteractor, + mActivityStarter) { @Override public ViewRootImpl getViewRootImpl() { return mViewRootImpl; |