blob: 19bf5369a57ba7dfb6ebb72b6f8e1efb39cab7bc [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;
32import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
33
Jorim Jaggi241ae102016-11-02 21:57:33 -070034import android.os.IBinder;
35import android.os.RemoteException;
36import android.util.Slog;
37
38import com.android.internal.policy.IKeyguardDismissCallback;
Jorim Jaggife762342016-10-13 14:33:27 +020039import com.android.server.wm.WindowManagerService;
40
Jorim Jaggi8d786932016-10-26 19:08:36 -070041import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020042import java.util.ArrayList;
43
44/**
45 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
46 * currently visible.
47 * <p>
48 * Note that everything in this class should only be accessed with the AM lock being held.
49 */
50class KeyguardController {
51
Jorim Jaggi241ae102016-11-02 21:57:33 -070052 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
53
Jorim Jaggife762342016-10-13 14:33:27 +020054 private final ActivityManagerService mService;
55 private final ActivityStackSupervisor mStackSupervisor;
56 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020057 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070058 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020059 private boolean mOccluded;
Jorim Jaggi07961872016-11-23 11:28:57 +010060 private boolean mDismissalRequested;
Jorim Jaggife762342016-10-13 14:33:27 +020061 private ActivityRecord mDismissingKeyguardActivity;
62 private int mBeforeUnoccludeTransit;
63 private int mVisibilityTransactionDepth;
64
65 KeyguardController(ActivityManagerService service,
66 ActivityStackSupervisor stackSupervisor) {
67 mService = service;
68 mStackSupervisor = stackSupervisor;
69 }
70
71 void setWindowManager(WindowManagerService windowManager) {
72 mWindowManager = windowManager;
73 }
74
75 /**
76 * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
77 */
78 boolean isKeyguardShowing() {
79 return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
80 }
81
82 /**
83 * @return true if Keyguard is either showing or occluded, but not going away
84 */
85 boolean isKeyguardLocked() {
86 return mKeyguardShowing && !mKeyguardGoingAway;
87 }
88
89 /**
90 * Update the Keyguard showing state.
91 */
92 void setKeyguardShown(boolean showing) {
93 if (showing == mKeyguardShowing) {
94 return;
95 }
96 mKeyguardShowing = showing;
97 if (showing) {
98 mKeyguardGoingAway = false;
Jorim Jaggi07961872016-11-23 11:28:57 +010099 mDismissalRequested = false;
Jorim Jaggife762342016-10-13 14:33:27 +0200100 }
101 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
102 mService.updateSleepIfNeededLocked();
103 }
104
105 /**
106 * Called when Keyguard is going away.
107 *
108 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
109 * etc.
110 */
111 void keyguardGoingAway(int flags) {
112 if (mKeyguardShowing) {
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700113 mWindowManager.deferSurfaceLayout();
114 try {
115 mKeyguardGoingAway = true;
116 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
117 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
118 false /* forceOverride */);
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700119 mService.updateSleepIfNeededLocked();
Jorim Jaggife762342016-10-13 14:33:27 +0200120
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700121 // Some stack visibility might change (e.g. docked stack)
122 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
123 mWindowManager.executeAppTransition();
124 mService.applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(),
125 true /* enable */);
126 } finally {
127 mWindowManager.continueSurfaceLayout();
128 }
Jorim Jaggife762342016-10-13 14:33:27 +0200129 }
130 }
131
Jorim Jaggi241ae102016-11-02 21:57:33 -0700132 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
133 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
134 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
135 failCallback(callback);
136 return;
137 }
138 mWindowManager.dismissKeyguard(callback);
139 }
140
141 private void failCallback(IKeyguardDismissCallback callback) {
142 try {
143 callback.onDismissError();
144 } catch (RemoteException e) {
145 Slog.w(TAG, "Failed to call callback", e);
146 }
147 }
148
Jorim Jaggife762342016-10-13 14:33:27 +0200149 private int convertTransitFlags(int keyguardGoingAwayFlags) {
150 int result = 0;
151 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
152 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
153 }
154 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
155 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
156 }
157 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
158 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
159 }
160 return result;
161 }
162
163 /**
164 * Starts a batch of visibility updates.
165 */
166 void beginActivityVisibilityUpdate() {
167 mVisibilityTransactionDepth++;
168 }
169
170 /**
171 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
172 * update lockscreen occluded/dismiss state if needed.
173 */
174 void endActivityVisibilityUpdate() {
175 mVisibilityTransactionDepth--;
176 if (mVisibilityTransactionDepth == 0) {
177 visibilitiesUpdated();
178 }
179 }
180
Jorim Jaggie69c9312016-10-31 18:24:38 -0700181 /**
182 * @return True if we may show an activity while Keyguard is showing because we are in the
183 * process of dismissing it anyways, false otherwise.
184 */
Jorim Jaggi07961872016-11-23 11:28:57 +0100185 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) {
186
187 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is
188 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss
189 // Keyguard.
190 return dismissKeyguard && canDismissKeyguard() &&
191 (mDismissalRequested || r != mDismissingKeyguardActivity);
192 }
193
194 /**
195 * @return True if we may show an activity while Keyguard is occluded, false otherwise.
196 */
197 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
198 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
Jorim Jaggie69c9312016-10-31 18:24:38 -0700199 }
200
Jorim Jaggife762342016-10-13 14:33:27 +0200201 private void visibilitiesUpdated() {
202 final boolean lastOccluded = mOccluded;
203 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
204 mOccluded = false;
205 mDismissingKeyguardActivity = null;
206 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
207 final int topStackNdx = stacks.size() - 1;
208 for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
209 final ActivityStack stack = stacks.get(stackNdx);
210
211 // Only the very top activity may control occluded state
212 if (stackNdx == topStackNdx) {
Jorim Jaggi07961872016-11-23 11:28:57 +0100213
214 // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
215 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
216 mOccluded = stack.topActivityOccludesKeyguard()
217 || (topDismissing != null
218 && stack.topRunningActivityLocked() == topDismissing
219 && canShowWhileOccluded(true /* dismissKeyguard */,
220 false /* showWhenLocked */));
Jorim Jaggife762342016-10-13 14:33:27 +0200221 }
222 if (mDismissingKeyguardActivity == null
223 && stack.getTopDismissingKeyguardActivity() != null) {
224 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
225 }
226 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700227 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200228 if (mOccluded != lastOccluded) {
229 handleOccludedChanged();
230 }
231 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
232 handleDismissKeyguard();
233 }
234 }
235
236 /**
237 * Called when occluded state changed.
238 */
239 private void handleOccludedChanged() {
240 mWindowManager.onKeyguardOccludedChanged(mOccluded);
241 if (isKeyguardLocked()) {
242 mWindowManager.deferSurfaceLayout();
243 try {
244 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
245 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
246 mService.updateSleepIfNeededLocked();
247 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
248 mWindowManager.executeAppTransition();
249 } finally {
250 mWindowManager.continueSurfaceLayout();
251 }
252 }
253 dismissDockedStackIfNeeded();
254 }
255
256 /**
257 * Called when somebody might want to dismiss the Keyguard.
258 */
259 private void handleDismissKeyguard() {
Jorim Jaggi07961872016-11-23 11:28:57 +0100260 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
261 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
262 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
263 if (!mOccluded && mDismissingKeyguardActivity != null
264 && mWindowManager.isKeyguardSecure()) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700265 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggi07961872016-11-23 11:28:57 +0100266 mDismissalRequested = true;
Jorim Jaggife762342016-10-13 14:33:27 +0200267
268 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
269 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
270 if (mKeyguardShowing && canDismissKeyguard()
271 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
272 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
273 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200274 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
275 mWindowManager.executeAppTransition();
276 }
277 }
278 }
279
280 /**
281 * @return true if Keyguard can be currently dismissed without entering credentials.
282 */
283 private boolean canDismissKeyguard() {
284 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
285 }
286
287 private int resolveOccludeTransit() {
288 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
289 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
290 && mOccluded) {
291
292 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
293 // actually occclude/unocclude Keyguard, but just run a normal transition.
294 return mBeforeUnoccludeTransit;
295 } else if (!mOccluded) {
296
297 // Save transit in case we dismiss/occlude Keyguard shortly after.
298 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
299 return TRANSIT_KEYGUARD_UNOCCLUDE;
300 } else {
301 return TRANSIT_KEYGUARD_OCCLUDE;
302 }
303 }
304
305 private void dismissDockedStackIfNeeded() {
306 if (mKeyguardShowing && mOccluded) {
307 // The lock screen is currently showing, but is occluded by a window that can
308 // show on top of the lock screen. In this can we want to dismiss the docked
309 // stack since it will be complicated/risky to try to put the activity on top
310 // of the lock screen in the right fullscreen configuration.
311 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
312 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
313 }
314 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700315
316 void dump(PrintWriter pw, String prefix) {
317 pw.println(prefix + "KeyguardController:");
318 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
319 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
320 pw.println(prefix + " mOccluded=" + mOccluded);
321 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
Jorim Jaggi07961872016-11-23 11:28:57 +0100322 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
Jorim Jaggi8d786932016-10-26 19:08:36 -0700323 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
324 }
Jorim Jaggife762342016-10-13 14:33:27 +0200325}