blob: 7101fc4eb93c8f8f2701a96ab47174a1ab91de38 [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;
Steven Timotius4346f0a2017-09-12 11:07:21 -070029import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_OCCLUDED;
30import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_SHOWING;
Jorim Jaggife762342016-10-13 14:33:27 +020031import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
32import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
33import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
34import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
35import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
36import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
37import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
38
David Stevens9440dc82017-03-16 19:00:20 -070039import android.app.ActivityManagerInternal.SleepToken;
Jorim Jaggi241ae102016-11-02 21:57:33 -070040import android.os.IBinder;
41import android.os.RemoteException;
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070042import android.os.Trace;
Jorim Jaggi241ae102016-11-02 21:57:33 -070043import android.util.Slog;
Steven Timotius4346f0a2017-09-12 11:07:21 -070044import android.util.proto.ProtoOutputStream;
Jorim Jaggi241ae102016-11-02 21:57:33 -070045
46import com.android.internal.policy.IKeyguardDismissCallback;
Jorim Jaggife762342016-10-13 14:33:27 +020047import com.android.server.wm.WindowManagerService;
48
Jorim Jaggi8d786932016-10-26 19:08:36 -070049import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020050import java.util.ArrayList;
51
52/**
53 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
54 * currently visible.
55 * <p>
56 * Note that everything in this class should only be accessed with the AM lock being held.
57 */
58class KeyguardController {
59
Jorim Jaggi241ae102016-11-02 21:57:33 -070060 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
61
Jorim Jaggife762342016-10-13 14:33:27 +020062 private final ActivityManagerService mService;
63 private final ActivityStackSupervisor mStackSupervisor;
64 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020065 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070066 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020067 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010068 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020069 private ActivityRecord mDismissingKeyguardActivity;
70 private int mBeforeUnoccludeTransit;
71 private int mVisibilityTransactionDepth;
David Stevens9440dc82017-03-16 19:00:20 -070072 private SleepToken mSleepToken;
David Stevens53a39ea2017-08-23 18:41:49 -070073 private int mSecondaryDisplayShowing = INVALID_DISPLAY;
Jorim Jaggife762342016-10-13 14:33:27 +020074
75 KeyguardController(ActivityManagerService service,
76 ActivityStackSupervisor stackSupervisor) {
77 mService = service;
78 mStackSupervisor = stackSupervisor;
79 }
80
81 void setWindowManager(WindowManagerService windowManager) {
82 mWindowManager = windowManager;
83 }
84
85 /**
David Stevens53a39ea2017-08-23 18:41:49 -070086 * @return true if Keyguard is showing, not going away, and not being occluded on the given
87 * display, false otherwise
Jorim Jaggife762342016-10-13 14:33:27 +020088 */
David Stevens53a39ea2017-08-23 18:41:49 -070089 boolean isKeyguardShowing(int displayId) {
90 return mKeyguardShowing && !mKeyguardGoingAway &&
91 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
Jorim Jaggife762342016-10-13 14:33:27 +020092 }
93
94 /**
95 * @return true if Keyguard is either showing or occluded, but not going away
96 */
97 boolean isKeyguardLocked() {
98 return mKeyguardShowing && !mKeyguardGoingAway;
99 }
100
101 /**
102 * Update the Keyguard showing state.
103 */
David Stevens53a39ea2017-08-23 18:41:49 -0700104 void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
105 boolean showingChanged = showing != mKeyguardShowing;
106 if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
Jorim Jaggife762342016-10-13 14:33:27 +0200107 return;
108 }
109 mKeyguardShowing = showing;
David Stevens53a39ea2017-08-23 18:41:49 -0700110 mSecondaryDisplayShowing = secondaryDisplayShowing;
111 if (showingChanged) {
112 dismissDockedStackIfNeeded();
113 if (showing) {
114 setKeyguardGoingAway(false);
115 mDismissalRequested = false;
116 }
Jorim Jaggife762342016-10-13 14:33:27 +0200117 }
118 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
David Stevens9440dc82017-03-16 19:00:20 -0700119 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200120 }
121
122 /**
123 * Called when Keyguard is going away.
124 *
125 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
126 * etc.
127 */
128 void keyguardGoingAway(int flags) {
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700129 if (!mKeyguardShowing) {
130 return;
131 }
132 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
133 mWindowManager.deferSurfaceLayout();
134 try {
135 setKeyguardGoingAway(true);
136 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
137 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
138 false /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700139 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200140
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700141 // Some stack visibility might change (e.g. docked stack)
142 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
143 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
144 mWindowManager.executeAppTransition();
145 } finally {
146 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
147 mWindowManager.continueSurfaceLayout();
148 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
149
150 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
Jorim Jaggife762342016-10-13 14:33:27 +0200151 }
152 }
153
Jorim Jaggi241ae102016-11-02 21:57:33 -0700154 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
155 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
156 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
157 failCallback(callback);
158 return;
159 }
Jorim Jaggid7214892017-07-18 14:05:19 +0200160 Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
chaviw59b98852017-06-13 12:05:44 -0700161
162 // If the client has requested to dismiss the keyguard and the Activity has the flag to
163 // turn the screen on, wakeup the screen if it's the top Activity.
164 if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
165 mStackSupervisor.wakeUp("dismissKeyguard");
166 }
167
Jorim Jaggi241ae102016-11-02 21:57:33 -0700168 mWindowManager.dismissKeyguard(callback);
169 }
170
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700171 private void setKeyguardGoingAway(boolean keyguardGoingAway) {
172 mKeyguardGoingAway = keyguardGoingAway;
173 mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
174 }
175
Jorim Jaggi241ae102016-11-02 21:57:33 -0700176 private void failCallback(IKeyguardDismissCallback callback) {
177 try {
178 callback.onDismissError();
179 } catch (RemoteException e) {
180 Slog.w(TAG, "Failed to call callback", e);
181 }
182 }
183
Jorim Jaggife762342016-10-13 14:33:27 +0200184 private int convertTransitFlags(int keyguardGoingAwayFlags) {
185 int result = 0;
186 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
187 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
188 }
189 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
190 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
191 }
192 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
193 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
194 }
195 return result;
196 }
197
198 /**
199 * Starts a batch of visibility updates.
200 */
201 void beginActivityVisibilityUpdate() {
202 mVisibilityTransactionDepth++;
203 }
204
205 /**
206 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
207 * update lockscreen occluded/dismiss state if needed.
208 */
209 void endActivityVisibilityUpdate() {
210 mVisibilityTransactionDepth--;
211 if (mVisibilityTransactionDepth == 0) {
212 visibilitiesUpdated();
213 }
214 }
215
Jorim Jaggie69c9312016-10-31 18:24:38 -0700216 /**
217 * @return True if we may show an activity while Keyguard is showing because we are in the
218 * process of dismissing it anyways, false otherwise.
219 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100220 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
221
222 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
223 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
224 // Keyguard.
225 return dismissKeyguard && canDismissKeyguard() &&
226 (mDismissalRequested || r != mDismissingKeyguardActivity);
227 }
228
229 /**
230 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
231 */
232 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
233 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700234 }
235
Jorim Jaggife762342016-10-13 14:33:27 +0200236 private void visibilitiesUpdated() {
237 final boolean lastOccluded = mOccluded;
238 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
239 mOccluded = false;
240 mDismissingKeyguardActivity = null;
241 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
Wale Ogunwalee287e192017-04-21 09:30:12 -0700242 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
Jorim Jaggife762342016-10-13 14:33:27 +0200243 final ActivityStack stack = stacks.get(stackNdx);
244
Wale Ogunwalee287e192017-04-21 09:30:12 -0700245 // Only the focused stack top activity may control occluded state
246 if (mStackSupervisor.isFocusedStack(stack)) {
Jorim Jaggi07961872016-11-23 11:28:57 +0100247
248 // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
249 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
250 mOccluded = stack.topActivityOccludesKeyguard()
251 || (topDismissing != null
252 && stack.topRunningActivityLocked() == topDismissing
253 && canShowWhileOccluded(true /* dismissKeyguard */,
254 false /* showWhenLocked */));
Jorim Jaggife762342016-10-13 14:33:27 +0200255 }
256 if (mDismissingKeyguardActivity == null
257 && stack.getTopDismissingKeyguardActivity() != null) {
258 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
259 }
260 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700261 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200262 if (mOccluded != lastOccluded) {
263 handleOccludedChanged();
264 }
265 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
266 handleDismissKeyguard();
267 }
268 }
269
270 /**
271 * Called when occluded state changed.
272 */
273 private void handleOccludedChanged() {
274 mWindowManager.onKeyguardOccludedChanged(mOccluded);
275 if (isKeyguardLocked()) {
276 mWindowManager.deferSurfaceLayout();
277 try {
278 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
279 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700280 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200281 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
282 mWindowManager.executeAppTransition();
283 } finally {
284 mWindowManager.continueSurfaceLayout();
285 }
286 }
287 dismissDockedStackIfNeeded();
288 }
289
290 /**
291 * Called when somebody might want to dismiss the Keyguard.
292 */
293 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100294 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
295 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
296 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
297 if (!mOccluded && mDismissingKeyguardActivity != null
298 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700299 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100300 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200301
302 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
303 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
304 if (mKeyguardShowing && canDismissKeyguard()
305 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
306 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
307 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200308 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
309 mWindowManager.executeAppTransition();
310 }
311 }
312 }
313
314 /**
315 * @return true if Keyguard can be currently dismissed without entering credentials.
316 */
Andrii Kulianfc8f82b2017-01-26 13:17:27 -0800317 boolean canDismissKeyguard() {
Jorim Jaggife762342016-10-13 14:33:27 +0200318 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
319 }
320
321 private int resolveOccludeTransit() {
322 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
323 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
324 && mOccluded) {
325
326 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
327 // actually occclude/unocclude Keyguard, but just run a normal transition.
328 return mBeforeUnoccludeTransit;
329 } else if (!mOccluded) {
330
331 // Save transit in case we dismiss/occlude Keyguard shortly after.
332 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
333 return TRANSIT_KEYGUARD_UNOCCLUDE;
334 } else {
335 return TRANSIT_KEYGUARD_OCCLUDE;
336 }
337 }
338
339 private void dismissDockedStackIfNeeded() {
340 if (mKeyguardShowing && mOccluded) {
341 // The lock screen is currently showing, but is occluded by a window that can
342 // show on top of the lock screen. In this can we want to dismiss the docked
343 // stack since it will be complicated/risky to try to put the activity on top
344 // of the lock screen in the right fullscreen configuration.
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700345 final ActivityStack stack = mStackSupervisor.getStack(DOCKED_STACK_ID);
346 if (stack == null) {
347 return;
348 }
349 mStackSupervisor.moveTasksToFullscreenStackLocked(stack,
350 mStackSupervisor.mFocusedStack == stack);
Jorim Jaggife762342016-10-13 14:33:27 +0200351 }
352 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700353
David Stevens9440dc82017-03-16 19:00:20 -0700354 private void updateKeyguardSleepToken() {
David Stevens53a39ea2017-08-23 18:41:49 -0700355 if (mSleepToken == null && isKeyguardShowing(DEFAULT_DISPLAY)) {
David Stevens9440dc82017-03-16 19:00:20 -0700356 mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
David Stevens53a39ea2017-08-23 18:41:49 -0700357 } else if (mSleepToken != null && !isKeyguardShowing(DEFAULT_DISPLAY)) {
David Stevens9440dc82017-03-16 19:00:20 -0700358 mSleepToken.release();
359 mSleepToken = null;
360 }
361 }
362
Jorim Jaggi8d786932016-10-26 19:08:36 -0700363 void dump(PrintWriter pw, String prefix) {
364 pw.println(prefix + "KeyguardController:");
365 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
366 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
367 pw.println(prefix + " mOccluded=" + mOccluded);
368 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100369 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700370 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
371 }
Steven Timotius4346f0a2017-09-12 11:07:21 -0700372
373 void writeToProto(ProtoOutputStream proto, long fieldId) {
374 final long token = proto.start(fieldId);
375 proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
376 proto.write(KEYGUARD_OCCLUDED, mOccluded);
377 proto.end(token);
378 }
Jorim Jaggife762342016-10-13 14:33:27 +0200379}