KeyguardServiceDelegate.java revision fe762344f4475a3a336bb46aef2d59c1fabf32ab
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, false /* animate */);
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 hasLockscreenWallpaper() {
214        if (mKeyguardService != null) {
215            return mKeyguardService.hasLockscreenWallpaper();
216        }
217        return false;
218    }
219
220    public boolean isInputRestricted() {
221        if (mKeyguardService != null) {
222            mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
223        }
224        return mKeyguardState.inputRestricted;
225    }
226
227    public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) {
228        if (mKeyguardService != null) {
229            mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult));
230        }
231    }
232
233    public void keyguardDone(boolean authenticated, boolean wakeup) {
234        if (mKeyguardService != null) {
235            mKeyguardService.keyguardDone(authenticated, wakeup);
236        }
237    }
238
239    public void setOccluded(boolean isOccluded, boolean animate) {
240        if (mKeyguardService != null) {
241            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
242            mKeyguardService.setOccluded(isOccluded, animate);
243        }
244        mKeyguardState.occluded = isOccluded;
245    }
246
247    public void dismiss(boolean allowWhileOccluded) {
248        if (mKeyguardService != null) {
249            mKeyguardService.dismiss(allowWhileOccluded);
250        }
251    }
252
253    public boolean isSecure(int userId) {
254        if (mKeyguardService != null) {
255            mKeyguardState.secure = mKeyguardService.isSecure(userId);
256        }
257        return mKeyguardState.secure;
258    }
259
260    public void onDreamingStarted() {
261        if (mKeyguardService != null) {
262            mKeyguardService.onDreamingStarted();
263        }
264        mKeyguardState.dreaming = true;
265    }
266
267    public void onDreamingStopped() {
268        if (mKeyguardService != null) {
269            mKeyguardService.onDreamingStopped();
270        }
271        mKeyguardState.dreaming = false;
272    }
273
274    public void onStartedWakingUp() {
275        if (mKeyguardService != null) {
276            if (DEBUG) Log.v(TAG, "onStartedWakingUp()");
277            mKeyguardService.onStartedWakingUp();
278        }
279        mKeyguardState.interactiveState = INTERACTIVE_STATE_AWAKE;
280    }
281
282    public void onScreenTurnedOff() {
283        if (mKeyguardService != null) {
284            if (DEBUG) Log.v(TAG, "onScreenTurnedOff()");
285            mKeyguardService.onScreenTurnedOff();
286        }
287        mKeyguardState.screenState = SCREEN_STATE_OFF;
288    }
289
290    public void onScreenTurningOn(final DrawnListener drawnListener) {
291        if (mKeyguardService != null) {
292            if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + drawnListener + ")");
293            mKeyguardService.onScreenTurningOn(new KeyguardShowDelegate(drawnListener));
294        } else {
295            // try again when we establish a connection
296            Slog.w(TAG, "onScreenTurningOn(): no keyguard service!");
297            // This shouldn't happen, but if it does, show the scrim immediately and
298            // invoke the listener's callback after the service actually connects.
299            mDrawnListenerWhenConnect = drawnListener;
300            showScrim();
301        }
302        mKeyguardState.screenState = SCREEN_STATE_TURNING_ON;
303    }
304
305    public void onScreenTurnedOn() {
306        if (mKeyguardService != null) {
307            if (DEBUG) Log.v(TAG, "onScreenTurnedOn()");
308            mKeyguardService.onScreenTurnedOn();
309        }
310        mKeyguardState.screenState = SCREEN_STATE_ON;
311    }
312
313    public void onStartedGoingToSleep(int why) {
314        if (mKeyguardService != null) {
315            mKeyguardService.onStartedGoingToSleep(why);
316        }
317        mKeyguardState.offReason = why;
318        mKeyguardState.interactiveState = INTERACTIVE_STATE_GOING_TO_SLEEP;
319    }
320
321    public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
322        if (mKeyguardService != null) {
323            mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered);
324        }
325        mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;
326    }
327
328    public void setKeyguardEnabled(boolean enabled) {
329        if (mKeyguardService != null) {
330            mKeyguardService.setKeyguardEnabled(enabled);
331        }
332        mKeyguardState.enabled = enabled;
333    }
334
335    public void onSystemReady() {
336        if (mKeyguardService != null) {
337            mKeyguardService.onSystemReady();
338        } else {
339            mKeyguardState.systemIsReady = true;
340        }
341    }
342
343    public void doKeyguardTimeout(Bundle options) {
344        if (mKeyguardService != null) {
345            mKeyguardService.doKeyguardTimeout(options);
346        }
347    }
348
349    public void setCurrentUser(int newUserId) {
350        if (mKeyguardService != null) {
351            mKeyguardService.setCurrentUser(newUserId);
352        }
353        mKeyguardState.currentUser = newUserId;
354    }
355
356    public void setSwitchingUser(boolean switching) {
357        if (mKeyguardService != null) {
358            mKeyguardService.setSwitchingUser(switching);
359        }
360    }
361
362    public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
363        if (mKeyguardService != null) {
364            mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration);
365        }
366    }
367
368    private static View createScrim(Context context, Handler handler) {
369        final View view = new View(context);
370
371        int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
372                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
373                | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
374                | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
375                ;
376
377        final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
378        final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
379        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
380                stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
381        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
382        lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
383        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
384        lp.setTitle("KeyguardScrim");
385        final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
386        // Disable pretty much everything in statusbar until keyguard comes back and we know
387        // the state of the world.
388        view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
389                | View.STATUS_BAR_DISABLE_BACK
390                | View.STATUS_BAR_DISABLE_RECENT
391                | View.STATUS_BAR_DISABLE_EXPAND
392                | View.STATUS_BAR_DISABLE_SEARCH);
393        handler.post(new Runnable() {
394            @Override
395            public void run() {
396                wm.addView(view, lp);
397            }
398        });
399        return view;
400    }
401
402    public void showScrim() {
403        synchronized (mKeyguardState) {
404            if (!mKeyguardState.deviceHasKeyguard) return;
405            mScrimHandler.post(new Runnable() {
406                @Override
407                public void run() {
408                    mScrim.setVisibility(View.VISIBLE);
409                }
410            });
411        }
412    }
413
414    public void hideScrim() {
415        mScrimHandler.post(new Runnable() {
416            @Override
417            public void run() {
418                mScrim.setVisibility(View.GONE);
419            }
420        });
421    }
422
423    public void onBootCompleted() {
424        if (mKeyguardService != null) {
425            mKeyguardService.onBootCompleted();
426        }
427        mKeyguardState.bootCompleted = true;
428    }
429
430    public void onActivityDrawn() {
431        if (mKeyguardService != null) {
432            mKeyguardService.onActivityDrawn();
433        }
434    }
435
436    public void dump(String prefix, PrintWriter pw) {
437        pw.println(prefix + TAG);
438        prefix += "  ";
439        pw.println(prefix + "showing=" + mKeyguardState.showing);
440        pw.println(prefix + "showingAndNotOccluded=" + mKeyguardState.showingAndNotOccluded);
441        pw.println(prefix + "inputRestricted=" + mKeyguardState.inputRestricted);
442        pw.println(prefix + "occluded=" + mKeyguardState.occluded);
443        pw.println(prefix + "secure=" + mKeyguardState.secure);
444        pw.println(prefix + "dreaming=" + mKeyguardState.dreaming);
445        pw.println(prefix + "systemIsReady=" + mKeyguardState.systemIsReady);
446        pw.println(prefix + "deviceHasKeyguard=" + mKeyguardState.deviceHasKeyguard);
447        pw.println(prefix + "enabled=" + mKeyguardState.enabled);
448        pw.println(prefix + "offReason=" + mKeyguardState.offReason);
449        pw.println(prefix + "currentUser=" + mKeyguardState.currentUser);
450        pw.println(prefix + "bootCompleted=" + mKeyguardState.bootCompleted);
451        pw.println(prefix + "screenState=" + mKeyguardState.screenState);
452        pw.println(prefix + "interactiveState=" + mKeyguardState.interactiveState);
453        if (mKeyguardService != null) {
454            mKeyguardService.dump(prefix, pw);
455        }
456    }
457}
458