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