1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
20 import static android.view.Display.DEFAULT_DISPLAY;
21 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
22 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
23 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
24 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
25 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
26 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
27 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
28 import static android.view.WindowManager.TRANSIT_UNSET;
29 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
30 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
31 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
32 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
33 
34 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
35 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
36 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
37 import static com.android.server.wm.KeyguardControllerProto.AOD_SHOWING;
38 import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
39 import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_SHOWING;
40 import static com.android.server.wm.KeyguardOccludedProto.DISPLAY_ID;
41 import static com.android.server.wm.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
42 
43 import android.os.IBinder;
44 import android.os.RemoteException;
45 import android.os.Trace;
46 import android.util.Slog;
47 import android.util.SparseArray;
48 import android.util.proto.ProtoOutputStream;
49 
50 import com.android.internal.policy.IKeyguardDismissCallback;
51 import com.android.server.policy.WindowManagerPolicy;
52 import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
53 
54 import java.io.PrintWriter;
55 
56 /**
57  * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
58  * currently visible.
59  * <p>
60  * Note that everything in this class should only be accessed with the AM lock being held.
61  */
62 class KeyguardController {
63 
64     private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_ATM;
65 
66     private final ActivityStackSupervisor mStackSupervisor;
67     private WindowManagerService mWindowManager;
68     private boolean mKeyguardShowing;
69     private boolean mAodShowing;
70     private boolean mKeyguardGoingAway;
71     private boolean mDismissalRequested;
72     private int mBeforeUnoccludeTransit;
73     private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
74     private final ActivityTaskManagerService mService;
75     private RootWindowContainer mRootWindowContainer;
76 
KeyguardController(ActivityTaskManagerService service, ActivityStackSupervisor stackSupervisor)77     KeyguardController(ActivityTaskManagerService service,
78             ActivityStackSupervisor stackSupervisor) {
79         mService = service;
80         mStackSupervisor = stackSupervisor;
81     }
82 
setWindowManager(WindowManagerService windowManager)83     void setWindowManager(WindowManagerService windowManager) {
84         mWindowManager = windowManager;
85         mRootWindowContainer = mService.mRootWindowContainer;
86     }
87 
88     /**
89      * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
90      *         on the given display, false otherwise.
91      */
isKeyguardOrAodShowing(int displayId)92     boolean isKeyguardOrAodShowing(int displayId) {
93         return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
94                 && !isDisplayOccluded(displayId);
95     }
96 
97     /**
98      * @return {@code true} for default display when AOD is showing. Otherwise, same as
99      *         {@link #isKeyguardOrAodShowing(int)}
100      * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
101      */
isKeyguardUnoccludedOrAodShowing(int displayId)102     boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
103         if (displayId == DEFAULT_DISPLAY && mAodShowing) {
104             return true;
105         }
106         return isKeyguardOrAodShowing(displayId);
107     }
108 
109     /**
110      * @return true if Keyguard is showing, not going away, and not being occluded on the given
111      *         display, false otherwise
112      */
isKeyguardShowing(int displayId)113     boolean isKeyguardShowing(int displayId) {
114         return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
115     }
116 
117     /**
118      * @return true if Keyguard is either showing or occluded, but not going away
119      */
isKeyguardLocked()120     boolean isKeyguardLocked() {
121         return mKeyguardShowing && !mKeyguardGoingAway;
122     }
123 
124     /**
125      * @return {@code true} if the keyguard is going away, {@code false} otherwise.
126      */
isKeyguardGoingAway()127     boolean isKeyguardGoingAway() {
128         // Also check keyguard showing in case value is stale.
129         return mKeyguardGoingAway && mKeyguardShowing;
130     }
131 
132     /**
133      * Update the Keyguard showing state.
134      */
setKeyguardShown(boolean keyguardShowing, boolean aodShowing)135     void setKeyguardShown(boolean keyguardShowing, boolean aodShowing) {
136         final boolean aodChanged = aodShowing != mAodShowing;
137         // If keyguard is going away, but SystemUI aborted the transition, need to reset state.
138         // Do not reset keyguardChanged status if this is aodChanged.
139         final boolean keyguardChanged = (keyguardShowing != mKeyguardShowing)
140                 || (mKeyguardGoingAway && keyguardShowing && !aodChanged);
141         if (!keyguardChanged && !aodChanged) {
142             return;
143         }
144         EventLogTags.writeWmSetKeyguardShown(
145                 keyguardShowing ? 1 : 0,
146                 aodShowing ? 1 : 0,
147                 mKeyguardGoingAway ? 1 : 0,
148                 "setKeyguardShown");
149         mKeyguardShowing = keyguardShowing;
150         mAodShowing = aodShowing;
151         mWindowManager.setAodShowing(aodShowing);
152 
153         if (keyguardChanged) {
154             // Irrelevant to AOD.
155             dismissDockedStackIfNeeded();
156             setKeyguardGoingAway(false);
157             if (keyguardShowing) {
158                 mDismissalRequested = false;
159             }
160         }
161         // TODO(b/113840485): Check usage for non-default display
162         mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
163                 isKeyguardOrAodShowing(DEFAULT_DISPLAY));
164 
165         // Update the sleep token first such that ensureActivitiesVisible has correct sleep token
166         // state when evaluating visibilities.
167         updateKeyguardSleepToken();
168         mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
169     }
170 
171     /**
172      * Called when Keyguard is going away.
173      *
174      * @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
175      *              etc.
176      */
keyguardGoingAway(int flags)177     void keyguardGoingAway(int flags) {
178         if (!mKeyguardShowing) {
179             return;
180         }
181         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "keyguardGoingAway");
182         mService.deferWindowLayout();
183         try {
184             setKeyguardGoingAway(true);
185             EventLogTags.writeWmSetKeyguardShown(
186                     1 /* keyguardShowing */,
187                     mAodShowing ? 1 : 0,
188                     1 /* keyguardGoingAway */,
189                     "keyguardGoingAway");
190             mRootWindowContainer.getDefaultDisplay().mDisplayContent
191                     .prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
192                             false /* alwaysKeepCurrent */, convertTransitFlags(flags),
193                             false /* forceOverride */);
194             updateKeyguardSleepToken();
195 
196             // Some stack visibility might change (e.g. docked stack)
197             mRootWindowContainer.resumeFocusedStacksTopActivities();
198             mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
199             mRootWindowContainer.addStartingWindowsForVisibleActivities();
200             mWindowManager.executeAppTransition();
201         } finally {
202             mService.continueWindowLayout();
203             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
204         }
205     }
206 
dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message)207     void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message) {
208         final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
209         if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
210             failCallback(callback);
211             return;
212         }
213         Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
214 
215         // If the client has requested to dismiss the keyguard and the Activity has the flag to
216         // turn the screen on, wakeup the screen if it's the top Activity.
217         if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
218             mStackSupervisor.wakeUp("dismissKeyguard");
219         }
220 
221         mWindowManager.dismissKeyguard(callback, message);
222     }
223 
setKeyguardGoingAway(boolean keyguardGoingAway)224     private void setKeyguardGoingAway(boolean keyguardGoingAway) {
225         mKeyguardGoingAway = keyguardGoingAway;
226         mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
227     }
228 
failCallback(IKeyguardDismissCallback callback)229     private void failCallback(IKeyguardDismissCallback callback) {
230         try {
231             callback.onDismissError();
232         } catch (RemoteException e) {
233             Slog.w(TAG, "Failed to call callback", e);
234         }
235     }
236 
convertTransitFlags(int keyguardGoingAwayFlags)237     private int convertTransitFlags(int keyguardGoingAwayFlags) {
238         int result = 0;
239         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
240             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
241         }
242         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
243             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
244         }
245         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
246             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
247         }
248         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS) != 0) {
249             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
250         }
251         return result;
252     }
253 
254     /**
255      * @return True if we may show an activity while Keyguard is showing because we are in the
256      *         process of dismissing it anyways, false otherwise.
257      */
canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard)258     boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
259 
260         // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
261         // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
262         // Keyguard.
263         return dismissKeyguard && canDismissKeyguard() && !mAodShowing
264                 && (mDismissalRequested
265                 || (r.canShowWhenLocked()
266                         && getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r));
267     }
268 
269     /**
270      * @return True if we may show an activity while Keyguard is occluded, false otherwise.
271      */
canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked)272     boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
273         return showWhenLocked || dismissKeyguard
274                 && !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
275     }
276 
277     /**
278      * Makes sure to update lockscreen occluded/dismiss state if needed after completing all
279      * visibility updates ({@link ActivityStackSupervisor#endActivityVisibilityUpdate}).
280      */
visibilitiesUpdated()281     void visibilitiesUpdated() {
282         boolean requestDismissKeyguard = false;
283         for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
284              displayNdx >= 0; displayNdx--) {
285             final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
286             final KeyguardDisplayState state = getDisplay(display.mDisplayId);
287             state.visibilitiesUpdated(this, display);
288             requestDismissKeyguard |= state.mRequestDismissKeyguard;
289         }
290 
291         // Dismissing Keyguard happens globally using the information from all displays.
292         if (requestDismissKeyguard) {
293             handleDismissKeyguard();
294         }
295     }
296 
297     /**
298      * Called when occluded state changed.
299      */
handleOccludedChanged(int displayId)300     private void handleOccludedChanged(int displayId) {
301         // TODO(b/113840485): Handle app transition for individual display, and apply occluded
302         // state change to secondary displays.
303         // For now, only default display fully supports occluded change. Other displays only
304         // updates keygaurd sleep token on that display.
305         if (displayId != DEFAULT_DISPLAY) {
306             updateKeyguardSleepToken(displayId);
307             return;
308         }
309 
310         mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY));
311         if (isKeyguardLocked()) {
312             mService.deferWindowLayout();
313             try {
314                 mRootWindowContainer.getDefaultDisplay().mDisplayContent
315                         .prepareAppTransition(resolveOccludeTransit(),
316                                 false /* alwaysKeepCurrent */, 0 /* flags */,
317                                 true /* forceOverride */);
318                 updateKeyguardSleepToken(DEFAULT_DISPLAY);
319                 mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
320                 mWindowManager.executeAppTransition();
321             } finally {
322                 mService.continueWindowLayout();
323             }
324         }
325         dismissDockedStackIfNeeded();
326     }
327 
328     /**
329      * Called when somebody wants to dismiss the Keyguard via the flag.
330      */
handleDismissKeyguard()331     private void handleDismissKeyguard() {
332         // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
333         // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
334         // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
335         if (!mWindowManager.isKeyguardSecure(mService.getCurrentUserId())) {
336             return;
337         }
338 
339         mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
340         mDismissalRequested = true;
341 
342         // If we are about to unocclude the Keyguard, but we can dismiss it without security,
343         // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
344         final DisplayContent dc =
345                 mRootWindowContainer.getDefaultDisplay().mDisplayContent;
346         if (mKeyguardShowing && canDismissKeyguard()
347                 && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
348             dc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
349                     0 /* flags */, true /* forceOverride */);
350             mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
351             mWindowManager.executeAppTransition();
352         }
353     }
354 
isDisplayOccluded(int displayId)355     private boolean isDisplayOccluded(int displayId) {
356         return getDisplay(displayId).mOccluded;
357     }
358 
359     /**
360      * @return true if Keyguard can be currently dismissed without entering credentials.
361      */
canDismissKeyguard()362     boolean canDismissKeyguard() {
363         return mWindowManager.mPolicy.isKeyguardTrustedLw()
364                 || !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
365     }
366 
resolveOccludeTransit()367     private int resolveOccludeTransit() {
368         final DisplayContent dc = mRootWindowContainer.getDefaultDisplay().mDisplayContent;
369         if (mBeforeUnoccludeTransit != TRANSIT_UNSET
370                 && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
371                 // TODO(b/113840485): Handle app transition for individual display.
372                 && isDisplayOccluded(DEFAULT_DISPLAY)) {
373 
374             // Reuse old transit in case we are occluding Keyguard again, meaning that we never
375             // actually occclude/unocclude Keyguard, but just run a normal transition.
376             return mBeforeUnoccludeTransit;
377             // TODO(b/113840485): Handle app transition for individual display.
378         } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
379 
380             // Save transit in case we dismiss/occlude Keyguard shortly after.
381             mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
382             return TRANSIT_KEYGUARD_UNOCCLUDE;
383         } else {
384             return TRANSIT_KEYGUARD_OCCLUDE;
385         }
386     }
387 
dismissDockedStackIfNeeded()388     private void dismissDockedStackIfNeeded() {
389         // TODO(b/113840485): Handle docked stack for individual display.
390         if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
391             // The lock screen is currently showing, but is occluded by a window that can
392             // show on top of the lock screen. In this can we want to dismiss the docked
393             // stack since it will be complicated/risky to try to put the activity on top
394             // of the lock screen in the right fullscreen configuration.
395             final TaskDisplayArea taskDisplayArea = mRootWindowContainer
396                     .getDefaultTaskDisplayArea();
397             if (!taskDisplayArea.isSplitScreenModeActivated()) {
398                 return;
399             }
400             taskDisplayArea.onSplitScreenModeDismissed();
401         }
402     }
403 
updateKeyguardSleepToken()404     private void updateKeyguardSleepToken() {
405         for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
406              displayNdx >= 0; displayNdx--) {
407             final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
408             updateKeyguardSleepToken(display.mDisplayId);
409         }
410     }
411 
updateKeyguardSleepToken(int displayId)412     private void updateKeyguardSleepToken(int displayId) {
413         final KeyguardDisplayState state = getDisplay(displayId);
414         if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
415             state.acquiredSleepToken();
416         } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
417             state.releaseSleepToken();
418         }
419     }
420 
getDisplay(int displayId)421     private KeyguardDisplayState getDisplay(int displayId) {
422         KeyguardDisplayState state = mDisplayStates.get(displayId);
423         if (state == null) {
424             state = new KeyguardDisplayState(mService, displayId);
425             mDisplayStates.append(displayId, state);
426         }
427         return state;
428     }
429 
onDisplayRemoved(int displayId)430     void onDisplayRemoved(int displayId) {
431         final KeyguardDisplayState state = mDisplayStates.get(displayId);
432         if (state != null) {
433             state.onRemoved();
434             mDisplayStates.remove(displayId);
435         }
436     }
437 
438     /** Represents Keyguard state per individual display. */
439     private static class KeyguardDisplayState {
440         private final int mDisplayId;
441         private boolean mOccluded;
442         private ActivityRecord mDismissingKeyguardActivity;
443         private boolean mRequestDismissKeyguard;
444         private final ActivityTaskManagerService mService;
445         private SleepToken mSleepToken;
446 
KeyguardDisplayState(ActivityTaskManagerService service, int displayId)447         KeyguardDisplayState(ActivityTaskManagerService service, int displayId) {
448             mService = service;
449             mDisplayId = displayId;
450         }
451 
onRemoved()452         void onRemoved() {
453             mDismissingKeyguardActivity = null;
454             releaseSleepToken();
455         }
456 
acquiredSleepToken()457         void acquiredSleepToken() {
458             if (mSleepToken == null) {
459                 mSleepToken = mService.acquireSleepToken("keyguard", mDisplayId);
460             }
461         }
462 
releaseSleepToken()463         void releaseSleepToken() {
464             if (mSleepToken != null) {
465                 mSleepToken.release();
466                 mSleepToken = null;
467             }
468         }
469 
visibilitiesUpdated(KeyguardController controller, DisplayContent display)470         void visibilitiesUpdated(KeyguardController controller, DisplayContent display) {
471             final boolean lastOccluded = mOccluded;
472             final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
473             mRequestDismissKeyguard = false;
474             mOccluded = false;
475             mDismissingKeyguardActivity = null;
476 
477             final ActivityStack stack = getStackForControllingOccluding(display);
478             if (stack != null) {
479                 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
480                 mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
481                         && stack.topRunningActivity() == topDismissing
482                         && controller.canShowWhileOccluded(
483                                 true /* dismissKeyguard */,
484                                 false /* showWhenLocked */));
485                 if (stack.getTopDismissingKeyguardActivity() != null) {
486                     mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
487                 }
488                 // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
489                 if (mDisplayId != DEFAULT_DISPLAY) {
490                     mOccluded |= stack.canShowWithInsecureKeyguard()
491                             && controller.canDismissKeyguard();
492                 }
493             }
494             // TODO(b/123372519): isShowingDream can only works on default display.
495             if (mDisplayId == DEFAULT_DISPLAY) {
496                 mOccluded |= mService.mRootWindowContainer.getDefaultDisplay().mDisplayContent
497                         .getDisplayPolicy().isShowingDreamLw();
498             }
499 
500             if (lastOccluded != mOccluded) {
501                 controller.handleOccludedChanged(mDisplayId);
502             }
503             if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
504                     && mDismissingKeyguardActivity != null
505                     && controller.mWindowManager.isKeyguardSecure(
506                             controller.mService.getCurrentUserId())) {
507                 mRequestDismissKeyguard = true;
508             }
509         }
510 
511         /**
512          * Gets the stack used to check the occluded state.
513          * <p>
514          * Only the top non-pinned activity of the focusable stack on each display can control its
515          * occlusion state.
516          */
getStackForControllingOccluding(DisplayContent display)517         private ActivityStack getStackForControllingOccluding(DisplayContent display) {
518             for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
519                 final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
520                 for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
521                     final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
522                     if (stack != null && stack.isFocusableAndVisible()
523                             && !stack.inPinnedWindowingMode()) {
524                         return stack;
525                     }
526                 }
527             }
528             return null;
529         }
530 
dumpStatus(PrintWriter pw, String prefix)531         void dumpStatus(PrintWriter pw, String prefix) {
532             final StringBuilder sb = new StringBuilder();
533             sb.append(prefix);
534             sb.append("  Occluded=").append(mOccluded)
535                     .append(" DismissingKeyguardActivity=")
536                     .append(mDismissingKeyguardActivity)
537                     .append(" at display=")
538                     .append(mDisplayId);
539             pw.println(sb.toString());
540         }
541 
dumpDebug(ProtoOutputStream proto, long fieldId)542         void dumpDebug(ProtoOutputStream proto, long fieldId) {
543             final long token = proto.start(fieldId);
544             proto.write(DISPLAY_ID, mDisplayId);
545             proto.write(KEYGUARD_OCCLUDED, mOccluded);
546             proto.end(token);
547         }
548     }
549 
dump(PrintWriter pw, String prefix)550     void dump(PrintWriter pw, String prefix) {
551         pw.println(prefix + "KeyguardController:");
552         pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);
553         pw.println(prefix + "  mAodShowing=" + mAodShowing);
554         pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway);
555         dumpDisplayStates(pw, prefix);
556         pw.println(prefix + "  mDismissalRequested=" + mDismissalRequested);
557         pw.println();
558     }
559 
dumpDebug(ProtoOutputStream proto, long fieldId)560     void dumpDebug(ProtoOutputStream proto, long fieldId) {
561         final long token = proto.start(fieldId);
562         proto.write(AOD_SHOWING, mAodShowing);
563         proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
564         writeDisplayStatesToProto(proto, KEYGUARD_OCCLUDED_STATES);
565         proto.end(token);
566     }
567 
dumpDisplayStates(PrintWriter pw, String prefix)568     private void dumpDisplayStates(PrintWriter pw, String prefix) {
569         for (int i = 0; i < mDisplayStates.size(); i++) {
570             mDisplayStates.valueAt(i).dumpStatus(pw, prefix);
571         }
572     }
573 
writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId)574     private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) {
575         for (int i = 0; i < mDisplayStates.size(); i++) {
576             mDisplayStates.valueAt(i).dumpDebug(proto, fieldId);
577         }
578     }
579 }
580