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.am;
18 
19 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
20 import static android.view.Display.DEFAULT_DISPLAY;
21 import static android.view.Display.INVALID_DISPLAY;
22 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
23 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
24 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
25 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
26 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
27 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
28 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
29 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
30 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
31 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
32 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
33 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
34 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
35 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
36 import static android.view.WindowManager.TRANSIT_UNSET;
37 
38 import android.app.ActivityManagerInternal.SleepToken;
39 import android.os.IBinder;
40 import android.os.RemoteException;
41 import android.os.Trace;
42 import android.util.Slog;
43 import android.util.proto.ProtoOutputStream;
44 
45 import com.android.internal.policy.IKeyguardDismissCallback;
46 import com.android.server.policy.WindowManagerPolicy;
47 import com.android.server.wm.WindowManagerService;
48 
49 import java.io.PrintWriter;
50 
51 /**
52  * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
53  * currently visible.
54  * <p>
55  * Note that everything in this class should only be accessed with the AM lock being held.
56  */
57 class KeyguardController {
58 
59     private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
60 
61     private final ActivityManagerService mService;
62     private final ActivityStackSupervisor mStackSupervisor;
63     private WindowManagerService mWindowManager;
64     private boolean mKeyguardShowing;
65     private boolean mAodShowing;
66     private boolean mKeyguardGoingAway;
67     private boolean mOccluded;
68     private boolean mDismissalRequested;
69     private ActivityRecord mDismissingKeyguardActivity;
70     private int mBeforeUnoccludeTransit;
71     private int mVisibilityTransactionDepth;
72     private SleepToken mSleepToken;
73     private int mSecondaryDisplayShowing = INVALID_DISPLAY;
74 
KeyguardController(ActivityManagerService service, ActivityStackSupervisor stackSupervisor)75     KeyguardController(ActivityManagerService service,
76             ActivityStackSupervisor stackSupervisor) {
77         mService = service;
78         mStackSupervisor = stackSupervisor;
79     }
80 
setWindowManager(WindowManagerService windowManager)81     void setWindowManager(WindowManagerService windowManager) {
82         mWindowManager = windowManager;
83     }
84 
85     /**
86      * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
87      *         on the given display, false otherwise
88      */
isKeyguardOrAodShowing(int displayId)89     boolean isKeyguardOrAodShowing(int displayId) {
90         return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway &&
91                 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
92     }
93 
94     /**
95      * @return true if Keyguard is showing, not going away, and not being occluded on the given
96      *         display, false otherwise
97      */
isKeyguardShowing(int displayId)98     boolean isKeyguardShowing(int displayId) {
99         return mKeyguardShowing && !mKeyguardGoingAway &&
100                 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
101     }
102 
103     /**
104      * @return true if Keyguard is either showing or occluded, but not going away
105      */
isKeyguardLocked()106     boolean isKeyguardLocked() {
107         return mKeyguardShowing && !mKeyguardGoingAway;
108     }
109 
110     /**
111      * @return {@code true} if the keyguard is going away, {@code false} otherwise.
112      */
isKeyguardGoingAway()113     boolean isKeyguardGoingAway() {
114         // Also check keyguard showing in case value is stale.
115         return mKeyguardGoingAway && mKeyguardShowing;
116     }
117 
118     /**
119      * Update the Keyguard showing state.
120      */
setKeyguardShown(boolean keyguardShowing, boolean aodShowing, int secondaryDisplayShowing)121     void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
122             int secondaryDisplayShowing) {
123         boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
124         // If keyguard is going away, but SystemUI aborted the transition, need to reset state.
125         showingChanged |= mKeyguardGoingAway && keyguardShowing;
126         if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
127             return;
128         }
129         mKeyguardShowing = keyguardShowing;
130         mAodShowing = aodShowing;
131         mSecondaryDisplayShowing = secondaryDisplayShowing;
132         mWindowManager.setAodShowing(aodShowing);
133         if (showingChanged) {
134             dismissDockedStackIfNeeded();
135             setKeyguardGoingAway(false);
136             mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
137                     isKeyguardOrAodShowing(DEFAULT_DISPLAY));
138             if (keyguardShowing) {
139                 mDismissalRequested = false;
140             }
141         }
142         mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
143         updateKeyguardSleepToken();
144     }
145 
146     /**
147      * Called when Keyguard is going away.
148      *
149      * @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
150      *              etc.
151      */
keyguardGoingAway(int flags)152     void keyguardGoingAway(int flags) {
153         if (!mKeyguardShowing) {
154             return;
155         }
156         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
157         mWindowManager.deferSurfaceLayout();
158         try {
159             setKeyguardGoingAway(true);
160             mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
161                     false /* alwaysKeepCurrent */, convertTransitFlags(flags),
162                     false /* forceOverride */);
163             updateKeyguardSleepToken();
164 
165             // Some stack visibility might change (e.g. docked stack)
166             mStackSupervisor.resumeFocusedStackTopActivityLocked();
167             mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
168             mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
169             mWindowManager.executeAppTransition();
170         } finally {
171             Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
172             mWindowManager.continueSurfaceLayout();
173             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
174 
175             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
176         }
177     }
178 
dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message)179     void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message) {
180         final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
181         if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
182             failCallback(callback);
183             return;
184         }
185         Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
186 
187         // If the client has requested to dismiss the keyguard and the Activity has the flag to
188         // turn the screen on, wakeup the screen if it's the top Activity.
189         if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
190             mStackSupervisor.wakeUp("dismissKeyguard");
191         }
192 
193         mWindowManager.dismissKeyguard(callback, message);
194     }
195 
setKeyguardGoingAway(boolean keyguardGoingAway)196     private void setKeyguardGoingAway(boolean keyguardGoingAway) {
197         mKeyguardGoingAway = keyguardGoingAway;
198         mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
199     }
200 
failCallback(IKeyguardDismissCallback callback)201     private void failCallback(IKeyguardDismissCallback callback) {
202         try {
203             callback.onDismissError();
204         } catch (RemoteException e) {
205             Slog.w(TAG, "Failed to call callback", e);
206         }
207     }
208 
convertTransitFlags(int keyguardGoingAwayFlags)209     private int convertTransitFlags(int keyguardGoingAwayFlags) {
210         int result = 0;
211         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
212             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
213         }
214         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
215             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
216         }
217         if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
218             result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
219         }
220         return result;
221     }
222 
223     /**
224      * Starts a batch of visibility updates.
225      */
beginActivityVisibilityUpdate()226     void beginActivityVisibilityUpdate() {
227         mVisibilityTransactionDepth++;
228     }
229 
230     /**
231      * Ends a batch of visibility updates. After all batches are done, this method makes sure to
232      * update lockscreen occluded/dismiss state if needed.
233      */
endActivityVisibilityUpdate()234     void endActivityVisibilityUpdate() {
235         mVisibilityTransactionDepth--;
236         if (mVisibilityTransactionDepth == 0) {
237             visibilitiesUpdated();
238         }
239     }
240 
241     /**
242      * @return True if we may show an activity while Keyguard is showing because we are in the
243      *         process of dismissing it anyways, false otherwise.
244      */
canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard)245     boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
246 
247         // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
248         // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
249         // Keyguard.
250         return dismissKeyguard && canDismissKeyguard() && !mAodShowing
251                 && (mDismissalRequested || r != mDismissingKeyguardActivity);
252     }
253 
254     /**
255      * @return True if we may show an activity while Keyguard is occluded, false otherwise.
256      */
canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked)257     boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
258         return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
259     }
260 
visibilitiesUpdated()261     private void visibilitiesUpdated() {
262         final boolean lastOccluded = mOccluded;
263         final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
264         mOccluded = false;
265         mDismissingKeyguardActivity = null;
266 
267         for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
268             final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
269             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
270                 final ActivityStack stack = display.getChildAt(stackNdx);
271 
272                 // Only the top activity of the focused stack on the default display may control
273                 // occluded state.
274                 if (display.mDisplayId == DEFAULT_DISPLAY
275                         && mStackSupervisor.isFocusedStack(stack)) {
276 
277                     // A dismissing activity occludes Keyguard in the insecure case for legacy
278                     // reasons.
279                     final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
280                     mOccluded =
281                             stack.topActivityOccludesKeyguard()
282                                     || (topDismissing != null
283                                             && stack.topRunningActivityLocked() == topDismissing
284                                             && canShowWhileOccluded(
285                                                     true /* dismissKeyguard */,
286                                                     false /* showWhenLocked */));
287                 }
288 
289                 if (mDismissingKeyguardActivity == null
290                         && stack.getTopDismissingKeyguardActivity() != null) {
291                     mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
292                 }
293             }
294         }
295         mOccluded |= mWindowManager.isShowingDream();
296         if (mOccluded != lastOccluded) {
297             handleOccludedChanged();
298         }
299         if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
300             handleDismissKeyguard();
301         }
302     }
303 
304     /**
305      * Called when occluded state changed.
306      */
handleOccludedChanged()307     private void handleOccludedChanged() {
308         mWindowManager.onKeyguardOccludedChanged(mOccluded);
309         if (isKeyguardLocked()) {
310             mWindowManager.deferSurfaceLayout();
311             try {
312                 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
313                         false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
314                 updateKeyguardSleepToken();
315                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
316                 mWindowManager.executeAppTransition();
317             } finally {
318                 mWindowManager.continueSurfaceLayout();
319             }
320         }
321         dismissDockedStackIfNeeded();
322     }
323 
324     /**
325      * Called when somebody might want to dismiss the Keyguard.
326      */
handleDismissKeyguard()327     private void handleDismissKeyguard() {
328         // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
329         // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
330         // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
331         if (!mOccluded && mDismissingKeyguardActivity != null
332                 && mWindowManager.isKeyguardSecure()) {
333             mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
334             mDismissalRequested = true;
335 
336             // If we are about to unocclude the Keyguard, but we can dismiss it without security,
337             // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
338             if (mKeyguardShowing && canDismissKeyguard()
339                     && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
340                 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
341                         false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
342                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
343                 mWindowManager.executeAppTransition();
344             }
345         }
346     }
347 
348     /**
349      * @return true if Keyguard can be currently dismissed without entering credentials.
350      */
canDismissKeyguard()351     boolean canDismissKeyguard() {
352         return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
353     }
354 
resolveOccludeTransit()355     private int resolveOccludeTransit() {
356         if (mBeforeUnoccludeTransit != TRANSIT_UNSET
357                 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
358                 && mOccluded) {
359 
360             // Reuse old transit in case we are occluding Keyguard again, meaning that we never
361             // actually occclude/unocclude Keyguard, but just run a normal transition.
362             return mBeforeUnoccludeTransit;
363         } else if (!mOccluded) {
364 
365             // Save transit in case we dismiss/occlude Keyguard shortly after.
366             mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
367             return TRANSIT_KEYGUARD_UNOCCLUDE;
368         } else {
369             return TRANSIT_KEYGUARD_OCCLUDE;
370         }
371     }
372 
dismissDockedStackIfNeeded()373     private void dismissDockedStackIfNeeded() {
374         if (mKeyguardShowing && mOccluded) {
375             // The lock screen is currently showing, but is occluded by a window that can
376             // show on top of the lock screen. In this can we want to dismiss the docked
377             // stack since it will be complicated/risky to try to put the activity on top
378             // of the lock screen in the right fullscreen configuration.
379             final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
380             if (stack == null) {
381                 return;
382             }
383             mStackSupervisor.moveTasksToFullscreenStackLocked(stack,
384                     mStackSupervisor.mFocusedStack == stack);
385         }
386     }
387 
updateKeyguardSleepToken()388     private void updateKeyguardSleepToken() {
389         if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
390             mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
391         } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
392             mSleepToken.release();
393             mSleepToken = null;
394         }
395     }
396 
dump(PrintWriter pw, String prefix)397     void dump(PrintWriter pw, String prefix) {
398         pw.println(prefix + "KeyguardController:");
399         pw.println(prefix + "  mKeyguardShowing=" + mKeyguardShowing);
400         pw.println(prefix + "  mAodShowing=" + mAodShowing);
401         pw.println(prefix + "  mKeyguardGoingAway=" + mKeyguardGoingAway);
402         pw.println(prefix + "  mOccluded=" + mOccluded);
403         pw.println(prefix + "  mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
404         pw.println(prefix + "  mDismissalRequested=" + mDismissalRequested);
405         pw.println(prefix + "  mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
406     }
407 
writeToProto(ProtoOutputStream proto, long fieldId)408     void writeToProto(ProtoOutputStream proto, long fieldId) {
409         final long token = proto.start(fieldId);
410         proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
411         proto.write(KEYGUARD_OCCLUDED, mOccluded);
412         proto.end(token);
413     }
414 }
415