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