blob: 2e0ec0b361e2b5a614931396c7e2b00f8f981d55 [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;
20import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
21import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
22import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
Jorim Jaggi241ae102016-11-02 21:57:33 -070023import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
24import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
Jorim Jaggife762342016-10-13 14:33:27 +020025import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
26import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
27import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
28import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
29import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
30import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
31import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
Jorim Jaggi8b702ed2017-01-20 16:59:03 +010032import static com.android.server.wm.AppTransition.TRANSIT_NONE;
Jorim Jaggife762342016-10-13 14:33:27 +020033import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
34
Jorim Jaggi241ae102016-11-02 21:57:33 -070035import android.os.IBinder;
36import android.os.RemoteException;
37import android.util.Slog;
38
39import com.android.internal.policy.IKeyguardDismissCallback;
Jorim Jaggife762342016-10-13 14:33:27 +020040import com.android.server.wm.WindowManagerService;
41
Jorim Jaggi8d786932016-10-26 19:08:36 -070042import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020043import java.util.ArrayList;
44
45/**
46 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
47 * currently visible.
48 * <p>
49 * Note that everything in this class should only be accessed with the AM lock being held.
50 */
51class KeyguardController {
52
Jorim Jaggi241ae102016-11-02 21:57:33 -070053 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
54
Jorim Jaggife762342016-10-13 14:33:27 +020055 private final ActivityManagerService mService;
56 private final ActivityStackSupervisor mStackSupervisor;
57 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020058 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070059 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020060 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010061 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020062 private ActivityRecord mDismissingKeyguardActivity;
63 private int mBeforeUnoccludeTransit;
64 private int mVisibilityTransactionDepth;
65
66 KeyguardController(ActivityManagerService service,
67 ActivityStackSupervisor stackSupervisor) {
68 mService = service;
69 mStackSupervisor = stackSupervisor;
70 }
71
72 void setWindowManager(WindowManagerService windowManager) {
73 mWindowManager = windowManager;
74 }
75
76 /**
77 * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
78 */
79 boolean isKeyguardShowing() {
80 return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
81 }
82
83 /**
84 * @return true if Keyguard is either showing or occluded, but not going away
85 */
86 boolean isKeyguardLocked() {
87 return mKeyguardShowing && !mKeyguardGoingAway;
88 }
89
90 /**
91 * Update the Keyguard showing state.
92 */
93 void setKeyguardShown(boolean showing) {
94 if (showing == mKeyguardShowing) {
95 return;
96 }
97 mKeyguardShowing = showing;
Matthew Ngf4344ef2017-04-20 15:19:58 -070098 dismissDockedStackIfNeeded();
Jorim Jaggife762342016-10-13 14:33:27 +020099 if (showing) {
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700100 setKeyguardGoingAway(false);
Jorim Jaggi07961872016-11-23 11:28:57 +0100101 mDismissalRequested = false;
Jorim Jaggife762342016-10-13 14:33:27 +0200102 }
103 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
104 mService.updateSleepIfNeededLocked();
105 }
106
107 /**
108 * Called when Keyguard is going away.
109 *
110 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
111 * etc.
112 */
113 void keyguardGoingAway(int flags) {
114 if (mKeyguardShowing) {
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700115 mWindowManager.deferSurfaceLayout();
116 try {
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700117 setKeyguardGoingAway(true);
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700118 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
119 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
120 false /* forceOverride */);
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700121 mService.updateSleepIfNeededLocked();
Jorim Jaggife762342016-10-13 14:33:27 +0200122
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700123 // Some stack visibility might change (e.g. docked stack)
124 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
Jorim Jaggi8b702ed2017-01-20 16:59:03 +0100125 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700126 mWindowManager.executeAppTransition();
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700127 } finally {
128 mWindowManager.continueSurfaceLayout();
129 }
Jorim Jaggife762342016-10-13 14:33:27 +0200130 }
131 }
132
Jorim Jaggi241ae102016-11-02 21:57:33 -0700133 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
134 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
135 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
136 failCallback(callback);
137 return;
138 }
139 mWindowManager.dismissKeyguard(callback);
140 }
141
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700142 private void setKeyguardGoingAway(boolean keyguardGoingAway) {
143 mKeyguardGoingAway = keyguardGoingAway;
144 mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
145 }
146
Jorim Jaggi241ae102016-11-02 21:57:33 -0700147 private void failCallback(IKeyguardDismissCallback callback) {
148 try {
149 callback.onDismissError();
150 } catch (RemoteException e) {
151 Slog.w(TAG, "Failed to call callback", e);
152 }
153 }
154
Jorim Jaggife762342016-10-13 14:33:27 +0200155 private int convertTransitFlags(int keyguardGoingAwayFlags) {
156 int result = 0;
157 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
158 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
159 }
160 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
161 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
162 }
163 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
164 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
165 }
166 return result;
167 }
168
169 /**
170 * Starts a batch of visibility updates.
171 */
172 void beginActivityVisibilityUpdate() {
173 mVisibilityTransactionDepth++;
174 }
175
176 /**
177 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
178 * update lockscreen occluded/dismiss state if needed.
179 */
180 void endActivityVisibilityUpdate() {
181 mVisibilityTransactionDepth--;
182 if (mVisibilityTransactionDepth == 0) {
183 visibilitiesUpdated();
184 }
185 }
186
Jorim Jaggie69c9312016-10-31 18:24:38 -0700187 /**
188 * @return True if we may show an activity while Keyguard is showing because we are in the
189 * process of dismissing it anyways, false otherwise.
190 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100191 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
192
193 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
194 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
195 // Keyguard.
196 return dismissKeyguard && canDismissKeyguard() &&
197 (mDismissalRequested || r != mDismissingKeyguardActivity);
198 }
199
200 /**
201 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
202 */
203 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
204 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700205 }
206
Jorim Jaggife762342016-10-13 14:33:27 +0200207 private void visibilitiesUpdated() {
208 final boolean lastOccluded = mOccluded;
209 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
210 mOccluded = false;
211 mDismissingKeyguardActivity = null;
212 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
Wale Ogunwalee287e192017-04-21 09:30:12 -0700213 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
Jorim Jaggife762342016-10-13 14:33:27 +0200214 final ActivityStack stack = stacks.get(stackNdx);
215
Wale Ogunwalee287e192017-04-21 09:30:12 -0700216 // Only the focused stack top activity may control occluded state
217 if (mStackSupervisor.isFocusedStack(stack)) {
Jorim Jaggi07961872016-11-23 11:28:57 +0100218
219 // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
220 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
221 mOccluded = stack.topActivityOccludesKeyguard()
222 || (topDismissing != null
223 && stack.topRunningActivityLocked() == topDismissing
224 && canShowWhileOccluded(true /* dismissKeyguard */,
225 false /* showWhenLocked */));
Jorim Jaggife762342016-10-13 14:33:27 +0200226 }
227 if (mDismissingKeyguardActivity == null
228 && stack.getTopDismissingKeyguardActivity() != null) {
229 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
230 }
231 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700232 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200233 if (mOccluded != lastOccluded) {
234 handleOccludedChanged();
235 }
236 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
237 handleDismissKeyguard();
238 }
239 }
240
241 /**
242 * Called when occluded state changed.
243 */
244 private void handleOccludedChanged() {
245 mWindowManager.onKeyguardOccludedChanged(mOccluded);
246 if (isKeyguardLocked()) {
247 mWindowManager.deferSurfaceLayout();
248 try {
249 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
250 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
251 mService.updateSleepIfNeededLocked();
252 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
253 mWindowManager.executeAppTransition();
254 } finally {
255 mWindowManager.continueSurfaceLayout();
256 }
257 }
258 dismissDockedStackIfNeeded();
259 }
260
261 /**
262 * Called when somebody might want to dismiss the Keyguard.
263 */
264 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100265 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
266 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
267 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
268 if (!mOccluded && mDismissingKeyguardActivity != null
269 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700270 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100271 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200272
273 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
274 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
275 if (mKeyguardShowing && canDismissKeyguard()
276 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
277 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
278 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200279 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
280 mWindowManager.executeAppTransition();
281 }
282 }
283 }
284
285 /**
286 * @return true if Keyguard can be currently dismissed without entering credentials.
287 */
Andrii Kulianfc8f82b2017-01-26 13:17:27 -0800288 boolean canDismissKeyguard() {
Jorim Jaggife762342016-10-13 14:33:27 +0200289 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
290 }
291
292 private int resolveOccludeTransit() {
293 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
294 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
295 && mOccluded) {
296
297 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
298 // actually occclude/unocclude Keyguard, but just run a normal transition.
299 return mBeforeUnoccludeTransit;
300 } else if (!mOccluded) {
301
302 // Save transit in case we dismiss/occlude Keyguard shortly after.
303 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
304 return TRANSIT_KEYGUARD_UNOCCLUDE;
305 } else {
306 return TRANSIT_KEYGUARD_OCCLUDE;
307 }
308 }
309
310 private void dismissDockedStackIfNeeded() {
311 if (mKeyguardShowing && mOccluded) {
312 // The lock screen is currently showing, but is occluded by a window that can
313 // show on top of the lock screen. In this can we want to dismiss the docked
314 // stack since it will be complicated/risky to try to put the activity on top
315 // of the lock screen in the right fullscreen configuration.
316 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
317 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
318 }
319 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700320
321 void dump(PrintWriter pw, String prefix) {
322 pw.println(prefix + "KeyguardController:");
323 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
324 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
325 pw.println(prefix + " mOccluded=" + mOccluded);
326 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100327 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700328 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
329 }
Jorim Jaggife762342016-10-13 14:33:27 +0200330}