blob: 35f4f253198fc693a3324a746dcbc74380d13398 [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
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070019import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
David Stevens9440dc82017-03-16 19:00:20 -070020import static android.view.Display.DEFAULT_DISPLAY;
David Stevens53a39ea2017-08-23 18:41:49 -070021import static android.view.Display.INVALID_DISPLAY;
Adrian Roose99bc052017-11-20 17:55:31 +010022import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
23import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
24import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
Jorim Jaggi241ae102016-11-02 21:57:33 -070025import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
26import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
Jorim Jaggife762342016-10-13 14:33:27 +020027import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
Steven Timotius4346f0a2017-09-12 11:07:21 -070028import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_OCCLUDED;
29import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_SHOWING;
Jorim Jaggife762342016-10-13 14:33:27 +020030import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
31import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
32import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
33import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
34import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
35import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
36import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
37
David Stevens9440dc82017-03-16 19:00:20 -070038import android.app.ActivityManagerInternal.SleepToken;
Jorim Jaggi241ae102016-11-02 21:57:33 -070039import android.os.IBinder;
40import android.os.RemoteException;
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070041import android.os.Trace;
Jorim Jaggi241ae102016-11-02 21:57:33 -070042import android.util.Slog;
Steven Timotius4346f0a2017-09-12 11:07:21 -070043import android.util.proto.ProtoOutputStream;
Adrian Roose99bc052017-11-20 17:55:31 +010044
Jorim Jaggi241ae102016-11-02 21:57:33 -070045import com.android.internal.policy.IKeyguardDismissCallback;
Adrian Roose99bc052017-11-20 17:55:31 +010046import com.android.server.policy.WindowManagerPolicy;
Jorim Jaggife762342016-10-13 14:33:27 +020047import com.android.server.wm.WindowManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +010048
Jorim Jaggi8d786932016-10-26 19:08:36 -070049import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020050
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 */
57class KeyguardController {
58
Jorim Jaggi241ae102016-11-02 21:57:33 -070059 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
60
Jorim Jaggife762342016-10-13 14:33:27 +020061 private final ActivityManagerService mService;
62 private final ActivityStackSupervisor mStackSupervisor;
63 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020064 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070065 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020066 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010067 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020068 private ActivityRecord mDismissingKeyguardActivity;
69 private int mBeforeUnoccludeTransit;
70 private int mVisibilityTransactionDepth;
David Stevens9440dc82017-03-16 19:00:20 -070071 private SleepToken mSleepToken;
David Stevens53a39ea2017-08-23 18:41:49 -070072 private int mSecondaryDisplayShowing = INVALID_DISPLAY;
Jorim Jaggife762342016-10-13 14:33:27 +020073
74 KeyguardController(ActivityManagerService service,
75 ActivityStackSupervisor stackSupervisor) {
76 mService = service;
77 mStackSupervisor = stackSupervisor;
78 }
79
80 void setWindowManager(WindowManagerService windowManager) {
81 mWindowManager = windowManager;
82 }
83
84 /**
David Stevens53a39ea2017-08-23 18:41:49 -070085 * @return true if Keyguard is showing, not going away, and not being occluded on the given
86 * display, false otherwise
Jorim Jaggife762342016-10-13 14:33:27 +020087 */
David Stevens53a39ea2017-08-23 18:41:49 -070088 boolean isKeyguardShowing(int displayId) {
89 return mKeyguardShowing && !mKeyguardGoingAway &&
90 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
Jorim Jaggife762342016-10-13 14:33:27 +020091 }
92
93 /**
94 * @return true if Keyguard is either showing or occluded, but not going away
95 */
96 boolean isKeyguardLocked() {
97 return mKeyguardShowing && !mKeyguardGoingAway;
98 }
99
100 /**
101 * Update the Keyguard showing state.
102 */
David Stevens53a39ea2017-08-23 18:41:49 -0700103 void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
104 boolean showingChanged = showing != mKeyguardShowing;
105 if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
Jorim Jaggife762342016-10-13 14:33:27 +0200106 return;
107 }
108 mKeyguardShowing = showing;
David Stevens53a39ea2017-08-23 18:41:49 -0700109 mSecondaryDisplayShowing = secondaryDisplayShowing;
110 if (showingChanged) {
111 dismissDockedStackIfNeeded();
112 if (showing) {
113 setKeyguardGoingAway(false);
114 mDismissalRequested = false;
115 }
Jorim Jaggife762342016-10-13 14:33:27 +0200116 }
117 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
David Stevens9440dc82017-03-16 19:00:20 -0700118 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200119 }
120
121 /**
122 * Called when Keyguard is going away.
123 *
Adrian Roose99bc052017-11-20 17:55:31 +0100124 * @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
Jorim Jaggife762342016-10-13 14:33:27 +0200125 * etc.
126 */
127 void keyguardGoingAway(int flags) {
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700128 if (!mKeyguardShowing) {
129 return;
130 }
131 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
132 mWindowManager.deferSurfaceLayout();
133 try {
134 setKeyguardGoingAway(true);
135 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
136 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
137 false /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700138 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200139
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700140 // Some stack visibility might change (e.g. docked stack)
141 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
142 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
143 mWindowManager.executeAppTransition();
144 } finally {
145 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
146 mWindowManager.continueSurfaceLayout();
147 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
148
149 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
Jorim Jaggife762342016-10-13 14:33:27 +0200150 }
151 }
152
Jorim Jaggi241ae102016-11-02 21:57:33 -0700153 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
154 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
155 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
156 failCallback(callback);
157 return;
158 }
Jorim Jaggid7214892017-07-18 14:05:19 +0200159 Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
chaviw59b98852017-06-13 12:05:44 -0700160
161 // If the client has requested to dismiss the keyguard and the Activity has the flag to
162 // turn the screen on, wakeup the screen if it's the top Activity.
163 if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
164 mStackSupervisor.wakeUp("dismissKeyguard");
165 }
166
Jorim Jaggi241ae102016-11-02 21:57:33 -0700167 mWindowManager.dismissKeyguard(callback);
168 }
169
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700170 private void setKeyguardGoingAway(boolean keyguardGoingAway) {
171 mKeyguardGoingAway = keyguardGoingAway;
172 mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
173 }
174
Jorim Jaggi241ae102016-11-02 21:57:33 -0700175 private void failCallback(IKeyguardDismissCallback callback) {
176 try {
177 callback.onDismissError();
178 } catch (RemoteException e) {
179 Slog.w(TAG, "Failed to call callback", e);
180 }
181 }
182
Jorim Jaggife762342016-10-13 14:33:27 +0200183 private int convertTransitFlags(int keyguardGoingAwayFlags) {
184 int result = 0;
185 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
186 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
187 }
188 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
189 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
190 }
191 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
192 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
193 }
194 return result;
195 }
196
197 /**
198 * Starts a batch of visibility updates.
199 */
200 void beginActivityVisibilityUpdate() {
201 mVisibilityTransactionDepth++;
202 }
203
204 /**
205 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
206 * update lockscreen occluded/dismiss state if needed.
207 */
208 void endActivityVisibilityUpdate() {
209 mVisibilityTransactionDepth--;
210 if (mVisibilityTransactionDepth == 0) {
211 visibilitiesUpdated();
212 }
213 }
214
Jorim Jaggie69c9312016-10-31 18:24:38 -0700215 /**
216 * @return True if we may show an activity while Keyguard is showing because we are in the
217 * process of dismissing it anyways, false otherwise.
218 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100219 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
220
221 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
222 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
223 // Keyguard.
224 return dismissKeyguard && canDismissKeyguard() &&
225 (mDismissalRequested || r != mDismissingKeyguardActivity);
226 }
227
228 /**
229 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
230 */
231 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
232 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700233 }
234
Jorim Jaggife762342016-10-13 14:33:27 +0200235 private void visibilitiesUpdated() {
236 final boolean lastOccluded = mOccluded;
237 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
238 mOccluded = false;
239 mDismissingKeyguardActivity = null;
Jorim Jaggife762342016-10-13 14:33:27 +0200240
Pat Plunkett40426e02017-10-31 14:06:29 -0700241 for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
242 final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
243 for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
244 final ActivityStack stack = display.getChildAt(stackNdx);
Jorim Jaggi07961872016-11-23 11:28:57 +0100245
Pat Plunkett40426e02017-10-31 14:06:29 -0700246 // Only the top activity of the focused stack on the default display may control
247 // occluded state.
248 if (display.mDisplayId == DEFAULT_DISPLAY
249 && mStackSupervisor.isFocusedStack(stack)) {
250
251 // A dismissing activity occludes Keyguard in the insecure case for legacy
252 // reasons.
253 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
254 mOccluded =
255 stack.topActivityOccludesKeyguard()
256 || (topDismissing != null
257 && stack.topRunningActivityLocked() == topDismissing
258 && canShowWhileOccluded(
259 true /* dismissKeyguard */,
260 false /* showWhenLocked */));
261 }
262
263 if (mDismissingKeyguardActivity == null
264 && stack.getTopDismissingKeyguardActivity() != null) {
265 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
266 }
Jorim Jaggife762342016-10-13 14:33:27 +0200267 }
268 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700269 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200270 if (mOccluded != lastOccluded) {
271 handleOccludedChanged();
272 }
273 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
274 handleDismissKeyguard();
275 }
276 }
277
278 /**
279 * Called when occluded state changed.
280 */
281 private void handleOccludedChanged() {
282 mWindowManager.onKeyguardOccludedChanged(mOccluded);
283 if (isKeyguardLocked()) {
284 mWindowManager.deferSurfaceLayout();
285 try {
286 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
287 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700288 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200289 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
290 mWindowManager.executeAppTransition();
291 } finally {
292 mWindowManager.continueSurfaceLayout();
293 }
294 }
295 dismissDockedStackIfNeeded();
296 }
297
298 /**
299 * Called when somebody might want to dismiss the Keyguard.
300 */
301 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100302 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
303 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
304 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
305 if (!mOccluded && mDismissingKeyguardActivity != null
306 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700307 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100308 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200309
310 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
311 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
312 if (mKeyguardShowing && canDismissKeyguard()
313 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
314 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
315 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200316 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
317 mWindowManager.executeAppTransition();
318 }
319 }
320 }
321
322 /**
323 * @return true if Keyguard can be currently dismissed without entering credentials.
324 */
Andrii Kulianfc8f82b2017-01-26 13:17:27 -0800325 boolean canDismissKeyguard() {
Jorim Jaggife762342016-10-13 14:33:27 +0200326 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
327 }
328
329 private int resolveOccludeTransit() {
330 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
331 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
332 && mOccluded) {
333
334 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
335 // actually occclude/unocclude Keyguard, but just run a normal transition.
336 return mBeforeUnoccludeTransit;
337 } else if (!mOccluded) {
338
339 // Save transit in case we dismiss/occlude Keyguard shortly after.
340 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
341 return TRANSIT_KEYGUARD_UNOCCLUDE;
342 } else {
343 return TRANSIT_KEYGUARD_OCCLUDE;
344 }
345 }
346
347 private void dismissDockedStackIfNeeded() {
348 if (mKeyguardShowing && mOccluded) {
349 // The lock screen is currently showing, but is occluded by a window that can
350 // show on top of the lock screen. In this can we want to dismiss the docked
351 // stack since it will be complicated/risky to try to put the activity on top
352 // of the lock screen in the right fullscreen configuration.
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700353 final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700354 if (stack == null) {
355 return;
356 }
357 mStackSupervisor.moveTasksToFullscreenStackLocked(stack,
358 mStackSupervisor.mFocusedStack == stack);
Jorim Jaggife762342016-10-13 14:33:27 +0200359 }
360 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700361
David Stevens9440dc82017-03-16 19:00:20 -0700362 private void updateKeyguardSleepToken() {
David Stevens53a39ea2017-08-23 18:41:49 -0700363 if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
David Stevens9440dc82017-03-16 19:00:20 -0700364 mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
David Stevens53a39ea2017-08-23 18:41:49 -0700365 } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
David Stevens9440dc82017-03-16 19:00:20 -0700366 mSleepToken.release();
367 mSleepToken = null;
368 }
369 }
370
Jorim Jaggi8d786932016-10-26 19:08:36 -0700371 void dump(PrintWriter pw, String prefix) {
372 pw.println(prefix + "KeyguardController:");
373 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
374 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
375 pw.println(prefix + " mOccluded=" + mOccluded);
376 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100377 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700378 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
379 }
Steven Timotius4346f0a2017-09-12 11:07:21 -0700380
381 void writeToProto(ProtoOutputStream proto, long fieldId) {
382 final long token = proto.start(fieldId);
383 proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
384 proto.write(KEYGUARD_OCCLUDED, mOccluded);
385 proto.end(token);
386 }
Jorim Jaggife762342016-10-13 14:33:27 +0200387}