Merge changes from topic "activity-starter" into udc-dev

* changes:
  Add ActivityStarterImpl
  Add use_new_activity_starter feature flag
  Remove centralsurfaces activitystarter invocations
This commit is contained in:
Aaron Liu
2023-04-24 17:00:11 +00:00
committed by Android (Google) Code Review
24 changed files with 1470 additions and 143 deletions

View File

@@ -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);
}

View File

@@ -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
@@ -91,6 +93,14 @@ public class ActivityStarterDelegate implements ActivityStarter {
starter -> starter.startActivity(intent, dismissShade));
}
@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,
@@ -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));
}
}

View File

@@ -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;
}

View File

@@ -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")
}

View File

@@ -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 */);

View File

@@ -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())

View File

@@ -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 */
)
}

View File

@@ -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) {

View File

@@ -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 */)

View File

@@ -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)}.

View File

@@ -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(

View File

@@ -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)));

View File

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

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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);
}
}

View File

@@ -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
);
}
/**

View File

@@ -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);
@@ -77,33 +75,20 @@ public class ActionProxyReceiverTest extends SysuiTestCase {
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, mMockPendingIntent);
}
@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
);
}
}

View File

@@ -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)

View File

@@ -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);

View File

@@ -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
);
}

View File

@@ -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)
}
}

View File

@@ -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()));

View File

@@ -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;