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