blob: 9d8c3835b33f781a57ce4e936e83ac01b01e94f4 [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;
23import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
24import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
25import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
26import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
27import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
28import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
29import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
30import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
31
32import com.android.server.wm.WindowManagerService;
33
Jorim Jaggi8d786932016-10-26 19:08:36 -070034import java.io.PrintWriter;
Jorim Jaggife762342016-10-13 14:33:27 +020035import java.util.ArrayList;
36
37/**
38 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
39 * currently visible.
40 * <p>
41 * Note that everything in this class should only be accessed with the AM lock being held.
42 */
43class KeyguardController {
44
45 private final ActivityManagerService mService;
46 private final ActivityStackSupervisor mStackSupervisor;
47 private WindowManagerService mWindowManager;
Jorim Jaggife762342016-10-13 14:33:27 +020048 private boolean mKeyguardShowing;
Jorim Jaggi8d786932016-10-26 19:08:36 -070049 private boolean mKeyguardGoingAway;
Jorim Jaggife762342016-10-13 14:33:27 +020050 private boolean mOccluded;
51 private ActivityRecord mDismissingKeyguardActivity;
52 private int mBeforeUnoccludeTransit;
53 private int mVisibilityTransactionDepth;
54
55 KeyguardController(ActivityManagerService service,
56 ActivityStackSupervisor stackSupervisor) {
57 mService = service;
58 mStackSupervisor = stackSupervisor;
59 }
60
61 void setWindowManager(WindowManagerService windowManager) {
62 mWindowManager = windowManager;
63 }
64
65 /**
66 * @return true if Keyguard is showing, not going away, and not being occluded, false otherwise
67 */
68 boolean isKeyguardShowing() {
69 return mKeyguardShowing && !mKeyguardGoingAway && !mOccluded;
70 }
71
72 /**
73 * @return true if Keyguard is either showing or occluded, but not going away
74 */
75 boolean isKeyguardLocked() {
76 return mKeyguardShowing && !mKeyguardGoingAway;
77 }
78
79 /**
80 * Update the Keyguard showing state.
81 */
82 void setKeyguardShown(boolean showing) {
83 if (showing == mKeyguardShowing) {
84 return;
85 }
86 mKeyguardShowing = showing;
87 if (showing) {
88 mKeyguardGoingAway = false;
89
90 // Allow an activity to redismiss Keyguard.
91 mDismissingKeyguardActivity = null;
92 }
93 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
94 mService.updateSleepIfNeededLocked();
95 }
96
97 /**
98 * Called when Keyguard is going away.
99 *
100 * @param flags See {@link android.view.WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
101 * etc.
102 */
103 void keyguardGoingAway(int flags) {
104 if (mKeyguardShowing) {
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700105 mWindowManager.deferSurfaceLayout();
106 try {
107 mKeyguardGoingAway = true;
108 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
109 false /* alwaysKeepCurrent */, convertTransitFlags(flags),
110 false /* forceOverride */);
111 mWindowManager.keyguardGoingAway(flags);
112 mService.updateSleepIfNeededLocked();
Jorim Jaggife762342016-10-13 14:33:27 +0200113
Jorim Jaggiab7ad382016-10-26 18:22:04 -0700114 // Some stack visibility might change (e.g. docked stack)
115 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
116 mWindowManager.executeAppTransition();
117 mService.applyVrModeIfNeededLocked(mStackSupervisor.getResumedActivityLocked(),
118 true /* enable */);
119 } finally {
120 mWindowManager.continueSurfaceLayout();
121 }
Jorim Jaggife762342016-10-13 14:33:27 +0200122 }
123 }
124
125 private int convertTransitFlags(int keyguardGoingAwayFlags) {
126 int result = 0;
127 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
128 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
129 }
130 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) {
131 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
132 }
133 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) {
134 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
135 }
136 return result;
137 }
138
139 /**
140 * Starts a batch of visibility updates.
141 */
142 void beginActivityVisibilityUpdate() {
143 mVisibilityTransactionDepth++;
144 }
145
146 /**
147 * Ends a batch of visibility updates. After all batches are done, this method makes sure to
148 * update lockscreen occluded/dismiss state if needed.
149 */
150 void endActivityVisibilityUpdate() {
151 mVisibilityTransactionDepth--;
152 if (mVisibilityTransactionDepth == 0) {
153 visibilitiesUpdated();
154 }
155 }
156
Jorim Jaggie69c9312016-10-31 18:24:38 -0700157 /**
158 * @return True if we may show an activity while Keyguard is showing because we are in the
159 * process of dismissing it anyways, false otherwise.
160 */
161 boolean canShowActivityWhileKeyguardShowing(boolean dismissKeyguard) {
162 return dismissKeyguard && canDismissKeyguard();
163 }
164
Jorim Jaggife762342016-10-13 14:33:27 +0200165 private void visibilitiesUpdated() {
166 final boolean lastOccluded = mOccluded;
167 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
168 mOccluded = false;
169 mDismissingKeyguardActivity = null;
170 final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay();
171 final int topStackNdx = stacks.size() - 1;
172 for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
173 final ActivityStack stack = stacks.get(stackNdx);
174
175 // Only the very top activity may control occluded state
176 if (stackNdx == topStackNdx) {
177 mOccluded = stack.topActivityOccludesKeyguard();
178 }
179 if (mDismissingKeyguardActivity == null
180 && stack.getTopDismissingKeyguardActivity() != null) {
181 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
182 }
183 }
Jorim Jaggi77e10432016-10-26 17:43:56 -0700184 mOccluded |= mWindowManager.isShowingDream();
Jorim Jaggife762342016-10-13 14:33:27 +0200185 if (mOccluded != lastOccluded) {
186 handleOccludedChanged();
187 }
188 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
189 handleDismissKeyguard();
190 }
191 }
192
193 /**
194 * Called when occluded state changed.
195 */
196 private void handleOccludedChanged() {
197 mWindowManager.onKeyguardOccludedChanged(mOccluded);
198 if (isKeyguardLocked()) {
199 mWindowManager.deferSurfaceLayout();
200 try {
201 mWindowManager.prepareAppTransition(resolveOccludeTransit(),
202 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
203 mService.updateSleepIfNeededLocked();
204 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
205 mWindowManager.executeAppTransition();
206 } finally {
207 mWindowManager.continueSurfaceLayout();
208 }
209 }
210 dismissDockedStackIfNeeded();
211 }
212
213 /**
214 * Called when somebody might want to dismiss the Keyguard.
215 */
216 private void handleDismissKeyguard() {
217 if (mDismissingKeyguardActivity != null) {
218 mWindowManager.dismissKeyguard();
219
220 // If we are about to unocclude the Keyguard, but we can dismiss it without security,
221 // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
222 if (mKeyguardShowing && canDismissKeyguard()
223 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
224 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
225 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
Jorim Jaggife762342016-10-13 14:33:27 +0200226 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
227 mWindowManager.executeAppTransition();
228 }
229 }
230 }
231
232 /**
233 * @return true if Keyguard can be currently dismissed without entering credentials.
234 */
235 private boolean canDismissKeyguard() {
236 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
237 }
238
239 private int resolveOccludeTransit() {
240 if (mBeforeUnoccludeTransit != TRANSIT_UNSET
241 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
242 && mOccluded) {
243
244 // Reuse old transit in case we are occluding Keyguard again, meaning that we never
245 // actually occclude/unocclude Keyguard, but just run a normal transition.
246 return mBeforeUnoccludeTransit;
247 } else if (!mOccluded) {
248
249 // Save transit in case we dismiss/occlude Keyguard shortly after.
250 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
251 return TRANSIT_KEYGUARD_UNOCCLUDE;
252 } else {
253 return TRANSIT_KEYGUARD_OCCLUDE;
254 }
255 }
256
257 private void dismissDockedStackIfNeeded() {
258 if (mKeyguardShowing && mOccluded) {
259 // The lock screen is currently showing, but is occluded by a window that can
260 // show on top of the lock screen. In this can we want to dismiss the docked
261 // stack since it will be complicated/risky to try to put the activity on top
262 // of the lock screen in the right fullscreen configuration.
263 mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
264 mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
265 }
266 }
Jorim Jaggi8d786932016-10-26 19:08:36 -0700267
268 void dump(PrintWriter pw, String prefix) {
269 pw.println(prefix + "KeyguardController:");
270 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
271 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
272 pw.println(prefix + " mOccluded=" + mOccluded);
273 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
274 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
275 }
Jorim Jaggife762342016-10-13 14:33:27 +0200276}