blob: cea80c8d0e9dea39500fd297452523e90cee0213 [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;
Jorim Jaggife762342016-10-13 14:33:27 +020022import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
23import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
24import static android.view.WindowManagerPolicy.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;
28import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
29import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
30import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
31import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
32import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
33import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
34import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
35
David Stevens9440dc82017-03-16 19:00:20 -070036import android.app.ActivityManagerInternal.SleepToken;
Jorim Jaggi241ae102016-11-02 21:57:33 -070037import android.os.IBinder;
38import android.os.RemoteException;
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -070039import android.os.Trace;
Jorim Jaggi241ae102016-11-02 21:57:33 -070040import android.util.Slog;
41
42import com.android.internal.policy.IKeyguardDismissCallback;
Jorim Jaggife762342016-10-13 14:33:27 +020043import com.android.server.wm.WindowManagerService;
44
Jorim Jaggi8d786932016-10-26 19:08:36 -070045import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020046import java.util.ArrayList;
47
48/**
49 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
50 * currently visible.
51 * <p>
52 * Note that everything in this class should only be accessed with the AM lock being held.
53 */
54class KeyguardController {
55
Jorim Jaggi241ae102016-11-02 21:57:33 -070056 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
57
Jorim Jaggife762342016-10-13 14:33:27 +020058 private final ActivityManagerService mService;
59 private final ActivityStackSupervisor mStackSupervisor;
60 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020061 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070062 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020063 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010064 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020065 private ActivityRecord mDismissingKeyguardActivity;
66 private int mBeforeUnoccludeTransit;
67 private int mVisibilityTransactionDepth;
David Stevens9440dc82017-03-16 19:00:20 -070068 private SleepToken mSleepToken;
Jorim Jaggife762342016-10-13 14:33:27 +020069
70 KeyguardController(ActivityManagerService service,
71 ActivityStackSupervisor stackSupervisor) {
72 mService = service;
73 mStackSupervisor = stackSupervisor;
74 }
75
76 void setWindowManager(WindowManagerService windowManager) {
77 mWindowManager = windowManager;
78 }
79
80 /**
81 * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
82 */
83 boolean isKeyguardShowing() {
84 return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
85 }
86
87 /**
88 * @return true if Keyguard is either showing or occluded, but not going away
89 */
90 boolean isKeyguardLocked() {
91 return mKeyguardShowing && !mKeyguardGoingAway;
92 }
93
94 /**
95 * Update the Keyguard showing state.
96 */
97 void setKeyguardShown(boolean showing) {
98 if (showing == mKeyguardShowing) {
99 return;
100 }
101 mKeyguardShowing = showing;
Matthew Ngf4344ef2017-04-20 15:19:58 -0700102 dismissDockedStackIfNeeded();
Jorim Jaggife762342016-10-13 14:33:27 +0200103 if (showing) {
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700104 setKeyguardGoingAway(false);
Jorim Jaggi07961872016-11-23 11:28:57 +0100105 mDismissalRequested = false;
Jorim Jaggife762342016-10-13 14:33:27 +0200106 }
107 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
David Stevens9440dc82017-03-16 19:00:20 -0700108 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200109 }
110
111 /**
112 * Called when Keyguard is going away.
113 *
114 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
115 * etc.
116 */
117 void keyguardGoingAway(int flags) {
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700118 if (!mKeyguardShowing) {
119 return;
120 }
121 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
122 mWindowManager.deferSurfaceLayout();
123 try {
124 setKeyguardGoingAway(true);
125 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
126 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
127 false /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700128 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200129
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700130 // Some stack visibility might change (e.g. docked stack)
131 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
132 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
133 mWindowManager.executeAppTransition();
134 } finally {
135 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
136 mWindowManager.continueSurfaceLayout();
137 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
138
139 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
Jorim Jaggife762342016-10-13 14:33:27 +0200140 }
141 }
142
Jorim Jaggi241ae102016-11-02 21:57:33 -0700143 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
144 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
145 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
146 failCallback(callback);
147 return;
148 }
Jorim Jaggid7214892017-07-18 14:05:19 +0200149 Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord);
chaviw59b98852017-06-13 12:05:44 -0700150
151 // If the client has requested to dismiss the keyguard and the Activity has the flag to
152 // turn the screen on, wakeup the screen if it's the top Activity.
153 if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
154 mStackSupervisor.wakeUp("dismissKeyguard");
155 }
156
Jorim Jaggi241ae102016-11-02 21:57:33 -0700157 mWindowManager.dismissKeyguard(callback);
158 }
159
Wale Ogunwalebfa81ad2017-05-24 15:14:42 -0700160 private void setKeyguardGoingAway(boolean keyguardGoingAway) {
161 mKeyguardGoingAway = keyguardGoingAway;
162 mWindowManager.setKeyguardGoingAway(keyguardGoingAway);
163 }
164
Jorim Jaggi241ae102016-11-02 21:57:33 -0700165 private void failCallback(IKeyguardDismissCallback callback) {
166 try {
167 callback.onDismissError();
168 } catch (RemoteException e) {
169 Slog.w(TAG, "Failed to call callback", e);
170 }
171 }
172
Jorim Jaggife762342016-10-13 14:33:27 +0200173 private int convertTransitFlags(int keyguardGoingAwayFlags) {
174 int result = 0;
175 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
176 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
177 }
178 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
179 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
180 }
181 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
182 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
183 }
184 return result;
185 }
186
187 /**
188 * Starts a batch of visibility updates.
189 */
190 void beginActivityVisibilityUpdate() {
191 mVisibilityTransactionDepth++;
192 }
193
194 /**
195 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
196 * update lockscreen occluded/dismiss state if needed.
197 */
198 void endActivityVisibilityUpdate() {
199 mVisibilityTransactionDepth--;
200 if (mVisibilityTransactionDepth == 0) {
201 visibilitiesUpdated();
202 }
203 }
204
Jorim Jaggie69c9312016-10-31 18:24:38 -0700205 /**
206 * @return True if we may show an activity while Keyguard is showing because we are in the
207 * process of dismissing it anyways, false otherwise.
208 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100209 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
210
211 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
212 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
213 // Keyguard.
214 return dismissKeyguard && canDismissKeyguard() &&
215 (mDismissalRequested || r != mDismissingKeyguardActivity);
216 }
217
218 /**
219 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
220 */
221 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
222 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700223 }
224
Jorim Jaggife762342016-10-13 14:33:27 +0200225 private void visibilitiesUpdated() {
226 final boolean lastOccluded = mOccluded;
227 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
228 mOccluded = false;
229 mDismissingKeyguardActivity = null;
230 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
Wale Ogunwalee287e192017-04-21 09:30:12 -0700231 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
Jorim Jaggife762342016-10-13 14:33:27 +0200232 final ActivityStack stack = stacks.get(stackNdx);
233
Wale Ogunwalee287e192017-04-21 09:30:12 -0700234 // Only the focused stack top activity may control occluded state
235 if (mStackSupervisor.isFocusedStack(stack)) {
Jorim Jaggi07961872016-11-23 11:28:57 +0100236
237 // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
238 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
239 mOccluded = stack.topActivityOccludesKeyguard()
240 || (topDismissing != null
241 && stack.topRunningActivityLocked() == topDismissing
242 && canShowWhileOccluded(true /* dismissKeyguard */,
243 false /* showWhenLocked */));
Jorim Jaggife762342016-10-13 14:33:27 +0200244 }
245 if (mDismissingKeyguardActivity == null
246 && stack.getTopDismissingKeyguardActivity() != null) {
247 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
248 }
249 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700250 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200251 if (mOccluded != lastOccluded) {
252 handleOccludedChanged();
253 }
254 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
255 handleDismissKeyguard();
256 }
257 }
258
259 /**
260 * Called when occluded state changed.
261 */
262 private void handleOccludedChanged() {
263 mWindowManager.onKeyguardOccludedChanged(mOccluded);
264 if (isKeyguardLocked()) {
265 mWindowManager.deferSurfaceLayout();
266 try {
267 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
268 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
David Stevens9440dc82017-03-16 19:00:20 -0700269 updateKeyguardSleepToken();
Jorim Jaggife762342016-10-13 14:33:27 +0200270 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
271 mWindowManager.executeAppTransition();
272 } finally {
273 mWindowManager.continueSurfaceLayout();
274 }
275 }
276 dismissDockedStackIfNeeded();
277 }
278
279 /**
280 * Called when somebody might want to dismiss the Keyguard.
281 */
282 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100283 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
284 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
285 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
286 if (!mOccluded && mDismissingKeyguardActivity != null
287 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700288 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100289 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200290
291 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
292 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
293 if (mKeyguardShowing && canDismissKeyguard()
294 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
295 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
296 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200297 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
298 mWindowManager.executeAppTransition();
299 }
300 }
301 }
302
303 /**
304 * @return true if Keyguard can be currently dismissed without entering credentials.
305 */
Andrii Kulianfc8f82b2017-01-26 13:17:27 -0800306 boolean canDismissKeyguard() {
Jorim Jaggife762342016-10-13 14:33:27 +0200307 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
308 }
309
310 private int resolveOccludeTransit() {
311 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
312 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
313 && mOccluded) {
314
315 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
316 // actually occclude/unocclude Keyguard, but just run a normal transition.
317 return mBeforeUnoccludeTransit;
318 } else if (!mOccluded) {
319
320 // Save transit in case we dismiss/occlude Keyguard shortly after.
321 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
322 return TRANSIT_KEYGUARD_UNOCCLUDE;
323 } else {
324 return TRANSIT_KEYGUARD_OCCLUDE;
325 }
326 }
327
328 private void dismissDockedStackIfNeeded() {
329 if (mKeyguardShowing && mOccluded) {
330 // The lock screen is currently showing, but is occluded by a window that can
331 // show on top of the lock screen. In this can we want to dismiss the docked
332 // stack since it will be complicated/risky to try to put the activity on top
333 // of the lock screen in the right fullscreen configuration.
334 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
335 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
336 }
337 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700338
David Stevens9440dc82017-03-16 19:00:20 -0700339 private void updateKeyguardSleepToken() {
340 if (mSleepToken == null && isKeyguardShowing()) {
341 mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
342 } else if (mSleepToken != null && !isKeyguardShowing()) {
343 mSleepToken.release();
344 mSleepToken = null;
345 }
346 }
347
Jorim Jaggi8d786932016-10-26 19:08:36 -0700348 void dump(PrintWriter pw, String prefix) {
349 pw.println(prefix + "KeyguardController:");
350 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
351 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
352 pw.println(prefix + " mOccluded=" + mOccluded);
353 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100354 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700355 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
356 }
Jorim Jaggife762342016-10-13 14:33:27 +0200357}