Add ActivityStarterImpl
This is a new class that will replace ActivityStarterDelegate/CentralSurfaces/CentralSurfacesImpl for ActivityStarter delegation. Bug: 278273334 Test: Open notifications from lockscreen Test: Open settings from quick settings Change-Id: Ie4513c0850e9a79ede133aba52d7dc6ac0dfa04d
This commit is contained in:
@@ -119,6 +119,16 @@ public interface ActivityStarter {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -206,4 +208,14 @@ public class ActivityStarterDelegate implements ActivityStarter {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ 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;
|
||||
@@ -612,4 +613,15 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -283,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 {
|
||||
@@ -1800,23 +1803,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,
|
||||
@@ -1825,6 +1832,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,
|
||||
@@ -2422,6 +2430,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) {
|
||||
@@ -2430,12 +2439,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,
|
||||
@@ -2447,6 +2458,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,
|
||||
@@ -2557,6 +2569,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(
|
||||
@@ -2586,6 +2600,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,
|
||||
@@ -2596,6 +2612,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,
|
||||
@@ -2706,16 +2723,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) {
|
||||
@@ -2917,6 +2937,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(() -> {
|
||||
@@ -2926,11 +2947,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) {
|
||||
@@ -2938,11 +2961,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) {
|
||||
@@ -2950,6 +2975,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,
|
||||
@@ -4100,11 +4126,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) {
|
||||
@@ -4112,6 +4140,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) {
|
||||
@@ -4125,6 +4154,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,
|
||||
@@ -4548,6 +4578,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);
|
||||
@@ -4570,4 +4602,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user