blob: 5e02597f1991b3924c735e2f245fa3c650d8780c [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;
60 private ActivityRecord mDismissingKeyguardActivity;
61 private int mBeforeUnoccludeTransit;
62 private int mVisibilityTransactionDepth;
63
64 KeyguardController(ActivityManagerService service,
65 ActivityStackSupervisor stackSupervisor) {
66 mService = service;
67 mStackSupervisor = stackSupervisor;
68 }
69
70 void setWindowManager(WindowManagerService windowManager) {
71 mWindowManager = windowManager;
72 }
73
74 /**
75 * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
76 */
77 boolean isKeyguardShowing() {
78 return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
79 }
80
81 /**
82 * @return true if Keyguard is either showing or occluded, but not going away
83 */
84 boolean isKeyguardLocked() {
85 return mKeyguardShowing && !mKeyguardGoingAway;
86 }
87
88 /**
89 * Update the Keyguard showing state.
90 */
91 void setKeyguardShown(boolean showing) {
92 if (showing == mKeyguardShowing) {
93 return;
94 }
95 mKeyguardShowing = showing;
96 if (showing) {
97 mKeyguardGoingAway = false;
98
99 // Allow an activity to redismiss Keyguard.
100 mDismissingKeyguardActivity = null;
101 }
102 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
103 mService.updateSleepIfNeededLocked();
104 }
105
106 /**
107 * Called when Keyguard is going away.
108 *
109 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
110 * etc.
111 */
112 void keyguardGoingAway(int flags) {
113 if (mKeyguardShowing) {
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700114 mWindowManager.deferSurfaceLayout();
115 try {
116 mKeyguardGoingAway = true;
117 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
118 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
119 false /* forceOverride */);
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700120 mService.updateSleepIfNeededLocked();
Jorim Jaggife762342016-10-13 14:33:27 +0200121
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700122 // Some stack visibility might change (e.g. docked stack)
123 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
124 mWindowManager.executeAppTransition();
125 mService.applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(),
126 true /* enable */);
127 } 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
142 private void failCallback(IKeyguardDismissCallback callback) {
143 try {
144 callback.onDismissError();
145 } catch (RemoteException e) {
146 Slog.w(TAG, "Failed to call callback", e);
147 }
148 }
149
Jorim Jaggife762342016-10-13 14:33:27 +0200150 private int convertTransitFlags(int keyguardGoingAwayFlags) {
151 int result = 0;
152 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
153 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
154 }
155 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
156 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
157 }
158 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
159 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
160 }
161 return result;
162 }
163
164 /**
165 * Starts a batch of visibility updates.
166 */
167 void beginActivityVisibilityUpdate() {
168 mVisibilityTransactionDepth++;
169 }
170
171 /**
172 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
173 * update lockscreen occluded/dismiss state if needed.
174 */
175 void endActivityVisibilityUpdate() {
176 mVisibilityTransactionDepth--;
177 if (mVisibilityTransactionDepth == 0) {
178 visibilitiesUpdated();
179 }
180 }
181
Jorim Jaggie69c9312016-10-31 18:24:38 -0700182 /**
183 * @return True if we may show an activity while Keyguard is showing because we are in the
184 * process of dismissing it anyways, false otherwise.
185 */
186 boolean canShowActivityWhileKeyguardShowing(boolean dismissKeyguard) {
187 return dismissKeyguard && canDismissKeyguard();
188 }
189
Jorim Jaggife762342016-10-13 14:33:27 +0200190 private void visibilitiesUpdated() {
191 final boolean lastOccluded = mOccluded;
192 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
193 mOccluded = false;
194 mDismissingKeyguardActivity = null;
195 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
196 final int topStackNdx = stacks.size() - 1;
197 for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
198 final ActivityStack stack = stacks.get(stackNdx);
199
200 // Only the very top activity may control occluded state
201 if (stackNdx == topStackNdx) {
202 mOccluded = stack.topActivityOccludesKeyguard();
203 }
204 if (mDismissingKeyguardActivity == null
205 && stack.getTopDismissingKeyguardActivity() != null) {
206 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
207 }
208 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700209 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200210 if (mOccluded != lastOccluded) {
211 handleOccludedChanged();
212 }
213 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
214 handleDismissKeyguard();
215 }
216 }
217
218 /**
219 * Called when occluded state changed.
220 */
221 private void handleOccludedChanged() {
222 mWindowManager.onKeyguardOccludedChanged(mOccluded);
223 if (isKeyguardLocked()) {
224 mWindowManager.deferSurfaceLayout();
225 try {
226 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
227 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
228 mService.updateSleepIfNeededLocked();
229 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
230 mWindowManager.executeAppTransition();
231 } finally {
232 mWindowManager.continueSurfaceLayout();
233 }
234 }
235 dismissDockedStackIfNeeded();
236 }
237
238 /**
239 * Called when somebody might want to dismiss the Keyguard.
240 */
241 private void handleDismissKeyguard() {
242 if (mDismissingKeyguardActivity != null) {
Jorim Jaggi241ae102016-11-02 21:57:33 -0700243 mWindowManager.dismissKeyguard(null /* callback */);
Jorim Jaggife762342016-10-13 14:33:27 +0200244
245 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
246 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
247 if (mKeyguardShowing && canDismissKeyguard()
248 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
249 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
250 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200251 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
252 mWindowManager.executeAppTransition();
253 }
254 }
255 }
256
257 /**
258 * @return true if Keyguard can be currently dismissed without entering credentials.
259 */
260 private boolean canDismissKeyguard() {
261 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
262 }
263
264 private int resolveOccludeTransit() {
265 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
266 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
267 && mOccluded) {
268
269 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
270 // actually occclude/unocclude Keyguard, but just run a normal transition.
271 return mBeforeUnoccludeTransit;
272 } else if (!mOccluded) {
273
274 // Save transit in case we dismiss/occlude Keyguard shortly after.
275 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
276 return TRANSIT_KEYGUARD_UNOCCLUDE;
277 } else {
278 return TRANSIT_KEYGUARD_OCCLUDE;
279 }
280 }
281
282 private void dismissDockedStackIfNeeded() {
283 if (mKeyguardShowing && mOccluded) {
284 // The lock screen is currently showing, but is occluded by a window that can
285 // show on top of the lock screen. In this can we want to dismiss the docked
286 // stack since it will be complicated/risky to try to put the activity on top
287 // of the lock screen in the right fullscreen configuration.
288 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
289 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
290 }
291 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700292
293 void dump(PrintWriter pw, String prefix) {
294 pw.println(prefix + "KeyguardController:");
295 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
296 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
297 pw.println(prefix + " mOccluded=" + mOccluded);
298 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
299 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
300 }
Jorim Jaggife762342016-10-13 14:33:27 +0200301}