KeyguardViewManager.java revision d2b82f70fede8c2ec4de34d8e6462ed4ece13c56
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.policy.impl.keyguard;
18
19import android.app.Activity;
20import android.app.ActivityManager;
21import android.content.Context;
22import android.content.pm.ActivityInfo;
23import android.content.res.Configuration;
24import android.content.res.Resources;
25import android.graphics.PixelFormat;
26import android.os.IBinder;
27import android.os.SystemProperties;
28import android.util.Log;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.view.ViewGroup;
32import android.view.ViewManager;
33import android.view.WindowManager;
34import android.widget.FrameLayout;
35
36import com.android.internal.widget.LockPatternUtils;
37import com.android.internal.R;
38
39/**
40 * Manages creating, showing, hiding and resetting the keyguard.  Calls back
41 * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke
42 * the wake lock and report that the keyguard is done, which is in turn,
43 * reported to this class by the current {@link KeyguardViewBase}.
44 */
45public class KeyguardViewManager {
46    private final static boolean DEBUG = false;
47    private static String TAG = "KeyguardViewManager";
48
49    private final Context mContext;
50    private final ViewManager mViewManager;
51    private final KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
52
53    private WindowManager.LayoutParams mWindowLayoutParams;
54    private boolean mNeedsInput = false;
55
56    private FrameLayout mKeyguardHost;
57    private KeyguardHostView mKeyguardView;
58
59    private boolean mScreenOn = false;
60    private LockPatternUtils mLockPatternUtils;
61
62    public interface ShowListener {
63        void onShown(IBinder windowToken);
64    };
65
66    /**
67     * @param context Used to create views.
68     * @param viewManager Keyguard will be attached to this.
69     * @param callback Used to notify of changes.
70     * @param lockPatternUtils
71     */
72    public KeyguardViewManager(Context context, ViewManager viewManager,
73            KeyguardViewMediator.ViewMediatorCallback callback,
74            LockPatternUtils lockPatternUtils) {
75        mContext = context;
76        mViewManager = viewManager;
77        mViewMediatorCallback = callback;
78        mLockPatternUtils = lockPatternUtils;
79    }
80
81    /**
82     * Show the keyguard.  Will handle creating and attaching to the view manager
83     * lazily.
84     */
85    public synchronized void show() {
86        if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
87
88        boolean enableScreenRotation = shouldEnableScreenRotation();
89
90        maybeCreateKeyguardLocked(enableScreenRotation);
91        maybeEnableScreenRotation(enableScreenRotation);
92
93        // Disable common aspects of the system/status/navigation bars that are not appropriate or
94        // useful on any keyguard screen but can be re-shown by dialogs or SHOW_WHEN_LOCKED
95        // activities. Other disabled bits are handled by the KeyguardViewMediator talking
96        // directly to the status bar service.
97        final int visFlags = View.STATUS_BAR_DISABLE_HOME;
98        if (DEBUG) Log.v(TAG, "KGVM: Set visibility on " + mKeyguardHost + " to " + visFlags);
99        mKeyguardHost.setSystemUiVisibility(visFlags);
100
101        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
102        mKeyguardHost.setVisibility(View.VISIBLE);
103        mKeyguardView.show();
104        mKeyguardView.requestFocus();
105    }
106
107    private boolean shouldEnableScreenRotation() {
108        Resources res = mContext.getResources();
109        return SystemProperties.getBoolean("lockscreen.rot_override",false)
110                || res.getBoolean(com.android.internal.R.bool.config_enableLockScreenRotation);
111    }
112
113    class ViewManagerHost extends FrameLayout {
114        public ViewManagerHost(Context context) {
115            super(context);
116        }
117
118        @Override
119        protected void onConfigurationChanged(Configuration newConfig) {
120            super.onConfigurationChanged(newConfig);
121            maybeCreateKeyguardLocked(shouldEnableScreenRotation());
122        }
123    }
124
125    private void maybeCreateKeyguardLocked(boolean enableScreenRotation) {
126        final boolean isActivity = (mContext instanceof Activity); // for test activity
127
128        if (mKeyguardHost == null) {
129            if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
130
131            mKeyguardHost = new ViewManagerHost(mContext);
132
133            int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
134                    | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
135
136            if (!mNeedsInput) {
137                flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
138            }
139            if (ActivityManager.isHighEndGfx()) {
140                flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
141            }
142
143            final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
144            final int type = isActivity ? WindowManager.LayoutParams.TYPE_APPLICATION
145                    : WindowManager.LayoutParams.TYPE_KEYGUARD;
146            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
147                    stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
148            lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
149            lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
150            if (ActivityManager.isHighEndGfx()) {
151                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
152                lp.privateFlags |=
153                        WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
154            }
155            lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
156            lp.setTitle(isActivity ? "KeyguardMock" : "Keyguard");
157            mWindowLayoutParams = lp;
158            mViewManager.addView(mKeyguardHost, lp);
159        }
160        inflateKeyguardView();
161        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
162    }
163
164    private void inflateKeyguardView() {
165        if (mKeyguardView != null) {
166            mKeyguardHost.removeView(mKeyguardView);
167        }
168        final LayoutInflater inflater = LayoutInflater.from(mContext);
169        View view = inflater.inflate(R.layout.keyguard_host_view, mKeyguardHost, true);
170        mKeyguardView = (KeyguardHostView) view.findViewById(R.id.keyguard_host_view);
171        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
172        mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
173
174        if (mScreenOn) {
175            mKeyguardView.show();
176        }
177    }
178
179    private void maybeEnableScreenRotation(boolean enableScreenRotation) {
180        // TODO: move this outside
181        if (enableScreenRotation) {
182            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!");
183            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
184        } else {
185            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!");
186            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
187        }
188        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
189    }
190
191    public void setNeedsInput(boolean needsInput) {
192        mNeedsInput = needsInput;
193        if (mWindowLayoutParams != null) {
194            if (needsInput) {
195                mWindowLayoutParams.flags &=
196                    ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
197            } else {
198                mWindowLayoutParams.flags |=
199                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
200            }
201
202            try {
203                mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
204            } catch (java.lang.IllegalArgumentException e) {
205                // TODO: Ensure this method isn't called on views that are changing...
206                Log.w(TAG,"Can't update input method on " + mKeyguardHost + " window not attached");
207            }
208        }
209    }
210
211    /**
212     * Reset the state of the view.
213     */
214    public synchronized void reset() {
215        if (DEBUG) Log.d(TAG, "reset()");
216        // User might have switched, check if we need to go back to keyguard
217        // TODO: It's preferable to stay and show the correct lockscreen or unlock if none
218        maybeCreateKeyguardLocked(shouldEnableScreenRotation());
219    }
220
221    public synchronized void onScreenTurnedOff() {
222        if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
223        mScreenOn = false;
224        if (mKeyguardView != null) {
225            mKeyguardView.onScreenTurnedOff();
226        }
227    }
228
229    public synchronized void onScreenTurnedOn(
230            final KeyguardViewManager.ShowListener showListener) {
231        if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
232        mScreenOn = true;
233        if (mKeyguardView != null) {
234            mKeyguardView.onScreenTurnedOn();
235
236            // Caller should wait for this window to be shown before turning
237            // on the screen.
238            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
239                // Keyguard may be in the process of being shown, but not yet
240                // updated with the window manager...  give it a chance to do so.
241                mKeyguardHost.post(new Runnable() {
242                    public void run() {
243                        if (mKeyguardHost.getVisibility() == View.VISIBLE) {
244                            showListener.onShown(mKeyguardHost.getWindowToken());
245                        } else {
246                            showListener.onShown(null);
247                        }
248                    }
249                });
250            } else {
251                showListener.onShown(null);
252            }
253        } else {
254            showListener.onShown(null);
255        }
256    }
257
258    public synchronized void verifyUnlock() {
259        if (DEBUG) Log.d(TAG, "verifyUnlock()");
260        show();
261        mKeyguardView.verifyUnlock();
262    }
263
264    /**
265     * A key has woken the device.  We use this to potentially adjust the state
266     * of the lock screen based on the key.
267     *
268     * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}.
269     * Be sure not to take any action that takes a long time; any significant
270     * action should be posted to a handler.
271     *
272     * @param keyCode The wake key.  May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking
273     * for a reason other than a key press.
274     */
275    public boolean wakeWhenReadyTq(int keyCode) {
276        if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")");
277        if (mKeyguardView != null) {
278            mKeyguardView.wakeWhenReadyTq(keyCode);
279            return true;
280        } else {
281            Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq");
282            return false;
283        }
284    }
285
286    /**
287     * Hides the keyguard view
288     */
289    public synchronized void hide() {
290        if (DEBUG) Log.d(TAG, "hide()");
291
292        if (mKeyguardHost != null) {
293            mKeyguardHost.setVisibility(View.GONE);
294            // Don't do this right away, so we can let the view continue to animate
295            // as it goes away.
296            if (mKeyguardView != null) {
297                final KeyguardViewBase lastView = mKeyguardView;
298                mKeyguardView = null;
299                mKeyguardHost.postDelayed(new Runnable() {
300                    public void run() {
301                        synchronized (KeyguardViewManager.this) {
302                            lastView.cleanUp();
303                            mKeyguardHost.removeView(lastView);
304                        }
305                    }
306                }, 500);
307            }
308        }
309    }
310
311    /**
312     * @return Whether the keyguard is showing
313     */
314    public synchronized boolean isShowing() {
315        return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);
316    }
317}
318