KeyguardServiceDelegate.java revision e5f910a667088ab63e017d5851f0956c77b823da
1package com.android.internal.policy.impl.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.graphics.PixelFormat;
9import android.os.Bundle;
10import android.os.IBinder;
11import android.os.RemoteException;
12import android.os.UserHandle;
13import android.util.Log;
14import android.util.Slog;
15import android.view.KeyEvent;
16import android.view.View;
17import android.view.ViewGroup;
18import android.view.WindowManager;
19import android.view.WindowManagerPolicy.OnKeyguardExitResult;
20
21import com.android.internal.policy.IKeyguardExitCallback;
22import com.android.internal.policy.IKeyguardShowCallback;
23import com.android.internal.policy.IKeyguardService;
24import com.android.internal.widget.LockPatternUtils;
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    // TODO: propagate changes to these to {@link KeyguardTouchDelegate}
33    public static final String KEYGUARD_PACKAGE = "com.android.keyguard";
34    public static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
35
36    private static final String TAG = "KeyguardServiceDelegate";
37    private static final boolean DEBUG = true;
38    protected KeyguardServiceWrapper mKeyguardService;
39    private View mScrim; // shown if keyguard crashes
40    private KeyguardState mKeyguardState = new KeyguardState();
41
42    /* package */ static final class KeyguardState {
43        boolean showing;
44        boolean showingAndNotHidden;
45        boolean inputRestricted;
46        boolean hidden;
47        boolean secure;
48        boolean dreaming;
49        boolean systemIsReady;
50        public boolean enabled;
51        public boolean dismissable;
52        public int offReason;
53        public int currentUser;
54        public boolean screenIsOn;
55        public boolean bootCompleted;
56    };
57
58    public interface ShowListener {
59        public void onShown(IBinder windowToken);
60    }
61
62    // A delegate class to map a particular invocation with a ShowListener object.
63    private final class KeyguardShowDelegate extends IKeyguardShowCallback.Stub {
64        private ShowListener mShowListener;
65
66        KeyguardShowDelegate(ShowListener showListener) {
67            mShowListener = showListener;
68        }
69
70        @Override
71        public void onShown(IBinder windowToken) throws RemoteException {
72            if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");
73            if (mShowListener != null) {
74                mShowListener.onShown(windowToken);
75            }
76            hideScrim();
77        }
78    };
79
80    // A delegate class to map a particular invocation with an OnKeyguardExitResult object.
81    private final class KeyguardExitDelegate extends IKeyguardExitCallback.Stub {
82        private OnKeyguardExitResult mOnKeyguardExitResult;
83
84        KeyguardExitDelegate(OnKeyguardExitResult onKeyguardExitResult) {
85            mOnKeyguardExitResult = onKeyguardExitResult;
86        }
87
88        @Override
89        public void onKeyguardExitResult(boolean success) throws RemoteException {
90            if (DEBUG) Log.v(TAG, "**** onKeyguardExitResult(" + success +") CALLED ****");
91            if (mOnKeyguardExitResult != null) {
92                mOnKeyguardExitResult.onKeyguardExitResult(success);
93            }
94        }
95    };
96
97    public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
98        Intent intent = new Intent();
99        intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
100        mScrim = createScrim(context);
101        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
102                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
103            if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
104        } else {
105            if (DEBUG) Log.v(TAG, "*** Keyguard started");
106        }
107    }
108
109    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
110        @Override
111        public void onServiceConnected(ComponentName name, IBinder service) {
112            if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
113            mKeyguardService = new KeyguardServiceWrapper(
114                    IKeyguardService.Stub.asInterface(service));
115            if (mKeyguardState.systemIsReady) {
116                // If the system is ready, it means keyguard crashed and restarted.
117                mKeyguardService.onSystemReady();
118                // This is used to hide the scrim once keyguard displays.
119                mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null));
120            }
121            if (mKeyguardState.bootCompleted) {
122                mKeyguardService.onBootCompleted();
123            }
124        }
125
126        @Override
127        public void onServiceDisconnected(ComponentName name) {
128            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
129            mKeyguardService = null;
130        }
131
132    };
133
134    public boolean isShowing() {
135        if (mKeyguardService != null) {
136            mKeyguardState.showing = mKeyguardService.isShowing();
137        }
138        return mKeyguardState.showing;
139    }
140
141    public boolean isShowingAndNotHidden() {
142        if (mKeyguardService != null) {
143            mKeyguardState.showingAndNotHidden = mKeyguardService.isShowingAndNotHidden();
144        }
145        return mKeyguardState.showingAndNotHidden;
146    }
147
148    public boolean isInputRestricted() {
149        if (mKeyguardService != null) {
150            mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
151        }
152        return mKeyguardState.inputRestricted;
153    }
154
155    public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) {
156        if (mKeyguardService != null) {
157            mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult));
158        }
159    }
160
161    public void keyguardDone(boolean authenticated, boolean wakeup) {
162        if (mKeyguardService != null) {
163            mKeyguardService.keyguardDone(authenticated, wakeup);
164        }
165    }
166
167    public void setHidden(boolean isHidden) {
168        if (mKeyguardService != null) {
169            mKeyguardService.setHidden(isHidden);
170        }
171        mKeyguardState.hidden = isHidden;
172    }
173
174    public void dismiss() {
175        if (mKeyguardService != null) {
176            mKeyguardService.dismiss();
177        }
178    }
179
180    public boolean isSecure() {
181        if (mKeyguardService != null) {
182            mKeyguardState.secure = mKeyguardService.isSecure();
183        }
184        return mKeyguardState.secure;
185    }
186
187    public void onDreamingStarted() {
188        if (mKeyguardService != null) {
189            mKeyguardService.onDreamingStarted();
190        }
191        mKeyguardState.dreaming = true;
192    }
193
194    public void onDreamingStopped() {
195        if (mKeyguardService != null) {
196            mKeyguardService.onDreamingStopped();
197        }
198        mKeyguardState.dreaming = false;
199    }
200
201    public void onScreenTurnedOn(final ShowListener showListener) {
202        if (mKeyguardService != null) {
203            if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + showListener + ")");
204            mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(showListener));
205        } else {
206            // try again when we establish a connection
207            Slog.w(TAG, "onScreenTurnedOn(): no keyguard service!");
208            // This shouldn't happen, but if it does, invoke the listener immediately
209            // to avoid a dark screen...
210            showListener.onShown(null);
211        }
212        mKeyguardState.screenIsOn = true;
213    }
214
215    public void onScreenTurnedOff(int why) {
216        if (mKeyguardService != null) {
217            mKeyguardService.onScreenTurnedOff(why);
218        }
219        mKeyguardState.offReason = why;
220        mKeyguardState.screenIsOn = false;
221    }
222
223    public void setKeyguardEnabled(boolean enabled) {
224        if (mKeyguardService != null) {
225            mKeyguardService.setKeyguardEnabled(enabled);
226        }
227        mKeyguardState.enabled = enabled;
228    }
229
230    public boolean isDismissable() {
231        if (mKeyguardService != null) {
232            mKeyguardState.dismissable = mKeyguardService.isDismissable();
233        }
234        return mKeyguardState.dismissable;
235    }
236
237    public void onSystemReady() {
238        if (mKeyguardService != null) {
239            mKeyguardService.onSystemReady();
240        } else {
241            if (DEBUG) Log.v(TAG, "onSystemReady() called before keyguard service was ready");
242            mKeyguardState.systemIsReady = true;
243        }
244    }
245
246    public void doKeyguardTimeout(Bundle options) {
247        if (mKeyguardService != null) {
248            mKeyguardService.doKeyguardTimeout(options);
249        }
250    }
251
252    public void showAssistant() {
253        if (mKeyguardService != null) {
254            mKeyguardService.showAssistant();
255        }
256    }
257
258    public void setCurrentUser(int newUserId) {
259        if (mKeyguardService != null) {
260            mKeyguardService.setCurrentUser(newUserId);
261        }
262        mKeyguardState.currentUser = newUserId;
263    }
264
265    private static final View createScrim(Context context) {
266        View view = new View(context);
267
268        int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
269                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
270                | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
271                | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
272                ;
273
274        final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
275        final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
276        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
277                stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
278        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
279        lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
280        lp.setTitle("KeyguardScrim");
281        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
282        wm.addView(view, lp);
283        view.setVisibility(View.GONE);
284        // Disable pretty much everything in statusbar until keyguard comes back and we know
285        // the state of the world.
286        view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
287                | View.STATUS_BAR_DISABLE_BACK
288                | View.STATUS_BAR_DISABLE_RECENT
289                | View.STATUS_BAR_DISABLE_EXPAND
290                | View.STATUS_BAR_DISABLE_SEARCH);
291        return view;
292    }
293
294    public void showScrim() {
295        mScrim.post(new Runnable() {
296            @Override
297            public void run() {
298                mScrim.setVisibility(View.VISIBLE);
299            }
300        });
301    }
302
303    public void hideScrim() {
304        mScrim.post(new Runnable() {
305            @Override
306            public void run() {
307                mScrim.setVisibility(View.GONE);
308            }
309        });
310    }
311
312    public void onBootCompleted() {
313        if (mKeyguardService != null) {
314            mKeyguardService.onBootCompleted();
315        }
316        mKeyguardState.bootCompleted = true;
317    }
318
319}
320