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