KeyguardServiceDelegate.java revision 6626f54e658e3da44fab8a5cd6d9d3d4852e2cd1
1package com.android.server.policy.keyguard; 2 3import android.content.ComponentName; 4import android.content.Context; 5import android.content.Intent; 6import android.content.ServiceConnection; 7import android.content.pm.ActivityInfo; 8import android.content.res.Resources; 9import android.graphics.PixelFormat; 10import android.os.Bundle; 11import android.os.Handler; 12import android.os.IBinder; 13import android.os.RemoteException; 14import android.os.UserHandle; 15import android.util.Log; 16import android.util.Slog; 17import android.view.View; 18import android.view.ViewGroup; 19import android.view.WindowManager; 20import android.view.WindowManagerPolicy.OnKeyguardExitResult; 21 22import com.android.internal.annotations.GuardedBy; 23import com.android.internal.policy.IKeyguardDrawnCallback; 24import com.android.internal.policy.IKeyguardExitCallback; 25import com.android.internal.policy.IKeyguardService; 26import com.android.server.UiThread; 27 28import java.io.PrintWriter; 29 30/** 31 * A local class that keeps a cache of keyguard state that can be restored in the event 32 * keyguard crashes. It currently also allows runtime-selectable 33 * local or remote instances of keyguard. 34 */ 35public class KeyguardServiceDelegate { 36 private static final String TAG = "KeyguardServiceDelegate"; 37 private static final boolean DEBUG = true; 38 39 private static final int SCREEN_STATE_OFF = 0; 40 private static final int SCREEN_STATE_TURNING_ON = 1; 41 private static final int SCREEN_STATE_ON = 2; 42 43 private static final int INTERACTIVE_STATE_SLEEP = 0; 44 private static final int INTERACTIVE_STATE_AWAKE = 1; 45 private static final int INTERACTIVE_STATE_GOING_TO_SLEEP = 2; 46 47 private final Object mWindowManagerLock; 48 protected KeyguardServiceWrapper mKeyguardService; 49 private final Context mContext; 50 private final View mScrim; // shown if keyguard crashes 51 private final Handler mScrimHandler; 52 private final KeyguardState mKeyguardState = new KeyguardState(); 53 private DrawnListener mDrawnListenerWhenConnect; 54 55 @GuardedBy("mWindowManagerLock") 56 private boolean mHideScrimPending; 57 58 private static final class KeyguardState { 59 KeyguardState() { 60 // Assume keyguard is showing and secure until we know for sure. This is here in 61 // the event something checks before the service is actually started. 62 // KeyguardService itself should default to this state until the real state is known. 63 showing = true; 64 showingAndNotOccluded = true; 65 secure = true; 66 deviceHasKeyguard = true; 67 currentUser = UserHandle.USER_NULL; 68 } 69 boolean showing; 70 boolean showingAndNotOccluded; 71 boolean inputRestricted; 72 boolean occluded; 73 boolean secure; 74 boolean dreaming; 75 boolean systemIsReady; 76 boolean deviceHasKeyguard; 77 public boolean enabled; 78 public int offReason; 79 public int currentUser; 80 public boolean bootCompleted; 81 public int screenState; 82 public int interactiveState; 83 }; 84 85 public interface DrawnListener { 86 void onDrawn(); 87 } 88 89 // A delegate class to map a particular invocation with a ShowListener object. 90 private final class KeyguardShowDelegate extends IKeyguardDrawnCallback.Stub { 91 private DrawnListener mDrawnListener; 92 93 KeyguardShowDelegate(DrawnListener drawnListener) { 94 mDrawnListener = drawnListener; 95 } 96 97 @Override 98 public void onDrawn() throws RemoteException { 99 if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****"); 100 synchronized (mWindowManagerLock) { 101 mHideScrimPending = true; 102 } 103 if (mDrawnListener != null) { 104 mDrawnListener.onDrawn(); 105 } 106 } 107 }; 108 109 // A delegate class to map a particular invocation with an OnKeyguardExitResult object. 110 private final class KeyguardExitDelegate extends IKeyguardExitCallback.Stub { 111 private OnKeyguardExitResult mOnKeyguardExitResult; 112 113 KeyguardExitDelegate(OnKeyguardExitResult onKeyguardExitResult) { 114 mOnKeyguardExitResult = onKeyguardExitResult; 115 } 116 117 @Override 118 public void onKeyguardExitResult(boolean success) throws RemoteException { 119 if (DEBUG) Log.v(TAG, "**** onKeyguardExitResult(" + success +") CALLED ****"); 120 if (mOnKeyguardExitResult != null) { 121 mOnKeyguardExitResult.onKeyguardExitResult(success); 122 } 123 } 124 }; 125 126 public KeyguardServiceDelegate(Context context, Object windowManagerLock) { 127 mWindowManagerLock = windowManagerLock; 128 mContext = context; 129 mScrimHandler = UiThread.getHandler(); 130 mScrim = createScrim(context, mScrimHandler); 131 } 132 133 public void bindService(Context context) { 134 Intent intent = new Intent(); 135 final Resources resources = context.getApplicationContext().getResources(); 136 137 final ComponentName keyguardComponent = ComponentName.unflattenFromString( 138 resources.getString(com.android.internal.R.string.config_keyguardComponent)); 139 intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); 140 intent.setComponent(keyguardComponent); 141 142 if (!context.bindServiceAsUser(intent, mKeyguardConnection, 143 Context.BIND_AUTO_CREATE, mScrimHandler, UserHandle.SYSTEM)) { 144 Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent); 145 mKeyguardState.showing = false; 146 mKeyguardState.showingAndNotOccluded = false; 147 mKeyguardState.secure = false; 148 synchronized (mKeyguardState) { 149 // TODO: Fix synchronisation model in this class. The other state in this class 150 // is at least self-healing but a race condition here can lead to the scrim being 151 // stuck on keyguard-less devices. 152 mKeyguardState.deviceHasKeyguard = false; 153 hideScrim(); 154 } 155 } else { 156 if (DEBUG) Log.v(TAG, "*** Keyguard started"); 157 } 158 } 159 160 private final ServiceConnection mKeyguardConnection = new ServiceConnection() { 161 @Override 162 public void onServiceConnected(ComponentName name, IBinder service) { 163 if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)"); 164 mKeyguardService = new KeyguardServiceWrapper(mContext, 165 IKeyguardService.Stub.asInterface(service)); 166 if (mKeyguardState.systemIsReady) { 167 // If the system is ready, it means keyguard crashed and restarted. 168 mKeyguardService.onSystemReady(); 169 if (mKeyguardState.currentUser != UserHandle.USER_NULL) { 170 // There has been a user switch earlier 171 mKeyguardService.setCurrentUser(mKeyguardState.currentUser); 172 } 173 // This is used to hide the scrim once keyguard displays. 174 if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) { 175 mKeyguardService.onStartedWakingUp(); 176 } 177 if (mKeyguardState.screenState == SCREEN_STATE_ON 178 || mKeyguardState.screenState == SCREEN_STATE_TURNING_ON) { 179 mKeyguardService.onScreenTurningOn( 180 new KeyguardShowDelegate(mDrawnListenerWhenConnect)); 181 } 182 if (mKeyguardState.screenState == SCREEN_STATE_ON) { 183 mKeyguardService.onScreenTurnedOn(); 184 } 185 mDrawnListenerWhenConnect = null; 186 } 187 if (mKeyguardState.bootCompleted) { 188 mKeyguardService.onBootCompleted(); 189 } 190 if (mKeyguardState.occluded) { 191 mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */); 192 } 193 } 194 195 @Override 196 public void onServiceDisconnected(ComponentName name) { 197 if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)"); 198 mKeyguardService = null; 199 } 200 201 }; 202 203 public boolean isShowing() { 204 if (mKeyguardService != null) { 205 mKeyguardState.showing = mKeyguardService.isShowing(); 206 } 207 return mKeyguardState.showing; 208 } 209 210 public boolean isTrusted() { 211 if (mKeyguardService != null) { 212 return mKeyguardService.isTrusted(); 213 } 214 return false; 215 } 216 217 public boolean hasLockscreenWallpaper() { 218 if (mKeyguardService != null) { 219 return mKeyguardService.hasLockscreenWallpaper(); 220 } 221 return false; 222 } 223 224 public boolean isInputRestricted() { 225 if (mKeyguardService != null) { 226 mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted(); 227 } 228 return mKeyguardState.inputRestricted; 229 } 230 231 public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) { 232 if (mKeyguardService != null) { 233 mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult)); 234 } 235 } 236 237 public void keyguardDone(boolean authenticated, boolean wakeup) { 238 if (mKeyguardService != null) { 239 mKeyguardService.keyguardDone(authenticated, wakeup); 240 } 241 } 242 243 public void setOccluded(boolean isOccluded, boolean animate) { 244 if (mKeyguardService != null) { 245 if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate); 246 mKeyguardService.setOccluded(isOccluded, animate); 247 } 248 mKeyguardState.occluded = isOccluded; 249 } 250 251 public void dismiss(boolean allowWhileOccluded) { 252 if (mKeyguardService != null) { 253 mKeyguardService.dismiss(allowWhileOccluded); 254 } 255 } 256 257 public boolean isSecure(int userId) { 258 if (mKeyguardService != null) { 259 mKeyguardState.secure = mKeyguardService.isSecure(userId); 260 } 261 return mKeyguardState.secure; 262 } 263 264 public void onDreamingStarted() { 265 if (mKeyguardService != null) { 266 mKeyguardService.onDreamingStarted(); 267 } 268 mKeyguardState.dreaming = true; 269 } 270 271 public void onDreamingStopped() { 272 if (mKeyguardService != null) { 273 mKeyguardService.onDreamingStopped(); 274 } 275 mKeyguardState.dreaming = false; 276 } 277 278 public void onStartedWakingUp() { 279 if (mKeyguardService != null) { 280 if (DEBUG) Log.v(TAG, "onStartedWakingUp()"); 281 mKeyguardService.onStartedWakingUp(); 282 } 283 mKeyguardState.interactiveState = INTERACTIVE_STATE_AWAKE; 284 } 285 286 public void onScreenTurnedOff() { 287 if (mKeyguardService != null) { 288 if (DEBUG) Log.v(TAG, "onScreenTurnedOff()"); 289 mKeyguardService.onScreenTurnedOff(); 290 } 291 mKeyguardState.screenState = SCREEN_STATE_OFF; 292 } 293 294 public void onScreenTurningOn(final DrawnListener drawnListener) { 295 if (mKeyguardService != null) { 296 if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + drawnListener + ")"); 297 mKeyguardService.onScreenTurningOn(new KeyguardShowDelegate(drawnListener)); 298 } else { 299 // try again when we establish a connection 300 Slog.w(TAG, "onScreenTurningOn(): no keyguard service!"); 301 // This shouldn't happen, but if it does, show the scrim immediately and 302 // invoke the listener's callback after the service actually connects. 303 mDrawnListenerWhenConnect = drawnListener; 304 showScrim(); 305 } 306 mKeyguardState.screenState = SCREEN_STATE_TURNING_ON; 307 } 308 309 public void onScreenTurnedOn() { 310 if (mKeyguardService != null) { 311 if (DEBUG) Log.v(TAG, "onScreenTurnedOn()"); 312 mKeyguardService.onScreenTurnedOn(); 313 } 314 mKeyguardState.screenState = SCREEN_STATE_ON; 315 } 316 317 public void onStartedGoingToSleep(int why) { 318 if (mKeyguardService != null) { 319 mKeyguardService.onStartedGoingToSleep(why); 320 } 321 mKeyguardState.offReason = why; 322 mKeyguardState.interactiveState = INTERACTIVE_STATE_GOING_TO_SLEEP; 323 } 324 325 public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) { 326 if (mKeyguardService != null) { 327 mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered); 328 } 329 mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP; 330 } 331 332 public void setKeyguardEnabled(boolean enabled) { 333 if (mKeyguardService != null) { 334 mKeyguardService.setKeyguardEnabled(enabled); 335 } 336 mKeyguardState.enabled = enabled; 337 } 338 339 public void onSystemReady() { 340 if (mKeyguardService != null) { 341 mKeyguardService.onSystemReady(); 342 } else { 343 mKeyguardState.systemIsReady = true; 344 } 345 } 346 347 public void doKeyguardTimeout(Bundle options) { 348 if (mKeyguardService != null) { 349 mKeyguardService.doKeyguardTimeout(options); 350 } 351 } 352 353 public void setCurrentUser(int newUserId) { 354 if (mKeyguardService != null) { 355 mKeyguardService.setCurrentUser(newUserId); 356 } 357 mKeyguardState.currentUser = newUserId; 358 } 359 360 public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { 361 if (mKeyguardService != null) { 362 mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration); 363 } 364 } 365 366 /** 367 * Called when all windows were fully drawn. 368 */ 369 public void onDrawCompleteLw() { 370 if (mHideScrimPending) { 371 hideScrim(); 372 mHideScrimPending = false; 373 } 374 } 375 376 private static View createScrim(Context context, Handler handler) { 377 final View view = new View(context); 378 379 int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 380 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR 381 | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN 382 | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER 383 ; 384 385 final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; 386 final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM; 387 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 388 stretch, stretch, type, flags, PixelFormat.TRANSLUCENT); 389 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 390 lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; 391 lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED; 392 lp.setTitle("KeyguardScrim"); 393 final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 394 // Disable pretty much everything in statusbar until keyguard comes back and we know 395 // the state of the world. 396 view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME 397 | View.STATUS_BAR_DISABLE_BACK 398 | View.STATUS_BAR_DISABLE_RECENT 399 | View.STATUS_BAR_DISABLE_EXPAND 400 | View.STATUS_BAR_DISABLE_SEARCH); 401 handler.post(new Runnable() { 402 @Override 403 public void run() { 404 wm.addView(view, lp); 405 } 406 }); 407 return view; 408 } 409 410 public void showScrim() { 411 synchronized (mKeyguardState) { 412 if (!mKeyguardState.deviceHasKeyguard) return; 413 mScrimHandler.post(new Runnable() { 414 @Override 415 public void run() { 416 mScrim.setVisibility(View.VISIBLE); 417 } 418 }); 419 } 420 } 421 422 public void hideScrim() { 423 mScrimHandler.post(new Runnable() { 424 @Override 425 public void run() { 426 mScrim.setVisibility(View.GONE); 427 } 428 }); 429 } 430 431 public void onBootCompleted() { 432 if (mKeyguardService != null) { 433 mKeyguardService.onBootCompleted(); 434 } 435 mKeyguardState.bootCompleted = true; 436 } 437 438 public void onActivityDrawn() { 439 if (mKeyguardService != null) { 440 mKeyguardService.onActivityDrawn(); 441 } 442 } 443 444 public void dump(String prefix, PrintWriter pw) { 445 pw.println(prefix + TAG); 446 prefix += " "; 447 pw.println(prefix + "showing=" + mKeyguardState.showing); 448 pw.println(prefix + "showingAndNotOccluded=" + mKeyguardState.showingAndNotOccluded); 449 pw.println(prefix + "inputRestricted=" + mKeyguardState.inputRestricted); 450 pw.println(prefix + "occluded=" + mKeyguardState.occluded); 451 pw.println(prefix + "secure=" + mKeyguardState.secure); 452 pw.println(prefix + "dreaming=" + mKeyguardState.dreaming); 453 pw.println(prefix + "systemIsReady=" + mKeyguardState.systemIsReady); 454 pw.println(prefix + "deviceHasKeyguard=" + mKeyguardState.deviceHasKeyguard); 455 pw.println(prefix + "enabled=" + mKeyguardState.enabled); 456 pw.println(prefix + "offReason=" + mKeyguardState.offReason); 457 pw.println(prefix + "currentUser=" + mKeyguardState.currentUser); 458 pw.println(prefix + "bootCompleted=" + mKeyguardState.bootCompleted); 459 pw.println(prefix + "screenState=" + mKeyguardState.screenState); 460 pw.println(prefix + "interactiveState=" + mKeyguardState.interactiveState); 461 if (mKeyguardService != null) { 462 mKeyguardService.dump(prefix, pw); 463 } 464 } 465} 466