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