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