blob: 58e71df3ba57671d46e5d93e155b5b55f99691f6 [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;
33import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
34
Jorim Jaggi241ae102016-11-02 21:57:33 -070035import android.os.IBinder;
36import android.os.RemoteException;
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070037import android.os.Trace;
Jorim Jaggi241ae102016-11-02 21:57:33 -070038import android.util.Slog;
39
40import com.android.internal.policy.IKeyguardDismissCallback;
Jorim Jaggife762342016-10-13 14:33:27 +020041import com.android.server.wm.WindowManagerService;
42
Jorim Jaggi8d786932016-10-26 19:08:36 -070043import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020044import java.util.ArrayList;
45
46/**
47 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
48 * currently visible.
49 * <p>
50 * Note that everything in this class should only be accessed with the AM lock being held.
51 */
52class KeyguardController {
53
Jorim Jaggi241ae102016-11-02 21:57:33 -070054 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
55
Jorim Jaggife762342016-10-13 14:33:27 +020056 private final ActivityManagerService mService;
57 private final ActivityStackSupervisor mStackSupervisor;
58 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020059 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070060 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020061 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010062 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020063 private ActivityRecord mDismissingKeyguardActivity;
64 private int mBeforeUnoccludeTransit;
65 private int mVisibilityTransactionDepth;
66
67 KeyguardController(ActivityManagerService service,
68 ActivityStackSupervisor stackSupervisor) {
69 mService = service;
70 mStackSupervisor = stackSupervisor;
71 }
72
73 void setWindowManager(WindowManagerService windowManager) {
74 mWindowManager = windowManager;
75 }
76
77 /**
78 * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
79 */
80 boolean isKeyguardShowing() {
81 return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
82 }
83
84 /**
85 * @return true if Keyguard is either showing or occluded, but not going away
86 */
87 boolean isKeyguardLocked() {
88 return mKeyguardShowing && !mKeyguardGoingAway;
89 }
90
91 /**
92 * Update the Keyguard showing state.
93 */
94 void setKeyguardShown(boolean showing) {
95 if (showing == mKeyguardShowing) {
96 return;
97 }
98 mKeyguardShowing = showing;
Matthew Ngf4344ef2017-04-20 15:19:58 -070099 dismissDockedStackIfNeeded();
Jorim Jaggife762342016-10-13 14:33:27 +0200100 if (showing) {
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700101 setKeyguardGoingAway(false);
Jorim Jaggi07961872016-11-23 11:28:57 +0100102 mDismissalRequested = false;
Jorim Jaggife762342016-10-13 14:33:27 +0200103 }
104 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
105 mService.updateSleepIfNeededLocked();
106 }
107
108 /**
109 * Called when Keyguard is going away.
110 *
111 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
112 * etc.
113 */
114 void keyguardGoingAway(int flags) {
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700115 if (!mKeyguardShowing) {
116 return;
117 }
118 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
119 mWindowManager.deferSurfaceLayout();
120 try {
121 setKeyguardGoingAway(true);
122 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
123 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
124 false /* forceOverride */);
125 mService.updateSleepIfNeededLocked();
Jorim Jaggife762342016-10-13 14:33:27 +0200126
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700127 // Some stack visibility might change (e.g. docked stack)
128 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
129 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
130 mWindowManager.executeAppTransition();
131 } finally {
132 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
133 mWindowManager.continueSurfaceLayout();
134 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
135
136 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
Jorim Jaggife762342016-10-13 14:33:27 +0200137 }
138 }
139
Jorim Jaggi241ae102016-11-02 21:57:33 -0700140 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
141 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
142 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
143 failCallback(callback);
144 return;
145 }
Jorim Jaggid7214892017-07-18 14:05:19 +0200146 Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
chaviw59b98852017-06-13 12:05:44 -0700147
148 // If the client has requested to dismiss the keyguard and the Activity has the flag to
149 // turn the screen on, wakeup the screen if it's the top Activity.
150 if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
151 mStackSupervisor.wakeUp("dismissKeyguard");
152 }
153
Jorim Jaggi241ae102016-11-02 21:57:33 -0700154 mWindowManager.dismissKeyguard(callback);
155 }
156
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700157 private void setKeyguardGoingAway(boolean keyguardGoingAway) {
158 mKeyguardGoingAway = keyguardGoingAway;
159 mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
160 }
161
Jorim Jaggi241ae102016-11-02 21:57:33 -0700162 private void failCallback(IKeyguardDismissCallback callback) {
163 try {
164 callback.onDismissError();
165 } catch (RemoteException e) {
166 Slog.w(TAG, "Failed to call callback", e);
167 }
168 }
169
Jorim Jaggife762342016-10-13 14:33:27 +0200170 private int convertTransitFlags(int keyguardGoingAwayFlags) {
171 int result = 0;
172 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
173 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
174 }
175 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
176 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
177 }
178 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
179 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
180 }
181 return result;
182 }
183
184 /**
185 * Starts a batch of visibility updates.
186 */
187 void beginActivityVisibilityUpdate() {
188 mVisibilityTransactionDepth++;
189 }
190
191 /**
192 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
193 * update lockscreen occluded/dismiss state if needed.
194 */
195 void endActivityVisibilityUpdate() {
196 mVisibilityTransactionDepth--;
197 if (mVisibilityTransactionDepth == 0) {
198 visibilitiesUpdated();
199 }
200 }
201
Jorim Jaggie69c9312016-10-31 18:24:38 -0700202 /**
203 * @return True if we may show an activity while Keyguard is showing because we are in the
204 * process of dismissing it anyways, false otherwise.
205 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100206 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
207
208 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
209 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
210 // Keyguard.
211 return dismissKeyguard && canDismissKeyguard() &&
212 (mDismissalRequested || r != mDismissingKeyguardActivity);
213 }
214
215 /**
216 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
217 */
218 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
219 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700220 }
221
Jorim Jaggife762342016-10-13 14:33:27 +0200222 private void visibilitiesUpdated() {
223 final boolean lastOccluded = mOccluded;
224 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
225 mOccluded = false;
226 mDismissingKeyguardActivity = null;
227 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
Wale Ogunwalee287e192017-04-21 09:30:12 -0700228 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
Jorim Jaggife762342016-10-13 14:33:27 +0200229 final ActivityStack stack = stacks.get(stackNdx);
230
Wale Ogunwalee287e192017-04-21 09:30:12 -0700231 // Only the focused stack top activity may control occluded state
232 if (mStackSupervisor.isFocusedStack(stack)) {
Jorim Jaggi07961872016-11-23 11:28:57 +0100233
234 // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
235 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
236 mOccluded = stack.topActivityOccludesKeyguard()
237 || (topDismissing != null
238 && stack.topRunningActivityLocked() == topDismissing
239 && canShowWhileOccluded(true /* dismissKeyguard */,
240 false /* showWhenLocked */));
Jorim Jaggife762342016-10-13 14:33:27 +0200241 }
242 if (mDismissingKeyguardActivity == null
243 && stack.getTopDismissingKeyguardActivity() != null) {
244 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
245 }
246 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700247 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200248 if (mOccluded != lastOccluded) {
249 handleOccludedChanged();
250 }
251 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
252 handleDismissKeyguard();
253 }
254 }
255
256 /**
257 * Called when occluded state changed.
258 */
259 private void handleOccludedChanged() {
260 mWindowManager.onKeyguardOccludedChanged(mOccluded);
261 if (isKeyguardLocked()) {
262 mWindowManager.deferSurfaceLayout();
263 try {
264 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
265 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
266 mService.updateSleepIfNeededLocked();
267 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
268 mWindowManager.executeAppTransition();
269 } finally {
270 mWindowManager.continueSurfaceLayout();
271 }
272 }
273 dismissDockedStackIfNeeded();
274 }
275
276 /**
277 * Called when somebody might want to dismiss the Keyguard.
278 */
279 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100280 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
281 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
282 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
283 if (!mOccluded && mDismissingKeyguardActivity != null
284 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700285 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100286 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200287
288 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
289 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
290 if (mKeyguardShowing && canDismissKeyguard()
291 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
292 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
293 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200294 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
295 mWindowManager.executeAppTransition();
296 }
297 }
298 }
299
300 /**
301 * @return true if Keyguard can be currently dismissed without entering credentials.
302 */
Andrii Kulianfc8f82b2017-01-26 13:17:27 -0800303 boolean canDismissKeyguard() {
Jorim Jaggife762342016-10-13 14:33:27 +0200304 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
305 }
306
307 private int resolveOccludeTransit() {
308 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
309 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
310 && mOccluded) {
311
312 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
313 // actually occclude/unocclude Keyguard, but just run a normal transition.
314 return mBeforeUnoccludeTransit;
315 } else if (!mOccluded) {
316
317 // Save transit in case we dismiss/occlude Keyguard shortly after.
318 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
319 return TRANSIT_KEYGUARD_UNOCCLUDE;
320 } else {
321 return TRANSIT_KEYGUARD_OCCLUDE;
322 }
323 }
324
325 private void dismissDockedStackIfNeeded() {
326 if (mKeyguardShowing && mOccluded) {
327 // The lock screen is currently showing, but is occluded by a window that can
328 // show on top of the lock screen. In this can we want to dismiss the docked
329 // stack since it will be complicated/risky to try to put the activity on top
330 // of the lock screen in the right fullscreen configuration.
331 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
332 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
333 }
334 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700335
336 void dump(PrintWriter pw, String prefix) {
337 pw.println(prefix + "KeyguardController:");
338 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
339 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
340 pw.println(prefix + " mOccluded=" + mOccluded);
341 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100342 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700343 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
344 }
Jorim Jaggife762342016-10-13 14:33:27 +0200345}