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