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;
18
19import com.android.internal.R;
20
21import android.content.Context;
22import android.content.pm.ActivityInfo;
23import android.graphics.PixelFormat;
24import android.graphics.Canvas;
25import android.util.Log;
26import android.view.View;
27import android.view.ViewGroup;
28import android.view.ViewManager;
29import android.view.WindowManager;
30import android.widget.FrameLayout;
31
32/**
33 * Manages creating, showing, hiding and resetting the keyguard.  Calls back
34 * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke
35 * the wake lock and report that the keyguard is done, which is in turn,
36 * reported to this class by the current {@link KeyguardViewBase}.
37 */
38public class KeyguardViewManager implements KeyguardWindowController {
39    private final static boolean DEBUG = false;
40    private static String TAG = "KeyguardViewManager";
41
42    private final Context mContext;
43    private final ViewManager mViewManager;
44    private final KeyguardViewCallback mCallback;
45    private final KeyguardViewProperties mKeyguardViewProperties;
46
47    private final KeyguardUpdateMonitor mUpdateMonitor;
48
49    private WindowManager.LayoutParams mWindowLayoutParams;
50    private boolean mNeedsInput = false;
51
52    private FrameLayout mKeyguardHost;
53    private KeyguardViewBase mKeyguardView;
54
55    private boolean mScreenOn = false;
56
57    /**
58     * @param context Used to create views.
59     * @param viewManager Keyguard will be attached to this.
60     * @param callback Used to notify of changes.
61     */
62    public KeyguardViewManager(Context context, ViewManager viewManager,
63            KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, KeyguardUpdateMonitor updateMonitor) {
64        mContext = context;
65        mViewManager = viewManager;
66        mCallback = callback;
67        mKeyguardViewProperties = keyguardViewProperties;
68
69        mUpdateMonitor = updateMonitor;
70    }
71
72    /**
73     * Helper class to host the keyguard view.
74     */
75    private static class KeyguardViewHost extends FrameLayout {
76        private final KeyguardViewCallback mCallback;
77
78        private KeyguardViewHost(Context context, KeyguardViewCallback callback) {
79            super(context);
80            mCallback = callback;
81        }
82
83        @Override
84        protected void dispatchDraw(Canvas canvas) {
85            super.dispatchDraw(canvas);
86            mCallback.keyguardDoneDrawing();
87        }
88    }
89
90    /**
91     * Show the keyguard.  Will handle creating and attaching to the view manager
92     * lazily.
93     */
94    public synchronized void show() {
95        if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
96
97        if (mKeyguardHost == null) {
98            if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
99
100            mKeyguardHost = new KeyguardViewHost(mContext, mCallback);
101
102            final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
103            int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
104                    | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
105                    | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
106                    /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
107                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
108            if (!mNeedsInput) {
109                flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
110            }
111            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
112                    stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD,
113                    flags, PixelFormat.TRANSLUCENT);
114            lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
115            lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
116            lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
117            lp.setTitle("Keyguard");
118            mWindowLayoutParams = lp;
119
120            mViewManager.addView(mKeyguardHost, lp);
121        }
122
123        if (mKeyguardView == null) {
124            if (DEBUG) Log.d(TAG, "keyguard view is null, creating it...");
125            mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this);
126            mKeyguardView.setId(R.id.lock_screen);
127            mKeyguardView.setCallback(mCallback);
128
129            final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams(
130                    ViewGroup.LayoutParams.MATCH_PARENT,
131                    ViewGroup.LayoutParams.MATCH_PARENT);
132
133            mKeyguardHost.addView(mKeyguardView, lp);
134
135            if (mScreenOn) {
136                mKeyguardView.onScreenTurnedOn();
137            }
138        }
139
140        mKeyguardHost.setVisibility(View.VISIBLE);
141        mKeyguardView.requestFocus();
142    }
143
144    public void setNeedsInput(boolean needsInput) {
145        mNeedsInput = needsInput;
146        if (mWindowLayoutParams != null) {
147            if (needsInput) {
148                mWindowLayoutParams.flags &=
149                    ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
150            } else {
151                mWindowLayoutParams.flags |=
152                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
153            }
154            mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
155        }
156    }
157
158    /**
159     * Reset the state of the view.
160     */
161    public synchronized void reset() {
162        if (DEBUG) Log.d(TAG, "reset()");
163        if (mKeyguardView != null) {
164            mKeyguardView.reset();
165        }
166    }
167
168    public synchronized void onScreenTurnedOff() {
169        if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
170        mScreenOn = false;
171        if (mKeyguardView != null) {
172            mKeyguardView.onScreenTurnedOff();
173        }
174    }
175
176    public synchronized void onScreenTurnedOn() {
177        if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
178        mScreenOn = true;
179        if (mKeyguardView != null) {
180            mKeyguardView.onScreenTurnedOn();
181        }
182    }
183
184    public synchronized void verifyUnlock() {
185        if (DEBUG) Log.d(TAG, "verifyUnlock()");
186        show();
187        mKeyguardView.verifyUnlock();
188    }
189
190    /**
191     * A key has woken the device.  We use this to potentially adjust the state
192     * of the lock screen based on the key.
193     *
194     * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}.
195     * Be sure not to take any action that takes a long time; any significant
196     * action should be posted to a handler.
197     *
198     * @param keyCode The wake key.
199     */
200    public boolean wakeWhenReadyTq(int keyCode) {
201        if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")");
202        if (mKeyguardView != null) {
203            mKeyguardView.wakeWhenReadyTq(keyCode);
204            return true;
205        } else {
206            Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq");
207            return false;
208        }
209    }
210
211    /**
212     * Hides the keyguard view
213     */
214    public synchronized void hide() {
215        if (DEBUG) Log.d(TAG, "hide()");
216        if (mKeyguardHost != null) {
217            mKeyguardHost.setVisibility(View.GONE);
218            // Don't do this right away, so we can let the view continue to animate
219            // as it goes away.
220            if (mKeyguardView != null) {
221                final KeyguardViewBase lastView = mKeyguardView;
222                mKeyguardView = null;
223                mKeyguardHost.postDelayed(new Runnable() {
224                    public void run() {
225                        synchronized (KeyguardViewManager.this) {
226                            lastView.cleanUp();
227                            mKeyguardHost.removeView(lastView);
228                        }
229                    }
230                }, 500);
231            }
232        }
233    }
234
235    /**
236     * @return Whether the keyguard is showing
237     */
238    public synchronized boolean isShowing() {
239        return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);
240    }
241}
242