1 /* 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 17 package com.android.server.am; 18 19 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; 20 import static android.view.Display.DEFAULT_DISPLAY; 21 import static android.view.Display.INVALID_DISPLAY; 22 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; 23 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; 24 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; 25 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 26 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 27 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; 28 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED; 29 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING; 30 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; 31 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; 32 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; 33 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; 34 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; 35 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; 36 import static android.view.WindowManager.TRANSIT_UNSET; 37 38 import android.app.ActivityManagerInternal.SleepToken; 39 import android.os.IBinder; 40 import android.os.RemoteException; 41 import android.os.Trace; 42 import android.util.Slog; 43 import android.util.proto.ProtoOutputStream; 44 45 import com.android.internal.policy.IKeyguardDismissCallback; 46 import com.android.server.policy.WindowManagerPolicy; 47 import com.android.server.wm.WindowManagerService; 48 49 import java.io.PrintWriter; 50 51 /** 52 * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are 53 * currently visible. 54 * <p> 55 * Note that everything in this class should only be accessed with the AM lock being held. 56 */ 57 class KeyguardController { 58 59 private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM; 60 61 private final ActivityManagerService mService; 62 private final ActivityStackSupervisor mStackSupervisor; 63 private WindowManagerService mWindowManager; 64 private boolean mKeyguardShowing; 65 private boolean mAodShowing; 66 private boolean mKeyguardGoingAway; 67 private boolean mOccluded; 68 private boolean mDismissalRequested; 69 private ActivityRecord mDismissingKeyguardActivity; 70 private int mBeforeUnoccludeTransit; 71 private int mVisibilityTransactionDepth; 72 private SleepToken mSleepToken; 73 private int mSecondaryDisplayShowing = INVALID_DISPLAY; 74 KeyguardController(ActivityManagerService service, ActivityStackSupervisor stackSupervisor)75 KeyguardController(ActivityManagerService service, 76 ActivityStackSupervisor stackSupervisor) { 77 mService = service; 78 mStackSupervisor = stackSupervisor; 79 } 80 setWindowManager(WindowManagerService windowManager)81 void setWindowManager(WindowManagerService windowManager) { 82 mWindowManager = windowManager; 83 } 84 85 /** 86 * @return true if either Keyguard or AOD are showing, not going away, and not being occluded 87 * on the given display, false otherwise 88 */ isKeyguardOrAodShowing(int displayId)89 boolean isKeyguardOrAodShowing(int displayId) { 90 return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway && 91 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); 92 } 93 94 /** 95 * @return true if Keyguard is showing, not going away, and not being occluded on the given 96 * display, false otherwise 97 */ isKeyguardShowing(int displayId)98 boolean isKeyguardShowing(int displayId) { 99 return mKeyguardShowing && !mKeyguardGoingAway && 100 (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); 101 } 102 103 /** 104 * @return true if Keyguard is either showing or occluded, but not going away 105 */ isKeyguardLocked()106 boolean isKeyguardLocked() { 107 return mKeyguardShowing && !mKeyguardGoingAway; 108 } 109 110 /** 111 * @return {@code true} if the keyguard is going away, {@code false} otherwise. 112 */ isKeyguardGoingAway()113 boolean isKeyguardGoingAway() { 114 // Also check keyguard showing in case value is stale. 115 return mKeyguardGoingAway && mKeyguardShowing; 116 } 117 118 /** 119 * Update the Keyguard showing state. 120 */ setKeyguardShown(boolean keyguardShowing, boolean aodShowing, int secondaryDisplayShowing)121 void setKeyguardShown(boolean keyguardShowing, boolean aodShowing, 122 int secondaryDisplayShowing) { 123 boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing; 124 // If keyguard is going away, but SystemUI aborted the transition, need to reset state. 125 showingChanged |= mKeyguardGoingAway && keyguardShowing; 126 if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) { 127 return; 128 } 129 mKeyguardShowing = keyguardShowing; 130 mAodShowing = aodShowing; 131 mSecondaryDisplayShowing = secondaryDisplayShowing; 132 mWindowManager.setAodShowing(aodShowing); 133 if (showingChanged) { 134 dismissDockedStackIfNeeded(); 135 setKeyguardGoingAway(false); 136 mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay( 137 isKeyguardOrAodShowing(DEFAULT_DISPLAY)); 138 if (keyguardShowing) { 139 mDismissalRequested = false; 140 } 141 } 142 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); 143 updateKeyguardSleepToken(); 144 } 145 146 /** 147 * Called when Keyguard is going away. 148 * 149 * @param flags See {@link WindowManagerPolicy#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE} 150 * etc. 151 */ keyguardGoingAway(int flags)152 void keyguardGoingAway(int flags) { 153 if (!mKeyguardShowing) { 154 return; 155 } 156 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway"); 157 mWindowManager.deferSurfaceLayout(); 158 try { 159 setKeyguardGoingAway(true); 160 mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, 161 false /* alwaysKeepCurrent */, convertTransitFlags(flags), 162 false /* forceOverride */); 163 updateKeyguardSleepToken(); 164 165 // Some stack visibility might change (e.g. docked stack) 166 mStackSupervisor.resumeFocusedStackTopActivityLocked(); 167 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); 168 mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */); 169 mWindowManager.executeAppTransition(); 170 } finally { 171 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout"); 172 mWindowManager.continueSurfaceLayout(); 173 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 174 175 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 176 } 177 } 178 dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message)179 void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message) { 180 final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token); 181 if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) { 182 failCallback(callback); 183 return; 184 } 185 Slog.i(TAG, "Activity requesting to dismiss Keyguard: " + activityRecord); 186 187 // If the client has requested to dismiss the keyguard and the Activity has the flag to 188 // turn the screen on, wakeup the screen if it's the top Activity. 189 if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) { 190 mStackSupervisor.wakeUp("dismissKeyguard"); 191 } 192 193 mWindowManager.dismissKeyguard(callback, message); 194 } 195 setKeyguardGoingAway(boolean keyguardGoingAway)196 private void setKeyguardGoingAway(boolean keyguardGoingAway) { 197 mKeyguardGoingAway = keyguardGoingAway; 198 mWindowManager.setKeyguardGoingAway(keyguardGoingAway); 199 } 200 failCallback(IKeyguardDismissCallback callback)201 private void failCallback(IKeyguardDismissCallback callback) { 202 try { 203 callback.onDismissError(); 204 } catch (RemoteException e) { 205 Slog.w(TAG, "Failed to call callback", e); 206 } 207 } 208 convertTransitFlags(int keyguardGoingAwayFlags)209 private int convertTransitFlags(int keyguardGoingAwayFlags) { 210 int result = 0; 211 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) { 212 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; 213 } 214 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS) != 0) { 215 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; 216 } 217 if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER) != 0) { 218 result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; 219 } 220 return result; 221 } 222 223 /** 224 * Starts a batch of visibility updates. 225 */ beginActivityVisibilityUpdate()226 void beginActivityVisibilityUpdate() { 227 mVisibilityTransactionDepth++; 228 } 229 230 /** 231 * Ends a batch of visibility updates. After all batches are done, this method makes sure to 232 * update lockscreen occluded/dismiss state if needed. 233 */ endActivityVisibilityUpdate()234 void endActivityVisibilityUpdate() { 235 mVisibilityTransactionDepth--; 236 if (mVisibilityTransactionDepth == 0) { 237 visibilitiesUpdated(); 238 } 239 } 240 241 /** 242 * @return True if we may show an activity while Keyguard is showing because we are in the 243 * process of dismissing it anyways, false otherwise. 244 */ canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard)245 boolean canShowActivityWhileKeyguardShowing(ActivityRecord r, boolean dismissKeyguard) { 246 247 // Allow to show it when we are about to dismiss Keyguard. This isn't allowed if r is 248 // already the dismissing activity, in which case we don't allow it to repeatedly dismiss 249 // Keyguard. 250 return dismissKeyguard && canDismissKeyguard() && !mAodShowing 251 && (mDismissalRequested || r != mDismissingKeyguardActivity); 252 } 253 254 /** 255 * @return True if we may show an activity while Keyguard is occluded, false otherwise. 256 */ canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked)257 boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) { 258 return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure(); 259 } 260 visibilitiesUpdated()261 private void visibilitiesUpdated() { 262 final boolean lastOccluded = mOccluded; 263 final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity; 264 mOccluded = false; 265 mDismissingKeyguardActivity = null; 266 267 for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) { 268 final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx); 269 for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { 270 final ActivityStack stack = display.getChildAt(stackNdx); 271 272 // Only the top activity of the focused stack on the default display may control 273 // occluded state. 274 if (display.mDisplayId == DEFAULT_DISPLAY 275 && mStackSupervisor.isFocusedStack(stack)) { 276 277 // A dismissing activity occludes Keyguard in the insecure case for legacy 278 // reasons. 279 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity(); 280 mOccluded = 281 stack.topActivityOccludesKeyguard() 282 || (topDismissing != null 283 && stack.topRunningActivityLocked() == topDismissing 284 && canShowWhileOccluded( 285 true /* dismissKeyguard */, 286 false /* showWhenLocked */)); 287 } 288 289 if (mDismissingKeyguardActivity == null 290 && stack.getTopDismissingKeyguardActivity() != null) { 291 mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity(); 292 } 293 } 294 } 295 mOccluded |= mWindowManager.isShowingDream(); 296 if (mOccluded != lastOccluded) { 297 handleOccludedChanged(); 298 } 299 if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) { 300 handleDismissKeyguard(); 301 } 302 } 303 304 /** 305 * Called when occluded state changed. 306 */ handleOccludedChanged()307 private void handleOccludedChanged() { 308 mWindowManager.onKeyguardOccludedChanged(mOccluded); 309 if (isKeyguardLocked()) { 310 mWindowManager.deferSurfaceLayout(); 311 try { 312 mWindowManager.prepareAppTransition(resolveOccludeTransit(), 313 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */); 314 updateKeyguardSleepToken(); 315 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); 316 mWindowManager.executeAppTransition(); 317 } finally { 318 mWindowManager.continueSurfaceLayout(); 319 } 320 } 321 dismissDockedStackIfNeeded(); 322 } 323 324 /** 325 * Called when somebody might want to dismiss the Keyguard. 326 */ handleDismissKeyguard()327 private void handleDismissKeyguard() { 328 // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy 329 // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the 330 // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded. 331 if (!mOccluded && mDismissingKeyguardActivity != null 332 && mWindowManager.isKeyguardSecure()) { 333 mWindowManager.dismissKeyguard(null /* callback */, null /* message */); 334 mDismissalRequested = true; 335 336 // If we are about to unocclude the Keyguard, but we can dismiss it without security, 337 // we immediately dismiss the Keyguard so the activity gets shown without a flicker. 338 if (mKeyguardShowing && canDismissKeyguard() 339 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) { 340 mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit, 341 false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */); 342 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); 343 mWindowManager.executeAppTransition(); 344 } 345 } 346 } 347 348 /** 349 * @return true if Keyguard can be currently dismissed without entering credentials. 350 */ canDismissKeyguard()351 boolean canDismissKeyguard() { 352 return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure(); 353 } 354 resolveOccludeTransit()355 private int resolveOccludeTransit() { 356 if (mBeforeUnoccludeTransit != TRANSIT_UNSET 357 && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE 358 && mOccluded) { 359 360 // Reuse old transit in case we are occluding Keyguard again, meaning that we never 361 // actually occclude/unocclude Keyguard, but just run a normal transition. 362 return mBeforeUnoccludeTransit; 363 } else if (!mOccluded) { 364 365 // Save transit in case we dismiss/occlude Keyguard shortly after. 366 mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition(); 367 return TRANSIT_KEYGUARD_UNOCCLUDE; 368 } else { 369 return TRANSIT_KEYGUARD_OCCLUDE; 370 } 371 } 372 dismissDockedStackIfNeeded()373 private void dismissDockedStackIfNeeded() { 374 if (mKeyguardShowing && mOccluded) { 375 // The lock screen is currently showing, but is occluded by a window that can 376 // show on top of the lock screen. In this can we want to dismiss the docked 377 // stack since it will be complicated/risky to try to put the activity on top 378 // of the lock screen in the right fullscreen configuration. 379 final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); 380 if (stack == null) { 381 return; 382 } 383 mStackSupervisor.moveTasksToFullscreenStackLocked(stack, 384 mStackSupervisor.mFocusedStack == stack); 385 } 386 } 387 updateKeyguardSleepToken()388 private void updateKeyguardSleepToken() { 389 if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) { 390 mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY); 391 } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) { 392 mSleepToken.release(); 393 mSleepToken = null; 394 } 395 } 396 dump(PrintWriter pw, String prefix)397 void dump(PrintWriter pw, String prefix) { 398 pw.println(prefix + "KeyguardController:"); 399 pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing); 400 pw.println(prefix + " mAodShowing=" + mAodShowing); 401 pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway); 402 pw.println(prefix + " mOccluded=" + mOccluded); 403 pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity); 404 pw.println(prefix + " mDismissalRequested=" + mDismissalRequested); 405 pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth); 406 } 407 writeToProto(ProtoOutputStream proto, long fieldId)408 void writeToProto(ProtoOutputStream proto, long fieldId) { 409 final long token = proto.start(fieldId); 410 proto.write(KEYGUARD_SHOWING, mKeyguardShowing); 411 proto.write(KEYGUARD_OCCLUDED, mOccluded); 412 proto.end(token); 413 } 414 } 415