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