KeyguardController.java revision e69c93181f1f313dcedd07f677af1cea953fdf16
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 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 34import java.io.PrintWriter; 35import 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; 48 private boolean mKeyguardShowing; 49 private boolean mKeyguardGoingAway; 50 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) { 105 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(); 113 114 // 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 } 122 } 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 157 /** 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 165 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 } 184 mOccluded |= mWindowManager.isShowingDream(); 185 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 */); 226 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 } 267 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 } 276} 277