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