summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/WindowManager.java108
-rw-r--r--core/proto/android/server/windowmanagerservice.proto4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java3
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java1672
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java7
9 files changed, 547 insertions, 1295 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 40898d02b97a..9bec409ea8a1 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -629,114 +629,6 @@ public interface WindowManager extends ViewManager {
@interface DisplayImePolicy {}
/**
- * The root state of all the state. This is an abstract state, and the keyguard should be in
- * one of this sub state.
- *
- * @hide
- */
- int KEYGUARD_STATE_ROOT = 0x0;
-
- /**
- * Keyguard is off, so activity can be shown on the screen.
- *
- * @hide
- */
- int KEYGUARD_STATE_OFF = 0x1;
-
- /**
- * The keyguard is off, but lock screen is still rendered on the screen. Waiting for
- * starting unlock animation.
- *
- * @hide
- */
- int KEYGUARD_STATE_GOING_AWAY = 0x11;
-
- /**
- * They keyguard is on, so normal activities cannot be shown on the screen. This is an abstract
- * state, and the keyguard should be in one of ths sub state.
- *
- * @hide
- */
- int KEYGUARD_STATE_ON = 0x2;
-
- /**
- * The keyguard is on and not occluded.
- * @hide
- */
- int KEYGUARD_STATE_KEYGUARD_TOP = 0x21;
-
- /**
- * The keyguard is on, and the lock screen is shown.
- *
- * @hide
- */
- int KEYGUARD_STATE_LOCKSCREEN_SHOWN = 0x211;
-
- /**
- * The keyguard is on, and the AOD is shown.
- *
- * @hide
- */
- int KEYGUARD_STATE_AOD_SHOWN = 0x212;
-
- /**
- * The keyguard is on but it's occluded by a normal SHOW_WHEN_LOCKED activity (i.e. non
- * occluded by Dream activity).
- *
- * @hide
- */
- int KEYGUARD_STATE_OCCLUDED = 0x22;
-
- /**
- * The keyguard is on but it's occluded by a Dream activity.
- *
- * @hide
- */
- int KEYGUARD_STATE_DREAMING = 0x221;
-
- /** @hide */
- @IntDef(prefix = { "KEYGUARD_STATE_" }, value = {
- KEYGUARD_STATE_ROOT,
- KEYGUARD_STATE_OFF,
- KEYGUARD_STATE_GOING_AWAY,
- KEYGUARD_STATE_ON,
- KEYGUARD_STATE_KEYGUARD_TOP,
- KEYGUARD_STATE_LOCKSCREEN_SHOWN,
- KEYGUARD_STATE_AOD_SHOWN,
- KEYGUARD_STATE_OCCLUDED,
- KEYGUARD_STATE_DREAMING,
- })
- @interface KeyguardState {}
-
- /**
- * @hide
- */
- static String keyguardStateToString(@KeyguardState int type) {
- switch (type) {
- case KEYGUARD_STATE_ROOT:
- return "ROOT";
- case KEYGUARD_STATE_OFF:
- return "KEYGUARD_OFF";
- case KEYGUARD_STATE_GOING_AWAY:
- return "KEYGUARD_GOING_AWAY";
- case KEYGUARD_STATE_ON:
- return "KEYGUARD_ON";
- case KEYGUARD_STATE_KEYGUARD_TOP:
- return "KEYGUARD_TOP";
- case KEYGUARD_STATE_LOCKSCREEN_SHOWN:
- return "KEYGUARD_LOCKSCREEN_SHOWN";
- case KEYGUARD_STATE_AOD_SHOWN:
- return "KEYGUARD_AOD_SHOWN";
- case KEYGUARD_STATE_OCCLUDED:
- return "KEYGUARD_OCCLUDED";
- case KEYGUARD_STATE_DREAMING:
- return "KEYGUARD_DREAMING";
- default:
- return "KEYGUARD_STATE_UNKNOWN(" + Integer.toHexString(type) + ")";
- }
- }
-
- /**
* Exception that is thrown when trying to add view whose
* {@link LayoutParams} {@link LayoutParams#token}
* is invalid.
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index b112e7a366bf..82e1777ab7cb 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -117,7 +117,7 @@ message KeyguardControllerProto {
repeated KeyguardOccludedProto keyguard_occluded_states = 2 [deprecated=true];
optional bool aod_showing = 3;
repeated KeyguardPerDisplayProto keyguard_per_display = 4;
- optional bool keyguard_going_away = 5 [deprecated=true];
+ optional bool keyguard_going_away = 5;
}
message KeyguardOccludedProto {
@@ -134,7 +134,7 @@ message KeyguardPerDisplayProto {
optional bool keyguard_showing = 2;
optional bool aod_showing = 3;
optional bool keyguard_occluded = 4;
- optional bool keyguard_going_away = 5 [deprecated=true];
+ optional bool keyguard_going_away = 5;
}
/* represents PhoneWindowManager */
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e0bcc0e3e883..4e9cd2e6337d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3770,6 +3770,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean setKeyguardOccludedLw(boolean isOccluded, boolean notify) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded);
mKeyguardOccludedChanged = false;
+ if (isKeyguardOccluded() == isOccluded) {
+ return false;
+ }
mKeyguardDelegate.setOccluded(isOccluded, notify);
return mKeyguardDelegate.isShowing();
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 718a9e3f0ffd..e9badefe1bb1 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -20,63 +20,47 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.KEYGUARD_STATE_AOD_SHOWN;
-import static android.view.WindowManager.KEYGUARD_STATE_DREAMING;
-import static android.view.WindowManager.KEYGUARD_STATE_GOING_AWAY;
-import static android.view.WindowManager.KEYGUARD_STATE_KEYGUARD_TOP;
-import static android.view.WindowManager.KEYGUARD_STATE_LOCKSCREEN_SHOWN;
-import static android.view.WindowManager.KEYGUARD_STATE_OCCLUDED;
-import static android.view.WindowManager.KEYGUARD_STATE_OFF;
-import static android.view.WindowManager.KEYGUARD_STATE_ON;
-import static android.view.WindowManager.KEYGUARD_STATE_ROOT;
-import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_WAKE;
-import static android.view.WindowManager.keyguardStateToString;
-import static android.view.WindowManager.transitTypeToString;
-import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
-
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.KeyguardControllerProto.AOD_SHOWING;
+import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_GOING_AWAY;
import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_PER_DISPLAY;
import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_SHOWING;
-import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import android.view.WindowManager;
-import android.view.WindowManager.KeyguardState;
-import android.window.TransitionInfo;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.wm.utils.StateMachine;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
/**
* Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
@@ -85,285 +69,171 @@ import java.util.Optional;
* Note that everything in this class should only be accessed with the AM lock being held.
*/
class KeyguardController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_ATM;
- private static final boolean DEBUG = true;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_ATM;
static final String KEYGUARD_SLEEP_TOKEN_TAG = "keyguard";
private static final int DEFER_WAKE_TRANSITION_TIMEOUT_MS = 5000;
- private final ActivityTaskManagerService mService;
private final ActivityTaskSupervisor mTaskSupervisor;
- private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer;
- private boolean mWaitingForWakeTransition;
private WindowManagerService mWindowManager;
+ private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
+ private final ActivityTaskManagerService mService;
private RootWindowContainer mRootWindowContainer;
-
- private final SparseArray<DisplayState> mDisplayStates = new SparseArray<>();
-
- @NonNull private final ServiceDelegate mServiceDelegate = new ServiceDelegate();
+ private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer;
+ private boolean mWaitingForWakeTransition;
KeyguardController(ActivityTaskManagerService service,
ActivityTaskSupervisor taskSupervisor) {
mService = service;
mTaskSupervisor = taskSupervisor;
- mSleepTokenAcquirer = service.new SleepTokenAcquirerImpl(KEYGUARD_SLEEP_TOKEN_TAG);
+ mSleepTokenAcquirer = mService.new SleepTokenAcquirerImpl(KEYGUARD_SLEEP_TOKEN_TAG);
}
void setWindowManager(WindowManagerService windowManager) {
mWindowManager = windowManager;
mRootWindowContainer = mService.mRootWindowContainer;
- mService.getTransitionController().registerLegacyListener(
- new WindowManagerInternal.AppTransitionListener() {
- @Override
- public int onAppTransitionStartingLocked(TransitionInfo info) {
- final List<TransitionInfo.Change> changes = info.getChanges();
- if (changes.size() == 0) {
- Slog.e(TAG, "TransitionInfo doesn't contain change: " + info);
- return 0;
- }
- final ActivityManager.RunningTaskInfo taskInfo =
- changes.get(0).getTaskInfo();
- if (taskInfo == null) {
- Slog.e(TAG, "No RunningTaskInfo: " + info);
- return 0;
- }
-
- // TODO(b/242856311): Filtering condition is defined here and in SysUI
- // Keyguard service, which need to be in sync. For a long term, we should
- // define a new API for notifying occlude status from WMS to SysUI, and
- // the filtering logic should only exist in WM Shell.
- if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) == 0) {
- return 0;
- }
-
- boolean occludeOpeningApp = false;
- boolean occludeClosingApp = false;
- for (int i = 0; i < changes.size(); ++i) {
- final TransitionInfo.Change change = changes.get(i);
- if (change.hasFlags(FLAG_OCCLUDES_KEYGUARD)) {
- if (change.getMode() == TRANSIT_OPEN
- || change.getMode() == TRANSIT_TO_FRONT) {
- occludeOpeningApp = true;
- }
- if (change.getMode() == TRANSIT_CLOSE
- || change.getMode() == TRANSIT_TO_BACK) {
- occludeClosingApp = true;
- }
- }
- }
- final DisplayState state = getDisplayState(taskInfo.displayId);
- if (occludeOpeningApp && !occludeClosingApp) {
- state.commitOccludedStatus(true /* occluded */);
- } else if (!occludeOpeningApp && occludeClosingApp) {
- state.commitOccludedStatus(false /* occluded */);
- }
- return 0;
- }
- });
}
boolean isAodShowing(int displayId) {
- return getDisplayState(displayId).isIn(KEYGUARD_STATE_AOD_SHOWN);
+ return getDisplayState(displayId).mAodShowing;
}
/**
- * @return {@code true} if either Keyguard or AOD are showing.
+ * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
+ * on the given display, false otherwise.
*/
boolean isKeyguardOrAodShowing(int displayId) {
- return getDisplayState(displayId).isIn(KEYGUARD_STATE_KEYGUARD_TOP);
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ return (state.mKeyguardShowing || state.mAodShowing)
+ && !state.mKeyguardGoingAway
+ && !isDisplayOccluded(displayId);
}
/**
- * @return {@codd true} if lock screen is showing.
+ * @return {@code true} for default display when AOD is showing, not going away. Otherwise, same
+ * as {@link #isKeyguardOrAodShowing(int)}
+ * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
*/
- boolean isLocksScreenShowing(int displayId) {
- // NOTE: This is only used by WindowManagerService#notifyKeyguardTrustedChanged
- return getDisplayState(displayId).isIn(KEYGUARD_STATE_LOCKSCREEN_SHOWN);
+ boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ if (displayId == DEFAULT_DISPLAY && state.mAodShowing) {
+ return !state.mKeyguardGoingAway;
+ }
+ return isKeyguardOrAodShowing(displayId);
}
/**
- * @return {@code true} if Keyguard is either showing or occluded.
+ * @return true if Keyguard is showing, not going away, and not being occluded on the given
+ * display, false otherwise
+ */
+ boolean isKeyguardShowing(int displayId) {
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ return state.mKeyguardShowing && !state.mKeyguardGoingAway
+ && !isDisplayOccluded(displayId);
+ }
+
+ /**
+ * @return true if Keyguard is either showing or occluded, but not going away
*/
boolean isKeyguardLocked(int displayId) {
- return getDisplayState(displayId).isIn(KEYGUARD_STATE_ON);
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ return state.mKeyguardShowing && !state.mKeyguardGoingAway;
}
/**
+ *
* @return true if the activity is controlling keyguard state.
*/
boolean topActivityOccludesKeyguard(ActivityRecord r) {
- return getDisplayState(r.getDisplayId()).topActivityOccludesKeyguard(r);
+ return getDisplayState(r.getDisplayId()).mTopOccludesActivity == r;
}
/**
* @return {@code true} if the keyguard is going away, {@code false} otherwise.
*/
boolean isKeyguardGoingAway(int displayId) {
- return getDisplayState(displayId).isIn(KEYGUARD_STATE_GOING_AWAY);
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ // Also check keyguard showing in case value is stale.
+ return state.mKeyguardGoingAway && state.mKeyguardShowing;
}
/**
- * Checks whether the top activity occludes the keyguard.
- */
- boolean isDisplayOccluded(int displayId) {
- return getDisplayState(displayId).isIn(KEYGUARD_STATE_OCCLUDED);
- }
-
- /**
- * @return Whether the dream activity is on top of default display.
- */
- boolean isShowingDream() {
- return getDisplayState(DEFAULT_DISPLAY).isIn(KEYGUARD_STATE_DREAMING);
- }
-
- /**
- * Checks whether {@param r} should be visible depending on Keyguard state.
- *
- * @return true if {@param r} is visible taken Keyguard state into account, false otherwise
+ * Update the Keyguard showing state.
*/
- boolean checkKeyguardVisibility(@NonNull ActivityRecord r) {
- if (r.mDisplayContent.canShowWithInsecureKeyguard() && canDismissKeyguard()) {
- return true;
- }
- return getDisplayState(r.mDisplayContent.getDisplayId()).checkKeyguardVisibility(r);
- }
-
- void onDisplayRemoved(int displayId) {
- final DisplayState state = mDisplayStates.get(displayId);
- if (state != null) {
- state.onRemoved();
- mDisplayStates.remove(displayId);
+ void setKeyguardShown(int displayId, boolean keyguardShowing, boolean aodShowing) {
+ if (mRootWindowContainer.getDisplayContent(displayId).isKeyguardAlwaysUnlocked()) {
+ Slog.i(TAG, "setKeyguardShown ignoring always unlocked display " + displayId);
+ return;
}
- }
- private final Runnable mResetWaitTransition = () -> {
- synchronized (mWindowManager.mGlobalLock) {
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ final boolean aodChanged = aodShowing != state.mAodShowing;
+ final boolean aodRemoved = state.mAodShowing && !aodShowing;
+ // If keyguard is going away, but SystemUI aborted the transition, need to reset state.
+ // Do not reset keyguardChanged status when only AOD is removed.
+ final boolean keyguardChanged = (keyguardShowing != state.mKeyguardShowing)
+ || (state.mKeyguardGoingAway && keyguardShowing && !aodRemoved);
+ if (aodRemoved) {
updateDeferTransitionForAod(false /* waiting */);
}
- };
-
- /**
- * Update if app transition should be deferred until AOD state changes.
- *
- * <p>Note: This is used for defer app transition before the device fully wakes up, since during
- * wake up process, activities life cycle can be messed up due to a display sleep token.
- *
- * @param waiting {@code true} to defer an app transition, {@code false} to continue an app
- * transition.
- */
- void updateDeferTransitionForAod(boolean waiting) {
- if (waiting == mWaitingForWakeTransition) {
- return;
- }
- if (!mService.getTransitionController().isCollecting()) {
+ if (!keyguardChanged && !aodChanged) {
+ setWakeTransitionReady();
return;
}
- // if AOD is showing, defer the wake transition until AOD state changed.
- if (waiting && isAodShowing(DEFAULT_DISPLAY)) {
- mWaitingForWakeTransition = true;
- mService.getTransitionController().deferTransitionReady();
- mWindowManager.mH.postDelayed(mResetWaitTransition, DEFER_WAKE_TRANSITION_TIMEOUT_MS);
- } else if (!waiting) {
- // dismiss the deferring if the AOD state change or cancel awake.
- mWaitingForWakeTransition = false;
- mService.getTransitionController().continueTransitionReady();
- mWindowManager.mH.removeCallbacks(mResetWaitTransition);
- }
- }
-
- /**
- * TODO(b/242851358): Remove this function once SysUI migrate to the new API.
- */
- @KeyguardState private static int convertToState(int displayId, boolean keyguardShowing,
- boolean aodShowing) {
- if (displayId == DEFAULT_DISPLAY) {
- if (aodShowing) {
- return KEYGUARD_STATE_AOD_SHOWN;
- } else if (keyguardShowing) {
- return KEYGUARD_STATE_LOCKSCREEN_SHOWN;
- } else {
- return KEYGUARD_STATE_OFF;
- }
- } else {
- if (keyguardShowing || aodShowing) {
- return KEYGUARD_STATE_LOCKSCREEN_SHOWN;
- } else {
- return KEYGUARD_STATE_OFF;
- }
- }
- }
-
- /**
- * Update the Keyguard showing state.
- *
- * @deprecated Use {@link #setKeyguardState(int, int)} instead. See b/242851358
- */
- @Deprecated
- void setKeyguardShown(int displayId, boolean keyguardShowing, boolean aodShowing) {
- final DisplayState state = getDisplayState(displayId);
EventLogTags.writeWmSetKeyguardShown(
displayId,
keyguardShowing ? 1 : 0,
aodShowing ? 1 : 0,
- state.isIn(KEYGUARD_STATE_GOING_AWAY) ? 1 : 0,
+ state.mKeyguardGoingAway ? 1 : 0,
"setKeyguardShown");
- setKeyguardState(displayId, convertToState(displayId, keyguardShowing, aodShowing));
- }
- /**
- * Set keyguard state.
- */
- private void setKeyguardState(int displayId, @KeyguardState int newState) {
- if (mRootWindowContainer.getDisplayContent(displayId).isKeyguardAlwaysUnlocked()) {
- Slog.i(TAG, "setKeyguardShown ignoring always unlocked display " + displayId);
- return;
- }
- if (newState != KEYGUARD_STATE_LOCKSCREEN_SHOWN
- && newState != KEYGUARD_STATE_AOD_SHOWN
- && newState != KEYGUARD_STATE_OFF
- && newState != KEYGUARD_STATE_GOING_AWAY) {
- Slog.i(TAG, "Invalid state is requested: displayId=" + displayId
- + ", state=" + keyguardStateToString(newState)
- + ", stack=" + Debug.getCallers(30));
- return;
- }
- if (isKeyguardLocked(displayId) && newState == KEYGUARD_STATE_OFF) {
- newState = KEYGUARD_STATE_GOING_AWAY;
+ // Update the task snapshot if the screen will not be turned off. To make sure that the
+ // unlocking animation can animate consistent content. The conditions are:
+ // - Either AOD or keyguard changes to be showing. So if the states change individually,
+ // the later one can be skipped to avoid taking snapshot again. While it still accepts
+ // if both of them change to show at the same time.
+ // - Keyguard was not going away. Because if it was, the closing transition is able to
+ // handle the snapshot.
+ // - The display state is ON. Because if AOD is not on or pulsing, the display state will
+ // be OFF or DOZE (the path of screen off may have handled it).
+ if (((aodShowing ^ keyguardShowing) || (aodShowing && aodChanged && keyguardChanged))
+ && !state.mKeyguardGoingAway && Display.isOnState(
+ mRootWindowContainer.getDefaultDisplay().getDisplayInfo().state)) {
+ mWindowManager.mTaskSnapshotController.snapshotForSleeping(DEFAULT_DISPLAY);
+ }
+
+ state.mKeyguardShowing = keyguardShowing;
+ state.mAodShowing = aodShowing;
+
+ if (keyguardChanged) {
+ // Irrelevant to AOD.
+ state.mKeyguardGoingAway = false;
+ if (keyguardShowing) {
+ state.mDismissalRequested = false;
+ }
}
- final DisplayState state = getDisplayState(displayId);
- // SysUI requests to show LOCKSCREEN, but the keyguard is already occluded. Ignore the
- // requests.
- if (state.isIn(KEYGUARD_STATE_OCCLUDED)
- && StateMachine.isIn(newState, KEYGUARD_STATE_LOCKSCREEN_SHOWN)) {
- Slog.w(TAG, "Ignore setKeyguardState request: OCCLUDE -> LOCK_SCREEN_SHOWN");
- return;
- }
- // SysUI requests to show AOD_SHOWN again. This can happen when SysUI still uses the old
- // API and enables AOD first, then lock screen, i.e. #setLockScreenShown(false, true), then
- // #setLockScreenShown(true, true)
- if (state.isIn(KEYGUARD_STATE_AOD_SHOWN)
- && StateMachine.isIn(newState, KEYGUARD_STATE_AOD_SHOWN)) {
- Slog.w(TAG, "Ignore setKeyguardState request: AOD_SHOWN -> AOD_SHOWN");
- return;
+ // Update the sleep token first such that ensureActivitiesVisible has correct sleep token
+ // state when evaluating visibilities.
+ updateKeyguardSleepToken();
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+ InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */);
+ setWakeTransitionReady();
+ if (aodChanged) {
+ // Ensure the new state takes effect.
+ mWindowManager.mWindowPlacerLocked.performSurfacePlacement();
}
- if (state.isIn(KEYGUARD_STATE_OFF)
- && StateMachine.isIn(newState, KEYGUARD_STATE_GOING_AWAY)) {
- Slog.w(TAG, "Ignore setKeyguardState request: OFF -> GOING_AWAY");
- return;
- }
- if (state.isIn(KEYGUARD_STATE_AOD_SHOWN)
- && StateMachine.isIn(newState, KEYGUARD_STATE_LOCKSCREEN_SHOWN)) {
- ActivityRecord top = getTopNonFinishingActivity(displayId);
- if (canOcclude(top)) {
- newState = isTopActivityDreaming(displayId) ? KEYGUARD_STATE_DREAMING
- : KEYGUARD_STATE_OCCLUDED;
- }
+ }
+
+ private void setWakeTransitionReady() {
+ if (mWindowManager.mAtmService.getTransitionController().getCollectingTransitionType()
+ == WindowManager.TRANSIT_WAKE) {
+ mWindowManager.mAtmService.getTransitionController().setReady(
+ mRootWindowContainer.getDefaultDisplay());
}
- state.setKeyguardState(newState);
}
/**
@@ -371,1008 +241,520 @@ class KeyguardController {
*
* @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
* etc.
- *
- * @deprecated Use {@link #setKeyguardState(int, int)}
*/
void keyguardGoingAway(int displayId, int flags) {
- // TODO(b/242851358): Remove IActivityTaskManagerService#keyguardGoingAway and SysUI should
- // request the state change via #setKeyguardState.
- final DisplayState state = getDisplayState(displayId);
- EventLogTags.writeWmSetKeyguardShown(
- displayId,
- state.isIn(KEYGUARD_STATE_LOCKSCREEN_SHOWN) ? 1 : 0,
- state.isIn(KEYGUARD_STATE_AOD_SHOWN) ? 1 : 0,
- 1 /* keyguardGoingAway */,
- "keyguardGoingAway");
- setKeyguardState(displayId, KEYGUARD_STATE_GOING_AWAY);
- }
-
- /**
- * Makes sure to update lockscreen state if needed before completing set all visibility
- * ({@link ActivityTaskSupervisor#beginActivityVisibilityUpdate}).
- */
- void updateVisibility() {
- for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
- displayNdx >= 0; displayNdx--) {
- final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
- if (display.isRemoving() || display.isRemoved()) continue;
- final DisplayState state = getDisplayState(display.mDisplayId);
- state.updateVisibility();
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ if (!state.mKeyguardShowing || state.mKeyguardGoingAway) {
+ return;
+ }
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "keyguardGoingAway");
+ mService.deferWindowLayout();
+ state.mKeyguardGoingAway = true;
+ try {
+ EventLogTags.writeWmSetKeyguardShown(
+ displayId,
+ 1 /* keyguardShowing */,
+ state.mAodShowing ? 1 : 0,
+ 1 /* keyguardGoingAway */,
+ "keyguardGoingAway");
+ final int transitFlags = convertTransitFlags(flags);
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
+ dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, transitFlags);
+ // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
+ // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going
+ // away.
+ dc.mAtmService.getTransitionController().requestTransitionIfNeeded(
+ TRANSIT_TO_BACK, transitFlags, null /* trigger */, dc);
+ updateKeyguardSleepToken();
+
+ // Some stack visibility might change (e.g. docked stack)
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+ mRootWindowContainer.addStartingWindowsForVisibleActivities();
+ mWindowManager.executeAppTransition();
+ } finally {
+ mService.continueWindowLayout();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message) {
- boolean ok;
- final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (r == null) {
- ok = false;
- } else {
- final DisplayState state = getDisplayState(r.getDisplayId());
- ok = state.dismissKeyguard(r, callback, message);
+ final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
+ if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
+ failCallback(callback);
+ return;
}
+ Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
- if (!ok) {
- try {
- callback.onDismissError();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to call callback", e);
- }
+ // If the client has requested to dismiss the keyguard and the Activity has the flag to
+ // turn the screen on, wakeup the screen if it's the top Activity.
+ if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
+ mTaskSupervisor.wakeUp("dismissKeyguard");
}
- }
- private boolean isKeyguardSecure() {
- return mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
+ mWindowManager.dismissKeyguard(callback, message);
}
- /**
- * @return true if Keyguard can be currently dismissed without entering credentials.
- */
- private boolean canDismissKeyguard() {
- return mWindowManager.mPolicy.isKeyguardTrustedLw() || !isKeyguardSecure();
+ private void failCallback(IKeyguardDismissCallback callback) {
+ try {
+ callback.onDismissError();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call callback", e);
+ }
}
- private boolean canOcclude(@Nullable ActivityRecord r) {
- if (r == null) {
- return false;
+ private int convertTransitFlags(int keyguardGoingAwayFlags) {
+ int result = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+ if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
+ result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
}
- // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
- if (r.getDisplayId() != DEFAULT_DISPLAY) {
- final DisplayContent dc = r.getDisplayContent();
- if (dc != null && dc.canShowWithInsecureKeyguard() && canDismissKeyguard()) {
- return true;
- }
+ if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
+ result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
}
- // FLAG_DISMISS_KEYGUARD activity
- // Insecure: Treat as FLAG_SHOW_WHEN_LOCKED
- // Trusted: Actually dismiss Keyguard.
- // Secure: Show bouncer.
- return r.canShowWhenLocked() || (r.containsDismissKeyguardWindow() && !isKeyguardSecure());
- }
-
- private boolean isTopActivityDreaming(int displayId) {
- final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
- final ActivityRecord top = getTopNonFinishingActivity(displayId);
- return dc.getDisplayPolicy().isShowingDreamLw()
- && top != null && top.getActivityType() == ACTIVITY_TYPE_DREAM;
- }
-
- @Nullable private ActivityRecord getTopNonFinishingActivity(int displayId) {
- final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
- final Task rootTask = dc == null ? null : dc.getRootTask(t ->
- t != null && t.isFocusableAndVisible() && !t.inPinnedWindowingMode());
- return rootTask != null ? rootTask.getTopNonFinishingActivity() : null;
- }
-
- private DisplayState getDisplayState(int displayId) {
- DisplayState state = mDisplayStates.get(displayId);
- if (state == null) {
- state = new DisplayState(displayId, mServiceDelegate);
- mDisplayStates.append(displayId, state);
+ if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
+ result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
}
- return state;
- }
-
- void dumpDebug(ProtoOutputStream proto, long fieldId) {
- final DisplayState default_state = getDisplayState(DEFAULT_DISPLAY);
- final long token = proto.start(fieldId);
- proto.write(AOD_SHOWING, default_state.isIn(KEYGUARD_STATE_AOD_SHOWN));
- proto.write(KEYGUARD_SHOWING, default_state.isIn(KEYGUARD_STATE_LOCKSCREEN_SHOWN));
- writeDisplayStatesToProto(proto, KEYGUARD_PER_DISPLAY);
- proto.end(token);
- }
-
- private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) {
- for (int i = 0; i < mDisplayStates.size(); i++) {
- mDisplayStates.valueAt(i).dumpDebug(proto, fieldId);
+ if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS) != 0) {
+ result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
}
- }
-
- void dump(PrintWriter pw, String prefix) {
- pw.print(prefix);
- pw.println("KeyguardController:");
- for (int i = 0; i < mDisplayStates.size(); i++) {
- mDisplayStates.valueAt(i).dump(pw, prefix);
+ if ((keyguardGoingAwayFlags
+ & KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT) != 0) {
+ result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
}
- pw.println();
+ return result;
}
/**
- * Interface for {@link DisplayState} to access non-local information.
- * <p>
- * Keep this interface as small as possible, and don't let {@link DisplayState} access arbitrary
- * large classes such as ActivityTaskSupervisor, which makes managing dependency complicated.
+ * @return True if we may show an activity while Keyguard is showing because we are in the
+ * process of dismissing it anyways, false otherwise.
*/
- private final class ServiceDelegate {
- boolean isKeyguardSecure() {
- return KeyguardController.this.isKeyguardSecure();
- }
-
- boolean canOcclude(@Nullable ActivityRecord r) {
- return KeyguardController.this.canOcclude(r);
- }
-
- boolean canDismissKeyguard() {
- return KeyguardController.this.canDismissKeyguard();
- }
-
- boolean isDeviceInteractive() {
- return mService.mWindowManager.mPowerManager.isInteractive();
- }
-
- void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message) {
- mWindowManager.dismissKeyguard(callback, message);
- }
-
- @Nullable
- ActivityRecord getTopNonFinishingActivity(int displayId) {
- return KeyguardController.this.getTopNonFinishingActivity(displayId);
- }
-
- boolean isTopActivityDreaming(int displayId) {
- return KeyguardController.this.isTopActivityDreaming(displayId);
- }
-
- void wakeUp(String reason) {
- mTaskSupervisor.wakeUp(reason);
- }
-
- void forceSyncOccludedStatus(boolean occluded) {
- if (DEBUG) {
- Slog.d(TAG, "forceSyncOccludedStatus: occluded=" + occluded);
- }
- mWindowManager.mPolicy.onKeyguardOccludedChangedLw(occluded);
- mWindowManager.mPolicy.applyKeyguardOcclusionChange(true /* notify */);
- }
-
- void snapshotForSleeping(int displayId) {
- if (displayId == DEFAULT_DISPLAY) {
- mWindowManager.mTaskSnapshotController.snapshotForSleeping(displayId);
- }
- }
+ boolean canShowActivityWhileKeyguardShowing(ActivityRecord r) {
+ // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
+ // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
+ // Keyguard.
+ final KeyguardDisplayState state = getDisplayState(r.getDisplayId());
+ return r.containsDismissKeyguardWindow() && canDismissKeyguard() && !state.mAodShowing
+ && (state.mDismissalRequested
+ || (r.canShowWhenLocked() && state.mDismissingKeyguardActivity != r));
+ }
- void notifyKeyguardOccludeChanged(boolean occluded) {
- // TODO: This updates status of KeyguardDelegate. Once we delete occlude status from
- // KeyguardDelegate, we should remove WindowManagerPolicy#onKeyguardOccludedChangedLw.
- mWindowManager.mPolicy.onKeyguardOccludedChangedLw(occluded);
- }
+ /**
+ * @return True if we may show an activity while Keyguard is occluded, false otherwise.
+ */
+ boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
+ return showWhenLocked || dismissKeyguard
+ && !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
+ }
- void collect(@NonNull WindowContainer wc) {
- mService.getTransitionController().collect(wc);
+ /**
+ * Checks whether {@param r} should be visible depending on Keyguard state.
+ *
+ * @return true if {@param r} is visible taken Keyguard state into account, false otherwise
+ */
+ boolean checkKeyguardVisibility(ActivityRecord r) {
+ if (r.mDisplayContent.canShowWithInsecureKeyguard() && canDismissKeyguard()) {
+ return true;
}
- void requestTransitionIfNeeded(int displayId, @WindowManager.TransitionType int transit,
- @WindowManager.TransitionFlags int flags) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- if (DEBUG) {
- Slog.d(TAG, "requestTransitionIfNeeded: display=" + displayId + ", transit="
- + transitTypeToString(transit));
- }
-
- final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
- if (dc == null) {
- Slog.e(TAG, "No DisplayContent exists: displayId=" + displayId);
- return;
- }
-
- if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
- dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, flags);
- // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
- // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard
- // going away.
- mService.getTransitionController().requestTransitionIfNeeded(
- TRANSIT_TO_BACK, flags, null /* trigger */, dc);
- } else {
- dc.requestTransitionAndLegacyPrepare(transit, flags);
- }
+ if (isKeyguardOrAodShowing(r.mDisplayContent.getDisplayId())) {
+ // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
+ // right away and AOD isn't visible.
+ return canShowActivityWhileKeyguardShowing(r);
+ } else if (isKeyguardLocked(r.getDisplayId())) {
+ return canShowWhileOccluded(r.containsDismissKeyguardWindow(), r.canShowWhenLocked());
+ } else {
+ return true;
}
+ }
- void acquireSleepToken(int displayId, boolean ensureActivitiesVisible) {
- mSleepTokenAcquirer.acquire(displayId);
- if (ensureActivitiesVisible) {
- mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+ /**
+ * Makes sure to update lockscreen occluded/dismiss/turnScreenOn state if needed before
+ * completing set all visibility
+ * ({@link ActivityTaskSupervisor#beginActivityVisibilityUpdate}).
+ */
+ void updateVisibility() {
+ for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
+ displayNdx >= 0; displayNdx--) {
+ final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
+ if (display.isRemoving() || display.isRemoved()) continue;
+ final KeyguardDisplayState state = getDisplayState(display.mDisplayId);
+ state.updateVisibility(this, display);
+ if (state.mRequestDismissKeyguard) {
+ handleDismissKeyguard(display.getDisplayId());
}
}
+ }
- void releaseSleepToken(int displayId, boolean resumeTopActivities) {
- mSleepTokenAcquirer.release(displayId);
- if (resumeTopActivities) {
- mRootWindowContainer.resumeFocusedTasksTopActivities();
- mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- mRootWindowContainer.addStartingWindowsForVisibleActivities();
-
- }
+ /**
+ * Called when occluded state changed.
+ *
+ * @param topActivity the activity that controls the state whether keyguard should
+ * be occluded. That is the activity to be shown on top of keyguard if it requests so.
+ */
+ private void handleOccludedChanged(int displayId, @Nullable ActivityRecord topActivity) {
+ // TODO(b/113840485): Handle app transition for individual display, and apply occluded
+ // state change to secondary displays.
+ // For now, only default display fully supports occluded change. Other displays only
+ // updates keyguard sleep token on that display.
+ if (displayId != DEFAULT_DISPLAY) {
+ updateKeyguardSleepToken(displayId);
+ return;
}
- void deferWindowLayout() {
+ mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY));
+ if (isKeyguardLocked(displayId)) {
mService.deferWindowLayout();
- }
-
- void continueWindowLayout() {
- mService.continueWindowLayout();
- }
-
- void executeAppTransition() {
- mWindowManager.executeAppTransition();
- }
-
- private void updateDeferTransitionForAod(boolean waiting) {
- KeyguardController.this.updateDeferTransitionForAod(waiting);
- }
-
- private void setWakeTransitionReady() {
- if (mService.getTransitionController().getCollectingTransitionType() == TRANSIT_WAKE) {
- mService.getTransitionController().setReady(
- mRootWindowContainer.getDefaultDisplay());
- }
- }
-
- void requestLayoutRedoWallpaper(int displayId) {
- final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
- if (!dc.isSleeping() && dc.mWallpaperController.getWallpaperTarget() != null) {
- dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ try {
+ mRootWindowContainer.getDefaultDisplay()
+ .requestTransitionAndLegacyPrepare(
+ isDisplayOccluded(DEFAULT_DISPLAY)
+ ? TRANSIT_KEYGUARD_OCCLUDE
+ : TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */);
+ updateKeyguardSleepToken(DEFAULT_DISPLAY);
+ mWindowManager.executeAppTransition();
+ } finally {
+ mService.continueWindowLayout();
}
}
- };
+ dismissMultiWindowModeForTaskIfNeeded(displayId, topActivity != null
+ ? topActivity.getRootTask() : null);
+ }
- private static class KeyguardDisplayStateMachine extends StateMachine {
- static final int EVENT_DISMISS_KEYGUARD_ACTIVITY = 1;
- static final int EVENT_SHOW_WHEN_LOCKED_ACTIVITY = 2;
- static final int EVENT_CHECK_KEYGUARD_VISIBILITY = 3;
- static final int EVENT_TOP_ACTIVITY_OCCLUDES_KEYGUARD = 4;
- static final int EVENT_LAYOUT_CHANGES = 5;
- static final int EVENT_DUMP = 6;
- static final int EVENT_DISMISS_KEYGUARD_API = 7;
- static final int EVENT_TURN_SCREEN_ON_ACTIVITY = 8;
- final int mDisplayId;
-
- static final class CheckKeyguardVisibilityParam {
- boolean mRet;
- @NonNull final ActivityRecord mActivity;
-
- CheckKeyguardVisibilityParam(@NonNull ActivityRecord activity) {
- mActivity = activity;
- }
+ /**
+ * Called when keyguard going away state changed.
+ */
+ private void handleKeyguardGoingAwayChanged(DisplayContent dc) {
+ mService.deferWindowLayout();
+ try {
+ dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, 0 /* transitFlags */);
+ // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
+ // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going
+ // away.
+ dc.mAtmService.getTransitionController().requestTransitionIfNeeded(
+ TRANSIT_OPEN, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, null /* trigger */, dc);
+ updateKeyguardSleepToken();
+ mWindowManager.executeAppTransition();
+ } finally {
+ mService.continueWindowLayout();
}
+ }
- static final class DismissKeyguardParam {
- boolean mRet;
- @NonNull final ActivityRecord mActivity;
- @Nullable final IKeyguardDismissCallback mCallback;
- @Nullable final CharSequence mMessage;
-
- DismissKeyguardParam(@NonNull ActivityRecord activity,
- @Nullable IKeyguardDismissCallback callback, @Nullable CharSequence message) {
- mActivity = activity;
- mCallback = callback;
- mMessage = message;
- }
+ /**
+ * Called when somebody wants to dismiss the Keyguard via the flag.
+ */
+ private void handleDismissKeyguard(int displayId) {
+ // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
+ // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
+ // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
+ if (!mWindowManager.isKeyguardSecure(mService.getCurrentUserId())) {
+ return;
}
- static final class TopActivityOccludesKeyguardParam {
- boolean mRet;
- @NonNull final ActivityRecord mActivity;
+ mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ state.mDismissalRequested = true;
- TopActivityOccludesKeyguardParam(@NonNull ActivityRecord activity) {
- mActivity = activity;
- }
+ // If we are about to unocclude the Keyguard, but we can dismiss it without security,
+ // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
+ if (state.mKeyguardShowing && canDismissKeyguard()
+ && dc.mAppTransition.containsTransitRequest(TRANSIT_KEYGUARD_UNOCCLUDE)) {
+ mWindowManager.executeAppTransition();
}
+ }
- static final class DumpParam {
- ArrayList<String> mRet = new ArrayList<>();
- String mPrefix;
-
- DumpParam(@NonNull String prefix) {
- mPrefix = prefix;
- }
- }
+ boolean isDisplayOccluded(int displayId) {
+ return getDisplayState(displayId).mOccluded;
+ }
- KeyguardDisplayStateMachine(int displayId, @KeyguardState int initialState) {
- super(initialState);
- mDisplayId = displayId;
- }
+ /**
+ * @return true if Keyguard can be currently dismissed without entering credentials.
+ */
+ boolean canDismissKeyguard() {
+ return mWindowManager.mPolicy.isKeyguardTrustedLw()
+ || !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
+ }
- @Nullable
- @Override
- public Handler addStateHandler(int state, Handler handler) {
- Handler prevHandler = super.addStateHandler(state, handler);
- if (prevHandler != null) {
- throw new IllegalStateException(
- "Duplicate state handler registration: display=" + mDisplayId
- + ", state=" + state);
- }
- return null;
- }
+ /**
+ * @return Whether the dream activity is on top of default display.
+ */
+ boolean isShowingDream() {
+ return getDisplayState(DEFAULT_DISPLAY).mShowingDream;
+ }
- @Override
- public void transit(@KeyguardState int newState) {
- if (DEBUG) {
- StringBuilder sb = new StringBuilder();
- sb.append("[ ");
- for (Command cmd : getCommands()) {
- sb.append(cmd);
- sb.append(' ');
- }
- sb.append(" ]");
- Slog.d(TAG, "State change: display=" + mDisplayId
- + ", current=" + keyguardStateToString(getCurrentState())
- + ", lastRequested=" + keyguardStateToString(getState())
- + ", newState=" + keyguardStateToString(newState)
- + ", command=" + sb
- + ", stack=" + Debug.getCallers(30));
- }
- super.transit(newState);
+ private void dismissMultiWindowModeForTaskIfNeeded(int displayId,
+ @Nullable Task currentTaskControllingOcclusion) {
+ // TODO(b/113840485): Handle docked stack for individual display.
+ if (!getDisplayState(displayId).mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
+ return;
}
- @Override
- public void enter(@KeyguardState int state) {
- if (DEBUG) {
- Slog.d(TAG, "enter: display=" + mDisplayId + ", state="
- + keyguardStateToString(state));
- }
- super.enter(state);
+ // Dismiss freeform windowing mode
+ if (currentTaskControllingOcclusion == null) {
+ return;
}
-
- @Override
- public void exit(@KeyguardState int state) {
- if (DEBUG) {
- Slog.d(TAG, "exit: display=" + mDisplayId + ", state="
- + keyguardStateToString(state));
- }
- super.exit(state);
+ if (currentTaskControllingOcclusion.inFreeformWindowingMode()) {
+ currentTaskControllingOcclusion.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
+ }
- void handleDismissKeyguardActivity() {
- handle(EVENT_DISMISS_KEYGUARD_ACTIVITY, null /* param */);
+ private void updateKeyguardSleepToken() {
+ for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
+ displayNdx >= 0; displayNdx--) {
+ final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
+ updateKeyguardSleepToken(display.mDisplayId);
}
+ }
- void handleTurnScreenOnActivity() {
- handle(EVENT_TURN_SCREEN_ON_ACTIVITY, null /* param */);
+ private void updateKeyguardSleepToken(int displayId) {
+ final KeyguardDisplayState state = getDisplayState(displayId);
+ if (isKeyguardUnoccludedOrAodShowing(displayId)) {
+ state.mSleepTokenAcquirer.acquire(displayId);
+ } else {
+ state.mSleepTokenAcquirer.release(displayId);
}
+ }
- boolean handleDismissKeyguard(@NonNull ActivityRecord r,
- @Nullable IKeyguardDismissCallback callback, @Nullable CharSequence message) {
- DismissKeyguardParam param = new DismissKeyguardParam(r, callback, message);
- handle(EVENT_DISMISS_KEYGUARD_API, param);
- return param.mRet;
+ private KeyguardDisplayState getDisplayState(int displayId) {
+ KeyguardDisplayState state = mDisplayStates.get(displayId);
+ if (state == null) {
+ state = new KeyguardDisplayState(mService, displayId, mSleepTokenAcquirer);
+ mDisplayStates.append(displayId, state);
}
+ return state;
+ }
- void handleShowWhenLockedActivity() {
- handle(EVENT_SHOW_WHEN_LOCKED_ACTIVITY, null /* param */);
+ void onDisplayRemoved(int displayId) {
+ final KeyguardDisplayState state = mDisplayStates.get(displayId);
+ if (state != null) {
+ state.onRemoved();
+ mDisplayStates.remove(displayId);
}
+ }
- void handleLayoutChanges() {
- handle(EVENT_LAYOUT_CHANGES, null /* param */);
+ private final Runnable mResetWaitTransition = () -> {
+ synchronized (mWindowManager.mGlobalLock) {
+ updateDeferTransitionForAod(false /* waiting */);
}
+ };
- boolean checkKeyguardVisibility(@NonNull ActivityRecord r) {
- final CheckKeyguardVisibilityParam param = new CheckKeyguardVisibilityParam(r);
- handle(EVENT_CHECK_KEYGUARD_VISIBILITY, param);
- return param.mRet;
+ // Defer transition until AOD dismissed.
+ void updateDeferTransitionForAod(boolean waiting) {
+ if (waiting == mWaitingForWakeTransition) {
+ return;
}
-
- boolean topActivityOccludesKeyguard(@NonNull ActivityRecord r) {
- final TopActivityOccludesKeyguardParam param = new TopActivityOccludesKeyguardParam(r);
- handle(EVENT_TOP_ACTIVITY_OCCLUDES_KEYGUARD, param);
- return param.mRet;
+ if (!mService.getTransitionController().isCollecting()) {
+ return;
}
-
- ArrayList<String> handleDump(String prefix) {
- final DumpParam param = new DumpParam(prefix);
- handle(EVENT_DUMP, param);
- return param.mRet;
+ // if AOD is showing, defer the wake transition until AOD state changed.
+ if (waiting && isAodShowing(DEFAULT_DISPLAY)) {
+ mWaitingForWakeTransition = true;
+ mWindowManager.mAtmService.getTransitionController().deferTransitionReady();
+ mWindowManager.mH.postDelayed(mResetWaitTransition, DEFER_WAKE_TRANSITION_TIMEOUT_MS);
+ } else if (!waiting) {
+ // dismiss the deferring if the AOD state change or cancel awake.
+ mWaitingForWakeTransition = false;
+ mWindowManager.mAtmService.getTransitionController().continueTransitionReady();
+ mWindowManager.mH.removeCallbacks(mResetWaitTransition);
}
}
- /**
- * Helper class for implementing handler in type-safe way.
- */
- private abstract static class Handler implements StateMachine.Handler {
- @Override
- public final boolean handle(int event, @Nullable Object param) {
- switch (event) {
- case KeyguardDisplayStateMachine.EVENT_DISMISS_KEYGUARD_ACTIVITY:
- return handleDismissKeyguardActivity();
- case KeyguardDisplayStateMachine.EVENT_TURN_SCREEN_ON_ACTIVITY:
- return handleTurnScreenOnActivity();
- case KeyguardDisplayStateMachine.EVENT_DISMISS_KEYGUARD_API: {
- final KeyguardDisplayStateMachine.DismissKeyguardParam typedParam =
- (KeyguardDisplayStateMachine.DismissKeyguardParam) param;
- Optional<Boolean> ret = handleDismissKeyguard(typedParam.mActivity,
- typedParam.mCallback, typedParam.mMessage);
- if (ret.isPresent()) {
- typedParam.mRet = ret.get();
- return true;
- }
- return false;
- }
- case KeyguardDisplayStateMachine.EVENT_SHOW_WHEN_LOCKED_ACTIVITY:
- return handleShowWhenLockedActivity();
- case KeyguardDisplayStateMachine.EVENT_CHECK_KEYGUARD_VISIBILITY: {
- final KeyguardDisplayStateMachine.CheckKeyguardVisibilityParam typedParam =
- (KeyguardDisplayStateMachine.CheckKeyguardVisibilityParam) param;
- Optional<Boolean> ret = checkKeyguardVisibility(typedParam.mActivity);
- if (ret.isPresent()) {
- typedParam.mRet = ret.get();
- return true;
- }
- return false;
- }
- case KeyguardDisplayStateMachine.EVENT_TOP_ACTIVITY_OCCLUDES_KEYGUARD: {
- final KeyguardDisplayStateMachine.TopActivityOccludesKeyguardParam typedParam =
- (KeyguardDisplayStateMachine.TopActivityOccludesKeyguardParam) param;
- Optional<Boolean> ret = topActivityOccludesKeyguardParam(typedParam.mActivity);
- if (ret.isPresent()) {
- typedParam.mRet = ret.get();
- return true;
- }
- return false;
- }
- case KeyguardDisplayStateMachine.EVENT_LAYOUT_CHANGES:
- return handleLayoutChanges();
- case KeyguardDisplayStateMachine.EVENT_DUMP:
- final KeyguardDisplayStateMachine.DumpParam typedParam =
- (KeyguardDisplayStateMachine.DumpParam) param;
- String dumpInfo = handleDump(typedParam.mPrefix);
- if (dumpInfo != null) {
- typedParam.mRet.add(dumpInfo);
- }
- // keep collecting information for dump up to top status.
- return false;
- default:
- Slog.e(TAG, "Handler.handle(): Unknown event(" + event + ")");
- return false;
- }
- }
-
- Optional<Boolean> checkKeyguardVisibility(@NonNull ActivityRecord activity) {
- return Optional.empty();
- }
- Optional<Boolean> topActivityOccludesKeyguardParam(@NonNull ActivityRecord r) {
- return Optional.empty();
- }
-
- /**
- * Handle flags in the activity which request to dismiss the keyguard.
- *
- * @see ActivityOptions#setDismissKeyguard()
- * @see WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD
- */
- boolean handleDismissKeyguardActivity() {
- return false;
- }
-
- /**
- * Handle flags in the activity which request to turn the screen on. This must be called
- * after dismiss keyguard flag is handled.
- */
- boolean handleTurnScreenOnActivity() {
- return false;
- }
- /**
- * Handle flags in the activity which decides if the activity can be shown on top of the
- * keyguard.
- *
- * @see android.app.Activity#setShowWhenLocked(boolean)
- * @see android.app.Activity#setInheritShowWhenLocked(boolean)
- */
- boolean handleShowWhenLockedActivity() {
- return false;
+ /** Represents Keyguard state per individual display. */
+ private static class KeyguardDisplayState {
+ private final int mDisplayId;
+ private boolean mKeyguardShowing;
+ private boolean mAodShowing;
+ private boolean mKeyguardGoingAway;
+ private boolean mDismissalRequested;
+ private boolean mOccluded;
+ private boolean mShowingDream;
+
+ private ActivityRecord mTopOccludesActivity;
+ private ActivityRecord mDismissingKeyguardActivity;
+ private ActivityRecord mTopTurnScreenOnActivity;
+
+ private boolean mRequestDismissKeyguard;
+ private final ActivityTaskManagerService mService;
+ private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer;
+
+ KeyguardDisplayState(ActivityTaskManagerService service, int displayId,
+ ActivityTaskManagerInternal.SleepTokenAcquirer acquirer) {
+ mService = service;
+ mDisplayId = displayId;
+ mSleepTokenAcquirer = acquirer;
}
- /**
- * Request relayout if necessary.
- */
- boolean handleLayoutChanges() {
- return false;
+ void onRemoved() {
+ mTopOccludesActivity = null;
+ mDismissingKeyguardActivity = null;
+ mTopTurnScreenOnActivity = null;
+ mSleepTokenAcquirer.release(mDisplayId);
}
/**
- * Called when the activity requests to dismiss the keyguard via KeyguardManager APIs.
- *
- * @param r The activity which requested to dismiss the keyguard.
- * @return Present if the state handles, delegate to its parent state otherwise. When the
- * value is present, the value is {@code true} if the keyguard dismiss request is
- * processed, {@code false} otherwise.
+ * Updates keyguard status if the top task could be visible. The top task may occlude
+ * keyguard, request to dismiss keyguard or make insecure keyguard go away based on its
+ * properties.
*/
- Optional<Boolean> handleDismissKeyguard(@NonNull ActivityRecord r,
- @Nullable IKeyguardDismissCallback callback, @Nullable CharSequence message) {
- return Optional.empty();
- }
-
- @Nullable String handleDump(@NonNull String prefix) {
- return null;
- }
- }
-
- private static class DisplayState {
- private final int mDisplayId;
- @NonNull private final ServiceDelegate mServiceDelegate;
- private final KeyguardDisplayStateMachine mStateMachine;
-
- // TODO: Set watchdog timer to sync mLastNotifiedOccludedState == isIn(OCCLUDED)
- private boolean mLastNotifiedOccludedState = false;
-
- // Top activity which has a window with FLAG_DISMISS_KEYGUARD flag. Valid only when the
- // current state is KEYGUARD_STATE_ON or one of its sub states.
- @Nullable private ActivityRecord mDismissingKeyguardActivity;
-
- // KeyguardController has requested to dismiss keyguard via IWindowManager#dismissKeyguard.
- // Reset this to false again, once the KeyguardController status is updated.
- private boolean mDismissalRequested = false;
-
- DisplayState(int displayId, @NonNull ServiceDelegate serviceDelegate) {
- mDisplayId = displayId;
- mServiceDelegate = serviceDelegate;
- mStateMachine = new KeyguardDisplayStateMachine(displayId, KEYGUARD_STATE_OFF);
-
- mStateMachine.addStateHandler(KEYGUARD_STATE_ROOT, new Handler() {
- @Override
- Optional<Boolean> checkKeyguardVisibility(@NonNull ActivityRecord activity) {
- return Optional.of(false);
+ void updateVisibility(KeyguardController controller, DisplayContent display) {
+ final boolean lastOccluded = mOccluded;
+ final boolean lastKeyguardGoingAway = mKeyguardGoingAway;
+
+ final ActivityRecord lastDismissKeyguardActivity = mDismissingKeyguardActivity;
+ final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity;
+
+ mRequestDismissKeyguard = false;
+ mOccluded = false;
+ mShowingDream = false;
+
+ mTopOccludesActivity = null;
+ mDismissingKeyguardActivity = null;
+ mTopTurnScreenOnActivity = null;
+
+ boolean occludedByActivity = false;
+ final Task task = getRootTaskForControllingOccluding(display);
+ final ActivityRecord top = task != null ? task.getTopNonFinishingActivity() : null;
+ if (top != null) {
+ if (top.containsDismissKeyguardWindow()) {
+ mDismissingKeyguardActivity = top;
}
-
- @Override
- Optional<Boolean> topActivityOccludesKeyguardParam(@NonNull ActivityRecord r) {
- return Optional.of(false);
+ if (top.getTurnScreenOnFlag() && top.currentLaunchCanTurnScreenOn()) {
+ mTopTurnScreenOnActivity = top;
}
- });
- mStateMachine.addStateHandler(KEYGUARD_STATE_OFF, new Handler() {
- @Override
- public Optional<Boolean> checkKeyguardVisibility(@NonNull ActivityRecord r) {
- return Optional.of(true);
+ if (top.mDismissKeyguard && mKeyguardShowing) {
+ mKeyguardGoingAway = true;
+ } else if (top.canShowWhenLocked()) {
+ mTopOccludesActivity = top;
}
-
- @Override
- Optional<Boolean> handleDismissKeyguard(
- @NonNull ActivityRecord r, @Nullable IKeyguardDismissCallback callback,
- @Nullable CharSequence message) {
- // Keyguard is not shown, so we don't handle the request to dismiss the
- // keyguard.
- return Optional.of(false);
- }
- });
-
- mStateMachine.addStateHandler(KEYGUARD_STATE_GOING_AWAY, new Handler() {
- @Override
- public void enter() {
- mServiceDelegate.deferWindowLayout();
- try {
- mServiceDelegate.requestTransitionIfNeeded(mDisplayId,
- TRANSIT_KEYGUARD_GOING_AWAY,
- TRANSIT_FLAG_KEYGUARD_GOING_AWAY
- | TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER);
- // Some stack visibility might change (e.g. docked stack)
- mServiceDelegate.releaseSleepToken(mDisplayId,
- true /* resumeTopActivities */);
- mServiceDelegate.executeAppTransition();
- } finally {
- mServiceDelegate.continueWindowLayout();
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- }
- });
-
- mStateMachine.addStateHandler(KEYGUARD_STATE_ON, new Handler() {
- public boolean handleDismissKeyguardActivity() {
- final ActivityRecord lastDismissingKeyguardActivity =
- mDismissingKeyguardActivity;
- final ActivityRecord top = mServiceDelegate.getTopNonFinishingActivity(
- mDisplayId);
- mDismissingKeyguardActivity =
- (top != null && top.containsDismissKeyguardWindow()) ? top : null;
- if (lastDismissingKeyguardActivity != mDismissingKeyguardActivity
- && mDismissingKeyguardActivity != null
- && mServiceDelegate.isKeyguardSecure()) {
- // We only allow dismissing Keyguard via the flag when Keyguard is secure
- // for legacy reasons, because that's how apps used to dismiss Keyguard in
- // the secure case. In the insecure case, we actually show it on top of the
- // lockscreen. See #canShowWhileOccluded.
- mDismissalRequested = true;
- mServiceDelegate.dismissKeyguard(null, null);
- }
- return true;
- }
-
- @Override
- Optional<Boolean> handleDismissKeyguard(@NonNull ActivityRecord r,
- @Nullable IKeyguardDismissCallback callback,
- @Nullable CharSequence message) {
- if (!r.visibleIgnoringKeyguard) {
- return Optional.of(false);
- }
- if (DEBUG) {
- Slog.d(TAG, "Activity requesting to dismiss Keyguard: " + r);
- }
- // If the client has requested to dismiss the keyguard and the Activity has the
- // flag to turn the screen on, wakeup the screen if it's the top Activity.
- // Note that it's possible that the client requests to dismiss the keyguard
- // before the activity adds a window. In this case the flag set on the window
- // is not yet visible from ActivityRecord, so we need to check the flag again
- // when the activity adds a window later. See #handleTurnScreenOnActivity().
- if (r.getTurnScreenOnFlag() && r.isTopRunningActivity()) {
- mServiceDelegate.wakeUp("ON/handleDismissKeyguard");
- r.setCurrentLaunchCanTurnScreenOn(false);
- }
- mDismissalRequested = true;
- mServiceDelegate.dismissKeyguard(callback, message);
- return Optional.of(true);
- }
-
- @Override
- public void enter() {
- // Update the task snapshot if the screen will not be turned off. To make sure
- // that the unlocking animation can animate consistent content.
- mServiceDelegate.snapshotForSleeping(mDisplayId);
+ top.mDismissKeyguard = false;
+
+ // Only the top activity may control occluded, as we can't occlude the Keyguard
+ // if the top app doesn't want to occlude it.
+ occludedByActivity = mTopOccludesActivity != null
+ || (mDismissingKeyguardActivity != null
+ && task.topRunningActivity() == mDismissingKeyguardActivity
+ && controller.canShowWhileOccluded(
+ true /* dismissKeyguard */, false /* showWhenLocked */));
+ // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
+ if (mDisplayId != DEFAULT_DISPLAY) {
+ occludedByActivity |= display.canShowWithInsecureKeyguard()
+ && controller.canDismissKeyguard();
}
+ }
- @Nullable
- @Override
- String handleDump(@NonNull String prefix) {
- StringBuffer sb = new StringBuffer();
- sb.append(prefix)
- .append(" mDismissingKeyguardActivity=")
- .append(mDismissingKeyguardActivity)
- .append("\n");
- return sb.toString();
- }
- });
-
- mStateMachine.addStateHandler(KEYGUARD_STATE_OCCLUDED, new Handler() {
- ActivityRecord mTopOccludesActivity;
-
- @Override
- Optional<Boolean> checkKeyguardVisibility(@NonNull ActivityRecord activity) {
- return Optional.of(mServiceDelegate.canOcclude(activity));
- }
-
- @Override
- public boolean handleShowWhenLockedActivity() {
- final ActivityRecord top = mServiceDelegate.getTopNonFinishingActivity(
- mDisplayId);
- final ActivityRecord topOccludesActivity = mServiceDelegate.canOcclude(top)
- ? top : null;
- if (mTopOccludesActivity == topOccludesActivity) {
- return true;
- }
- // Launch SHOW_WHEN_LOCKED or INHERIT_SHOW_WHEN_LOCKED activity on top of an
- // occluding activity.
- mTopOccludesActivity = topOccludesActivity;
- if (mServiceDelegate.isTopActivityDreaming(mDisplayId)) {
- // Dream activity is launched on top of the previous SHOW_WHEN_LOCKED
- // activity.
- setKeyguardState(KEYGUARD_STATE_DREAMING);
- } else if (topOccludesActivity == null) {
- // SHOW_WHEN_LOCKED activity finishes.
- setKeyguardState(KEYGUARD_STATE_LOCKSCREEN_SHOWN);
- }
- return true;
- }
-
- @Override
- boolean handleLayoutChanges() {
- // The occluding activity may be translucent or not fill screen. Then let
- // wallpaper to check whether it should set itself as target to avoid blank
- // background.
- if (!mTopOccludesActivity.fillsParent()) {
- mServiceDelegate.requestLayoutRedoWallpaper(mDisplayId);
- }
- return true;
- }
-
- @Override
- Optional<Boolean> topActivityOccludesKeyguardParam(@NonNull ActivityRecord r) {
- return Optional.of(mTopOccludesActivity == r);
- }
-
- @Override
- public void enter() {
- mTopOccludesActivity = mServiceDelegate.getTopNonFinishingActivity(mDisplayId);
- if (!mServiceDelegate.canOcclude(mTopOccludesActivity)) {
- Slog.e(TAG, "enter(OCCLUDE): no occluding activity");
- setKeyguardState(KEYGUARD_STATE_LOCKSCREEN_SHOWN);
- return;
- }
-
- if (DEBUG) {
- Slog.d(TAG, "handleOccludedChanged: display=" + mDisplayId
- + ", topActivity=" + mTopOccludesActivity);
- }
- // Collect the participates for shell transition, so that transition won't
- // happen too early since the transition was set ready.
- mServiceDelegate.collect(mTopOccludesActivity);
- // TODO(b/113840485): Handle app transition for individual display, and apply
- // occluded state change to secondary displays. For now, only default display
- // fully supports occluded change. Other displays only updates keyguard sleep
- // token on that display.
- if (mDisplayId != DEFAULT_DISPLAY) {
- mServiceDelegate.releaseSleepToken(mDisplayId,
- false /* resumeTopActivities */);
- return;
- }
-
- if (mTopOccludesActivity.getTurnScreenOnFlag()
- && mTopOccludesActivity.currentLaunchCanTurnScreenOn()
- && !mServiceDelegate.isDeviceInteractive()) {
- mServiceDelegate.wakeUp("OCCLUDE/enter");
- mTopOccludesActivity.setCurrentLaunchCanTurnScreenOn(false);
- }
-
- mServiceDelegate.notifyKeyguardOccludeChanged(true /* occluded */);
- mServiceDelegate.deferWindowLayout();
- try {
- mServiceDelegate.requestTransitionIfNeeded(mDisplayId,
- TRANSIT_KEYGUARD_OCCLUDE, 0 /* flags */);
- mServiceDelegate.releaseSleepToken(mDisplayId,
- false /* resumeTopActivities */);
- mServiceDelegate.executeAppTransition();
- } finally {
- mServiceDelegate.continueWindowLayout();
- }
- // Dismiss freeform windowing mode
- final Task currentTaskControllingOcclusion = mTopOccludesActivity.getRootTask();
- if (currentTaskControllingOcclusion != null
- && currentTaskControllingOcclusion.inFreeformWindowingMode()) {
- currentTaskControllingOcclusion.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- }
- }
-
- @Override
- public void exit() {
- mTopOccludesActivity = null;
- if (DEBUG) {
- Slog.d(TAG, "handleOccludedChanged: topActivity=" + null);
- }
- // TODO(b/113840485): Handle app transition for individual display, and apply
- // occluded state change to secondary displays.
- // For now, only default display fully supports occluded change. Other displays
- // only updates keyguard sleep token on that display.
- if (mDisplayId != DEFAULT_DISPLAY) {
- mServiceDelegate.acquireSleepToken(
- mDisplayId, false /* ensureActivitiesVisible */);
- return;
- }
-
- mServiceDelegate.notifyKeyguardOccludeChanged(false /* occluded */);
- mServiceDelegate.deferWindowLayout();
- try {
- mServiceDelegate.requestTransitionIfNeeded(mDisplayId,
- TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */);
- mServiceDelegate.acquireSleepToken(
- mDisplayId, false /* ensureActivitiesVisible */);
- mServiceDelegate.executeAppTransition();
- } finally {
- mServiceDelegate.continueWindowLayout();
- }
- }
-
- @Nullable
- @Override
- String handleDump(@NonNull String prefix) {
- StringBuffer sb = new StringBuffer();
- sb.append(prefix)
- .append(" mTopOccludesActivity=")
- .append(mTopOccludesActivity)
- .append("\n");
- return sb.toString();
- }
- });
-
- mStateMachine.addStateHandler(KEYGUARD_STATE_KEYGUARD_TOP, new Handler() {
- @Override
- public boolean handleDismissKeyguardActivity() {
- final ActivityRecord top = mServiceDelegate.getTopNonFinishingActivity(
- mDisplayId);
- if (top != null && top.mDismissKeyguard) {
- // Top activity has been launched with ActivityOptions#setDismissKeyguard.
- // Authentication has already been passed, so we can turn off the keyguard
- // immediately.
- top.mDismissKeyguard = false;
- setKeyguardState(KEYGUARD_STATE_GOING_AWAY);
- // Collect the participates for shell transition, so that transition won't
- // happen too early since the transition was set ready.
- mServiceDelegate.collect(top);
- return true;
- }
- return false;
- }
-
- @Override
- public void enter() {
- mServiceDelegate.acquireSleepToken(mDisplayId,
- true /* ensureActivitiesVisible */);
- InputMethodManagerInternal.get().updateImeWindowStatus(
- false /* disableImeIcon */);
- mServiceDelegate.setWakeTransitionReady();
- }
-
- @Override
- public void exit() {
- // Sleep token is released in enter() action in other states, since we need
- // to call requestTransition() before updating visibility of the activities.
- }
- });
-
- mStateMachine.addStateHandler(KEYGUARD_STATE_LOCKSCREEN_SHOWN, new Handler() {
- @Override
- public Optional<Boolean> checkKeyguardVisibility(@NonNull ActivityRecord r) {
- // If lock screen is showing, nothing is visible, except if we are able to
- // dismiss Keyguard right away. This isn't allowed if r is already the
- // dismissing activity, in which case we don't allow it to repeatedly
- // dismiss Keyguard.
- return Optional.of(r.containsDismissKeyguardWindow()
- && mServiceDelegate.canDismissKeyguard()
- && (mDismissalRequested
- || (r.canShowWhenLocked() && mDismissingKeyguardActivity != r)));
- }
-
- @Override
- public boolean handleShowWhenLockedActivity() {
- final ActivityRecord top = mServiceDelegate.getTopNonFinishingActivity(
- mDisplayId);
- final ActivityRecord topOccludesActivity = mServiceDelegate.canOcclude(top)
- ? top : null;
- if (topOccludesActivity != null) {
- setKeyguardState(mServiceDelegate.isTopActivityDreaming(mDisplayId)
- ? KEYGUARD_STATE_DREAMING : KEYGUARD_STATE_OCCLUDED);
- }
- return true;
- }
- });
-
- mStateMachine.addStateHandler(KEYGUARD_STATE_AOD_SHOWN, new Handler() {
- // Top activity which has FLAG_TURN_SCREEN_ON flag.
- @Nullable private ActivityRecord mTopTurnScreenOnActivity;
-
- @Override
- public Optional<Boolean> checkKeyguardVisibility(@NonNull ActivityRecord r) {
- return Optional.of(false);
- }
-
- @Override
- boolean handleTurnScreenOnActivity() {
- final ActivityRecord lastTopTurnScreenOnActivity = mTopTurnScreenOnActivity;
- final ActivityRecord top = mServiceDelegate.getTopNonFinishingActivity(
- mDisplayId);
- mTopTurnScreenOnActivity = (top != null && top.getTurnScreenOnFlag()
- && top.currentLaunchCanTurnScreenOn()) ? top : null;
- if (mTopTurnScreenOnActivity != lastTopTurnScreenOnActivity
- && mTopTurnScreenOnActivity != null
- && !mServiceDelegate.isDeviceInteractive()
- && mDismissalRequested) {
- mServiceDelegate.wakeUp("AOD_SHOWN/handleTurnScreenOnActivity");
- mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
- }
- return true;
- }
-
- @Override
- public void enter() {
- if (mLastNotifiedOccludedState) {
- if (mDisplayId == DEFAULT_DISPLAY) {
- mServiceDelegate.forceSyncOccludedStatus(false);
- }
- commitOccludedStatus(false);
- }
- }
-
- @Override
- public void exit() {
- mServiceDelegate.updateDeferTransitionForAod(false /* waiting */);
- }
-
- @Nullable
- @Override
- String handleDump(@NonNull String prefix) {
- StringBuffer sb = new StringBuffer();
- sb.append(prefix)
- .append(" mTopTurnScreenOnActivity=")
- .append(mTopTurnScreenOnActivity)
- .append("\n");
- return sb.toString();
- }
- });
- }
-
- void onRemoved() {
- mServiceDelegate.releaseSleepToken(mDisplayId, false /* resumeTopActivities */);
- }
-
- void updateVisibility() {
- mStateMachine.handleDismissKeyguardActivity();
- mStateMachine.handleTurnScreenOnActivity();
- mStateMachine.handleShowWhenLockedActivity();
- mStateMachine.handleLayoutChanges();
- }
-
- boolean dismissKeyguard(@NonNull ActivityRecord r,
- @Nullable IKeyguardDismissCallback callback,
- @Nullable CharSequence message) {
- return mStateMachine.handleDismissKeyguard(r, callback, message);
- }
-
- void commitOccludedStatus(boolean occluded) {
- mLastNotifiedOccludedState = occluded;
- }
-
- void setKeyguardState(@KeyguardState int newState) {
- mDismissalRequested = false;
- mStateMachine.transit(newState);
- }
-
- boolean isKeyguardTop() {
- return mStateMachine.isIn(KEYGUARD_STATE_KEYGUARD_TOP);
- }
+ mShowingDream = display.getDisplayPolicy().isShowingDreamLw() && (top != null
+ && top.getActivityType() == ACTIVITY_TYPE_DREAM);
+ mOccluded = mShowingDream || occludedByActivity;
+ mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity
+ && !mOccluded && !mKeyguardGoingAway
+ && mDismissingKeyguardActivity != null;
+ if (mOccluded && mKeyguardShowing && !display.isSleeping() && !top.fillsParent()
+ && display.mWallpaperController.getWallpaperTarget() == null) {
+ // The occluding activity may be translucent or not fill screen. Then let wallpaper
+ // to check whether it should set itself as target to avoid blank background.
+ display.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ }
- boolean isIn(@KeyguardState int category) {
- return mStateMachine.isIn(category);
- }
+ if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
+ && mTopTurnScreenOnActivity != null
+ && !mService.mWindowManager.mPowerManager.isInteractive()
+ && (mRequestDismissKeyguard || occludedByActivity)) {
+ controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
+ mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
+ }
- boolean topActivityOccludesKeyguard(@NonNull ActivityRecord r) {
- return mStateMachine.topActivityOccludesKeyguard(r);
+ boolean hasChange = false;
+ if (lastOccluded != mOccluded) {
+ controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
+ hasChange = true;
+ } else if (!lastKeyguardGoingAway && mKeyguardGoingAway) {
+ controller.handleKeyguardGoingAwayChanged(display);
+ hasChange = true;
+ }
+ // Collect the participates for shell transition, so that transition won't happen too
+ // early since the transition was set ready.
+ if (hasChange && top != null && (mOccluded || mKeyguardGoingAway)) {
+ display.mTransitionController.collect(top);
+ }
}
- boolean checkKeyguardVisibility(@NonNull ActivityRecord r) {
- return mStateMachine.checkKeyguardVisibility(r);
+ /**
+ * Gets the stack used to check the occluded state.
+ * <p>
+ * Only the top non-pinned activity of the focusable stack on each display can control its
+ * occlusion state.
+ */
+ @Nullable
+ private Task getRootTaskForControllingOccluding(DisplayContent display) {
+ return display.getRootTask(task ->
+ task != null && task.isFocusableAndVisible() && !task.inPinnedWindowingMode());
+ }
+
+ void dumpStatus(PrintWriter pw, String prefix) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(prefix);
+ sb.append(" KeyguardShowing=")
+ .append(mKeyguardShowing)
+ .append(" AodShowing=")
+ .append(mAodShowing)
+ .append(" KeyguardGoingAway=")
+ .append(mKeyguardGoingAway)
+ .append(" DismissalRequested=")
+ .append(mDismissalRequested)
+ .append(" Occluded=")
+ .append(mOccluded)
+ .append(" DismissingKeyguardActivity=")
+ .append(mDismissingKeyguardActivity)
+ .append(" TurnScreenOnActivity=")
+ .append(mTopTurnScreenOnActivity)
+ .append(" at display=")
+ .append(mDisplayId);
+ pw.println(sb.toString());
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(KeyguardPerDisplayProto.DISPLAY_ID, mDisplayId);
- proto.write(KeyguardPerDisplayProto.KEYGUARD_SHOWING,
- isIn(KEYGUARD_STATE_LOCKSCREEN_SHOWN));
- proto.write(KeyguardPerDisplayProto.AOD_SHOWING, isIn(KEYGUARD_STATE_AOD_SHOWN));
- proto.write(KeyguardPerDisplayProto.KEYGUARD_OCCLUDED, isIn(KEYGUARD_STATE_OCCLUDED));
+ proto.write(KeyguardPerDisplayProto.KEYGUARD_SHOWING, mKeyguardShowing);
+ proto.write(KeyguardPerDisplayProto.AOD_SHOWING, mAodShowing);
+ proto.write(KeyguardPerDisplayProto.KEYGUARD_OCCLUDED, mOccluded);
+ proto.write(KeyguardPerDisplayProto.KEYGUARD_GOING_AWAY, mKeyguardGoingAway);
proto.end(token);
}
+ }
- void dump(PrintWriter pw, String prefix) {
- StringBuffer sb = new StringBuffer();
- sb.append(prefix)
- .append("* display=")
- .append(mDisplayId)
- .append("\n");
- sb.append(prefix)
- .append(" state=")
- .append(keyguardStateToString(mStateMachine.getState()))
- .append("\n");
- sb.append(prefix)
- .append(" mLastNotifiedOccludedState=")
- .append(mLastNotifiedOccludedState)
- .append("\n");
- sb.append(prefix)
- .append(" mDismissalRequested=")
- .append(mDismissalRequested)
- .append("\n");
- pw.print(sb.toString());
+ void dump(PrintWriter pw, String prefix) {
+ final KeyguardDisplayState default_state = getDisplayState(DEFAULT_DISPLAY);
+ pw.println(prefix + "KeyguardController:");
+ pw.println(prefix + " mKeyguardShowing=" + default_state.mKeyguardShowing);
+ pw.println(prefix + " mAodShowing=" + default_state.mAodShowing);
+ pw.println(prefix + " mKeyguardGoingAway=" + default_state.mKeyguardGoingAway);
+ dumpDisplayStates(pw, prefix);
+ pw.println(prefix + " mDismissalRequested=" + default_state.mDismissalRequested);
+ pw.println();
+ }
- ArrayList<String> dumpInfo = mStateMachine.handleDump(prefix);
- for (int i = dumpInfo.size() - 1; i >= 0; --i) {
- pw.print(dumpInfo.get(i));
- }
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final KeyguardDisplayState default_state = getDisplayState(DEFAULT_DISPLAY);
+ final long token = proto.start(fieldId);
+ proto.write(AOD_SHOWING, default_state.mAodShowing);
+ proto.write(KEYGUARD_SHOWING, default_state.mKeyguardShowing);
+ proto.write(KEYGUARD_GOING_AWAY, default_state.mKeyguardGoingAway);
+ writeDisplayStatesToProto(proto, KEYGUARD_PER_DISPLAY);
+ proto.end(token);
+ }
+
+ private void dumpDisplayStates(PrintWriter pw, String prefix) {
+ for (int i = 0; i < mDisplayStates.size(); i++) {
+ mDisplayStates.valueAt(i).dumpStatus(pw, prefix);
+ }
+ }
+
+ private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) {
+ for (int i = 0; i < mDisplayStates.size(); i++) {
+ mDisplayStates.valueAt(i).dumpDebug(proto, fieldId);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 80965a78bc9b..5e116baa3fae 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -730,7 +730,7 @@ class TransitionController {
void dispatchLegacyAppTransitionStarting(TransitionInfo info, long statusBarTransitionDelay) {
for (int i = 0; i < mLegacyListeners.size(); ++i) {
- mLegacyListeners.get(i).onAppTransitionStartingLocked(info);
+ // TODO(shell-transitions): handle (un)occlude transition.
mLegacyListeners.get(i).onAppTransitionStartingLocked(
SystemClock.uptimeMillis() + statusBarTransitionDelay,
AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ad6bd3c6ccf6..1282acbc9e5a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -44,7 +44,6 @@ import android.view.SurfaceControlViewHost;
import android.view.WindowInfo;
import android.view.WindowManager.DisplayImePolicy;
import android.view.inputmethod.ImeTracker;
-import android.window.TransitionInfo;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.server.input.InputManagerService;
@@ -213,7 +212,7 @@ public abstract class WindowManagerInternal {
* Abstract class to be notified about {@link com.android.server.wm.AppTransition} events. Held
* as an abstract class so a listener only needs to implement the methods of its interest.
*/
- public abstract static class AppTransitionListener {
+ public static abstract class AppTransitionListener {
/**
* Called when an app transition is being setup and about to be executed.
@@ -252,20 +251,6 @@ public abstract class WindowManagerInternal {
}
/**
- * Called when an app transition gets started when WM shell is enabled.
- *
- * @param info Information about what is changing during a transition.
- *
- * @return Return any bit set of {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER},
- * or {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
- */
- public int onAppTransitionStartingLocked(TransitionInfo info) {
- return 0;
- }
-
- /**
* Called when an app transition is finished running.
*
* @param token the token for app whose transition has finished
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f6cb06866cf3..a596eed2a500 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3132,7 +3132,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void notifyKeyguardTrustedChanged() {
synchronized (mGlobalLock) {
- if (mAtmService.mKeyguardController.isLocksScreenShowing(DEFAULT_DISPLAY)) {
+ if (mAtmService.mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
mRoot.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 9fda2043c5d2..e663245157cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1475,6 +1475,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Make keyguard locked and set the top activity show-when-locked.
KeyguardController keyguardController = activity.mTaskSupervisor.getKeyguardController();
int displayId = activity.getDisplayId();
+ doReturn(true).when(keyguardController).isKeyguardLocked(eq(displayId));
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
topActivity.setVisibleRequested(true);
topActivity.nowVisible = true;
@@ -1484,24 +1485,18 @@ public class ActivityRecordTests extends WindowTestsBase {
anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
topActivity.setShowWhenLocked(true);
- try {
- keyguardController.setKeyguardShown(displayId, true, false);
-
- // Verify the stack-top activity is occluded keyguard.
- assertEquals(topActivity, task.topRunningActivity());
- assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
+ // Verify the stack-top activity is occluded keyguard.
+ assertEquals(topActivity, task.topRunningActivity());
+ assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
- // Finish the top activity
- topActivity.setState(PAUSED, "true");
- topActivity.finishing = true;
- topActivity.completeFinishing("test");
+ // Finish the top activity
+ topActivity.setState(PAUSED, "true");
+ topActivity.finishing = true;
+ topActivity.completeFinishing("test");
- // Verify new top activity does not occlude keyguard.
- assertEquals(activity, task.topRunningActivity());
- assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
- } finally {
- keyguardController.setKeyguardShown(displayId, false, false);
- }
+ // Verify new top activity does not occlude keyguard.
+ assertEquals(activity, task.topRunningActivity());
+ assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 305260b23d12..3dcae91f5c89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -252,12 +252,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
mAtm.setLockScreenShown(true, true);
mRootWindowContainer.forAllDisplays(displayContent -> {
assertTrue(displayContent.isKeyguardLocked());
- // Only default display supports AOD.
- if (displayContent.isDefaultDisplay) {
- assertTrue(displayContent.isAodShowing());
- } else {
- assertFalse(displayContent.isAodShowing());
- }
+ assertTrue(displayContent.isAodShowing());
});
// Check setLockScreenShown unlocking both displays