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