KeyguardServiceDelegate.java revision 241ae10b2189f449e57d8d660235ac56d8fb1b80
1package com.android.server.policy.keyguard;
2
3import android.app.ActivityManager;
4import android.content.ComponentName;
5import android.content.Context;
6import android.content.Intent;
7import android.content.ServiceConnection;
8import android.content.res.Resources;
9import android.os.Bundle;
10import android.os.Handler;
11import android.os.IBinder;
12import android.os.RemoteException;
13import android.os.UserHandle;
14import android.util.Log;
15import android.util.Slog;
16import android.view.WindowManagerPolicy.OnKeyguardExitResult;
17
18import com.android.internal.policy.IKeyguardDismissCallback;
19import com.android.internal.policy.IKeyguardDrawnCallback;
20import com.android.internal.policy.IKeyguardExitCallback;
21import com.android.internal.policy.IKeyguardService;
22import com.android.server.UiThread;
23
24import java.io.PrintWriter;
25
26/**
27 * A local class that keeps a cache of keyguard state that can be restored in the event
28 * keyguard crashes. It currently also allows runtime-selectable
29 * local or remote instances of keyguard.
30 */
31public class KeyguardServiceDelegate {
32    private static final String TAG = "KeyguardServiceDelegate";
33    private static final boolean DEBUG = true;
34
35    private static final int SCREEN_STATE_OFF = 0;
36    private static final int SCREEN_STATE_TURNING_ON = 1;
37    private static final int SCREEN_STATE_ON = 2;
38
39    private static final int INTERACTIVE_STATE_SLEEP = 0;
40    private static final int INTERACTIVE_STATE_AWAKE = 1;
41    private static final int INTERACTIVE_STATE_GOING_TO_SLEEP = 2;
42
43    protected KeyguardServiceWrapper mKeyguardService;
44    private final Context mContext;
45    private final Handler mHandler;
46    private final KeyguardState mKeyguardState = new KeyguardState();
47    private final KeyguardStateMonitor.StateCallback mCallback;
48
49    private DrawnListener mDrawnListenerWhenConnect;
50
51    private static final class KeyguardState {
52        KeyguardState() {
53            reset();
54        }
55        boolean showing;
56        boolean showingAndNotOccluded;
57        boolean inputRestricted;
58        boolean occluded;
59        boolean secure;
60        boolean dreaming;
61        boolean systemIsReady;
62        boolean deviceHasKeyguard;
63        public boolean enabled;
64        public int offReason;
65        public int currentUser;
66        public boolean bootCompleted;
67        public int screenState;
68        public int interactiveState;
69
70        private void reset() {
71            // Assume keyguard is showing and secure until we know for sure. This is here in
72            // the event something checks before the service is actually started.
73            // KeyguardService itself should default to this state until the real state is known.
74            showing = true;
75            showingAndNotOccluded = true;
76            secure = true;
77            deviceHasKeyguard = true;
78            enabled = true;
79            currentUser = UserHandle.USER_NULL;
80        }
81    };
82
83    public interface DrawnListener {
84        void onDrawn();
85    }
86
87    // A delegate class to map a particular invocation with a ShowListener object.
88    private final class KeyguardShowDelegate extends IKeyguardDrawnCallback.Stub {
89        private DrawnListener mDrawnListener;
90
91        KeyguardShowDelegate(DrawnListener drawnListener) {
92            mDrawnListener = drawnListener;
93        }
94
95        @Override
96        public void onDrawn() throws RemoteException {
97            if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");
98            if (mDrawnListener != null) {
99                mDrawnListener.onDrawn();
100            }
101        }
102    };
103
104    // A delegate class to map a particular invocation with an OnKeyguardExitResult object.
105    private final class KeyguardExitDelegate extends IKeyguardExitCallback.Stub {
106        private OnKeyguardExitResult mOnKeyguardExitResult;
107
108        KeyguardExitDelegate(OnKeyguardExitResult onKeyguardExitResult) {
109            mOnKeyguardExitResult = onKeyguardExitResult;
110        }
111
112        @Override
113        public void onKeyguardExitResult(boolean success) throws RemoteException {
114            if (DEBUG) Log.v(TAG, "**** onKeyguardExitResult(" + success +") CALLED ****");
115            if (mOnKeyguardExitResult != null) {
116                mOnKeyguardExitResult.onKeyguardExitResult(success);
117            }
118        }
119    };
120
121    public KeyguardServiceDelegate(Context context, KeyguardStateMonitor.StateCallback callback) {
122        mContext = context;
123        mHandler = UiThread.getHandler();
124        mCallback = callback;
125    }
126
127    public void bindService(Context context) {
128        Intent intent = new Intent();
129        final Resources resources = context.getApplicationContext().getResources();
130
131        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
132                resources.getString(com.android.internal.R.string.config_keyguardComponent));
133        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
134        intent.setComponent(keyguardComponent);
135
136        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
137                Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {
138            Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
139            mKeyguardState.showing = false;
140            mKeyguardState.showingAndNotOccluded = false;
141            mKeyguardState.secure = false;
142            synchronized (mKeyguardState) {
143                // TODO: Fix synchronisation model in this class. The other state in this class
144                // is at least self-healing but a race condition here can lead to the scrim being
145                // stuck on keyguard-less devices.
146                mKeyguardState.deviceHasKeyguard = false;
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), mCallback);
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            mKeyguardState.reset();
196            mHandler.post(() -> {
197                try {
198                    ActivityManager.getService().setLockScreenShown(true);
199                } catch (RemoteException e) {
200                    // Local call.
201                }
202            });
203        }
204    };
205
206    public boolean isShowing() {
207        if (mKeyguardService != null) {
208            mKeyguardState.showing = mKeyguardService.isShowing();
209        }
210        return mKeyguardState.showing;
211    }
212
213    public boolean isTrusted() {
214        if (mKeyguardService != null) {
215            return mKeyguardService.isTrusted();
216        }
217        return false;
218    }
219
220    public boolean hasLockscreenWallpaper() {
221        if (mKeyguardService != null) {
222            return mKeyguardService.hasLockscreenWallpaper();
223        }
224        return false;
225    }
226
227    public boolean isInputRestricted() {
228        if (mKeyguardService != null) {
229            mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
230        }
231        return mKeyguardState.inputRestricted;
232    }
233
234    public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) {
235        if (mKeyguardService != null) {
236            mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult));
237        }
238    }
239
240    public void setOccluded(boolean isOccluded, boolean animate) {
241        if (mKeyguardService != null) {
242            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
243            mKeyguardService.setOccluded(isOccluded, animate);
244        }
245        mKeyguardState.occluded = isOccluded;
246    }
247
248    public void dismiss(IKeyguardDismissCallback callback) {
249        if (mKeyguardService != null) {
250            mKeyguardService.dismiss(callback);
251        }
252    }
253
254    public boolean isSecure(int userId) {
255        if (mKeyguardService != null) {
256            mKeyguardState.secure = mKeyguardService.isSecure(userId);
257        }
258        return mKeyguardState.secure;
259    }
260
261    public void onDreamingStarted() {
262        if (mKeyguardService != null) {
263            mKeyguardService.onDreamingStarted();
264        }
265        mKeyguardState.dreaming = true;
266    }
267
268    public void onDreamingStopped() {
269        if (mKeyguardService != null) {
270            mKeyguardService.onDreamingStopped();
271        }
272        mKeyguardState.dreaming = false;
273    }
274
275    public void onStartedWakingUp() {
276        if (mKeyguardService != null) {
277            if (DEBUG) Log.v(TAG, "onStartedWakingUp()");
278            mKeyguardService.onStartedWakingUp();
279        }
280        mKeyguardState.interactiveState = INTERACTIVE_STATE_AWAKE;
281    }
282
283    public void onScreenTurnedOff() {
284        if (mKeyguardService != null) {
285            if (DEBUG) Log.v(TAG, "onScreenTurnedOff()");
286            mKeyguardService.onScreenTurnedOff();
287        }
288        mKeyguardState.screenState = SCREEN_STATE_OFF;
289    }
290
291    public void onScreenTurningOn(final DrawnListener drawnListener) {
292        if (mKeyguardService != null) {
293            if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + drawnListener + ")");
294            mKeyguardService.onScreenTurningOn(new KeyguardShowDelegate(drawnListener));
295        } else {
296            // try again when we establish a connection
297            Slog.w(TAG, "onScreenTurningOn(): no keyguard service!");
298            // This shouldn't happen, but if it does, show the scrim immediately and
299            // invoke the listener's callback after the service actually connects.
300            mDrawnListenerWhenConnect = drawnListener;
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    public void onBootCompleted() {
369        if (mKeyguardService != null) {
370            mKeyguardService.onBootCompleted();
371        }
372        mKeyguardState.bootCompleted = true;
373    }
374
375    public void dump(String prefix, PrintWriter pw) {
376        pw.println(prefix + TAG);
377        prefix += "  ";
378        pw.println(prefix + "showing=" + mKeyguardState.showing);
379        pw.println(prefix + "showingAndNotOccluded=" + mKeyguardState.showingAndNotOccluded);
380        pw.println(prefix + "inputRestricted=" + mKeyguardState.inputRestricted);
381        pw.println(prefix + "occluded=" + mKeyguardState.occluded);
382        pw.println(prefix + "secure=" + mKeyguardState.secure);
383        pw.println(prefix + "dreaming=" + mKeyguardState.dreaming);
384        pw.println(prefix + "systemIsReady=" + mKeyguardState.systemIsReady);
385        pw.println(prefix + "deviceHasKeyguard=" + mKeyguardState.deviceHasKeyguard);
386        pw.println(prefix + "enabled=" + mKeyguardState.enabled);
387        pw.println(prefix + "offReason=" + mKeyguardState.offReason);
388        pw.println(prefix + "currentUser=" + mKeyguardState.currentUser);
389        pw.println(prefix + "bootCompleted=" + mKeyguardState.bootCompleted);
390        pw.println(prefix + "screenState=" + mKeyguardState.screenState);
391        pw.println(prefix + "interactiveState=" + mKeyguardState.interactiveState);
392        if (mKeyguardService != null) {
393            mKeyguardService.dump(prefix, pw);
394        }
395    }
396}
397