blob: a46c85170ba2a8ea59f9dc03e7fc1e7e6eac787e [file] [log] [blame]
Jorim Jaggife762342016-10-13 14:33:27 +02001/*
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
17package com.android.server.am;
18
19import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070020import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
Jorim Jaggife762342016-10-13 14:33:27 +020021import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
22import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
23import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
Jorim Jaggi241ae102016-11-02 21:57:33 -070024import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
25import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
Jorim Jaggife762342016-10-13 14:33:27 +020026import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
27import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
28import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
29import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
30import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
31import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
32import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
Jorim Jaggi8b702ed2017-01-20 16:59:03 +010033import static com.android.server.wm.AppTransition.TRANSIT_NONE;
Jorim Jaggife762342016-10-13 14:33:27 +020034import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
35
Jorim Jaggi241ae102016-11-02 21:57:33 -070036import android.os.IBinder;
37import android.os.RemoteException;
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070038import android.os.Trace;
Jorim Jaggi241ae102016-11-02 21:57:33 -070039import android.util.Slog;
40
41import com.android.internal.policy.IKeyguardDismissCallback;
Jorim Jaggife762342016-10-13 14:33:27 +020042import com.android.server.wm.WindowManagerService;
43
Jorim Jaggi8d786932016-10-26 19:08:36 -070044import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020045import java.util.ArrayList;
46
47/**
48 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
49 * currently visible.
50 * <p>
51 * Note that everything in this class should only be accessed with the AM lock being held.
52 */
53class KeyguardController {
54
Jorim Jaggi241ae102016-11-02 21:57:33 -070055 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
56
Jorim Jaggife762342016-10-13 14:33:27 +020057 private final ActivityManagerService mService;
58 private final ActivityStackSupervisor mStackSupervisor;
59 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020060 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070061 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020062 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010063 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020064 private ActivityRecord mDismissingKeyguardActivity;
65 private int mBeforeUnoccludeTransit;
66 private int mVisibilityTransactionDepth;
67
68 KeyguardController(ActivityManagerService service,
69 ActivityStackSupervisor stackSupervisor) {
70 mService = service;
71 mStackSupervisor = stackSupervisor;
72 }
73
74 void setWindowManager(WindowManagerService windowManager) {
75 mWindowManager = windowManager;
76 }
77
78 /**
79 * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
80 */
81 boolean isKeyguardShowing() {
82 return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
83 }
84
85 /**
86 * @return true if Keyguard is either showing or occluded, but not going away
87 */
88 boolean isKeyguardLocked() {
89 return mKeyguardShowing && !mKeyguardGoingAway;
90 }
91
92 /**
93 * Update the Keyguard showing state.
94 */
95 void setKeyguardShown(boolean showing) {
96 if (showing == mKeyguardShowing) {
97 return;
98 }
99 mKeyguardShowing = showing;
Matthew Ngf4344ef2017-04-20 15:19:58 -0700100 dismissDockedStackIfNeeded();
Jorim Jaggife762342016-10-13 14:33:27 +0200101 if (showing) {
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700102 setKeyguardGoingAway(false);
Jorim Jaggi07961872016-11-23 11:28:57 +0100103 mDismissalRequested = false;
Jorim Jaggife762342016-10-13 14:33:27 +0200104 }
105 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
106 mService.updateSleepIfNeededLocked();
107 }
108
109 /**
110 * Called when Keyguard is going away.
111 *
112 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
113 * etc.
114 */
115 void keyguardGoingAway(int flags) {
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700116 if (!mKeyguardShowing) {
117 return;
118 }
119 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
120 mWindowManager.deferSurfaceLayout();
121 try {
122 setKeyguardGoingAway(true);
123 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
124 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
125 false /* forceOverride */);
126 mService.updateSleepIfNeededLocked();
Jorim Jaggife762342016-10-13 14:33:27 +0200127
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700128 // Some stack visibility might change (e.g. docked stack)
129 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
130 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
131 mWindowManager.executeAppTransition();
132 } finally {
133 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
134 mWindowManager.continueSurfaceLayout();
135 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
136
137 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
Jorim Jaggife762342016-10-13 14:33:27 +0200138 }
139 }
140
Jorim Jaggi241ae102016-11-02 21:57:33 -0700141 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
142 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
143 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
144 failCallback(callback);
145 return;
146 }
147 mWindowManager.dismissKeyguard(callback);
148 }
149
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700150 private void setKeyguardGoingAway(boolean keyguardGoingAway) {
151 mKeyguardGoingAway = keyguardGoingAway;
152 mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
153 }
154
Jorim Jaggi241ae102016-11-02 21:57:33 -0700155 private void failCallback(IKeyguardDismissCallback callback) {
156 try {
157 callback.onDismissError();
158 } catch (RemoteException e) {
159 Slog.w(TAG, "Failed to call callback", e);
160 }
161 }
162
Jorim Jaggife762342016-10-13 14:33:27 +0200163 private int convertTransitFlags(int keyguardGoingAwayFlags) {
164 int result = 0;
165 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
166 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
167 }
168 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
169 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
170 }
171 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
172 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
173 }
174 return result;
175 }
176
177 /**
178 * Starts a batch of visibility updates.
179 */
180 void beginActivityVisibilityUpdate() {
181 mVisibilityTransactionDepth++;
182 }
183
184 /**
185 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
186 * update lockscreen occluded/dismiss state if needed.
187 */
188 void endActivityVisibilityUpdate() {
189 mVisibilityTransactionDepth--;
190 if (mVisibilityTransactionDepth == 0) {
191 visibilitiesUpdated();
192 }
193 }
194
Jorim Jaggie69c9312016-10-31 18:24:38 -0700195 /**
196 * @return True if we may show an activity while Keyguard is showing because we are in the
197 * process of dismissing it anyways, false otherwise.
198 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100199 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
200
201 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
202 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
203 // Keyguard.
204 return dismissKeyguard && canDismissKeyguard() &&
205 (mDismissalRequested || r != mDismissingKeyguardActivity);
206 }
207
208 /**
209 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
210 */
211 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
212 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700213 }
214
Jorim Jaggife762342016-10-13 14:33:27 +0200215 private void visibilitiesUpdated() {
216 final boolean lastOccluded = mOccluded;
217 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
218 mOccluded = false;
219 mDismissingKeyguardActivity = null;
220 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
Wale Ogunwalee287e192017-04-21 09:30:12 -0700221 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
Jorim Jaggife762342016-10-13 14:33:27 +0200222 final ActivityStack stack = stacks.get(stackNdx);
223
Wale Ogunwalee287e192017-04-21 09:30:12 -0700224 // Only the focused stack top activity may control occluded state
225 if (mStackSupervisor.isFocusedStack(stack)) {
Jorim Jaggi07961872016-11-23 11:28:57 +0100226
227 // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
228 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
229 mOccluded = stack.topActivityOccludesKeyguard()
230 || (topDismissing != null
231 && stack.topRunningActivityLocked() == topDismissing
232 && canShowWhileOccluded(true /* dismissKeyguard */,
233 false /* showWhenLocked */));
Jorim Jaggife762342016-10-13 14:33:27 +0200234 }
235 if (mDismissingKeyguardActivity == null
236 && stack.getTopDismissingKeyguardActivity() != null) {
237 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
238 }
239 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700240 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200241 if (mOccluded != lastOccluded) {
242 handleOccludedChanged();
243 }
244 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
245 handleDismissKeyguard();
246 }
247 }
248
249 /**
250 * Called when occluded state changed.
251 */
252 private void handleOccludedChanged() {
253 mWindowManager.onKeyguardOccludedChanged(mOccluded);
254 if (isKeyguardLocked()) {
255 mWindowManager.deferSurfaceLayout();
256 try {
257 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
258 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
259 mService.updateSleepIfNeededLocked();
260 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
261 mWindowManager.executeAppTransition();
262 } finally {
263 mWindowManager.continueSurfaceLayout();
264 }
265 }
266 dismissDockedStackIfNeeded();
267 }
268
269 /**
270 * Called when somebody might want to dismiss the Keyguard.
271 */
272 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100273 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
274 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
275 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
276 if (!mOccluded && mDismissingKeyguardActivity != null
277 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700278 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100279 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200280
281 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
282 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
283 if (mKeyguardShowing && canDismissKeyguard()
284 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
285 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
286 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200287 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
288 mWindowManager.executeAppTransition();
289 }
290 }
291 }
292
293 /**
294 * @return true if Keyguard can be currently dismissed without entering credentials.
295 */
Andrii Kulianfc8f82b2017-01-26 13:17:27 -0800296 boolean canDismissKeyguard() {
Jorim Jaggife762342016-10-13 14:33:27 +0200297 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
298 }
299
300 private int resolveOccludeTransit() {
301 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
302 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
303 && mOccluded) {
304
305 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
306 // actually occclude/unocclude Keyguard, but just run a normal transition.
307 return mBeforeUnoccludeTransit;
308 } else if (!mOccluded) {
309
310 // Save transit in case we dismiss/occlude Keyguard shortly after.
311 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
312 return TRANSIT_KEYGUARD_UNOCCLUDE;
313 } else {
314 return TRANSIT_KEYGUARD_OCCLUDE;
315 }
316 }
317
318 private void dismissDockedStackIfNeeded() {
319 if (mKeyguardShowing && mOccluded) {
320 // The lock screen is currently showing, but is occluded by a window that can
321 // show on top of the lock screen. In this can we want to dismiss the docked
322 // stack since it will be complicated/risky to try to put the activity on top
323 // of the lock screen in the right fullscreen configuration.
324 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
325 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
326 }
327 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700328
329 void dump(PrintWriter pw, String prefix) {
330 pw.println(prefix + "KeyguardController:");
331 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
332 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
333 pw.println(prefix + " mOccluded=" + mOccluded);
334 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100335 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700336 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
337 }
Jorim Jaggife762342016-10-13 14:33:27 +0200338}