blob: 85961135d84f1a664b7c706e1508b13500e47f57 [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;
David Stevens9440dc82017-03-16 19:00:20 -070021import static android.view.Display.DEFAULT_DISPLAY;
David Stevens53a39ea2017-08-23 18:41:49 -070022import static android.view.Display.INVALID_DISPLAY;
Jorim Jaggife762342016-10-13 14:33:27 +020023import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
24import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
25import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
Jorim Jaggi241ae102016-11-02 21:57:33 -070026import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
27import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
Jorim Jaggife762342016-10-13 14:33:27 +020028import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
29import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
30import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
31import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
32import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
33import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
34import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
35import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
36
David Stevens9440dc82017-03-16 19:00:20 -070037import android.app.ActivityManagerInternal.SleepToken;
Jorim Jaggi241ae102016-11-02 21:57:33 -070038import android.os.IBinder;
39import android.os.RemoteException;
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070040import android.os.Trace;
Jorim Jaggi241ae102016-11-02 21:57:33 -070041import android.util.Slog;
42
43import com.android.internal.policy.IKeyguardDismissCallback;
Jorim Jaggife762342016-10-13 14:33:27 +020044import com.android.server.wm.WindowManagerService;
45
Jorim Jaggi8d786932016-10-26 19:08:36 -070046import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020047import java.util.ArrayList;
48
49/**
50 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
51 * currently visible.
52 * <p>
53 * Note that everything in this class should only be accessed with the AM lock being held.
54 */
55class KeyguardController {
56
Jorim Jaggi241ae102016-11-02 21:57:33 -070057 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
58
Jorim Jaggife762342016-10-13 14:33:27 +020059 private final ActivityManagerService mService;
60 private final ActivityStackSupervisor mStackSupervisor;
61 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020062 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070063 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020064 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010065 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020066 private ActivityRecord mDismissingKeyguardActivity;
67 private int mBeforeUnoccludeTransit;
68 private int mVisibilityTransactionDepth;
David Stevens9440dc82017-03-16 19:00:20 -070069 private SleepToken mSleepToken;
David Stevens53a39ea2017-08-23 18:41:49 -070070 private int mSecondaryDisplayShowing = INVALID_DISPLAY;
Jorim Jaggife762342016-10-13 14:33:27 +020071
72 KeyguardController(ActivityManagerService service,
73 ActivityStackSupervisor stackSupervisor) {
74 mService = service;
75 mStackSupervisor = stackSupervisor;
76 }
77
78 void setWindowManager(WindowManagerService windowManager) {
79 mWindowManager = windowManager;
80 }
81
82 /**
David Stevens53a39ea2017-08-23 18:41:49 -070083 * @return true if Keyguard is showing, not going away, and not being occluded on the given
84 * display, false otherwise
Jorim Jaggife762342016-10-13 14:33:27 +020085 */
David Stevens53a39ea2017-08-23 18:41:49 -070086 boolean isKeyguardShowing(int displayId) {
87 return mKeyguardShowing && !mKeyguardGoingAway &&
88 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
Jorim Jaggife762342016-10-13 14:33:27 +020089 }
90
91 /**
92 * @return true if Keyguard is either showing or occluded, but not going away
93 */
94 boolean isKeyguardLocked() {
95 return mKeyguardShowing && !mKeyguardGoingAway;
96 }
97
98 /**
99 * Update the Keyguard showing state.
100 */
David Stevens53a39ea2017-08-23 18:41:49 -0700101 void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
102 boolean showingChanged = showing != mKeyguardShowing;
103 if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
Jorim Jaggife762342016-10-13 14:33:27 +0200104 return;
105 }
106 mKeyguardShowing = showing;
David Stevens53a39ea2017-08-23 18:41:49 -0700107 mSecondaryDisplayShowing = secondaryDisplayShowing;
108 if (showingChanged) {
109 dismissDockedStackIfNeeded();
110 if (showing) {
111 setKeyguardGoingAway(false);
112 mDismissalRequested = false;
113 }
Jorim Jaggife762342016-10-13 14:33:27 +0200114 }
115 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
David Stevens9440dc82017-03-16 19:00:20 -0700116 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200117 }
118
119 /**
120 * Called when Keyguard is going away.
121 *
122 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
123 * etc.
124 */
125 void keyguardGoingAway(int flags) {
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700126 if (!mKeyguardShowing) {
127 return;
128 }
129 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
130 mWindowManager.deferSurfaceLayout();
131 try {
132 setKeyguardGoingAway(true);
133 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
134 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
135 false /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700136 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200137
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700138 // Some stack visibility might change (e.g. docked stack)
139 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
140 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
141 mWindowManager.executeAppTransition();
142 } finally {
143 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
144 mWindowManager.continueSurfaceLayout();
145 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
146
147 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
Jorim Jaggife762342016-10-13 14:33:27 +0200148 }
149 }
150
Jorim Jaggi241ae102016-11-02 21:57:33 -0700151 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
152 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
153 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
154 failCallback(callback);
155 return;
156 }
Jorim Jaggid7214892017-07-18 14:05:19 +0200157 Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
chaviw59b98852017-06-13 12:05:44 -0700158
159 // If the client has requested to dismiss the keyguard and the Activity has the flag to
160 // turn the screen on, wakeup the screen if it's the top Activity.
161 if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
162 mStackSupervisor.wakeUp("dismissKeyguard");
163 }
164
Jorim Jaggi241ae102016-11-02 21:57:33 -0700165 mWindowManager.dismissKeyguard(callback);
166 }
167
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700168 private void setKeyguardGoingAway(boolean keyguardGoingAway) {
169 mKeyguardGoingAway = keyguardGoingAway;
170 mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
171 }
172
Jorim Jaggi241ae102016-11-02 21:57:33 -0700173 private void failCallback(IKeyguardDismissCallback callback) {
174 try {
175 callback.onDismissError();
176 } catch (RemoteException e) {
177 Slog.w(TAG, "Failed to call callback", e);
178 }
179 }
180
Jorim Jaggife762342016-10-13 14:33:27 +0200181 private int convertTransitFlags(int keyguardGoingAwayFlags) {
182 int result = 0;
183 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
184 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
185 }
186 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
187 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
188 }
189 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
190 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
191 }
192 return result;
193 }
194
195 /**
196 * Starts a batch of visibility updates.
197 */
198 void beginActivityVisibilityUpdate() {
199 mVisibilityTransactionDepth++;
200 }
201
202 /**
203 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
204 * update lockscreen occluded/dismiss state if needed.
205 */
206 void endActivityVisibilityUpdate() {
207 mVisibilityTransactionDepth--;
208 if (mVisibilityTransactionDepth == 0) {
209 visibilitiesUpdated();
210 }
211 }
212
Jorim Jaggie69c9312016-10-31 18:24:38 -0700213 /**
214 * @return True if we may show an activity while Keyguard is showing because we are in the
215 * process of dismissing it anyways, false otherwise.
216 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100217 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
218
219 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
220 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
221 // Keyguard.
222 return dismissKeyguard && canDismissKeyguard() &&
223 (mDismissalRequested || r != mDismissingKeyguardActivity);
224 }
225
226 /**
227 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
228 */
229 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
230 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700231 }
232
Jorim Jaggife762342016-10-13 14:33:27 +0200233 private void visibilitiesUpdated() {
234 final boolean lastOccluded = mOccluded;
235 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
236 mOccluded = false;
237 mDismissingKeyguardActivity = null;
238 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
Wale Ogunwalee287e192017-04-21 09:30:12 -0700239 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
Jorim Jaggife762342016-10-13 14:33:27 +0200240 final ActivityStack stack = stacks.get(stackNdx);
241
Wale Ogunwalee287e192017-04-21 09:30:12 -0700242 // Only the focused stack top activity may control occluded state
243 if (mStackSupervisor.isFocusedStack(stack)) {
Jorim Jaggi07961872016-11-23 11:28:57 +0100244
245 // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
246 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
247 mOccluded = stack.topActivityOccludesKeyguard()
248 || (topDismissing != null
249 && stack.topRunningActivityLocked() == topDismissing
250 && canShowWhileOccluded(true /* dismissKeyguard */,
251 false /* showWhenLocked */));
Jorim Jaggife762342016-10-13 14:33:27 +0200252 }
253 if (mDismissingKeyguardActivity == null
254 && stack.getTopDismissingKeyguardActivity() != null) {
255 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
256 }
257 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700258 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200259 if (mOccluded != lastOccluded) {
260 handleOccludedChanged();
261 }
262 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
263 handleDismissKeyguard();
264 }
265 }
266
267 /**
268 * Called when occluded state changed.
269 */
270 private void handleOccludedChanged() {
271 mWindowManager.onKeyguardOccludedChanged(mOccluded);
272 if (isKeyguardLocked()) {
273 mWindowManager.deferSurfaceLayout();
274 try {
275 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
276 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700277 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200278 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
279 mWindowManager.executeAppTransition();
280 } finally {
281 mWindowManager.continueSurfaceLayout();
282 }
283 }
284 dismissDockedStackIfNeeded();
285 }
286
287 /**
288 * Called when somebody might want to dismiss the Keyguard.
289 */
290 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100291 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
292 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
293 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
294 if (!mOccluded && mDismissingKeyguardActivity != null
295 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700296 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100297 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200298
299 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
300 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
301 if (mKeyguardShowing && canDismissKeyguard()
302 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
303 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
304 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200305 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
306 mWindowManager.executeAppTransition();
307 }
308 }
309 }
310
311 /**
312 * @return true if Keyguard can be currently dismissed without entering credentials.
313 */
Andrii Kulianfc8f82b2017-01-26 13:17:27 -0800314 boolean canDismissKeyguard() {
Jorim Jaggife762342016-10-13 14:33:27 +0200315 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
316 }
317
318 private int resolveOccludeTransit() {
319 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
320 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
321 && mOccluded) {
322
323 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
324 // actually occclude/unocclude Keyguard, but just run a normal transition.
325 return mBeforeUnoccludeTransit;
326 } else if (!mOccluded) {
327
328 // Save transit in case we dismiss/occlude Keyguard shortly after.
329 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
330 return TRANSIT_KEYGUARD_UNOCCLUDE;
331 } else {
332 return TRANSIT_KEYGUARD_OCCLUDE;
333 }
334 }
335
336 private void dismissDockedStackIfNeeded() {
337 if (mKeyguardShowing && mOccluded) {
338 // The lock screen is currently showing, but is occluded by a window that can
339 // show on top of the lock screen. In this can we want to dismiss the docked
340 // stack since it will be complicated/risky to try to put the activity on top
341 // of the lock screen in the right fullscreen configuration.
342 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
343 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
344 }
345 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700346
David Stevens9440dc82017-03-16 19:00:20 -0700347 private void updateKeyguardSleepToken() {
David Stevens53a39ea2017-08-23 18:41:49 -0700348 if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
David Stevens9440dc82017-03-16 19:00:20 -0700349 mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
David Stevens53a39ea2017-08-23 18:41:49 -0700350 } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
David Stevens9440dc82017-03-16 19:00:20 -0700351 mSleepToken.release();
352 mSleepToken = null;
353 }
354 }
355
Jorim Jaggi8d786932016-10-26 19:08:36 -0700356 void dump(PrintWriter pw, String prefix) {
357 pw.println(prefix + "KeyguardController:");
358 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
359 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
360 pw.println(prefix + " mOccluded=" + mOccluded);
361 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100362 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700363 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
364 }
Jorim Jaggife762342016-10-13 14:33:27 +0200365}