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