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