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