PhoneWindowManager.java revision 10a058c96b20aad06066f40f7f4fcd6a7b8aa0b7
1/*
2 * Copyright (C) 2006 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 android.app.Activity;
20import android.app.ActivityManagerNative;
21import android.app.IActivityManager;
22import android.app.IUiModeManager;
23import android.app.UiModeManager;
24import android.content.ActivityNotFoundException;
25import android.content.BroadcastReceiver;
26import android.content.ComponentName;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.ServiceConnection;
32import android.content.pm.ActivityInfo;
33import android.content.pm.PackageManager;
34import android.content.res.CompatibilityInfo;
35import android.content.res.Configuration;
36import android.content.res.Resources;
37import android.database.ContentObserver;
38import android.graphics.PixelFormat;
39import android.graphics.Rect;
40import android.os.Binder;
41import android.os.Handler;
42import android.os.IBinder;
43import android.os.LocalPowerManager;
44import android.os.PowerManager;
45import android.os.RemoteException;
46import android.os.ServiceManager;
47import android.os.SystemClock;
48import android.os.SystemProperties;
49import android.os.UEventObserver;
50import android.os.Vibrator;
51import android.provider.Settings;
52
53import com.android.internal.R;
54import com.android.internal.app.ShutdownThread;
55import com.android.internal.policy.PolicyManager;
56import com.android.internal.statusbar.IStatusBarService;
57import com.android.internal.telephony.ITelephony;
58import com.android.internal.view.BaseInputHandler;
59import com.android.internal.widget.PointerLocationView;
60
61import android.util.DisplayMetrics;
62import android.util.EventLog;
63import android.util.Log;
64import android.util.Slog;
65import android.view.Gravity;
66import android.view.HapticFeedbackConstants;
67import android.view.IWindowManager;
68import android.view.InputChannel;
69import android.view.InputDevice;
70import android.view.InputQueue;
71import android.view.InputHandler;
72import android.view.KeyCharacterMap;
73import android.view.KeyEvent;
74import android.view.MotionEvent;
75import android.view.WindowOrientationListener;
76import android.view.Surface;
77import android.view.View;
78import android.view.ViewConfiguration;
79import android.view.Window;
80import android.view.WindowManager;
81import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
82import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
83import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
84import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
85import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
86import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
87import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
88import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
89import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
90import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
91import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
92import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
93import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
94import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
95import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
96import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
97import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
98import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
99import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
100import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
101import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
102import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
103import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
104import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
105import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
106import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
107import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
108import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
109import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
110import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
111import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
112import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
113import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
114import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
115import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
116import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
117import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
118import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
119import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
120import android.view.WindowManagerImpl;
121import android.view.WindowManagerPolicy;
122import android.view.KeyCharacterMap.FallbackAction;
123import android.view.animation.Animation;
124import android.view.animation.AnimationUtils;
125import android.media.IAudioService;
126import android.media.AudioManager;
127
128import java.io.File;
129import java.io.FileDescriptor;
130import java.io.FileReader;
131import java.io.IOException;
132import java.io.PrintWriter;
133import java.util.ArrayList;
134
135/**
136 * WindowManagerPolicy implementation for the Android phone UI.  This
137 * introduces a new method suffix, Lp, for an internal lock of the
138 * PhoneWindowManager.  This is used to protect some internal state, and
139 * can be acquired with either thw Lw and Li lock held, so has the restrictions
140 * of both of those when held.
141 */
142public class PhoneWindowManager implements WindowManagerPolicy {
143    static final String TAG = "WindowManager";
144    static final boolean DEBUG = false;
145    static final boolean localLOGV = false;
146    static final boolean DEBUG_LAYOUT = false;
147    static final boolean DEBUG_FALLBACK = false;
148    static final boolean SHOW_STARTING_ANIMATIONS = true;
149    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
150
151    static final int LONG_PRESS_POWER_NOTHING = 0;
152    static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
153    static final int LONG_PRESS_POWER_SHUT_OFF = 2;
154
155    // These need to match the documentation/constant in
156    // core/res/res/values/config.xml
157    static final int LONG_PRESS_HOME_NOTHING = 0;
158    static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
159    static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
160
161    // wallpaper is at the bottom, though the window manager may move it.
162    static final int WALLPAPER_LAYER = 2;
163    static final int APPLICATION_LAYER = 2;
164    static final int PHONE_LAYER = 3;
165    static final int SEARCH_BAR_LAYER = 4;
166    static final int SYSTEM_DIALOG_LAYER = 5;
167    // toasts and the plugged-in battery thing
168    static final int TOAST_LAYER = 6;
169    // SIM errors and unlock.  Not sure if this really should be in a high layer.
170    static final int PRIORITY_PHONE_LAYER = 7;
171    // like the ANR / app crashed dialogs
172    static final int SYSTEM_ALERT_LAYER = 8;
173    // system-level error dialogs
174    static final int SYSTEM_ERROR_LAYER = 9;
175    // on-screen keyboards and other such input method user interfaces go here.
176    static final int INPUT_METHOD_LAYER = 10;
177    // on-screen keyboards and other such input method user interfaces go here.
178    static final int INPUT_METHOD_DIALOG_LAYER = 11;
179    // the keyguard; nothing on top of these can take focus, since they are
180    // responsible for power management when displayed.
181    static final int KEYGUARD_LAYER = 12;
182    static final int KEYGUARD_DIALOG_LAYER = 13;
183    static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
184    static final int STATUS_BAR_LAYER = 15;
185    static final int STATUS_BAR_PANEL_LAYER = 16;
186    // the navigation bar, if available, shows atop most things
187    static final int NAVIGATION_BAR_LAYER = 17;
188    // the on-screen volume indicator and controller shown when the user
189    // changes the device volume
190    static final int VOLUME_OVERLAY_LAYER = 18;
191    // the drag layer: input for drag-and-drop is associated with this window,
192    // which sits above all other focusable windows
193    static final int DRAG_LAYER = 19;
194    // things in here CAN NOT take focus, but are shown on top of everything else.
195    static final int SYSTEM_OVERLAY_LAYER = 20;
196    static final int SECURE_SYSTEM_OVERLAY_LAYER = 21;
197    // the (mouse) pointer layer
198    static final int POINTER_LAYER = 22;
199
200    static final int APPLICATION_MEDIA_SUBLAYER = -2;
201    static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
202    static final int APPLICATION_PANEL_SUBLAYER = 1;
203    static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
204
205    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
206    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
207    static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
208    static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
209
210    // Useful scan codes.
211    private static final int SW_LID = 0x00;
212    private static final int BTN_MOUSE = 0x110;
213
214    final Object mLock = new Object();
215
216    Context mContext;
217    IWindowManager mWindowManager;
218    LocalPowerManager mPowerManager;
219    IStatusBarService mStatusBarService;
220    Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
221
222    // Vibrator pattern for haptic feedback of a long press.
223    long[] mLongPressVibePattern;
224
225    // Vibrator pattern for haptic feedback of virtual key press.
226    long[] mVirtualKeyVibePattern;
227
228    // Vibrator pattern for a short vibration.
229    long[] mKeyboardTapVibePattern;
230
231    // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
232    long[] mSafeModeDisabledVibePattern;
233
234    // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
235    long[] mSafeModeEnabledVibePattern;
236
237    /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
238    boolean mEnableShiftMenuBugReports = false;
239
240    boolean mSafeMode;
241    WindowState mStatusBar = null;
242    boolean mStatusBarCanHide;
243    int mStatusBarHeight;
244    final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
245    WindowState mNavigationBar = null;
246    boolean mHasNavigationBar = false;
247    int mNavigationBarWidth = 0, mNavigationBarHeight = 0;
248
249    WindowState mKeyguard = null;
250    KeyguardViewMediator mKeyguardMediator;
251    GlobalActions mGlobalActions;
252    volatile boolean mPowerKeyHandled;
253    RecentApplicationsDialog mRecentAppsDialog;
254    Handler mHandler;
255
256    private static final int LID_ABSENT = -1;
257    private static final int LID_CLOSED = 0;
258    private static final int LID_OPEN = 1;
259
260    int mLidOpen = LID_ABSENT;
261
262    boolean mSystemReady;
263    boolean mHdmiPlugged;
264    int mUiMode = Configuration.UI_MODE_TYPE_NORMAL;
265    int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
266    int mLidOpenRotation;
267    int mCarDockRotation;
268    int mDeskDockRotation;
269
270    int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
271    int mUserRotation = Surface.ROTATION_0;
272
273    boolean mAllowAllRotations;
274    boolean mCarDockEnablesAccelerometer;
275    boolean mDeskDockEnablesAccelerometer;
276    int mLidKeyboardAccessibility;
277    int mLidNavigationAccessibility;
278    int mLongPressOnPowerBehavior = -1;
279    boolean mScreenOn = false;
280    boolean mOrientationSensorEnabled = false;
281    int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
282    static final int DEFAULT_ACCELEROMETER_ROTATION = 0;
283    int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION;
284    boolean mHasSoftInput = false;
285
286    int mPointerLocationMode = 0;
287    PointerLocationView mPointerLocationView = null;
288    InputChannel mPointerLocationInputChannel;
289
290    // The last window we were told about in focusChanged.
291    WindowState mFocusedWindow;
292
293    private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() {
294        @Override
295        public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
296            boolean handled = false;
297            try {
298                if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
299                    synchronized (mLock) {
300                        if (mPointerLocationView != null) {
301                            mPointerLocationView.addPointerEvent(event);
302                            handled = true;
303                        }
304                    }
305                }
306            } finally {
307                finishedCallback.finished(handled);
308            }
309        }
310    };
311
312    // The current size of the screen; really; (ir)regardless of whether the status
313    // bar can be hidden or not
314    int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
315    int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
316    // The current size of the screen; these may be different than (0,0)-(dw,dh)
317    // if the status bar can't be hidden; in that case it effectively carves out
318    // that area of the display from all other windows.
319    int mRestrictedScreenLeft, mRestrictedScreenTop;
320    int mRestrictedScreenWidth, mRestrictedScreenHeight;
321    // During layout, the current screen borders with all outer decoration
322    // (status bar, input method dock) accounted for.
323    int mCurLeft, mCurTop, mCurRight, mCurBottom;
324    // During layout, the frame in which content should be displayed
325    // to the user, accounting for all screen decoration except for any
326    // space they deem as available for other content.  This is usually
327    // the same as mCur*, but may be larger if the screen decor has supplied
328    // content insets.
329    int mContentLeft, mContentTop, mContentRight, mContentBottom;
330    // During layout, the current screen borders along which input method
331    // windows are placed.
332    int mDockLeft, mDockTop, mDockRight, mDockBottom;
333    // During layout, the layer at which the doc window is placed.
334    int mDockLayer;
335
336    static final Rect mTmpParentFrame = new Rect();
337    static final Rect mTmpDisplayFrame = new Rect();
338    static final Rect mTmpContentFrame = new Rect();
339    static final Rect mTmpVisibleFrame = new Rect();
340
341    WindowState mTopFullscreenOpaqueWindowState;
342    WindowState mTopAppWindowState;
343    WindowState mLastTopAppWindowState;
344    boolean mTopIsFullscreen;
345    boolean mForceStatusBar;
346    boolean mHideLockScreen;
347    boolean mDismissKeyguard;
348    boolean mHomePressed;
349    Intent mHomeIntent;
350    Intent mCarDockIntent;
351    Intent mDeskDockIntent;
352    int mShortcutKeyPressed = -1;
353    boolean mConsumeShortcutKeyUp;
354
355    // support for activating the lock screen while the screen is on
356    boolean mAllowLockscreenWhenOn;
357    int mLockScreenTimeout;
358    boolean mLockScreenTimerActive;
359
360    // visual screen saver support
361    int mScreenSaverTimeout;
362    boolean mScreenSaverEnabled = false;
363
364    // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
365    int mEndcallBehavior;
366
367    // Behavior of POWER button while in-call and screen on.
368    // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.)
369    int mIncallPowerBehavior;
370
371    int mLandscapeRotation = 0;  // default landscape rotation
372    int mSeascapeRotation = 0;   // "other" landscape rotation, 180 degrees from mLandscapeRotation
373    int mPortraitRotation = 0;   // default portrait rotation
374    int mUpsideDownRotation = 0; // "other" portrait rotation
375
376    // Nothing to see here, move along...
377    int mFancyRotationAnimation;
378
379    // What we do when the user long presses on home
380    private int mLongPressOnHomeBehavior = -1;
381
382    // Screenshot trigger states
383    private boolean mVolumeDownTriggered;
384    private boolean mPowerDownTriggered;
385
386    ShortcutManager mShortcutManager;
387    PowerManager.WakeLock mBroadcastWakeLock;
388
389    final KeyCharacterMap.FallbackAction mFallbackAction = new KeyCharacterMap.FallbackAction();
390
391    private UEventObserver mHDMIObserver = new UEventObserver() {
392        @Override
393        public void onUEvent(UEventObserver.UEvent event) {
394            setHdmiPlugged("1".equals(event.get("SWITCH_STATE")));
395        }
396    };
397
398    class SettingsObserver extends ContentObserver {
399        SettingsObserver(Handler handler) {
400            super(handler);
401        }
402
403        void observe() {
404            ContentResolver resolver = mContext.getContentResolver();
405            resolver.registerContentObserver(Settings.System.getUriFor(
406                    Settings.System.END_BUTTON_BEHAVIOR), false, this);
407            resolver.registerContentObserver(Settings.Secure.getUriFor(
408                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this);
409            resolver.registerContentObserver(Settings.System.getUriFor(
410                    Settings.System.ACCELEROMETER_ROTATION), false, this);
411            resolver.registerContentObserver(Settings.System.getUriFor(
412                    Settings.System.USER_ROTATION), false, this);
413            resolver.registerContentObserver(Settings.System.getUriFor(
414                    Settings.System.SCREEN_OFF_TIMEOUT), false, this);
415            resolver.registerContentObserver(Settings.System.getUriFor(
416                    Settings.System.WINDOW_ORIENTATION_LISTENER_LOG), false, this);
417            resolver.registerContentObserver(Settings.System.getUriFor(
418                    Settings.System.POINTER_LOCATION), false, this);
419            resolver.registerContentObserver(Settings.Secure.getUriFor(
420                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
421            resolver.registerContentObserver(Settings.System.getUriFor(
422                    "fancy_rotation_anim"), false, this);
423            resolver.registerContentObserver(Settings.System.getUriFor(
424                    Settings.Secure.DREAM_TIMEOUT), false, this);
425            updateSettings();
426        }
427
428        @Override public void onChange(boolean selfChange) {
429            updateSettings();
430            try {
431                mWindowManager.setRotation(USE_LAST_ROTATION, false,
432                        mFancyRotationAnimation);
433            } catch (RemoteException e) {
434                // Ignore
435            }
436        }
437    }
438
439    class MyOrientationListener extends WindowOrientationListener {
440        MyOrientationListener(Context context) {
441            super(context);
442        }
443
444        @Override
445        public void onOrientationChanged(int rotation) {
446            // Send updates based on orientation value
447            if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation);
448            try {
449                mWindowManager.setRotation(rotation, false,
450                        mFancyRotationAnimation);
451            } catch (RemoteException e) {
452                // Ignore
453
454            }
455        }
456    }
457    MyOrientationListener mOrientationListener;
458
459    boolean useSensorForOrientationLp(int appOrientation) {
460        // The app says use the sensor.
461        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
462                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
463                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
464                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
465            return true;
466        }
467        // The user preference says we can rotate, and the app is willing to rotate.
468        if (mAccelerometerDefault != 0 &&
469                (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
470                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
471            return true;
472        }
473        // We're in a dock that has a rotation affinity, and the app is willing to rotate.
474        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR)
475                || (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
476            // Note we override the nosensor flag here.
477            if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
478                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
479                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
480                return true;
481            }
482        }
483        // Else, don't use the sensor.
484        return false;
485    }
486
487    /*
488     * We always let the sensor be switched on by default except when
489     * the user has explicitly disabled sensor based rotation or when the
490     * screen is switched off.
491     */
492    boolean needSensorRunningLp() {
493        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
494                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
495                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
496                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
497            // If the application has explicitly requested to follow the
498            // orientation, then we need to turn the sensor or.
499            return true;
500        }
501        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
502                (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
503            // enable accelerometer if we are docked in a dock that enables accelerometer
504            // orientation management,
505            return true;
506        }
507        if (mAccelerometerDefault == 0) {
508            // If the setting for using the sensor by default is enabled, then
509            // we will always leave it on.  Note that the user could go to
510            // a window that forces an orientation that does not use the
511            // sensor and in theory we could turn it off... however, when next
512            // turning it on we won't have a good value for the current
513            // orientation for a little bit, which can cause orientation
514            // changes to lag, so we'd like to keep it always on.  (It will
515            // still be turned off when the screen is off.)
516            return false;
517        }
518        return true;
519    }
520
521    /*
522     * Various use cases for invoking this function
523     * screen turning off, should always disable listeners if already enabled
524     * screen turned on and current app has sensor based orientation, enable listeners
525     * if not already enabled
526     * screen turned on and current app does not have sensor orientation, disable listeners if
527     * already enabled
528     * screen turning on and current app has sensor based orientation, enable listeners if needed
529     * screen turning on and current app has nosensor based orientation, do nothing
530     */
531    void updateOrientationListenerLp() {
532        if (!mOrientationListener.canDetectOrientation()) {
533            // If sensor is turned off or nonexistent for some reason
534            return;
535        }
536        //Could have been invoked due to screen turning on or off or
537        //change of the currently visible window's orientation
538        if (localLOGV) Log.v(TAG, "Screen status="+mScreenOn+
539                ", current orientation="+mCurrentAppOrientation+
540                ", SensorEnabled="+mOrientationSensorEnabled);
541        boolean disable = true;
542        if (mScreenOn) {
543            if (needSensorRunningLp()) {
544                disable = false;
545                //enable listener if not already enabled
546                if (!mOrientationSensorEnabled) {
547                    mOrientationListener.enable();
548                    if(localLOGV) Log.v(TAG, "Enabling listeners");
549                    mOrientationSensorEnabled = true;
550                }
551            }
552        }
553        //check if sensors need to be disabled
554        if (disable && mOrientationSensorEnabled) {
555            mOrientationListener.disable();
556            if(localLOGV) Log.v(TAG, "Disabling listeners");
557            mOrientationSensorEnabled = false;
558        }
559    }
560
561    private void interceptPowerKeyDown(boolean handled) {
562        mPowerKeyHandled = handled;
563        if (!handled) {
564            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
565        }
566    }
567
568    private boolean interceptPowerKeyUp(boolean canceled) {
569        if (!mPowerKeyHandled) {
570            mHandler.removeCallbacks(mPowerLongPress);
571            return !canceled;
572        } else {
573            mPowerKeyHandled = true;
574            return false;
575        }
576    }
577
578    private final Runnable mPowerLongPress = new Runnable() {
579        public void run() {
580            if (!mPowerKeyHandled) {
581                // The context isn't read
582                if (mLongPressOnPowerBehavior < 0) {
583                    mLongPressOnPowerBehavior = mContext.getResources().getInteger(
584                            com.android.internal.R.integer.config_longPressOnPowerBehavior);
585                }
586                switch (mLongPressOnPowerBehavior) {
587                case LONG_PRESS_POWER_NOTHING:
588                    break;
589                case LONG_PRESS_POWER_GLOBAL_ACTIONS:
590                    mPowerKeyHandled = true;
591                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
592                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
593                    showGlobalActionsDialog();
594                    break;
595                case LONG_PRESS_POWER_SHUT_OFF:
596                    mPowerKeyHandled = true;
597                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
598                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
599                    ShutdownThread.shutdown(mContext, true);
600                    break;
601                }
602            }
603        }
604    };
605
606    void showGlobalActionsDialog() {
607        if (mGlobalActions == null) {
608            mGlobalActions = new GlobalActions(mContext);
609        }
610        final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden();
611        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
612        if (keyguardShowing) {
613            // since it took two seconds of long press to bring this up,
614            // poke the wake lock so they have some time to see the dialog.
615            mKeyguardMediator.pokeWakelock();
616        }
617    }
618
619    boolean isDeviceProvisioned() {
620        return Settings.Secure.getInt(
621                mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
622    }
623
624    /**
625     * When a home-key longpress expires, close other system windows and launch the recent apps
626     */
627    Runnable mHomeLongPress = new Runnable() {
628        public void run() {
629            handleLongPressOnHome();
630        }
631    };
632
633    private void handleLongPressOnHome() {
634        // We can't initialize this in init() since the configuration hasn't been loaded yet.
635        if (mLongPressOnHomeBehavior < 0) {
636            mLongPressOnHomeBehavior
637                    = mContext.getResources().getInteger(R.integer.config_longPressOnHomeBehavior);
638            if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
639                    mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
640                mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
641            }
642        }
643
644        if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
645            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
646            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
647
648            // Eat the longpress so it won't dismiss the recent apps dialog when
649            // the user lets go of the home key
650            mHomePressed = false;
651        }
652
653        if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) {
654            showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
655        } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
656            try {
657                mStatusBarService.toggleRecentApps();
658            } catch (RemoteException e) {
659                Slog.e(TAG, "RemoteException when showing recent apps", e);
660            }
661        }
662    }
663
664    /**
665     * Create (if necessary) and launch the recent apps dialog, or hide it if it is
666     * already shown.
667     */
668    void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) {
669        mHandler.post(new Runnable() {
670            @Override
671            public void run() {
672                if (mRecentAppsDialog == null) {
673                    mRecentAppsDialog = new RecentApplicationsDialog(mContext);
674                }
675                if (mRecentAppsDialog.isShowing()) {
676                    if (dismissIfShown) {
677                        mRecentAppsDialog.dismiss();
678                    }
679                } else {
680                    mRecentAppsDialog.setHeldModifiers(heldModifiers);
681                    mRecentAppsDialog.show();
682                }
683            }
684        });
685    }
686
687    /** {@inheritDoc} */
688    public void init(Context context, IWindowManager windowManager,
689            LocalPowerManager powerManager) {
690        mContext = context;
691        mWindowManager = windowManager;
692        mPowerManager = powerManager;
693        mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
694        mHandler = new Handler();
695        mOrientationListener = new MyOrientationListener(mContext);
696        SettingsObserver settingsObserver = new SettingsObserver(mHandler);
697        settingsObserver.observe();
698        mShortcutManager = new ShortcutManager(context, mHandler);
699        mShortcutManager.observe();
700        mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
701        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
702        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
703                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
704        mCarDockIntent =  new Intent(Intent.ACTION_MAIN, null);
705        mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
706        mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
707                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
708        mDeskDockIntent =  new Intent(Intent.ACTION_MAIN, null);
709        mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
710        mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
711                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
712
713        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
714        mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
715                "PhoneWindowManager.mBroadcastWakeLock");
716        mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
717        mLidOpenRotation = readRotation(
718                com.android.internal.R.integer.config_lidOpenRotation);
719        mCarDockRotation = readRotation(
720                com.android.internal.R.integer.config_carDockRotation);
721        mDeskDockRotation = readRotation(
722                com.android.internal.R.integer.config_deskDockRotation);
723        mAllowAllRotations = mContext.getResources().getBoolean(
724                com.android.internal.R.bool.config_allowAllRotations);
725        mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
726                com.android.internal.R.bool.config_carDockEnablesAccelerometer);
727        mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
728                com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
729        mLidKeyboardAccessibility = mContext.getResources().getInteger(
730                com.android.internal.R.integer.config_lidKeyboardAccessibility);
731        mLidNavigationAccessibility = mContext.getResources().getInteger(
732                com.android.internal.R.integer.config_lidNavigationAccessibility);
733        // register for dock events
734        IntentFilter filter = new IntentFilter();
735        filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
736        filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE);
737        filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE);
738        filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE);
739        filter.addAction(Intent.ACTION_DOCK_EVENT);
740        Intent intent = context.registerReceiver(mDockReceiver, filter);
741        if (intent != null) {
742            // Retrieve current sticky dock event broadcast.
743            mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
744                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
745        }
746        mVibrator = new Vibrator();
747        mLongPressVibePattern = getLongIntArray(mContext.getResources(),
748                com.android.internal.R.array.config_longPressVibePattern);
749        mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
750                com.android.internal.R.array.config_virtualKeyVibePattern);
751        mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(),
752                com.android.internal.R.array.config_keyboardTapVibePattern);
753        mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
754                com.android.internal.R.array.config_safeModeDisabledVibePattern);
755        mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
756                com.android.internal.R.array.config_safeModeEnabledVibePattern);
757
758        // Controls rotation and the like.
759        initializeHdmiState();
760    }
761
762    public void setInitialDisplaySize(int width, int height) {
763        int shortSize;
764        if (width > height) {
765            shortSize = height;
766            mLandscapeRotation = Surface.ROTATION_0;
767            mSeascapeRotation = Surface.ROTATION_180;
768            if (mContext.getResources().getBoolean(
769                    com.android.internal.R.bool.config_reverseDefaultRotation)) {
770                mPortraitRotation = Surface.ROTATION_90;
771                mUpsideDownRotation = Surface.ROTATION_270;
772            } else {
773                mPortraitRotation = Surface.ROTATION_270;
774                mUpsideDownRotation = Surface.ROTATION_90;
775            }
776        } else {
777            shortSize = width;
778            mPortraitRotation = Surface.ROTATION_0;
779            mUpsideDownRotation = Surface.ROTATION_180;
780            if (mContext.getResources().getBoolean(
781                    com.android.internal.R.bool.config_reverseDefaultRotation)) {
782                mLandscapeRotation = Surface.ROTATION_270;
783                mSeascapeRotation = Surface.ROTATION_90;
784            } else {
785                mLandscapeRotation = Surface.ROTATION_90;
786                mSeascapeRotation = Surface.ROTATION_270;
787            }
788        }
789
790        // Determine whether the status bar can hide based on the size
791        // of the screen.  We assume sizes > 600dp are tablets where we
792        // will use the system bar.
793        int shortSizeDp = shortSize
794                * DisplayMetrics.DENSITY_DEFAULT
795                / DisplayMetrics.DENSITY_DEVICE;
796        mStatusBarCanHide = shortSizeDp < 600;
797        mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
798                mStatusBarCanHide
799                ? com.android.internal.R.dimen.status_bar_height
800                : com.android.internal.R.dimen.system_bar_height);
801
802        mHasNavigationBar = mContext.getResources().getBoolean(
803                com.android.internal.R.bool.config_showNavigationBar);
804        mNavigationBarHeight = mHasNavigationBar
805                ? mContext.getResources().getDimensionPixelSize(
806                    com.android.internal.R.dimen.navigation_bar_height)
807                : 0;
808        mNavigationBarWidth = mHasNavigationBar
809                ? mContext.getResources().getDimensionPixelSize(
810                    com.android.internal.R.dimen.navigation_bar_width)
811                : 0;
812    }
813
814    public void updateSettings() {
815        ContentResolver resolver = mContext.getContentResolver();
816        boolean updateRotation = false;
817        View addView = null;
818        View removeView = null;
819        synchronized (mLock) {
820            mEndcallBehavior = Settings.System.getInt(resolver,
821                    Settings.System.END_BUTTON_BEHAVIOR,
822                    Settings.System.END_BUTTON_BEHAVIOR_DEFAULT);
823            mIncallPowerBehavior = Settings.Secure.getInt(resolver,
824                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
825                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
826            mFancyRotationAnimation = Settings.System.getInt(resolver,
827                    "fancy_rotation_anim", 0) != 0 ? 0x80 : 0;
828            int accelerometerDefault = Settings.System.getInt(resolver,
829                    Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
830
831            // set up rotation lock state
832            mUserRotationMode = (accelerometerDefault == 0)
833                ? WindowManagerPolicy.USER_ROTATION_LOCKED
834                : WindowManagerPolicy.USER_ROTATION_FREE;
835            mUserRotation = Settings.System.getInt(resolver,
836                    Settings.System.USER_ROTATION,
837                    Surface.ROTATION_0);
838
839            if (mAccelerometerDefault != accelerometerDefault) {
840                mAccelerometerDefault = accelerometerDefault;
841                updateOrientationListenerLp();
842            }
843
844            mOrientationListener.setLogEnabled(
845                    Settings.System.getInt(resolver,
846                            Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, 0) != 0);
847
848            if (mSystemReady) {
849                int pointerLocation = Settings.System.getInt(resolver,
850                        Settings.System.POINTER_LOCATION, 0);
851                if (mPointerLocationMode != pointerLocation) {
852                    mPointerLocationMode = pointerLocation;
853                    if (pointerLocation != 0) {
854                        if (mPointerLocationView == null) {
855                            mPointerLocationView = new PointerLocationView(mContext);
856                            mPointerLocationView.setPrintCoords(false);
857                            addView = mPointerLocationView;
858                        }
859                    } else {
860                        removeView = mPointerLocationView;
861                        mPointerLocationView = null;
862                    }
863                }
864            }
865            // use screen off timeout setting as the timeout for the lockscreen
866            mLockScreenTimeout = Settings.System.getInt(resolver,
867                    Settings.System.SCREEN_OFF_TIMEOUT, 0);
868            String imId = Settings.Secure.getString(resolver,
869                    Settings.Secure.DEFAULT_INPUT_METHOD);
870            boolean hasSoftInput = imId != null && imId.length() > 0;
871            if (mHasSoftInput != hasSoftInput) {
872                mHasSoftInput = hasSoftInput;
873                updateRotation = true;
874            }
875
876            mScreenSaverTimeout = Settings.System.getInt(resolver,
877                    Settings.Secure.DREAM_TIMEOUT, 0);
878            mScreenSaverEnabled = true;
879            updateScreenSaverTimeoutLocked();
880        }
881        if (updateRotation) {
882            updateRotation(0);
883        }
884        if (addView != null) {
885            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
886                    WindowManager.LayoutParams.MATCH_PARENT,
887                    WindowManager.LayoutParams.MATCH_PARENT);
888            lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
889            lp.flags =
890                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
891                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
892                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
893            lp.format = PixelFormat.TRANSLUCENT;
894            lp.setTitle("PointerLocation");
895            WindowManager wm = (WindowManager)
896                    mContext.getSystemService(Context.WINDOW_SERVICE);
897            wm.addView(addView, lp);
898
899            if (mPointerLocationInputChannel == null) {
900                try {
901                    mPointerLocationInputChannel =
902                        mWindowManager.monitorInput("PointerLocationView");
903                    InputQueue.registerInputChannel(mPointerLocationInputChannel,
904                            mPointerLocationInputHandler, mHandler.getLooper().getQueue());
905                } catch (RemoteException ex) {
906                    Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.",
907                            ex);
908                }
909            }
910        }
911        if (removeView != null) {
912            if (mPointerLocationInputChannel != null) {
913                InputQueue.unregisterInputChannel(mPointerLocationInputChannel);
914                mPointerLocationInputChannel.dispose();
915                mPointerLocationInputChannel = null;
916            }
917
918            WindowManager wm = (WindowManager)
919                    mContext.getSystemService(Context.WINDOW_SERVICE);
920            wm.removeView(removeView);
921        }
922    }
923
924    private int readRotation(int resID) {
925        try {
926            int rotation = mContext.getResources().getInteger(resID);
927            switch (rotation) {
928                case 0:
929                    return Surface.ROTATION_0;
930                case 90:
931                    return Surface.ROTATION_90;
932                case 180:
933                    return Surface.ROTATION_180;
934                case 270:
935                    return Surface.ROTATION_270;
936            }
937        } catch (Resources.NotFoundException e) {
938            // fall through
939        }
940        return -1;
941    }
942
943    /** {@inheritDoc} */
944    public int checkAddPermission(WindowManager.LayoutParams attrs) {
945        int type = attrs.type;
946
947        if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
948                || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
949            return WindowManagerImpl.ADD_OKAY;
950        }
951        String permission = null;
952        switch (type) {
953            case TYPE_TOAST:
954                // XXX right now the app process has complete control over
955                // this...  should introduce a token to let the system
956                // monitor/control what they are doing.
957                break;
958            case TYPE_INPUT_METHOD:
959            case TYPE_WALLPAPER:
960                // The window manager will check these.
961                break;
962            case TYPE_PHONE:
963            case TYPE_PRIORITY_PHONE:
964            case TYPE_SYSTEM_ALERT:
965            case TYPE_SYSTEM_ERROR:
966            case TYPE_SYSTEM_OVERLAY:
967                permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
968                break;
969            default:
970                permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
971        }
972        if (permission != null) {
973            if (mContext.checkCallingOrSelfPermission(permission)
974                    != PackageManager.PERMISSION_GRANTED) {
975                return WindowManagerImpl.ADD_PERMISSION_DENIED;
976            }
977        }
978        return WindowManagerImpl.ADD_OKAY;
979    }
980
981    public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
982        switch (attrs.type) {
983            case TYPE_SYSTEM_OVERLAY:
984            case TYPE_SECURE_SYSTEM_OVERLAY:
985            case TYPE_TOAST:
986                // These types of windows can't receive input events.
987                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
988                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
989                break;
990        }
991    }
992
993    void readLidState() {
994        try {
995            int sw = mWindowManager.getSwitchState(SW_LID);
996            if (sw > 0) {
997                mLidOpen = LID_OPEN;
998            } else if (sw == 0) {
999                mLidOpen = LID_CLOSED;
1000            } else {
1001                mLidOpen = LID_ABSENT;
1002            }
1003        } catch (RemoteException e) {
1004            // Ignore
1005        }
1006    }
1007
1008    private int determineHiddenState(int mode, int hiddenValue, int visibleValue) {
1009        if (mLidOpen != LID_ABSENT) {
1010            switch (mode) {
1011                case 1:
1012                    return mLidOpen == LID_OPEN ? visibleValue : hiddenValue;
1013                case 2:
1014                    return mLidOpen == LID_OPEN ? hiddenValue : visibleValue;
1015            }
1016        }
1017        return visibleValue;
1018    }
1019
1020    /** {@inheritDoc} */
1021    public void adjustConfigurationLw(Configuration config) {
1022        readLidState();
1023
1024        mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN);
1025
1026        if (config.keyboard == Configuration.KEYBOARD_NOKEYS) {
1027            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
1028        } else {
1029            config.hardKeyboardHidden = determineHiddenState(mLidKeyboardAccessibility,
1030                    Configuration.HARDKEYBOARDHIDDEN_YES, Configuration.HARDKEYBOARDHIDDEN_NO);
1031        }
1032
1033        if (config.navigation == Configuration.NAVIGATION_NONAV) {
1034            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_YES;
1035        } else {
1036            config.navigationHidden = determineHiddenState(mLidNavigationAccessibility,
1037                    Configuration.NAVIGATIONHIDDEN_YES, Configuration.NAVIGATIONHIDDEN_NO);
1038        }
1039
1040        if (mHasSoftInput || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
1041            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
1042        } else {
1043            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES;
1044        }
1045    }
1046
1047    /** {@inheritDoc} */
1048    public int windowTypeToLayerLw(int type) {
1049        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
1050            return APPLICATION_LAYER;
1051        }
1052        switch (type) {
1053        case TYPE_STATUS_BAR:
1054            return STATUS_BAR_LAYER;
1055        case TYPE_STATUS_BAR_PANEL:
1056            return STATUS_BAR_PANEL_LAYER;
1057        case TYPE_STATUS_BAR_SUB_PANEL:
1058            return STATUS_BAR_SUB_PANEL_LAYER;
1059        case TYPE_SYSTEM_DIALOG:
1060            return SYSTEM_DIALOG_LAYER;
1061        case TYPE_SEARCH_BAR:
1062            return SEARCH_BAR_LAYER;
1063        case TYPE_PHONE:
1064            return PHONE_LAYER;
1065        case TYPE_KEYGUARD:
1066            return KEYGUARD_LAYER;
1067        case TYPE_KEYGUARD_DIALOG:
1068            return KEYGUARD_DIALOG_LAYER;
1069        case TYPE_SYSTEM_ALERT:
1070            return SYSTEM_ALERT_LAYER;
1071        case TYPE_SYSTEM_ERROR:
1072            return SYSTEM_ERROR_LAYER;
1073        case TYPE_INPUT_METHOD:
1074            return INPUT_METHOD_LAYER;
1075        case TYPE_INPUT_METHOD_DIALOG:
1076            return INPUT_METHOD_DIALOG_LAYER;
1077        case TYPE_VOLUME_OVERLAY:
1078            return VOLUME_OVERLAY_LAYER;
1079        case TYPE_SYSTEM_OVERLAY:
1080            return SYSTEM_OVERLAY_LAYER;
1081        case TYPE_SECURE_SYSTEM_OVERLAY:
1082            return SECURE_SYSTEM_OVERLAY_LAYER;
1083        case TYPE_PRIORITY_PHONE:
1084            return PRIORITY_PHONE_LAYER;
1085        case TYPE_TOAST:
1086            return TOAST_LAYER;
1087        case TYPE_WALLPAPER:
1088            return WALLPAPER_LAYER;
1089        case TYPE_DRAG:
1090            return DRAG_LAYER;
1091        case TYPE_POINTER:
1092            return POINTER_LAYER;
1093        case TYPE_NAVIGATION_BAR:
1094            return NAVIGATION_BAR_LAYER;
1095        }
1096        Log.e(TAG, "Unknown window type: " + type);
1097        return APPLICATION_LAYER;
1098    }
1099
1100    /** {@inheritDoc} */
1101    public int subWindowTypeToLayerLw(int type) {
1102        switch (type) {
1103        case TYPE_APPLICATION_PANEL:
1104        case TYPE_APPLICATION_ATTACHED_DIALOG:
1105            return APPLICATION_PANEL_SUBLAYER;
1106        case TYPE_APPLICATION_MEDIA:
1107            return APPLICATION_MEDIA_SUBLAYER;
1108        case TYPE_APPLICATION_MEDIA_OVERLAY:
1109            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
1110        case TYPE_APPLICATION_SUB_PANEL:
1111            return APPLICATION_SUB_PANEL_SUBLAYER;
1112        }
1113        Log.e(TAG, "Unknown sub-window type: " + type);
1114        return 0;
1115    }
1116
1117    public int getMaxWallpaperLayer() {
1118        return STATUS_BAR_LAYER;
1119    }
1120
1121    public boolean canStatusBarHide() {
1122        return mStatusBarCanHide;
1123    }
1124
1125    public int getNonDecorDisplayWidth(int rotation, int fullWidth) {
1126        // Assumes that the navigation bar appears on the side of the display in landscape.
1127        final boolean horizontal
1128            = (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90);
1129        return fullWidth - (horizontal ? mNavigationBarWidth : 0);
1130    }
1131
1132    public int getNonDecorDisplayHeight(int rotation, int fullHeight) {
1133        final boolean horizontal
1134            = (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90);
1135        return fullHeight
1136            - (mStatusBarCanHide ? 0 : mStatusBarHeight)
1137            - (horizontal ? 0 : mNavigationBarHeight);
1138    }
1139
1140    public int getConfigDisplayWidth(int rotation, int fullWidth) {
1141        return getNonDecorDisplayWidth(rotation, fullWidth);
1142    }
1143
1144    public int getConfigDisplayHeight(int rotation, int fullHeight) {
1145        return getNonDecorDisplayHeight(rotation, fullHeight);
1146    }
1147
1148    public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
1149        return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
1150    }
1151
1152    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
1153        return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
1154                && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
1155    }
1156
1157    /** {@inheritDoc} */
1158    public View addStartingWindow(IBinder appToken, String packageName, int theme,
1159            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
1160            int icon, int windowFlags) {
1161        if (!SHOW_STARTING_ANIMATIONS) {
1162            return null;
1163        }
1164        if (packageName == null) {
1165            return null;
1166        }
1167
1168        try {
1169            Context context = mContext;
1170            //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
1171            //        + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
1172            if (theme != context.getThemeResId() || labelRes != 0) {
1173                try {
1174                    context = context.createPackageContext(packageName, 0);
1175                    context.setTheme(theme);
1176                } catch (PackageManager.NameNotFoundException e) {
1177                    // Ignore
1178                }
1179            }
1180
1181            Window win = PolicyManager.makeNewWindow(context);
1182            if (win.getWindowStyle().getBoolean(
1183                    com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
1184                return null;
1185            }
1186
1187            Resources r = context.getResources();
1188            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
1189
1190            win.setType(
1191                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
1192            // Force the window flags: this is a fake window, so it is not really
1193            // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
1194            // flag because we do know that the next window will take input
1195            // focus, so we want to get the IME window up on top of us right away.
1196            win.setFlags(
1197                windowFlags|
1198                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
1199                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
1200                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
1201                windowFlags|
1202                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
1203                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
1204                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
1205
1206            if (!compatInfo.supportsScreen()) {
1207                win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW);
1208            }
1209
1210            win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
1211                    WindowManager.LayoutParams.MATCH_PARENT);
1212
1213            final WindowManager.LayoutParams params = win.getAttributes();
1214            params.token = appToken;
1215            params.packageName = packageName;
1216            params.windowAnimations = win.getWindowStyle().getResourceId(
1217                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
1218            params.setTitle("Starting " + packageName);
1219
1220            WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
1221            View view = win.getDecorView();
1222
1223            if (win.isFloating()) {
1224                // Whoops, there is no way to display an animation/preview
1225                // of such a thing!  After all that work...  let's skip it.
1226                // (Note that we must do this here because it is in
1227                // getDecorView() where the theme is evaluated...  maybe
1228                // we should peek the floating attribute from the theme
1229                // earlier.)
1230                return null;
1231            }
1232
1233            if (localLOGV) Log.v(
1234                TAG, "Adding starting window for " + packageName
1235                + " / " + appToken + ": "
1236                + (view.getParent() != null ? view : null));
1237
1238            wm.addView(view, params);
1239
1240            // Only return the view if it was successfully added to the
1241            // window manager... which we can tell by it having a parent.
1242            return view.getParent() != null ? view : null;
1243        } catch (WindowManagerImpl.BadTokenException e) {
1244            // ignore
1245            Log.w(TAG, appToken + " already running, starting window not displayed");
1246        } catch (RuntimeException e) {
1247            // don't crash if something else bad happens, for example a
1248            // failure loading resources because we are loading from an app
1249            // on external storage that has been unmounted.
1250            Log.w(TAG, appToken + " failed creating starting window", e);
1251        }
1252
1253        return null;
1254    }
1255
1256    /** {@inheritDoc} */
1257    public void removeStartingWindow(IBinder appToken, View window) {
1258        // RuntimeException e = new RuntimeException();
1259        // Log.i(TAG, "remove " + appToken + " " + window, e);
1260
1261        if (localLOGV) Log.v(
1262            TAG, "Removing starting window for " + appToken + ": " + window);
1263
1264        if (window != null) {
1265            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1266            wm.removeView(window);
1267        }
1268    }
1269
1270    /**
1271     * Preflight adding a window to the system.
1272     *
1273     * Currently enforces that three window types are singletons:
1274     * <ul>
1275     * <li>STATUS_BAR_TYPE</li>
1276     * <li>KEYGUARD_TYPE</li>
1277     * </ul>
1278     *
1279     * @param win The window to be added
1280     * @param attrs Information about the window to be added
1281     *
1282     * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
1283     */
1284    public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
1285        switch (attrs.type) {
1286            case TYPE_STATUS_BAR:
1287                mContext.enforceCallingOrSelfPermission(
1288                        android.Manifest.permission.STATUS_BAR_SERVICE,
1289                        "PhoneWindowManager");
1290                // TODO: Need to handle the race condition of the status bar proc
1291                // dying and coming back before the removeWindowLw cleanup has happened.
1292                if (mStatusBar != null) {
1293                    return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
1294                }
1295                mStatusBar = win;
1296                break;
1297            case TYPE_NAVIGATION_BAR:
1298                mContext.enforceCallingOrSelfPermission(
1299                        android.Manifest.permission.STATUS_BAR_SERVICE,
1300                        "PhoneWindowManager");
1301                mNavigationBar = win;
1302                if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
1303                break;
1304            case TYPE_STATUS_BAR_PANEL:
1305                mContext.enforceCallingOrSelfPermission(
1306                        android.Manifest.permission.STATUS_BAR_SERVICE,
1307                        "PhoneWindowManager");
1308                mStatusBarPanels.add(win);
1309                break;
1310            case TYPE_STATUS_BAR_SUB_PANEL:
1311                mContext.enforceCallingOrSelfPermission(
1312                        android.Manifest.permission.STATUS_BAR_SERVICE,
1313                        "PhoneWindowManager");
1314                mStatusBarPanels.add(win);
1315                break;
1316            case TYPE_KEYGUARD:
1317                if (mKeyguard != null) {
1318                    return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
1319                }
1320                mKeyguard = win;
1321                break;
1322        }
1323        return WindowManagerImpl.ADD_OKAY;
1324    }
1325
1326    /** {@inheritDoc} */
1327    public void removeWindowLw(WindowState win) {
1328        if (mStatusBar == win) {
1329            mStatusBar = null;
1330        } else if (mKeyguard == win) {
1331            mKeyguard = null;
1332        } else if (mNavigationBar == win) {
1333            mNavigationBar = null;
1334        } else {
1335            mStatusBarPanels.remove(win);
1336        }
1337    }
1338
1339    static final boolean PRINT_ANIM = false;
1340
1341    /** {@inheritDoc} */
1342    public int selectAnimationLw(WindowState win, int transit) {
1343        if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
1344              + ": transit=" + transit);
1345        if (transit == TRANSIT_PREVIEW_DONE) {
1346            if (win.hasAppShownWindows()) {
1347                if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
1348                return com.android.internal.R.anim.app_starting_exit;
1349            }
1350        }
1351
1352        return 0;
1353    }
1354
1355    public Animation createForceHideEnterAnimation() {
1356        return AnimationUtils.loadAnimation(mContext,
1357                com.android.internal.R.anim.lock_screen_behind_enter);
1358    }
1359
1360    static ITelephony getTelephonyService() {
1361        ITelephony telephonyService = ITelephony.Stub.asInterface(
1362                ServiceManager.checkService(Context.TELEPHONY_SERVICE));
1363        if (telephonyService == null) {
1364            Log.w(TAG, "Unable to find ITelephony interface.");
1365        }
1366        return telephonyService;
1367    }
1368
1369    static IAudioService getAudioService() {
1370        IAudioService audioService = IAudioService.Stub.asInterface(
1371                ServiceManager.checkService(Context.AUDIO_SERVICE));
1372        if (audioService == null) {
1373            Log.w(TAG, "Unable to find IAudioService interface.");
1374        }
1375        return audioService;
1376    }
1377
1378    boolean keyguardOn() {
1379        return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode();
1380    }
1381
1382    private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
1383            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
1384            WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
1385        };
1386
1387    /** {@inheritDoc} */
1388    @Override
1389    public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
1390        final boolean keyguardOn = keyguardOn();
1391        final int keyCode = event.getKeyCode();
1392        final int repeatCount = event.getRepeatCount();
1393        final int metaState = event.getMetaState();
1394        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
1395        final boolean canceled = event.isCanceled();
1396
1397        if (false) {
1398            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
1399                    + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
1400        }
1401
1402        // First we always handle the home key here, so applications
1403        // can never break it, although if keyguard is on, we do let
1404        // it handle it, because that gives us the correct 5 second
1405        // timeout.
1406        if (keyCode == KeyEvent.KEYCODE_HOME) {
1407            // Clear a pending HOME longpress if the user releases Home
1408            if (!down) {
1409                mHandler.removeCallbacks(mHomeLongPress);
1410            }
1411
1412            // If we have released the home key, and didn't do anything else
1413            // while it was pressed, then it is time to go home!
1414            if (mHomePressed && !down) {
1415                mHomePressed = false;
1416                if (!canceled) {
1417                    // If an incoming call is ringing, HOME is totally disabled.
1418                    // (The user is already on the InCallScreen at this point,
1419                    // and his ONLY options are to answer or reject the call.)
1420                    boolean incomingRinging = false;
1421                    try {
1422                        ITelephony telephonyService = getTelephonyService();
1423                        if (telephonyService != null) {
1424                            incomingRinging = telephonyService.isRinging();
1425                        }
1426                    } catch (RemoteException ex) {
1427                        Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
1428                    }
1429
1430                    if (incomingRinging) {
1431                        Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
1432                    } else {
1433                        launchHomeFromHotKey();
1434                    }
1435                } else {
1436                    Log.i(TAG, "Ignoring HOME; event canceled.");
1437                }
1438                return true;
1439            }
1440
1441            // If a system window has focus, then it doesn't make sense
1442            // right now to interact with applications.
1443            WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
1444            if (attrs != null) {
1445                final int type = attrs.type;
1446                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
1447                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
1448                    // the "app" is keyguard, so give it the key
1449                    return false;
1450                }
1451                final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
1452                for (int i=0; i<typeCount; i++) {
1453                    if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
1454                        // don't do anything, but also don't pass it to the app
1455                        return true;
1456                    }
1457                }
1458            }
1459
1460            if (down && repeatCount == 0) {
1461                if (!keyguardOn) {
1462                    mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
1463                }
1464                mHomePressed = true;
1465            }
1466            return true;
1467        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
1468            // Hijack modified menu keys for debugging features
1469            final int chordBug = KeyEvent.META_SHIFT_ON;
1470
1471            if (down && repeatCount == 0) {
1472                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
1473                    Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
1474                    mContext.sendOrderedBroadcast(intent, null);
1475                    return true;
1476                } else if (SHOW_PROCESSES_ON_ALT_MENU &&
1477                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
1478                    Intent service = new Intent();
1479                    service.setClassName(mContext, "com.android.server.LoadAverageService");
1480                    ContentResolver res = mContext.getContentResolver();
1481                    boolean shown = Settings.System.getInt(
1482                            res, Settings.System.SHOW_PROCESSES, 0) != 0;
1483                    if (!shown) {
1484                        mContext.startService(service);
1485                    } else {
1486                        mContext.stopService(service);
1487                    }
1488                    Settings.System.putInt(
1489                            res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
1490                    return true;
1491                }
1492            }
1493        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
1494            if (down) {
1495                if (repeatCount == 0) {
1496                    mShortcutKeyPressed = keyCode;
1497                    mConsumeShortcutKeyUp = false;
1498                }
1499            } else if (keyCode == mShortcutKeyPressed) {
1500                mShortcutKeyPressed = -1;
1501                if (mConsumeShortcutKeyUp) {
1502                    mConsumeShortcutKeyUp = false;
1503                    return true;
1504                }
1505            }
1506            return false;
1507        } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
1508            if (down && repeatCount == 0) {
1509                showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
1510            }
1511            return true;
1512        }
1513
1514        // Shortcuts are invoked through Search+key, so intercept those here
1515        // Any printing key that is chorded with Search should be consumed
1516        // even if no shortcut was invoked.  This prevents text from being
1517        // inadvertently inserted when using a keyboard that has built-in macro
1518        // shortcut keys (that emit Search+x) and some of them are not registered.
1519        if (mShortcutKeyPressed != -1) {
1520            final KeyCharacterMap kcm = event.getKeyCharacterMap();
1521            if (kcm.isPrintingKey(keyCode)) {
1522                mConsumeShortcutKeyUp = true;
1523                if (down && repeatCount == 0 && !keyguardOn) {
1524                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState);
1525                    if (shortcutIntent != null) {
1526                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1527                        try {
1528                            mContext.startActivity(shortcutIntent);
1529                        } catch (ActivityNotFoundException ex) {
1530                            Slog.w(TAG, "Dropping shortcut key combination because "
1531                                    + "the activity to which it is registered was not found: "
1532                                    + KeyEvent.keyCodeToString(mShortcutKeyPressed)
1533                                    + "+" + KeyEvent.keyCodeToString(keyCode), ex);
1534                        }
1535                    } else {
1536                        Slog.i(TAG, "Dropping unregistered shortcut key combination: "
1537                                + KeyEvent.keyCodeToString(mShortcutKeyPressed)
1538                                + "+" + KeyEvent.keyCodeToString(keyCode));
1539                    }
1540                }
1541                return true;
1542            }
1543        }
1544
1545        return false;
1546    }
1547
1548    /** {@inheritDoc} */
1549    @Override
1550    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
1551        // Note: This method is only called if the initial down was unhandled.
1552        if (DEBUG_FALLBACK) {
1553            Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
1554                    + ", flags=" + event.getFlags()
1555                    + ", keyCode=" + event.getKeyCode()
1556                    + ", scanCode=" + event.getScanCode()
1557                    + ", metaState=" + event.getMetaState()
1558                    + ", repeatCount=" + event.getRepeatCount()
1559                    + ", policyFlags=" + policyFlags);
1560        }
1561
1562        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
1563            final KeyCharacterMap kcm = event.getKeyCharacterMap();
1564            final int keyCode = event.getKeyCode();
1565            final int metaState = event.getMetaState();
1566            final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
1567                    && event.getRepeatCount() == 0;
1568
1569            if (initialDown) {
1570                // Invoke shortcuts using Meta as a fallback.
1571                if ((metaState & KeyEvent.META_META_ON) != 0) {
1572                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
1573                            metaState & ~(KeyEvent.META_META_ON
1574                                    | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
1575                    if (shortcutIntent != null) {
1576                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1577                        try {
1578                            mContext.startActivity(shortcutIntent);
1579                        } catch (ActivityNotFoundException ex) {
1580                            Slog.w(TAG, "Dropping shortcut key combination because "
1581                                    + "the activity to which it is registered was not found: "
1582                                    + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
1583                        }
1584                        return null;
1585                    }
1586                }
1587
1588                // Display task switcher for ALT-TAB or Meta-TAB.
1589                if (keyCode == KeyEvent.KEYCODE_TAB) {
1590                    final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
1591                    if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
1592                            || KeyEvent.metaStateHasModifiers(
1593                                    shiftlessModifiers, KeyEvent.META_META_ON)) {
1594                        showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/);
1595                        return null;
1596                    }
1597                }
1598            }
1599
1600            // Check for fallback actions specified by the key character map.
1601            if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) {
1602                if (DEBUG_FALLBACK) {
1603                    Slog.d(TAG, "Fallback: keyCode=" + mFallbackAction.keyCode
1604                            + " metaState=" + Integer.toHexString(mFallbackAction.metaState));
1605                }
1606
1607                int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
1608                KeyEvent fallbackEvent = KeyEvent.obtain(
1609                        event.getDownTime(), event.getEventTime(),
1610                        event.getAction(), mFallbackAction.keyCode,
1611                        event.getRepeatCount(), mFallbackAction.metaState,
1612                        event.getDeviceId(), event.getScanCode(),
1613                        flags, event.getSource(), null);
1614                int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
1615                if ((actions & ACTION_PASS_TO_USER) != 0) {
1616                    if (!interceptKeyBeforeDispatching(win, fallbackEvent, policyFlags)) {
1617                        if (DEBUG_FALLBACK) {
1618                            Slog.d(TAG, "Performing fallback.");
1619                        }
1620                        return fallbackEvent;
1621                    }
1622                }
1623                fallbackEvent.recycle();
1624            }
1625        }
1626
1627        if (DEBUG_FALLBACK) {
1628            Slog.d(TAG, "No fallback.");
1629        }
1630        return null;
1631    }
1632
1633    private boolean getFallbackAction(KeyCharacterMap kcm, int keyCode, int metaState,
1634            FallbackAction outFallbackAction) {
1635        // Consult the key character map for specific fallback actions.
1636        // For example, map NUMPAD_1 to MOVE_HOME when NUMLOCK is not pressed.
1637        return kcm.getFallbackAction(keyCode, metaState, outFallbackAction);
1638    }
1639
1640    /**
1641     * A home key -> launch home action was detected.  Take the appropriate action
1642     * given the situation with the keyguard.
1643     */
1644    void launchHomeFromHotKey() {
1645        if (mKeyguardMediator.isShowingAndNotHidden()) {
1646            // don't launch home if keyguard showing
1647        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
1648            // when in keyguard restricted mode, must first verify unlock
1649            // before launching home
1650            mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
1651                public void onKeyguardExitResult(boolean success) {
1652                    if (success) {
1653                        try {
1654                            ActivityManagerNative.getDefault().stopAppSwitches();
1655                        } catch (RemoteException e) {
1656                        }
1657                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1658                        startDockOrHome();
1659                    }
1660                }
1661            });
1662        } else {
1663            // no keyguard stuff to worry about, just launch home!
1664            try {
1665                ActivityManagerNative.getDefault().stopAppSwitches();
1666            } catch (RemoteException e) {
1667            }
1668            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1669            startDockOrHome();
1670        }
1671    }
1672
1673    public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
1674        final int fl = attrs.flags;
1675
1676        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1677                == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1678            contentInset.set(mCurLeft, mCurTop,
1679                    (mRestrictedScreenLeft+mRestrictedScreenWidth) - mCurRight,
1680                    (mRestrictedScreenTop+mRestrictedScreenHeight) - mCurBottom);
1681        } else {
1682            contentInset.setEmpty();
1683        }
1684    }
1685
1686    /** {@inheritDoc} */
1687    public void beginLayoutLw(int displayWidth, int displayHeight) {
1688        mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
1689        mUnrestrictedScreenWidth = displayWidth;
1690        mUnrestrictedScreenHeight = displayHeight;
1691        mRestrictedScreenLeft = mRestrictedScreenTop = 0;
1692        mRestrictedScreenWidth = displayWidth;
1693        mRestrictedScreenHeight = displayHeight;
1694        mDockLeft = mContentLeft = mCurLeft = 0;
1695        mDockTop = mContentTop = mCurTop = 0;
1696        mDockRight = mContentRight = mCurRight = displayWidth;
1697        mDockBottom = mContentBottom = mCurBottom = displayHeight;
1698        mDockLayer = 0x10000000;
1699
1700        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
1701        final Rect pf = mTmpParentFrame;
1702        final Rect df = mTmpDisplayFrame;
1703        final Rect vf = mTmpVisibleFrame;
1704        pf.left = df.left = vf.left = mDockLeft;
1705        pf.top = df.top = vf.top = mDockTop;
1706        pf.right = df.right = vf.right = mDockRight;
1707        pf.bottom = df.bottom = vf.bottom = mDockBottom;
1708
1709        // decide where the status bar goes ahead of time
1710        if (mStatusBar != null) {
1711            Rect navr = null;
1712            if (mNavigationBar != null) {
1713                mNavigationBar.computeFrameLw(pf, df, vf, vf);
1714                if (mNavigationBar.isVisibleLw()) {
1715                    navr = mNavigationBar.getFrameLw();
1716
1717                    if (navr.top == 0) {
1718                        // Navigation bar is vertical
1719                        if (mDockLeft == navr.left) {
1720                            mDockLeft = navr.right;
1721                        } else if (mDockRight == navr.right) {
1722                            mDockRight = navr.left;
1723                        }
1724                    } else {
1725                        // Navigation bar horizontal, at bottom
1726                        if (mDockBottom == navr.bottom) {
1727                            mDockBottom = navr.top;
1728                        }
1729                    }
1730                }
1731            }
1732            if (DEBUG_LAYOUT) {
1733                Log.i(TAG, "mNavigationBar frame: " + navr);
1734                Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
1735                            mDockLeft, mDockTop, mDockRight, mDockBottom));
1736            }
1737
1738            // apply navigation bar insets
1739            pf.left = df.left = vf.left = mDockLeft;
1740            pf.top = df.top = vf.top = mDockTop;
1741            pf.right = df.right = vf.right = mDockRight;
1742            pf.bottom = df.bottom = vf.bottom = mDockBottom;
1743
1744            mStatusBar.computeFrameLw(pf, df, vf, vf);
1745
1746            // now, let's consider the navigation bar; if it exists, it must be removed from the
1747            // available screen real estate (like an un-hideable status bar)
1748            if (navr != null) {
1749                if (navr.top == 0) {
1750                    // Navigation bar is vertical
1751                    if (mRestrictedScreenLeft == navr.left) {
1752                        mRestrictedScreenLeft = navr.right;
1753                        mRestrictedScreenWidth -= (navr.right - navr.left);
1754                    } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
1755                        mRestrictedScreenWidth -= (navr.right - navr.left);
1756                    }
1757                } else {
1758                    // Navigation bar horizontal, at bottom
1759                    if ((mRestrictedScreenHeight+mRestrictedScreenTop) == navr.bottom) {
1760                        mRestrictedScreenHeight -= (navr.bottom-navr.top);
1761                    }
1762                }
1763            }
1764
1765            if (mStatusBar.isVisibleLw()) {
1766                // If the status bar is hidden, we don't want to cause
1767                // windows behind it to scroll.
1768                final Rect r = mStatusBar.getFrameLw();
1769                if (mStatusBarCanHide) {
1770                    // Status bar may go away, so the screen area it occupies
1771                    // is available to apps but just covering them when the
1772                    // status bar is visible.
1773                    if (mDockTop == r.top) mDockTop = r.bottom;
1774                    else if (mDockBottom == r.bottom) mDockBottom = r.top;
1775
1776                    mContentTop = mCurTop = mDockTop;
1777                    mContentBottom = mCurBottom = mDockBottom;
1778                    mContentLeft = mCurLeft = mDockLeft;
1779                    mContentRight = mCurRight = mDockRight;
1780
1781                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
1782                        String.format(
1783                            "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
1784                            mDockLeft, mDockTop, mDockRight, mDockBottom,
1785                            mContentLeft, mContentTop, mContentRight, mContentBottom,
1786                            mCurLeft, mCurTop, mCurRight, mCurBottom));
1787                } else {
1788                    // Status bar can't go away; the part of the screen it
1789                    // covers does not exist for anything behind it.
1790                    if (mRestrictedScreenTop == r.top) {
1791                        mRestrictedScreenTop = r.bottom;
1792                        mRestrictedScreenHeight -= (r.bottom-r.top);
1793                    } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
1794                        mRestrictedScreenHeight -= (r.bottom-r.top);
1795                    }
1796
1797                    mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
1798                    mContentBottom = mCurBottom = mDockBottom
1799                            = mRestrictedScreenTop + mRestrictedScreenHeight;
1800                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: ("
1801                            + mRestrictedScreenLeft + ","
1802                            + mRestrictedScreenTop + ","
1803                            + (mRestrictedScreenLeft + mRestrictedScreenWidth) + ","
1804                            + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")");
1805                }
1806            }
1807        }
1808    }
1809
1810    void setAttachedWindowFrames(WindowState win, int fl, int adjust,
1811            WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
1812        if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
1813            // Here's a special case: if this attached window is a panel that is
1814            // above the dock window, and the window it is attached to is below
1815            // the dock window, then the frames we computed for the window it is
1816            // attached to can not be used because the dock is effectively part
1817            // of the underlying window and the attached window is floating on top
1818            // of the whole thing.  So, we ignore the attached window and explicitly
1819            // compute the frames that would be appropriate without the dock.
1820            df.left = cf.left = vf.left = mDockLeft;
1821            df.top = cf.top = vf.top = mDockTop;
1822            df.right = cf.right = vf.right = mDockRight;
1823            df.bottom = cf.bottom = vf.bottom = mDockBottom;
1824        } else {
1825            // The effective display frame of the attached window depends on
1826            // whether it is taking care of insetting its content.  If not,
1827            // we need to use the parent's content frame so that the entire
1828            // window is positioned within that content.  Otherwise we can use
1829            // the display frame and let the attached window take care of
1830            // positioning its content appropriately.
1831            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1832                cf.set(attached.getDisplayFrameLw());
1833            } else {
1834                // If the window is resizing, then we want to base the content
1835                // frame on our attached content frame to resize...  however,
1836                // things can be tricky if the attached window is NOT in resize
1837                // mode, in which case its content frame will be larger.
1838                // Ungh.  So to deal with that, make sure the content frame
1839                // we end up using is not covering the IM dock.
1840                cf.set(attached.getContentFrameLw());
1841                if (attached.getSurfaceLayer() < mDockLayer) {
1842                    if (cf.left < mContentLeft) cf.left = mContentLeft;
1843                    if (cf.top < mContentTop) cf.top = mContentTop;
1844                    if (cf.right > mContentRight) cf.right = mContentRight;
1845                    if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
1846                }
1847            }
1848            df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
1849            vf.set(attached.getVisibleFrameLw());
1850        }
1851        // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
1852        // window should be positioned relative to its parent or the entire
1853        // screen.
1854        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
1855                ? attached.getFrameLw() : df);
1856    }
1857
1858    /** {@inheritDoc} */
1859    public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
1860            WindowState attached) {
1861        // we've already done the status bar
1862        if (win == mStatusBar) {
1863            return;
1864        }
1865
1866        final int fl = attrs.flags;
1867        final int sim = attrs.softInputMode;
1868
1869        final Rect pf = mTmpParentFrame;
1870        final Rect df = mTmpDisplayFrame;
1871        final Rect cf = mTmpContentFrame;
1872        final Rect vf = mTmpVisibleFrame;
1873
1874        final boolean hasNavBar = (mHasNavigationBar
1875                && mNavigationBar != null && mNavigationBar.isVisibleLw());
1876
1877        if (attrs.type == TYPE_INPUT_METHOD) {
1878            pf.left = df.left = cf.left = vf.left = mDockLeft;
1879            pf.top = df.top = cf.top = vf.top = mDockTop;
1880            pf.right = df.right = cf.right = vf.right = mDockRight;
1881            pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
1882            // IM dock windows always go to the bottom of the screen.
1883            attrs.gravity = Gravity.BOTTOM;
1884            mDockLayer = win.getSurfaceLayer();
1885        } else {
1886            final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1887
1888            if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1889                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1890                if (DEBUG_LAYOUT)
1891                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1892                            + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
1893                // This is the case for a normal activity window: we want it
1894                // to cover all of the screen space, and it can take care of
1895                // moving its contents to account for screen decorations that
1896                // intrude into that space.
1897                if (attached != null) {
1898                    // If this window is attached to another, our display
1899                    // frame is the same as the one we are attached to.
1900                    setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
1901                } else {
1902                    if (attrs.type == TYPE_STATUS_BAR_PANEL
1903                            || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
1904                        // Status bar panels are the only windows who can go on top of
1905                        // the status bar.  They are protected by the STATUS_BAR_SERVICE
1906                        // permission, so they have the same privileges as the status
1907                        // bar itself.
1908                        //
1909                        // However, they should still dodge the navigation bar if it exists.
1910
1911                        pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
1912                        pf.top = df.top = mUnrestrictedScreenTop;
1913                        pf.right = df.right = hasNavBar
1914                                            ? mRestrictedScreenLeft+mRestrictedScreenWidth
1915                                            : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
1916                        pf.bottom = df.bottom = hasNavBar
1917                                              ? mRestrictedScreenTop+mRestrictedScreenHeight
1918                                              : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
1919
1920                        if (DEBUG_LAYOUT) {
1921                            Log.v(TAG, String.format(
1922                                        "Laying out status bar window: (%d,%d - %d,%d)",
1923                                        pf.left, pf.top, pf.right, pf.bottom));
1924                        }
1925                    } else {
1926                        pf.left = df.left = mRestrictedScreenLeft;
1927                        pf.top = df.top = mRestrictedScreenTop;
1928                        pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
1929                        pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight;
1930                    }
1931                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1932                        cf.left = mDockLeft;
1933                        cf.top = mDockTop;
1934                        cf.right = mDockRight;
1935                        cf.bottom = mDockBottom;
1936                    } else {
1937                        cf.left = mContentLeft;
1938                        cf.top = mContentTop;
1939                        cf.right = mContentRight;
1940                        cf.bottom = mContentBottom;
1941                    }
1942                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1943                        vf.left = mCurLeft;
1944                        vf.top = mCurTop;
1945                        vf.right = mCurRight;
1946                        vf.bottom = mCurBottom;
1947                    } else {
1948                        vf.set(cf);
1949                    }
1950                }
1951            } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
1952                if (DEBUG_LAYOUT)
1953                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
1954                // A window that has requested to fill the entire screen just
1955                // gets everything, period.
1956                if (attrs.type == TYPE_STATUS_BAR_PANEL
1957                        || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
1958                    pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
1959                    pf.top = df.top = cf.top = mUnrestrictedScreenTop;
1960                    pf.right = df.right = cf.right = hasNavBar
1961                                        ? mRestrictedScreenLeft+mRestrictedScreenWidth
1962                                        : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
1963                    pf.bottom = df.bottom = cf.bottom = hasNavBar
1964                                          ? mRestrictedScreenTop+mRestrictedScreenHeight
1965                                          : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
1966
1967                    if (DEBUG_LAYOUT) {
1968                        Log.v(TAG, String.format(
1969                                    "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
1970                                    pf.left, pf.top, pf.right, pf.bottom));
1971                    }
1972                } else if (attrs.type == TYPE_NAVIGATION_BAR) {
1973                    // The navigation bar has Real Ultimate Power.
1974                    pf.left = df.left = mUnrestrictedScreenLeft;
1975                    pf.top = df.top = mUnrestrictedScreenTop;
1976                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
1977                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
1978                    if (DEBUG_LAYOUT) {
1979                        Log.v(TAG, String.format(
1980                                    "Laying out navigation bar window: (%d,%d - %d,%d)",
1981                                    pf.left, pf.top, pf.right, pf.bottom));
1982                    }
1983                } else {
1984                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
1985                    pf.top = df.top = cf.top = mRestrictedScreenTop;
1986                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
1987                    pf.bottom = df.bottom = cf.bottom
1988                            = mRestrictedScreenTop+mRestrictedScreenHeight;
1989                }
1990                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1991                    vf.left = mCurLeft;
1992                    vf.top = mCurTop;
1993                    vf.right = mCurRight;
1994                    vf.bottom = mCurBottom;
1995                } else {
1996                    vf.set(cf);
1997                }
1998            } else if (attached != null) {
1999                if (DEBUG_LAYOUT)
2000                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
2001                // A child window should be placed inside of the same visible
2002                // frame that its parent had.
2003                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
2004            } else {
2005                if (DEBUG_LAYOUT)
2006                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
2007                // Otherwise, a normal window must be placed inside the content
2008                // of all screen decorations.
2009                if (attrs.type == TYPE_STATUS_BAR_PANEL) {
2010                    // Status bar panels are the only windows who can go on top of
2011                    // the status bar.  They are protected by the STATUS_BAR_SERVICE
2012                    // permission, so they have the same privileges as the status
2013                    // bar itself.
2014                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
2015                    pf.top = df.top = cf.top = mRestrictedScreenTop;
2016                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
2017                    pf.bottom = df.bottom = cf.bottom
2018                            = mRestrictedScreenTop+mRestrictedScreenHeight;
2019                } else {
2020                    pf.left = mContentLeft;
2021                    pf.top = mContentTop;
2022                    pf.right = mContentRight;
2023                    pf.bottom = mContentBottom;
2024                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2025                        df.left = cf.left = mDockLeft;
2026                        df.top = cf.top = mDockTop;
2027                        df.right = cf.right = mDockRight;
2028                        df.bottom = cf.bottom = mDockBottom;
2029                    } else {
2030                        df.left = cf.left = mContentLeft;
2031                        df.top = cf.top = mContentTop;
2032                        df.right = cf.right = mContentRight;
2033                        df.bottom = cf.bottom = mContentBottom;
2034                    }
2035                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2036                        vf.left = mCurLeft;
2037                        vf.top = mCurTop;
2038                        vf.right = mCurRight;
2039                        vf.bottom = mCurBottom;
2040                    } else {
2041                        vf.set(cf);
2042                    }
2043                }
2044            }
2045        }
2046
2047        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
2048            df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
2049            df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2050        }
2051
2052        if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
2053                + ": sim=#" + Integer.toHexString(sim)
2054                + " attach=" + attached + " type=" + attrs.type
2055                + String.format(" flags=0x%08x", fl)
2056                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2057                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
2058
2059        win.computeFrameLw(pf, df, cf, vf);
2060
2061        // Dock windows carve out the bottom of the screen, so normal windows
2062        // can't appear underneath them.
2063        if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
2064            int top = win.getContentFrameLw().top;
2065            top += win.getGivenContentInsetsLw().top;
2066            if (mContentBottom > top) {
2067                mContentBottom = top;
2068            }
2069            top = win.getVisibleFrameLw().top;
2070            top += win.getGivenVisibleInsetsLw().top;
2071            if (mCurBottom > top) {
2072                mCurBottom = top;
2073            }
2074            if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom="
2075                    + mDockBottom + " mContentBottom="
2076                    + mContentBottom + " mCurBottom=" + mCurBottom);
2077        }
2078    }
2079
2080    /** {@inheritDoc} */
2081    public int finishLayoutLw() {
2082        return 0;
2083    }
2084
2085    /** {@inheritDoc} */
2086    public void beginAnimationLw(int displayWidth, int displayHeight) {
2087        mTopFullscreenOpaqueWindowState = null;
2088        mTopAppWindowState = null;
2089        mForceStatusBar = false;
2090
2091        mHideLockScreen = false;
2092        mAllowLockscreenWhenOn = false;
2093        mDismissKeyguard = false;
2094    }
2095
2096    /** {@inheritDoc} */
2097    public void animatingWindowLw(WindowState win,
2098                                WindowManager.LayoutParams attrs) {
2099        if (mTopFullscreenOpaqueWindowState == null &&
2100                win.isVisibleOrBehindKeyguardLw()) {
2101            if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2102                mForceStatusBar = true;
2103            }
2104            if (attrs.type >= FIRST_APPLICATION_WINDOW
2105                    && attrs.type <= LAST_APPLICATION_WINDOW
2106                    && attrs.x == 0 && attrs.y == 0
2107                    && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
2108                    && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
2109                if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
2110                mTopFullscreenOpaqueWindowState = win;
2111                if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
2112                    if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
2113                    mHideLockScreen = true;
2114                }
2115                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
2116                    if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
2117                    mDismissKeyguard = true;
2118                }
2119                if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2120                    mAllowLockscreenWhenOn = true;
2121                }
2122            }
2123        }
2124        if (mTopAppWindowState == null && win.isVisibleOrBehindKeyguardLw()) {
2125            if (attrs.type >= FIRST_APPLICATION_WINDOW
2126                    && attrs.type <= LAST_APPLICATION_WINDOW) {
2127                mTopAppWindowState = win;
2128            }
2129        }
2130    }
2131
2132    /** {@inheritDoc} */
2133    public int finishAnimationLw() {
2134        int changes = 0;
2135        boolean topIsFullscreen = false;
2136
2137        final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null)
2138                ? mTopFullscreenOpaqueWindowState.getAttrs()
2139                : null;
2140
2141        if (mStatusBar != null) {
2142            if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar
2143                    + " top=" + mTopFullscreenOpaqueWindowState);
2144            if (mForceStatusBar) {
2145                if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
2146                if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
2147            } else if (mTopFullscreenOpaqueWindowState != null) {
2148                if (localLOGV) {
2149                    Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
2150                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
2151                    Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2152                            + " lp.flags=0x" + Integer.toHexString(lp.flags));
2153                }
2154                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
2155                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2156                // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
2157                // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
2158                // case though.
2159                if (topIsFullscreen) {
2160                    if (mStatusBarCanHide) {
2161                        if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
2162                        if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
2163                    } else if (localLOGV) {
2164                        Log.v(TAG, "Preventing status bar from hiding by policy");
2165                    }
2166                } else {
2167                    if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
2168                    if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
2169                }
2170            }
2171        }
2172
2173        mTopIsFullscreen = topIsFullscreen;
2174
2175        if (mTopAppWindowState != null && mTopAppWindowState != mLastTopAppWindowState) {
2176            mLastTopAppWindowState = mTopAppWindowState;
2177
2178            final boolean topNeedsMenu = (mTopAppWindowState.getAttrs().flags
2179                    & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
2180
2181            mHandler.post(new Runnable() {
2182                    public void run() {
2183                        if (mStatusBarService == null) {
2184                            // This is the one that can not go away, but it doesn't come up
2185                            // before the window manager does, so don't fail if it doesn't
2186                            // exist. This works as long as no fullscreen windows come up
2187                            // before the status bar service does.
2188                            mStatusBarService = IStatusBarService.Stub.asInterface(
2189                                    ServiceManager.getService("statusbar"));
2190                        }
2191                        final IStatusBarService sbs = mStatusBarService;
2192                        if (mStatusBarService != null) {
2193                            try {
2194                                sbs.topAppWindowChanged(topNeedsMenu);
2195                            } catch (RemoteException e) {
2196                                // This should be impossible because we're in the same process.
2197                                mStatusBarService = null;
2198                            }
2199                        }
2200                    }
2201                });
2202        }
2203
2204        // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
2205        // when the screen is locked
2206        if (mKeyguard != null) {
2207            if (localLOGV) Log.v(TAG, "finishAnimationLw::mHideKeyguard="+mHideLockScreen);
2208            if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
2209                if (mKeyguard.hideLw(true)) {
2210                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2211                            | FINISH_LAYOUT_REDO_CONFIG
2212                            | FINISH_LAYOUT_REDO_WALLPAPER;
2213                }
2214                if (mKeyguardMediator.isShowing()) {
2215                    mHandler.post(new Runnable() {
2216                        public void run() {
2217                            mKeyguardMediator.keyguardDone(false, false);
2218                        }
2219                    });
2220                }
2221            } else if (mHideLockScreen) {
2222                if (mKeyguard.hideLw(true)) {
2223                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2224                            | FINISH_LAYOUT_REDO_CONFIG
2225                            | FINISH_LAYOUT_REDO_WALLPAPER;
2226                }
2227                mKeyguardMediator.setHidden(true);
2228            } else {
2229                if (mKeyguard.showLw(true)) {
2230                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2231                            | FINISH_LAYOUT_REDO_CONFIG
2232                            | FINISH_LAYOUT_REDO_WALLPAPER;
2233                }
2234                mKeyguardMediator.setHidden(false);
2235            }
2236        }
2237
2238        updateSystemUiVisibility();
2239
2240        // update since mAllowLockscreenWhenOn might have changed
2241        updateLockScreenTimeout();
2242        return changes;
2243    }
2244
2245    public boolean allowAppAnimationsLw() {
2246        if (mKeyguard != null && mKeyguard.isVisibleLw()) {
2247            // If keyguard is currently visible, no reason to animate
2248            // behind it.
2249            return false;
2250        }
2251        if (false) {
2252            // Don't do this on the tablet, since the system bar never completely
2253            // covers the screen, and with all its transparency this will
2254            // incorrectly think it does cover it when it doesn't.  We'll revisit
2255            // this later when we re-do the phone status bar.
2256            if (mStatusBar != null && mStatusBar.isVisibleLw()) {
2257                Rect rect = new Rect(mStatusBar.getShownFrameLw());
2258                for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
2259                    WindowState w = mStatusBarPanels.get(i);
2260                    if (w.isVisibleLw()) {
2261                        rect.union(w.getShownFrameLw());
2262                    }
2263                }
2264                final int insetw = mRestrictedScreenWidth/10;
2265                final int inseth = mRestrictedScreenHeight/10;
2266                if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw,
2267                            mRestrictedScreenHeight-inseth)) {
2268                    // All of the status bar windows put together cover the
2269                    // screen, so the app can't be seen.  (Note this test doesn't
2270                    // work if the rects of these windows are at off offsets or
2271                    // sizes, causing gaps in the rect union we have computed.)
2272                    return false;
2273                }
2274            }
2275        }
2276        return true;
2277    }
2278
2279    public void focusChanged(WindowState lastFocus, WindowState newFocus) {
2280        mFocusedWindow = newFocus;
2281        updateSystemUiVisibility();
2282    }
2283
2284    /** {@inheritDoc} */
2285    public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
2286        // lid changed state
2287        mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED;
2288        boolean awakeNow = mKeyguardMediator.doLidChangeTq(lidOpen);
2289        updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2290        if (awakeNow) {
2291            // If the lid is opening and we don't have to keep the
2292            // keyguard up, then we can turn on the screen
2293            // immediately.
2294            mKeyguardMediator.pokeWakelock();
2295        } else if (keyguardIsShowingTq()) {
2296            if (lidOpen) {
2297                // If we are opening the lid and not hiding the
2298                // keyguard, then we need to have it turn on the
2299                // screen once it is shown.
2300                mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
2301                        KeyEvent.KEYCODE_POWER);
2302            }
2303        } else {
2304            // Light up the keyboard if we are sliding up.
2305            if (lidOpen) {
2306                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
2307                        LocalPowerManager.BUTTON_EVENT);
2308            } else {
2309                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
2310                        LocalPowerManager.OTHER_EVENT);
2311            }
2312        }
2313    }
2314
2315    void setHdmiPlugged(boolean plugged) {
2316        if (mHdmiPlugged != plugged) {
2317            mHdmiPlugged = plugged;
2318            updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2319            Intent intent = new Intent(ACTION_HDMI_PLUGGED);
2320            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2321            intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
2322            mContext.sendStickyBroadcast(intent);
2323        }
2324    }
2325
2326    void initializeHdmiState() {
2327        boolean plugged = false;
2328        // watch for HDMI plug messages if the hdmi switch exists
2329        if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
2330            mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
2331
2332            final String filename = "/sys/class/switch/hdmi/state";
2333            FileReader reader = null;
2334            try {
2335                reader = new FileReader(filename);
2336                char[] buf = new char[15];
2337                int n = reader.read(buf);
2338                if (n > 1) {
2339                    plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));
2340                }
2341            } catch (IOException ex) {
2342                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
2343            } catch (NumberFormatException ex) {
2344                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
2345            } finally {
2346                if (reader != null) {
2347                    try {
2348                        reader.close();
2349                    } catch (IOException ex) {
2350                    }
2351                }
2352            }
2353        }
2354        // This dance forces the code in setHdmiPlugged to run.
2355        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
2356        mHdmiPlugged = !plugged;
2357        setHdmiPlugged(!mHdmiPlugged);
2358    }
2359
2360    /**
2361     * @return Whether music is being played right now.
2362     */
2363    boolean isMusicActive() {
2364        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
2365        if (am == null) {
2366            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
2367            return false;
2368        }
2369        return am.isMusicActive();
2370    }
2371
2372    /**
2373     * Tell the audio service to adjust the volume appropriate to the event.
2374     * @param keycode
2375     */
2376    void handleVolumeKey(int stream, int keycode) {
2377        IAudioService audioService = getAudioService();
2378        if (audioService == null) {
2379            return;
2380        }
2381        try {
2382            // since audio is playing, we shouldn't have to hold a wake lock
2383            // during the call, but we do it as a precaution for the rare possibility
2384            // that the music stops right before we call this
2385            // TODO: Actually handle MUTE.
2386            mBroadcastWakeLock.acquire();
2387            audioService.adjustStreamVolume(stream,
2388                keycode == KeyEvent.KEYCODE_VOLUME_UP
2389                            ? AudioManager.ADJUST_RAISE
2390                            : AudioManager.ADJUST_LOWER,
2391                    0);
2392        } catch (RemoteException e) {
2393            Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
2394        } finally {
2395            mBroadcastWakeLock.release();
2396        }
2397    }
2398
2399    private void takeScreenshot() {
2400        mHandler.post(new Runnable() {
2401            @Override
2402            public void run() {
2403                ComponentName cn = new ComponentName("com.android.systemui",
2404                        "com.android.systemui.screenshot.TakeScreenshotService");
2405                Intent intent = new Intent();
2406                intent.setComponent(cn);
2407                ServiceConnection conn = new ServiceConnection() {
2408                    @Override
2409                    public void onServiceConnected(ComponentName name, IBinder service) {}
2410                    @Override
2411                    public void onServiceDisconnected(ComponentName name) {}
2412                };
2413                mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
2414                mContext.unbindService(conn);
2415            }
2416        });
2417    }
2418
2419    /** {@inheritDoc} */
2420    @Override
2421    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
2422        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
2423        final boolean canceled = event.isCanceled();
2424        final int keyCode = event.getKeyCode();
2425
2426        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
2427
2428        // If screen is off then we treat the case where the keyguard is open but hidden
2429        // the same as if it were open and in front.
2430        // This will prevent any keys other than the power button from waking the screen
2431        // when the keyguard is hidden by another activity.
2432        final boolean keyguardActive = (isScreenOn ?
2433                                        mKeyguardMediator.isShowingAndNotHidden() :
2434                                        mKeyguardMediator.isShowing());
2435
2436        if (false) {
2437            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
2438                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
2439        }
2440
2441        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
2442            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
2443        }
2444
2445        // Basic policy based on screen state and keyguard.
2446        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
2447        //        is on or off, really.  We should care about whether the device is in an
2448        //        interactive state or is in suspend pretending to be "off".
2449        //        The primary screen might be turned off due to proximity sensor or
2450        //        because we are presenting media on an auxiliary screen or remotely controlling
2451        //        the device some other way (which is why we have an exemption here for injected
2452        //        events).
2453        int result;
2454        if (isScreenOn || isInjected) {
2455            // When the screen is on or if the key is injected pass the key to the application.
2456            result = ACTION_PASS_TO_USER;
2457        } else {
2458            // When the screen is off and the key is not injected, determine whether
2459            // to wake the device but don't pass the key to the application.
2460            result = 0;
2461
2462            final boolean isWakeKey = (policyFlags
2463                    & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
2464            if (down && isWakeKey) {
2465                if (keyguardActive) {
2466                    // If the keyguard is showing, let it decide what to do with the wake key.
2467                    mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
2468                } else {
2469                    // Otherwise, wake the device ourselves.
2470                    result |= ACTION_POKE_USER_ACTIVITY;
2471                }
2472            }
2473        }
2474
2475        // Handle special keys.
2476        switch (keyCode) {
2477            case KeyEvent.KEYCODE_VOLUME_DOWN:
2478                if (down) {
2479                    if (isScreenOn) {
2480                        // If the power key down was already triggered, take the screenshot
2481                        if (mPowerDownTriggered) {
2482                            // Dismiss the power-key longpress
2483                            mHandler.removeCallbacks(mPowerLongPress);
2484                            mPowerKeyHandled = true;
2485
2486                            // Take the screenshot
2487                            takeScreenshot();
2488
2489                            // Prevent the event from being passed through to the current activity
2490                            result &= ~ACTION_PASS_TO_USER;
2491                            break;
2492                        }
2493                        mVolumeDownTriggered = true;
2494                    }
2495                } else {
2496                    mVolumeDownTriggered = false;
2497                }
2498            case KeyEvent.KEYCODE_VOLUME_UP:
2499            case KeyEvent.KEYCODE_VOLUME_MUTE: {
2500                if (down) {
2501                    ITelephony telephonyService = getTelephonyService();
2502                    if (telephonyService != null) {
2503                        try {
2504                            if (telephonyService.isRinging()) {
2505                                // If an incoming call is ringing, either VOLUME key means
2506                                // "silence ringer".  We handle these keys here, rather than
2507                                // in the InCallScreen, to make sure we'll respond to them
2508                                // even if the InCallScreen hasn't come to the foreground yet.
2509                                // Look for the DOWN event here, to agree with the "fallback"
2510                                // behavior in the InCallScreen.
2511                                Log.i(TAG, "interceptKeyBeforeQueueing:"
2512                                      + " VOLUME key-down while ringing: Silence ringer!");
2513
2514                                // Silence the ringer.  (It's safe to call this
2515                                // even if the ringer has already been silenced.)
2516                                telephonyService.silenceRinger();
2517
2518                                // And *don't* pass this key thru to the current activity
2519                                // (which is probably the InCallScreen.)
2520                                result &= ~ACTION_PASS_TO_USER;
2521                                break;
2522                            }
2523                            if (telephonyService.isOffhook()
2524                                    && (result & ACTION_PASS_TO_USER) == 0) {
2525                                // If we are in call but we decided not to pass the key to
2526                                // the application, handle the volume change here.
2527                                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
2528                                break;
2529                            }
2530                        } catch (RemoteException ex) {
2531                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2532                        }
2533                    }
2534
2535                    if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
2536                        // If music is playing but we decided not to pass the key to the
2537                        // application, handle the volume change here.
2538                        handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
2539                        break;
2540                    }
2541                }
2542                break;
2543            }
2544
2545            case KeyEvent.KEYCODE_ENDCALL: {
2546                result &= ~ACTION_PASS_TO_USER;
2547                if (down) {
2548                    ITelephony telephonyService = getTelephonyService();
2549                    boolean hungUp = false;
2550                    if (telephonyService != null) {
2551                        try {
2552                            hungUp = telephonyService.endCall();
2553                        } catch (RemoteException ex) {
2554                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2555                        }
2556                    }
2557                    interceptPowerKeyDown(!isScreenOn || hungUp);
2558                } else {
2559                    if (interceptPowerKeyUp(canceled)) {
2560                        if ((mEndcallBehavior
2561                                & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
2562                            if (goHome()) {
2563                                break;
2564                            }
2565                        }
2566                        if ((mEndcallBehavior
2567                                & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
2568                            result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
2569                        }
2570                    }
2571                }
2572                break;
2573            }
2574
2575            case KeyEvent.KEYCODE_POWER: {
2576                result &= ~ACTION_PASS_TO_USER;
2577                if (down) {
2578                    if (isScreenOn) {
2579                        // If the volume down key has been triggered, then just take the screenshot
2580                        if (mVolumeDownTriggered) {
2581                            // Take the screenshot
2582                            takeScreenshot();
2583                            mPowerKeyHandled = true;
2584
2585                            // Prevent the event from being passed through to the current activity
2586                            break;
2587                        }
2588                        mPowerDownTriggered = true;
2589                    }
2590
2591                    ITelephony telephonyService = getTelephonyService();
2592                    boolean hungUp = false;
2593                    if (telephonyService != null) {
2594                        try {
2595                            if (telephonyService.isRinging()) {
2596                                // Pressing Power while there's a ringing incoming
2597                                // call should silence the ringer.
2598                                telephonyService.silenceRinger();
2599                            } else if ((mIncallPowerBehavior
2600                                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
2601                                    && telephonyService.isOffhook()) {
2602                                // Otherwise, if "Power button ends call" is enabled,
2603                                // the Power button will hang up any current active call.
2604                                hungUp = telephonyService.endCall();
2605                            }
2606                        } catch (RemoteException ex) {
2607                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2608                        }
2609                    }
2610                    interceptPowerKeyDown(!isScreenOn || hungUp);
2611                } else {
2612                    mPowerDownTriggered = false;
2613                    if (interceptPowerKeyUp(canceled)) {
2614                        result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
2615                    }
2616                }
2617                break;
2618            }
2619
2620            case KeyEvent.KEYCODE_MEDIA_PLAY:
2621            case KeyEvent.KEYCODE_MEDIA_PAUSE:
2622            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
2623                if (down) {
2624                    ITelephony telephonyService = getTelephonyService();
2625                    if (telephonyService != null) {
2626                        try {
2627                            if (!telephonyService.isIdle()) {
2628                                // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
2629                                // to avoid music playback.
2630                                break;
2631                            }
2632                        } catch (RemoteException ex) {
2633                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2634                        }
2635                    }
2636                }
2637            case KeyEvent.KEYCODE_HEADSETHOOK:
2638            case KeyEvent.KEYCODE_MUTE:
2639            case KeyEvent.KEYCODE_MEDIA_STOP:
2640            case KeyEvent.KEYCODE_MEDIA_NEXT:
2641            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
2642            case KeyEvent.KEYCODE_MEDIA_REWIND:
2643            case KeyEvent.KEYCODE_MEDIA_RECORD:
2644            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
2645                if ((result & ACTION_PASS_TO_USER) == 0) {
2646                    // Only do this if we would otherwise not pass it to the user. In that
2647                    // case, the PhoneWindow class will do the same thing, except it will
2648                    // only do it if the showing app doesn't process the key on its own.
2649                    mBroadcastWakeLock.acquire();
2650                    mHandler.post(new PassHeadsetKey(new KeyEvent(event)));
2651                }
2652                break;
2653            }
2654
2655            case KeyEvent.KEYCODE_CALL: {
2656                if (down) {
2657                    ITelephony telephonyService = getTelephonyService();
2658                    if (telephonyService != null) {
2659                        try {
2660                            if (telephonyService.isRinging()) {
2661                                Log.i(TAG, "interceptKeyBeforeQueueing:"
2662                                      + " CALL key-down while ringing: Answer the call!");
2663                                telephonyService.answerRingingCall();
2664
2665                                // And *don't* pass this key thru to the current activity
2666                                // (which is presumably the InCallScreen.)
2667                                result &= ~ACTION_PASS_TO_USER;
2668                            }
2669                        } catch (RemoteException ex) {
2670                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2671                        }
2672                    }
2673                }
2674                break;
2675            }
2676        }
2677        return result;
2678    }
2679
2680    /** {@inheritDoc} */
2681    @Override
2682    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
2683        int result = 0;
2684
2685        final boolean isWakeMotion = (policyFlags
2686                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
2687        if (isWakeMotion) {
2688            if (mKeyguardMediator.isShowing()) {
2689                // If the keyguard is showing, let it decide what to do with the wake motion.
2690                mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
2691            } else {
2692                // Otherwise, wake the device ourselves.
2693                result |= ACTION_POKE_USER_ACTIVITY;
2694            }
2695        }
2696        return result;
2697    }
2698
2699    class PassHeadsetKey implements Runnable {
2700        KeyEvent mKeyEvent;
2701
2702        PassHeadsetKey(KeyEvent keyEvent) {
2703            mKeyEvent = keyEvent;
2704        }
2705
2706        public void run() {
2707            if (ActivityManagerNative.isSystemReady()) {
2708                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
2709                intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
2710                mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
2711                        mHandler, Activity.RESULT_OK, null, null);
2712            }
2713        }
2714    }
2715
2716    BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
2717        public void onReceive(Context context, Intent intent) {
2718            mBroadcastWakeLock.release();
2719        }
2720    };
2721
2722    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
2723        public void onReceive(Context context, Intent intent) {
2724            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
2725                mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
2726                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
2727            } else {
2728                try {
2729                    IUiModeManager uiModeService = IUiModeManager.Stub.asInterface(
2730                            ServiceManager.getService(Context.UI_MODE_SERVICE));
2731                    mUiMode = uiModeService.getCurrentModeType();
2732                } catch (RemoteException e) {
2733                }
2734            }
2735            updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2736            updateOrientationListenerLp();
2737        }
2738    };
2739
2740    /** {@inheritDoc} */
2741    public void screenTurnedOff(int why) {
2742        EventLog.writeEvent(70000, 0);
2743        mKeyguardMediator.onScreenTurnedOff(why);
2744        synchronized (mLock) {
2745            mScreenOn = false;
2746            updateOrientationListenerLp();
2747            updateLockScreenTimeout();
2748            updateScreenSaverTimeoutLocked();
2749        }
2750    }
2751
2752    /** {@inheritDoc} */
2753    public void screenTurnedOn() {
2754        EventLog.writeEvent(70000, 1);
2755        mKeyguardMediator.onScreenTurnedOn();
2756        synchronized (mLock) {
2757            mScreenOn = true;
2758            updateOrientationListenerLp();
2759            updateLockScreenTimeout();
2760            updateScreenSaverTimeoutLocked();
2761        }
2762    }
2763
2764    /** {@inheritDoc} */
2765    public boolean isScreenOn() {
2766        return mScreenOn;
2767    }
2768
2769    /** {@inheritDoc} */
2770    public void enableKeyguard(boolean enabled) {
2771        mKeyguardMediator.setKeyguardEnabled(enabled);
2772    }
2773
2774    /** {@inheritDoc} */
2775    public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
2776        mKeyguardMediator.verifyUnlock(callback);
2777    }
2778
2779    private boolean keyguardIsShowingTq() {
2780        return mKeyguardMediator.isShowingAndNotHidden();
2781    }
2782
2783
2784    /** {@inheritDoc} */
2785    public boolean isKeyguardLocked() {
2786        return keyguardOn();
2787    }
2788
2789    /** {@inheritDoc} */
2790    public boolean isKeyguardSecure() {
2791        return mKeyguardMediator.isSecure();
2792    }
2793
2794    /** {@inheritDoc} */
2795    public boolean inKeyguardRestrictedKeyInputMode() {
2796        return mKeyguardMediator.isInputRestricted();
2797    }
2798
2799    void sendCloseSystemWindows() {
2800        sendCloseSystemWindows(mContext, null);
2801    }
2802
2803    void sendCloseSystemWindows(String reason) {
2804        sendCloseSystemWindows(mContext, reason);
2805    }
2806
2807    static void sendCloseSystemWindows(Context context, String reason) {
2808        if (ActivityManagerNative.isSystemReady()) {
2809            try {
2810                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
2811            } catch (RemoteException e) {
2812            }
2813        }
2814    }
2815
2816    public int rotationForOrientationLw(int orientation, int lastRotation,
2817            boolean displayEnabled) {
2818
2819        if (false) {
2820            Slog.v(TAG, "rotationForOrientationLw(orient="
2821                        + orientation + ", last=" + lastRotation
2822                        + "); user=" + mUserRotation + " "
2823                        + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
2824                            ? "USER_ROTATION_LOCKED" : "")
2825                        );
2826        }
2827
2828        synchronized (mLock) {
2829            switch (orientation) {
2830                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
2831                    //always return portrait if orientation set to portrait
2832                    return mPortraitRotation;
2833                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
2834                    //always return landscape if orientation set to landscape
2835                    return mLandscapeRotation;
2836                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
2837                    //always return portrait if orientation set to portrait
2838                    return mUpsideDownRotation;
2839                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
2840                    //always return seascape if orientation set to reverse landscape
2841                    return mSeascapeRotation;
2842                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
2843                    //return either landscape rotation based on the sensor
2844                    return getCurrentLandscapeRotation(lastRotation);
2845                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
2846                    return getCurrentPortraitRotation(lastRotation);
2847            }
2848
2849            // case for nosensor meaning ignore sensor and consider only lid
2850            // or orientation sensor disabled
2851            //or case.unspecified
2852            if (mHdmiPlugged) {
2853                return mLandscapeRotation;
2854            } else if (mLidOpen == LID_OPEN) {
2855                return mLidOpenRotation;
2856            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
2857                return mCarDockRotation;
2858            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
2859                return mDeskDockRotation;
2860            } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
2861                return mUserRotation;
2862            } else {
2863                if (useSensorForOrientationLp(orientation)) {
2864                    // Disable 180 degree rotation unless allowed by default for the device
2865                    // or explicitly requested by the application.
2866                    int rotation = mOrientationListener.getCurrentRotation(lastRotation);
2867                    if (rotation == Surface.ROTATION_180
2868                            && !mAllowAllRotations
2869                            && orientation != ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR) {
2870                        return lastRotation;
2871                    }
2872                    return rotation;
2873                }
2874                return Surface.ROTATION_0;
2875            }
2876        }
2877    }
2878
2879    public int getLockedRotationLw() {
2880        synchronized (mLock) {
2881            if (false) {
2882                // Not yet working.
2883                if (mHdmiPlugged) {
2884                    return Surface.ROTATION_0;
2885                } else if (mLidOpen == LID_OPEN) {
2886                    return mLidOpenRotation;
2887                } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
2888                    return mCarDockRotation;
2889                } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
2890                    return mDeskDockRotation;
2891                } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
2892                    return mUserRotation;
2893                }
2894            }
2895            return -1;
2896        }
2897    }
2898
2899    private int getCurrentLandscapeRotation(int lastRotation) {
2900        // if the user has locked rotation, we ignore the sensor
2901        if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
2902            if (isLandscapeOrSeascape(mUserRotation)) {
2903                return mUserRotation;
2904            } else {
2905                // it seems odd to obey the sensor at all if rotation lock is enabled
2906                return mLandscapeRotation;
2907            }
2908        }
2909
2910        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
2911        if (isLandscapeOrSeascape(sensorRotation)) {
2912            return sensorRotation;
2913        }
2914        // try to preserve the old rotation if it was landscape
2915        if (isLandscapeOrSeascape(lastRotation)) {
2916            return lastRotation;
2917        }
2918        // default to one of the primary landscape rotation
2919        return mLandscapeRotation;
2920    }
2921
2922    private boolean isLandscapeOrSeascape(int sensorRotation) {
2923        return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation;
2924    }
2925
2926    private int getCurrentPortraitRotation(int lastRotation) {
2927        // if the user has locked rotation, we ignore the sensor
2928        if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
2929            if (isAnyPortrait(mUserRotation)) {
2930                return mUserRotation;
2931            } else {
2932                // it seems odd to obey the sensor at all if rotation lock is enabled
2933                return mPortraitRotation;
2934            }
2935        }
2936
2937        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
2938        if (isAnyPortrait(sensorRotation)) {
2939            return sensorRotation;
2940        }
2941        // try to preserve the old rotation if it was portrait
2942        if (isAnyPortrait(lastRotation)) {
2943            return lastRotation;
2944        }
2945        // default to one of the primary portrait rotations
2946        return mPortraitRotation;
2947    }
2948
2949    private boolean isAnyPortrait(int sensorRotation) {
2950        return sensorRotation == mPortraitRotation || sensorRotation == mUpsideDownRotation;
2951    }
2952
2953
2954    // User rotation: to be used when all else fails in assigning an orientation to the device
2955    public void setUserRotationMode(int mode, int rot) {
2956        ContentResolver res = mContext.getContentResolver();
2957
2958        // mUserRotationMode and mUserRotation will be assigned by the content observer
2959        if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
2960            Settings.System.putInt(res,
2961                    Settings.System.USER_ROTATION,
2962                    rot);
2963            Settings.System.putInt(res,
2964                    Settings.System.ACCELEROMETER_ROTATION,
2965                    0);
2966        } else {
2967            Settings.System.putInt(res,
2968                    Settings.System.ACCELEROMETER_ROTATION,
2969                    1);
2970        }
2971    }
2972
2973    public boolean detectSafeMode() {
2974        try {
2975            int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
2976            int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
2977            int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
2978            int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE);
2979            int volumeDownState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_VOLUME_DOWN);
2980            mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
2981                    || volumeDownState > 0;
2982            performHapticFeedbackLw(null, mSafeMode
2983                    ? HapticFeedbackConstants.SAFE_MODE_ENABLED
2984                    : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
2985            if (mSafeMode) {
2986                Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
2987                        + " dpad=" + dpadState + " trackball=" + trackballState + ")");
2988            } else {
2989                Log.i(TAG, "SAFE MODE not enabled");
2990            }
2991            return mSafeMode;
2992        } catch (RemoteException e) {
2993            // Doom! (it's also local)
2994            throw new RuntimeException("window manager dead");
2995        }
2996    }
2997
2998    static long[] getLongIntArray(Resources r, int resid) {
2999        int[] ar = r.getIntArray(resid);
3000        if (ar == null) {
3001            return null;
3002        }
3003        long[] out = new long[ar.length];
3004        for (int i=0; i<ar.length; i++) {
3005            out[i] = ar[i];
3006        }
3007        return out;
3008    }
3009
3010    /** {@inheritDoc} */
3011    public void systemReady() {
3012        // tell the keyguard
3013        mKeyguardMediator.onSystemReady();
3014        android.os.SystemProperties.set("dev.bootcomplete", "1");
3015        synchronized (mLock) {
3016            updateOrientationListenerLp();
3017            mSystemReady = true;
3018            mHandler.post(new Runnable() {
3019                public void run() {
3020                    updateSettings();
3021                }
3022            });
3023        }
3024    }
3025
3026    /** {@inheritDoc} */
3027    public void userActivity() {
3028        synchronized (mScreenLockTimeout) {
3029            if (mLockScreenTimerActive) {
3030                // reset the timer
3031                mHandler.removeCallbacks(mScreenLockTimeout);
3032                mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
3033            }
3034        }
3035
3036        if (mStatusBarService != null) {
3037            try {
3038                mStatusBarService.userActivity();
3039            } catch (RemoteException ex) {}
3040        }
3041
3042        synchronized (mLock) {
3043            updateScreenSaverTimeoutLocked();
3044        }
3045    }
3046
3047    Runnable mScreenSaverActivator = null;
3048    /*new Runnable() {
3049        public void run() {
3050            synchronized (this) {
3051                if (!(mScreenSaverEnabled && mScreenOn)) {
3052                    Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?");
3053                    return;
3054                }
3055
3056                if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland");
3057                try {
3058                    String component = Settings.System.getString(
3059                            mContext.getContentResolver(), Settings.Secure.DREAM_COMPONENT);
3060                    if (component != null) {
3061                        ComponentName cn = ComponentName.unflattenFromString(component);
3062                        Intent intent = new Intent(Intent.ACTION_MAIN)
3063                            .setComponent(cn)
3064                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
3065                                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
3066                                | Intent.FLAG_ACTIVITY_NO_USER_ACTION
3067                                | Intent.FLAG_ACTIVITY_SINGLE_TOP);
3068                        mContext.startActivity(intent);
3069                    } else {
3070                        Log.e(TAG, "Couldn't start screen saver: none selected");
3071                    }
3072                } catch (android.content.ActivityNotFoundException exc) {
3073                    // no screensaver? give up
3074                    Log.e(TAG, "Couldn't start screen saver: none installed");
3075                }
3076            }
3077        }
3078    };
3079    */
3080
3081    // Must call while holding mLock
3082    private void updateScreenSaverTimeoutLocked() {
3083        if (mScreenSaverActivator == null) return;
3084
3085        synchronized (mScreenSaverActivator) {
3086            mHandler.removeCallbacks(mScreenSaverActivator);
3087            if (mScreenSaverEnabled && mScreenOn && mScreenSaverTimeout > 0) {
3088                if (localLOGV)
3089                    Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now");
3090                mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout);
3091            } else {
3092                if (localLOGV) {
3093                    if (mScreenSaverTimeout == 0)
3094                        Log.v(TAG, "screen saver disabled by user");
3095                    else if (!mScreenOn)
3096                        Log.v(TAG, "screen saver disabled while screen off");
3097                    else
3098                        Log.v(TAG, "screen saver disabled by wakelock");
3099                }
3100            }
3101        }
3102    }
3103
3104    Runnable mScreenLockTimeout = new Runnable() {
3105        public void run() {
3106            synchronized (this) {
3107                if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
3108                mKeyguardMediator.doKeyguardTimeout();
3109                mLockScreenTimerActive = false;
3110            }
3111        }
3112    };
3113
3114    private void updateLockScreenTimeout() {
3115        synchronized (mScreenLockTimeout) {
3116            boolean enable = (mAllowLockscreenWhenOn && mScreenOn && mKeyguardMediator.isSecure());
3117            if (mLockScreenTimerActive != enable) {
3118                if (enable) {
3119                    if (localLOGV) Log.v(TAG, "setting lockscreen timer");
3120                    mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
3121                } else {
3122                    if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
3123                    mHandler.removeCallbacks(mScreenLockTimeout);
3124                }
3125                mLockScreenTimerActive = enable;
3126            }
3127        }
3128    }
3129
3130    /** {@inheritDoc} */
3131    public void enableScreenAfterBoot() {
3132        readLidState();
3133        updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
3134    }
3135
3136    void updateRotation(int animFlags) {
3137        mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN);
3138        int rotation = Surface.ROTATION_0;
3139        if (mHdmiPlugged) {
3140            rotation = Surface.ROTATION_0;
3141        } else if (mLidOpen == LID_OPEN) {
3142            rotation = mLidOpenRotation;
3143        } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
3144            rotation = mCarDockRotation;
3145        } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
3146            rotation = mDeskDockRotation;
3147        }
3148        //if lid is closed orientation will be portrait
3149        try {
3150            //set orientation on WindowManager
3151            mWindowManager.setRotation(rotation, true,
3152                    mFancyRotationAnimation | animFlags);
3153        } catch (RemoteException e) {
3154            // Ignore
3155        }
3156    }
3157
3158    /**
3159     * Return an Intent to launch the currently active dock as home.  Returns
3160     * null if the standard home should be launched.
3161     * @return
3162     */
3163    Intent createHomeDockIntent() {
3164        Intent intent;
3165
3166        // What home does is based on the mode, not the dock state.  That
3167        // is, when in car mode you should be taken to car home regardless
3168        // of whether we are actually in a car dock.
3169        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
3170            intent = mCarDockIntent;
3171        } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) {
3172            intent = mDeskDockIntent;
3173        } else {
3174            return null;
3175        }
3176
3177        ActivityInfo ai = intent.resolveActivityInfo(
3178                mContext.getPackageManager(), PackageManager.GET_META_DATA);
3179        if (ai == null) {
3180            return null;
3181        }
3182
3183        if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
3184            intent = new Intent(intent);
3185            intent.setClassName(ai.packageName, ai.name);
3186            return intent;
3187        }
3188
3189        return null;
3190    }
3191
3192    void startDockOrHome() {
3193        Intent dock = createHomeDockIntent();
3194        if (dock != null) {
3195            try {
3196                mContext.startActivity(dock);
3197                return;
3198            } catch (ActivityNotFoundException e) {
3199            }
3200        }
3201        mContext.startActivity(mHomeIntent);
3202    }
3203
3204    /**
3205     * goes to the home screen
3206     * @return whether it did anything
3207     */
3208    boolean goHome() {
3209        if (false) {
3210            // This code always brings home to the front.
3211            try {
3212                ActivityManagerNative.getDefault().stopAppSwitches();
3213            } catch (RemoteException e) {
3214            }
3215            sendCloseSystemWindows();
3216            startDockOrHome();
3217        } else {
3218            // This code brings home to the front or, if it is already
3219            // at the front, puts the device to sleep.
3220            try {
3221                if (SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1) {
3222                    /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry.
3223                    Log.d(TAG, "UTS-TEST-MODE");
3224                } else {
3225                    ActivityManagerNative.getDefault().stopAppSwitches();
3226                    sendCloseSystemWindows();
3227                    Intent dock = createHomeDockIntent();
3228                    if (dock != null) {
3229                        int result = ActivityManagerNative.getDefault()
3230                                .startActivity(null, dock,
3231                                        dock.resolveTypeIfNeeded(mContext.getContentResolver()),
3232                                        null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
3233                        if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
3234                            return false;
3235                        }
3236                    }
3237                }
3238                int result = ActivityManagerNative.getDefault()
3239                        .startActivity(null, mHomeIntent,
3240                                mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
3241                                null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
3242                if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
3243                    return false;
3244                }
3245            } catch (RemoteException ex) {
3246                // bummer, the activity manager, which is in this process, is dead
3247            }
3248        }
3249        return true;
3250    }
3251
3252    public void setCurrentOrientationLw(int newOrientation) {
3253        synchronized (mLock) {
3254            if (newOrientation != mCurrentAppOrientation) {
3255                mCurrentAppOrientation = newOrientation;
3256                updateOrientationListenerLp();
3257            }
3258        }
3259    }
3260
3261    public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
3262        final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(),
3263                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0;
3264        if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) {
3265            return false;
3266        }
3267        long[] pattern = null;
3268        switch (effectId) {
3269            case HapticFeedbackConstants.LONG_PRESS:
3270                pattern = mLongPressVibePattern;
3271                break;
3272            case HapticFeedbackConstants.VIRTUAL_KEY:
3273                pattern = mVirtualKeyVibePattern;
3274                break;
3275            case HapticFeedbackConstants.KEYBOARD_TAP:
3276                pattern = mKeyboardTapVibePattern;
3277                break;
3278            case HapticFeedbackConstants.SAFE_MODE_DISABLED:
3279                pattern = mSafeModeDisabledVibePattern;
3280                break;
3281            case HapticFeedbackConstants.SAFE_MODE_ENABLED:
3282                pattern = mSafeModeEnabledVibePattern;
3283                break;
3284            default:
3285                return false;
3286        }
3287        if (pattern.length == 1) {
3288            // One-shot vibration
3289            mVibrator.vibrate(pattern[0]);
3290        } else {
3291            // Pattern vibration
3292            mVibrator.vibrate(pattern, -1);
3293        }
3294        return true;
3295    }
3296
3297    public void screenOnStartedLw() {
3298        // The window manager has just grabbed a wake lock. This is our cue to disable the screen
3299        // saver.
3300        synchronized (mLock) {
3301            mScreenSaverEnabled = false;
3302        }
3303    }
3304
3305    public void screenOnStoppedLw() {
3306        if (mPowerManager.isScreenOn()) {
3307            if (!mKeyguardMediator.isShowingAndNotHidden()) {
3308                long curTime = SystemClock.uptimeMillis();
3309                mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
3310            }
3311
3312            synchronized (mLock) {
3313                // even if the keyguard is up, now that all the wakelocks have been released, we
3314                // should re-enable the screen saver
3315                mScreenSaverEnabled = true;
3316                updateScreenSaverTimeoutLocked();
3317            }
3318        }
3319    }
3320
3321    public boolean allowKeyRepeat() {
3322        // disable key repeat when screen is off
3323        return mScreenOn;
3324    }
3325
3326    private void updateSystemUiVisibility() {
3327        // If there is no window focused, there will be nobody to handle the events
3328        // anyway, so just hang on in whatever state we're in until things settle down.
3329        if (mFocusedWindow != null) {
3330            final WindowManager.LayoutParams params = mFocusedWindow.getAttrs();
3331            final int visibility = params.systemUiVisibility | params.subtreeSystemUiVisibility;
3332            mHandler.post(new Runnable() {
3333                    public void run() {
3334                        if (mStatusBarService == null) {
3335                            mStatusBarService = IStatusBarService.Stub.asInterface(
3336                                    ServiceManager.getService("statusbar"));
3337                        }
3338                        if (mStatusBarService != null) {
3339                            // need to assume status bar privileges to invoke lights on
3340                            long origId = Binder.clearCallingIdentity();
3341                            try {
3342                                mStatusBarService.setSystemUiVisibility(visibility);
3343                            } catch (RemoteException e) {
3344                                // not much to be done
3345                                mStatusBarService = null;
3346                            } finally {
3347                                Binder.restoreCallingIdentity(origId);
3348                            }
3349                        }
3350                    }
3351                });
3352        }
3353    }
3354
3355    public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
3356        pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
3357                pw.print(" mSystemRead="); pw.println(mSystemReady);
3358        pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
3359                pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
3360                pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
3361        pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
3362                pw.print(" mDockMode="); pw.print(mDockMode);
3363                pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
3364                pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation);
3365        pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode);
3366                pw.print(" mUserRotation="); pw.print(mUserRotation);
3367                pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations);
3368        pw.print(prefix); pw.print("mAccelerometerDefault="); pw.print(mAccelerometerDefault);
3369                pw.print(" mCurrentAppOrientation="); pw.println(mCurrentAppOrientation);
3370        pw.print(prefix); pw.print("mCarDockEnablesAccelerometer=");
3371                pw.print(mCarDockEnablesAccelerometer);
3372                pw.print(" mDeskDockEnablesAccelerometer=");
3373                pw.println(mDeskDockEnablesAccelerometer);
3374        pw.print(prefix); pw.print("mLidKeyboardAccessibility=");
3375                pw.print(mLidKeyboardAccessibility);
3376                pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility);
3377                pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
3378        pw.print(prefix); pw.print("mScreenOn="); pw.print(mScreenOn);
3379                pw.print(" mOrientationSensorEnabled="); pw.print(mOrientationSensorEnabled);
3380                pw.print(" mHasSoftInput="); pw.println(mHasSoftInput);
3381        pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
3382                pw.print(","); pw.print(mUnrestrictedScreenTop);
3383                pw.print(") "); pw.print(mUnrestrictedScreenWidth);
3384                pw.print("x"); pw.println(mUnrestrictedScreenHeight);
3385        pw.print(prefix); pw.print("mRestrictedScreen=("); pw.print(mRestrictedScreenLeft);
3386                pw.print(","); pw.print(mRestrictedScreenTop);
3387                pw.print(") "); pw.print(mRestrictedScreenWidth);
3388                pw.print("x"); pw.println(mRestrictedScreenHeight);
3389        pw.print(prefix); pw.print("mCur=("); pw.print(mCurLeft);
3390                pw.print(","); pw.print(mCurTop);
3391                pw.print(")-("); pw.print(mCurRight);
3392                pw.print(","); pw.print(mCurBottom); pw.println(")");
3393        pw.print(prefix); pw.print("mContent=("); pw.print(mContentLeft);
3394                pw.print(","); pw.print(mContentTop);
3395                pw.print(")-("); pw.print(mContentRight);
3396                pw.print(","); pw.print(mContentBottom); pw.println(")");
3397        pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft);
3398                pw.print(","); pw.print(mDockTop);
3399                pw.print(")-("); pw.print(mDockRight);
3400                pw.print(","); pw.print(mDockBottom); pw.println(")");
3401        pw.print(prefix); pw.print("mDockLayer="); pw.println(mDockLayer);
3402        pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3403                pw.println(mTopFullscreenOpaqueWindowState);
3404        pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3405                pw.print(" mForceStatusBar="); pw.print(mForceStatusBar);
3406                pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
3407        pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
3408                pw.print(" mHomePressed="); pw.println(mHomePressed);
3409        pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
3410                pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
3411                pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
3412        pw.print(prefix); pw.print("mEndcallBehavior="); pw.print(mEndcallBehavior);
3413                pw.print(" mIncallPowerBehavior="); pw.print(mIncallPowerBehavior);
3414                pw.print(" mLongPressOnHomeBehavior="); pw.println(mLongPressOnHomeBehavior);
3415        pw.print(prefix); pw.print("mLandscapeRotation="); pw.print(mLandscapeRotation);
3416                pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
3417        pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
3418                pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
3419    }
3420}
3421