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