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