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