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