PhoneWindowManager.java revision eb3e4b98a45722d5d1ea73e45d86c119d678bb05
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 = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
1642                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1643                try {
1644                    mContext.startActivity(intent);
1645                } catch (ActivityNotFoundException ex) {
1646                    Slog.w(TAG, "Dropping application launch key because "
1647                            + "the activity to which it is registered was not found: "
1648                            + "keyCode=" + keyCode + ", category=" + category, ex);
1649                }
1650            }
1651        }
1652
1653        return 0;
1654    }
1655
1656    /** {@inheritDoc} */
1657    @Override
1658    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
1659        // Note: This method is only called if the initial down was unhandled.
1660        if (DEBUG_FALLBACK) {
1661            Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
1662                    + ", flags=" + event.getFlags()
1663                    + ", keyCode=" + event.getKeyCode()
1664                    + ", scanCode=" + event.getScanCode()
1665                    + ", metaState=" + event.getMetaState()
1666                    + ", repeatCount=" + event.getRepeatCount()
1667                    + ", policyFlags=" + policyFlags);
1668        }
1669
1670        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
1671            final KeyCharacterMap kcm = event.getKeyCharacterMap();
1672            final int keyCode = event.getKeyCode();
1673            final int metaState = event.getMetaState();
1674            final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
1675                    && event.getRepeatCount() == 0;
1676
1677            if (initialDown) {
1678                // Invoke shortcuts using Meta as a fallback.
1679                if ((metaState & KeyEvent.META_META_ON) != 0) {
1680                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
1681                            metaState & ~(KeyEvent.META_META_ON
1682                                    | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
1683                    if (shortcutIntent != null) {
1684                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1685                        try {
1686                            mContext.startActivity(shortcutIntent);
1687                        } catch (ActivityNotFoundException ex) {
1688                            Slog.w(TAG, "Dropping shortcut key combination because "
1689                                    + "the activity to which it is registered was not found: "
1690                                    + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
1691                        }
1692                        return null;
1693                    }
1694                }
1695
1696                // Display task switcher for ALT-TAB or Meta-TAB.
1697                if (keyCode == KeyEvent.KEYCODE_TAB) {
1698                    final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
1699                    if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
1700                            || KeyEvent.metaStateHasModifiers(
1701                                    shiftlessModifiers, KeyEvent.META_META_ON)) {
1702                        showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/);
1703                        return null;
1704                    }
1705                }
1706            }
1707
1708            // Check for fallback actions specified by the key character map.
1709            if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) {
1710                if (DEBUG_FALLBACK) {
1711                    Slog.d(TAG, "Fallback: keyCode=" + mFallbackAction.keyCode
1712                            + " metaState=" + Integer.toHexString(mFallbackAction.metaState));
1713                }
1714
1715                int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
1716                KeyEvent fallbackEvent = KeyEvent.obtain(
1717                        event.getDownTime(), event.getEventTime(),
1718                        event.getAction(), mFallbackAction.keyCode,
1719                        event.getRepeatCount(), mFallbackAction.metaState,
1720                        event.getDeviceId(), event.getScanCode(),
1721                        flags, event.getSource(), null);
1722                int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
1723                if ((actions & ACTION_PASS_TO_USER) != 0) {
1724                    long delayMillis = interceptKeyBeforeDispatching(
1725                            win, fallbackEvent, policyFlags);
1726                    if (delayMillis == 0) {
1727                        if (DEBUG_FALLBACK) {
1728                            Slog.d(TAG, "Performing fallback.");
1729                        }
1730                        return fallbackEvent;
1731                    }
1732                }
1733                fallbackEvent.recycle();
1734            }
1735        }
1736
1737        if (DEBUG_FALLBACK) {
1738            Slog.d(TAG, "No fallback.");
1739        }
1740        return null;
1741    }
1742
1743    private boolean getFallbackAction(KeyCharacterMap kcm, int keyCode, int metaState,
1744            FallbackAction outFallbackAction) {
1745        // Consult the key character map for specific fallback actions.
1746        // For example, map NUMPAD_1 to MOVE_HOME when NUMLOCK is not pressed.
1747        return kcm.getFallbackAction(keyCode, metaState, outFallbackAction);
1748    }
1749
1750    /**
1751     * A home key -> launch home action was detected.  Take the appropriate action
1752     * given the situation with the keyguard.
1753     */
1754    void launchHomeFromHotKey() {
1755        if (mKeyguardMediator.isShowingAndNotHidden()) {
1756            // don't launch home if keyguard showing
1757        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
1758            // when in keyguard restricted mode, must first verify unlock
1759            // before launching home
1760            mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
1761                public void onKeyguardExitResult(boolean success) {
1762                    if (success) {
1763                        try {
1764                            ActivityManagerNative.getDefault().stopAppSwitches();
1765                        } catch (RemoteException e) {
1766                        }
1767                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1768                        startDockOrHome();
1769                    }
1770                }
1771            });
1772        } else {
1773            // no keyguard stuff to worry about, just launch home!
1774            try {
1775                ActivityManagerNative.getDefault().stopAppSwitches();
1776            } catch (RemoteException e) {
1777            }
1778            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1779            startDockOrHome();
1780        }
1781    }
1782
1783    /**
1784     * A delayed callback use to determine when it is okay to re-allow applications
1785     * to use certain system UI flags.  This is used to prevent applications from
1786     * spamming system UI changes that prevent the navigation bar from being shown.
1787     */
1788    final Runnable mAllowSystemUiDelay = new Runnable() {
1789        @Override public void run() {
1790        }
1791    };
1792
1793    /**
1794     * Input handler used while nav bar is hidden.  Captures any touch on the screen,
1795     * to determine when the nav bar should be shown and prevent applications from
1796     * receiving those touches.
1797     */
1798    final InputHandler mHideNavInputHandler = new BaseInputHandler() {
1799        @Override
1800        public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
1801            boolean handled = false;
1802            try {
1803                if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1804                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
1805                        // When the user taps down, we re-show the nav bar.
1806                        boolean changed = false;
1807                        synchronized (mLock) {
1808                            // Any user activity always causes us to show the navigation controls,
1809                            // if they had been hidden.
1810                            int newVal = mResettingSystemUiFlags
1811                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1812                            if (mResettingSystemUiFlags != newVal) {
1813                                mResettingSystemUiFlags = newVal;
1814                                changed = true;
1815                            }
1816                            // We don't allow the system's nav bar to be hidden
1817                            // again for 1 second, to prevent applications from
1818                            // spamming us and keeping it from being shown.
1819                            newVal = mForceClearedSystemUiFlags
1820                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1821                            if (mForceClearedSystemUiFlags != newVal) {
1822                                mForceClearedSystemUiFlags = newVal;
1823                                changed = true;
1824                                mHandler.postDelayed(new Runnable() {
1825                                    @Override public void run() {
1826                                        synchronized (mLock) {
1827                                            mForceClearedSystemUiFlags &=
1828                                                    ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1829                                        }
1830                                        mWindowManagerFuncs.reevaluateStatusBarVisibility();
1831                                    }
1832                                }, 1000);
1833                            }
1834                        }
1835                        if (changed) {
1836                            mWindowManagerFuncs.reevaluateStatusBarVisibility();
1837                        }
1838                    }
1839                }
1840            } finally {
1841                finishedCallback.finished(handled);
1842            }
1843        }
1844    };
1845
1846    @Override
1847    public int adjustSystemUiVisibilityLw(int visibility) {
1848        // Reset any bits in mForceClearingStatusBarVisibility that
1849        // are now clear.
1850        mResettingSystemUiFlags &= visibility;
1851        // Clear any bits in the new visibility that are currently being
1852        // force cleared, before reporting it.
1853        return visibility & ~mResettingSystemUiFlags
1854                & ~mForceClearedSystemUiFlags;
1855    }
1856
1857    public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
1858        final int fl = attrs.flags;
1859
1860        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1861                == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1862            contentInset.set(mCurLeft, mCurTop,
1863                    (mRestrictedScreenLeft+mRestrictedScreenWidth) - mCurRight,
1864                    (mRestrictedScreenTop+mRestrictedScreenHeight) - mCurBottom);
1865        } else {
1866            contentInset.setEmpty();
1867        }
1868    }
1869
1870    /** {@inheritDoc} */
1871    public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotation) {
1872        mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
1873        mUnrestrictedScreenWidth = displayWidth;
1874        mUnrestrictedScreenHeight = displayHeight;
1875        mRestrictedScreenLeft = mRestrictedScreenTop = 0;
1876        mRestrictedScreenWidth = displayWidth;
1877        mRestrictedScreenHeight = displayHeight;
1878        mDockLeft = mContentLeft = mCurLeft = 0;
1879        mDockTop = mContentTop = mCurTop = 0;
1880        mDockRight = mContentRight = mCurRight = displayWidth;
1881        mDockBottom = mContentBottom = mCurBottom = displayHeight;
1882        mDockLayer = 0x10000000;
1883
1884        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
1885        final Rect pf = mTmpParentFrame;
1886        final Rect df = mTmpDisplayFrame;
1887        final Rect vf = mTmpVisibleFrame;
1888        pf.left = df.left = vf.left = mDockLeft;
1889        pf.top = df.top = vf.top = mDockTop;
1890        pf.right = df.right = vf.right = mDockRight;
1891        pf.bottom = df.bottom = vf.bottom = mDockBottom;
1892
1893        final boolean navVisible = (mNavigationBar == null || mNavigationBar.isVisibleLw()) &&
1894                (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1895
1896        // When the navigation bar isn't visible, we put up a fake
1897        // input window to catch all touch events.  This way we can
1898        // detect when the user presses anywhere to bring back the nav
1899        // bar and ensure the application doesn't see the event.
1900        if (navVisible) {
1901            if (mHideNavFakeWindow != null) {
1902                mHideNavFakeWindow.dismiss();
1903                mHideNavFakeWindow = null;
1904            }
1905        } else if (mHideNavFakeWindow == null) {
1906            mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
1907                    mHandler.getLooper(), mHideNavInputHandler,
1908                    "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
1909                    0, false, false, true);
1910        }
1911
1912        // decide where the status bar goes ahead of time
1913        if (mStatusBar != null) {
1914            if (mNavigationBar != null) {
1915                // Force the navigation bar to its appropriate place and
1916                // size.  We need to do this directly, instead of relying on
1917                // it to bubble up from the nav bar, because this needs to
1918                // change atomically with screen rotations.
1919                if (displayWidth < displayHeight) {
1920                    // Portrait screen; nav bar goes on bottom.
1921                    mTmpNavigationFrame.set(0, displayHeight-mNavigationBarHeight,
1922                            displayWidth, displayHeight);
1923                    if (navVisible) {
1924                        mDockBottom = mTmpNavigationFrame.top;
1925                        mRestrictedScreenHeight = mDockBottom - mDockTop;
1926                    } else {
1927                        // We currently want to hide the navigation UI.  Do this by just
1928                        // moving it off the screen, so it can still receive input events
1929                        // to know when to be re-shown.
1930                        mTmpNavigationFrame.offset(0, mNavigationBarHeight);
1931                    }
1932                } else {
1933                    // Landscape screen; nav bar goes to the right.
1934                    mTmpNavigationFrame.set(displayWidth-mNavigationBarWidth, 0,
1935                            displayWidth, displayHeight);
1936                    if (navVisible) {
1937                        mDockRight = mTmpNavigationFrame.left;
1938                        mRestrictedScreenWidth = mDockRight - mDockLeft;
1939                    } else {
1940                        // We currently want to hide the navigation UI.  Do this by just
1941                        // moving it off the screen, so it can still receive input events
1942                        // to know when to be re-shown.
1943                        mTmpNavigationFrame.offset(mNavigationBarWidth, 0);
1944                    }
1945                }
1946                // And compute the final frame.
1947                mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
1948                        mTmpNavigationFrame, mTmpNavigationFrame);
1949                if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
1950            }
1951            if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
1952                    mDockLeft, mDockTop, mDockRight, mDockBottom));
1953
1954            // apply navigation bar insets
1955            pf.left = df.left = vf.left = mDockLeft;
1956            pf.top = df.top = vf.top = mDockTop;
1957            pf.right = df.right = vf.right = mDockRight;
1958            pf.bottom = df.bottom = vf.bottom = mDockBottom;
1959
1960            mStatusBar.computeFrameLw(pf, df, vf, vf);
1961
1962            if (mStatusBar.isVisibleLw()) {
1963                // If the status bar is hidden, we don't want to cause
1964                // windows behind it to scroll.
1965                final Rect r = mStatusBar.getFrameLw();
1966                if (mStatusBarCanHide) {
1967                    // Status bar may go away, so the screen area it occupies
1968                    // is available to apps but just covering them when the
1969                    // status bar is visible.
1970                    if (mDockTop == r.top) mDockTop = r.bottom;
1971                    else if (mDockBottom == r.bottom) mDockBottom = r.top;
1972
1973                    mContentTop = mCurTop = mDockTop;
1974                    mContentBottom = mCurBottom = mDockBottom;
1975                    mContentLeft = mCurLeft = mDockLeft;
1976                    mContentRight = mCurRight = mDockRight;
1977
1978                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
1979                        String.format(
1980                            "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
1981                            mDockLeft, mDockTop, mDockRight, mDockBottom,
1982                            mContentLeft, mContentTop, mContentRight, mContentBottom,
1983                            mCurLeft, mCurTop, mCurRight, mCurBottom));
1984                } else {
1985                    // Status bar can't go away; the part of the screen it
1986                    // covers does not exist for anything behind it.
1987                    if (mRestrictedScreenTop == r.top) {
1988                        mRestrictedScreenTop = r.bottom;
1989                        mRestrictedScreenHeight -= (r.bottom-r.top);
1990                    } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
1991                        mRestrictedScreenHeight -= (r.bottom-r.top);
1992                    }
1993
1994                    mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
1995                    mContentBottom = mCurBottom = mDockBottom
1996                            = mRestrictedScreenTop + mRestrictedScreenHeight;
1997                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: ("
1998                            + mRestrictedScreenLeft + ","
1999                            + mRestrictedScreenTop + ","
2000                            + (mRestrictedScreenLeft + mRestrictedScreenWidth) + ","
2001                            + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")");
2002                }
2003            }
2004        }
2005    }
2006
2007    void setAttachedWindowFrames(WindowState win, int fl, int adjust,
2008            WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
2009        if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
2010            // Here's a special case: if this attached window is a panel that is
2011            // above the dock window, and the window it is attached to is below
2012            // the dock window, then the frames we computed for the window it is
2013            // attached to can not be used because the dock is effectively part
2014            // of the underlying window and the attached window is floating on top
2015            // of the whole thing.  So, we ignore the attached window and explicitly
2016            // compute the frames that would be appropriate without the dock.
2017            df.left = cf.left = vf.left = mDockLeft;
2018            df.top = cf.top = vf.top = mDockTop;
2019            df.right = cf.right = vf.right = mDockRight;
2020            df.bottom = cf.bottom = vf.bottom = mDockBottom;
2021        } else {
2022            // The effective display frame of the attached window depends on
2023            // whether it is taking care of insetting its content.  If not,
2024            // we need to use the parent's content frame so that the entire
2025            // window is positioned within that content.  Otherwise we can use
2026            // the display frame and let the attached window take care of
2027            // positioning its content appropriately.
2028            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2029                cf.set(attached.getDisplayFrameLw());
2030            } else {
2031                // If the window is resizing, then we want to base the content
2032                // frame on our attached content frame to resize...  however,
2033                // things can be tricky if the attached window is NOT in resize
2034                // mode, in which case its content frame will be larger.
2035                // Ungh.  So to deal with that, make sure the content frame
2036                // we end up using is not covering the IM dock.
2037                cf.set(attached.getContentFrameLw());
2038                if (attached.getSurfaceLayer() < mDockLayer) {
2039                    if (cf.left < mContentLeft) cf.left = mContentLeft;
2040                    if (cf.top < mContentTop) cf.top = mContentTop;
2041                    if (cf.right > mContentRight) cf.right = mContentRight;
2042                    if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
2043                }
2044            }
2045            df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
2046            vf.set(attached.getVisibleFrameLw());
2047        }
2048        // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
2049        // window should be positioned relative to its parent or the entire
2050        // screen.
2051        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
2052                ? attached.getFrameLw() : df);
2053    }
2054
2055    /** {@inheritDoc} */
2056    public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
2057            WindowState attached) {
2058        // we've already done the status bar
2059        if (win == mStatusBar || win == mNavigationBar) {
2060            return;
2061        }
2062
2063        final int fl = attrs.flags;
2064        final int sim = attrs.softInputMode;
2065
2066        final Rect pf = mTmpParentFrame;
2067        final Rect df = mTmpDisplayFrame;
2068        final Rect cf = mTmpContentFrame;
2069        final Rect vf = mTmpVisibleFrame;
2070
2071        final boolean hasNavBar = (mHasNavigationBar
2072                && mNavigationBar != null && mNavigationBar.isVisibleLw());
2073
2074        if (attrs.type == TYPE_INPUT_METHOD) {
2075            pf.left = df.left = cf.left = vf.left = mDockLeft;
2076            pf.top = df.top = cf.top = vf.top = mDockTop;
2077            pf.right = df.right = cf.right = vf.right = mDockRight;
2078            pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
2079            // IM dock windows always go to the bottom of the screen.
2080            attrs.gravity = Gravity.BOTTOM;
2081            mDockLayer = win.getSurfaceLayer();
2082        } else {
2083            final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
2084
2085            if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
2086                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
2087                if (DEBUG_LAYOUT)
2088                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2089                            + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
2090                // This is the case for a normal activity window: we want it
2091                // to cover all of the screen space, and it can take care of
2092                // moving its contents to account for screen decorations that
2093                // intrude into that space.
2094                if (attached != null) {
2095                    // If this window is attached to another, our display
2096                    // frame is the same as the one we are attached to.
2097                    setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
2098                } else {
2099                    if (attrs.type == TYPE_STATUS_BAR_PANEL
2100                            || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
2101                        // Status bar panels are the only windows who can go on top of
2102                        // the status bar.  They are protected by the STATUS_BAR_SERVICE
2103                        // permission, so they have the same privileges as the status
2104                        // bar itself.
2105                        //
2106                        // However, they should still dodge the navigation bar if it exists.
2107
2108                        pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
2109                        pf.top = df.top = mUnrestrictedScreenTop;
2110                        pf.right = df.right = hasNavBar
2111                                            ? mRestrictedScreenLeft+mRestrictedScreenWidth
2112                                            : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
2113                        pf.bottom = df.bottom = hasNavBar
2114                                              ? mRestrictedScreenTop+mRestrictedScreenHeight
2115                                              : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
2116
2117                        if (DEBUG_LAYOUT) {
2118                            Log.v(TAG, String.format(
2119                                        "Laying out status bar window: (%d,%d - %d,%d)",
2120                                        pf.left, pf.top, pf.right, pf.bottom));
2121                        }
2122                    } else {
2123                        pf.left = df.left = mRestrictedScreenLeft;
2124                        pf.top = df.top = mRestrictedScreenTop;
2125                        pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
2126                        pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight;
2127                    }
2128                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2129                        cf.left = mDockLeft;
2130                        cf.top = mDockTop;
2131                        cf.right = mDockRight;
2132                        cf.bottom = mDockBottom;
2133                    } else {
2134                        cf.left = mContentLeft;
2135                        cf.top = mContentTop;
2136                        cf.right = mContentRight;
2137                        cf.bottom = mContentBottom;
2138                    }
2139                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2140                        vf.left = mCurLeft;
2141                        vf.top = mCurTop;
2142                        vf.right = mCurRight;
2143                        vf.bottom = mCurBottom;
2144                    } else {
2145                        vf.set(cf);
2146                    }
2147                }
2148            } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
2149                if (DEBUG_LAYOUT)
2150                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
2151                // A window that has requested to fill the entire screen just
2152                // gets everything, period.
2153                if (attrs.type == TYPE_STATUS_BAR_PANEL
2154                        || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
2155                    pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
2156                    pf.top = df.top = cf.top = mUnrestrictedScreenTop;
2157                    pf.right = df.right = cf.right = hasNavBar
2158                                        ? mRestrictedScreenLeft+mRestrictedScreenWidth
2159                                        : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
2160                    pf.bottom = df.bottom = cf.bottom = hasNavBar
2161                                          ? mRestrictedScreenTop+mRestrictedScreenHeight
2162                                          : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
2163
2164                    if (DEBUG_LAYOUT) {
2165                        Log.v(TAG, String.format(
2166                                    "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
2167                                    pf.left, pf.top, pf.right, pf.bottom));
2168                    }
2169                } else if (attrs.type == TYPE_NAVIGATION_BAR) {
2170                    // The navigation bar has Real Ultimate Power.
2171                    pf.left = df.left = mUnrestrictedScreenLeft;
2172                    pf.top = df.top = mUnrestrictedScreenTop;
2173                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
2174                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
2175                    if (DEBUG_LAYOUT) {
2176                        Log.v(TAG, String.format(
2177                                    "Laying out navigation bar window: (%d,%d - %d,%d)",
2178                                    pf.left, pf.top, pf.right, pf.bottom));
2179                    }
2180                } else if (attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
2181                        && ((fl & FLAG_FULLSCREEN) != 0)) {
2182                    // Fullscreen secure system overlays get what they ask for.
2183                    pf.left = df.left = mUnrestrictedScreenLeft;
2184                    pf.top = df.top = mUnrestrictedScreenTop;
2185                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
2186                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
2187                } else {
2188                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
2189                    pf.top = df.top = cf.top = mRestrictedScreenTop;
2190                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
2191                    pf.bottom = df.bottom = cf.bottom
2192                            = mRestrictedScreenTop+mRestrictedScreenHeight;
2193                }
2194                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2195                    vf.left = mCurLeft;
2196                    vf.top = mCurTop;
2197                    vf.right = mCurRight;
2198                    vf.bottom = mCurBottom;
2199                } else {
2200                    vf.set(cf);
2201                }
2202            } else if (attached != null) {
2203                if (DEBUG_LAYOUT)
2204                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
2205                // A child window should be placed inside of the same visible
2206                // frame that its parent had.
2207                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
2208            } else {
2209                if (DEBUG_LAYOUT)
2210                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
2211                // Otherwise, a normal window must be placed inside the content
2212                // of all screen decorations.
2213                if (attrs.type == TYPE_STATUS_BAR_PANEL) {
2214                    // Status bar panels are the only windows who can go on top of
2215                    // the status bar.  They are protected by the STATUS_BAR_SERVICE
2216                    // permission, so they have the same privileges as the status
2217                    // bar itself.
2218                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
2219                    pf.top = df.top = cf.top = mRestrictedScreenTop;
2220                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
2221                    pf.bottom = df.bottom = cf.bottom
2222                            = mRestrictedScreenTop+mRestrictedScreenHeight;
2223                } else {
2224                    pf.left = mContentLeft;
2225                    pf.top = mContentTop;
2226                    pf.right = mContentRight;
2227                    pf.bottom = mContentBottom;
2228                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2229                        df.left = cf.left = mDockLeft;
2230                        df.top = cf.top = mDockTop;
2231                        df.right = cf.right = mDockRight;
2232                        df.bottom = cf.bottom = mDockBottom;
2233                    } else {
2234                        df.left = cf.left = mContentLeft;
2235                        df.top = cf.top = mContentTop;
2236                        df.right = cf.right = mContentRight;
2237                        df.bottom = cf.bottom = mContentBottom;
2238                    }
2239                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2240                        vf.left = mCurLeft;
2241                        vf.top = mCurTop;
2242                        vf.right = mCurRight;
2243                        vf.bottom = mCurBottom;
2244                    } else {
2245                        vf.set(cf);
2246                    }
2247                }
2248            }
2249        }
2250
2251        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
2252            df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
2253            df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2254        }
2255
2256        if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
2257                + ": sim=#" + Integer.toHexString(sim)
2258                + " attach=" + attached + " type=" + attrs.type
2259                + String.format(" flags=0x%08x", fl)
2260                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2261                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
2262
2263        win.computeFrameLw(pf, df, cf, vf);
2264
2265        // Dock windows carve out the bottom of the screen, so normal windows
2266        // can't appear underneath them.
2267        if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
2268            int top = win.getContentFrameLw().top;
2269            top += win.getGivenContentInsetsLw().top;
2270            if (mContentBottom > top) {
2271                mContentBottom = top;
2272            }
2273            top = win.getVisibleFrameLw().top;
2274            top += win.getGivenVisibleInsetsLw().top;
2275            if (mCurBottom > top) {
2276                mCurBottom = top;
2277            }
2278            if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom="
2279                    + mDockBottom + " mContentBottom="
2280                    + mContentBottom + " mCurBottom=" + mCurBottom);
2281        }
2282    }
2283
2284    /** {@inheritDoc} */
2285    public int finishLayoutLw() {
2286        return 0;
2287    }
2288
2289    /** {@inheritDoc} */
2290    public void beginAnimationLw(int displayWidth, int displayHeight) {
2291        mTopFullscreenOpaqueWindowState = null;
2292        mForceStatusBar = false;
2293
2294        mHideLockScreen = false;
2295        mAllowLockscreenWhenOn = false;
2296        mDismissKeyguard = false;
2297    }
2298
2299    /** {@inheritDoc} */
2300    public void animatingWindowLw(WindowState win,
2301                                WindowManager.LayoutParams attrs) {
2302        if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
2303                + win.isVisibleOrBehindKeyguardLw());
2304        if (mTopFullscreenOpaqueWindowState == null &&
2305                win.isVisibleOrBehindKeyguardLw()) {
2306            if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2307                mForceStatusBar = true;
2308            }
2309            if (attrs.type >= FIRST_APPLICATION_WINDOW
2310                    && attrs.type <= LAST_APPLICATION_WINDOW
2311                    && attrs.x == 0 && attrs.y == 0
2312                    && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
2313                    && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
2314                if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
2315                mTopFullscreenOpaqueWindowState = win;
2316                if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
2317                    if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
2318                    mHideLockScreen = true;
2319                }
2320                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
2321                    if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
2322                    mDismissKeyguard = true;
2323                }
2324                if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2325                    mAllowLockscreenWhenOn = true;
2326                }
2327            }
2328        }
2329    }
2330
2331    /** {@inheritDoc} */
2332    public int finishAnimationLw() {
2333        int changes = 0;
2334        boolean topIsFullscreen = false;
2335
2336        final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null)
2337                ? mTopFullscreenOpaqueWindowState.getAttrs()
2338                : null;
2339
2340        if (mStatusBar != null) {
2341            if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar
2342                    + " top=" + mTopFullscreenOpaqueWindowState);
2343            if (mForceStatusBar) {
2344                if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced");
2345                if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
2346            } else if (mTopFullscreenOpaqueWindowState != null) {
2347                if (localLOGV) {
2348                    Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
2349                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
2350                    Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2351                            + " lp.flags=0x" + Integer.toHexString(lp.flags));
2352                }
2353                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
2354                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2355                // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
2356                // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
2357                // case though.
2358                if (topIsFullscreen) {
2359                    if (mStatusBarCanHide) {
2360                        if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
2361                        if (mStatusBar.hideLw(true)) {
2362                            changes |= FINISH_LAYOUT_REDO_LAYOUT;
2363
2364                            mHandler.post(new Runnable() { public void run() {
2365                                if (mStatusBarService != null) {
2366                                    try {
2367                                        mStatusBarService.collapse();
2368                                    } catch (RemoteException ex) {}
2369                                }
2370                            }});
2371                        }
2372                    } else if (DEBUG_LAYOUT) {
2373                        Log.v(TAG, "Preventing status bar from hiding by policy");
2374                    }
2375                } else {
2376                    if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: top is not fullscreen");
2377                    if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
2378                }
2379            }
2380        }
2381
2382        mTopIsFullscreen = topIsFullscreen;
2383
2384        // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
2385        // when the screen is locked
2386        if (mKeyguard != null) {
2387            if (localLOGV) Log.v(TAG, "finishAnimationLw::mHideKeyguard="+mHideLockScreen);
2388            if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
2389                if (mKeyguard.hideLw(true)) {
2390                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2391                            | FINISH_LAYOUT_REDO_CONFIG
2392                            | FINISH_LAYOUT_REDO_WALLPAPER;
2393                }
2394                if (mKeyguardMediator.isShowing()) {
2395                    mHandler.post(new Runnable() {
2396                        public void run() {
2397                            mKeyguardMediator.keyguardDone(false, false);
2398                        }
2399                    });
2400                }
2401            } else if (mHideLockScreen) {
2402                if (mKeyguard.hideLw(true)) {
2403                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2404                            | FINISH_LAYOUT_REDO_CONFIG
2405                            | FINISH_LAYOUT_REDO_WALLPAPER;
2406                }
2407                mKeyguardMediator.setHidden(true);
2408            } else {
2409                if (mKeyguard.showLw(true)) {
2410                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2411                            | FINISH_LAYOUT_REDO_CONFIG
2412                            | FINISH_LAYOUT_REDO_WALLPAPER;
2413                }
2414                mKeyguardMediator.setHidden(false);
2415            }
2416        }
2417
2418        if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
2419            // If the navigation bar has been hidden or shown, we need to do another
2420            // layout pass to update that window.
2421            changes |= FINISH_LAYOUT_REDO_LAYOUT;
2422        }
2423
2424        // update since mAllowLockscreenWhenOn might have changed
2425        updateLockScreenTimeout();
2426        return changes;
2427    }
2428
2429    public boolean allowAppAnimationsLw() {
2430        if (mKeyguard != null && mKeyguard.isVisibleLw()) {
2431            // If keyguard is currently visible, no reason to animate
2432            // behind it.
2433            return false;
2434        }
2435        if (false) {
2436            // Don't do this on the tablet, since the system bar never completely
2437            // covers the screen, and with all its transparency this will
2438            // incorrectly think it does cover it when it doesn't.  We'll revisit
2439            // this later when we re-do the phone status bar.
2440            if (mStatusBar != null && mStatusBar.isVisibleLw()) {
2441                RectF rect = new RectF(mStatusBar.getShownFrameLw());
2442                for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
2443                    WindowState w = mStatusBarPanels.get(i);
2444                    if (w.isVisibleLw()) {
2445                        rect.union(w.getShownFrameLw());
2446                    }
2447                }
2448                final int insetw = mRestrictedScreenWidth/10;
2449                final int inseth = mRestrictedScreenHeight/10;
2450                if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw,
2451                            mRestrictedScreenHeight-inseth)) {
2452                    // All of the status bar windows put together cover the
2453                    // screen, so the app can't be seen.  (Note this test doesn't
2454                    // work if the rects of these windows are at off offsets or
2455                    // sizes, causing gaps in the rect union we have computed.)
2456                    return false;
2457                }
2458            }
2459        }
2460        return true;
2461    }
2462
2463    public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
2464        mFocusedWindow = newFocus;
2465        if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
2466            // If the navigation bar has been hidden or shown, we need to do another
2467            // layout pass to update that window.
2468            return FINISH_LAYOUT_REDO_LAYOUT;
2469        }
2470        return 0;
2471    }
2472
2473    /** {@inheritDoc} */
2474    public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
2475        // lid changed state
2476        mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED;
2477        updateKeyboardVisibility();
2478
2479        boolean awakeNow = mKeyguardMediator.doLidChangeTq(lidOpen);
2480        updateRotation(true);
2481        if (awakeNow) {
2482            // If the lid is opening and we don't have to keep the
2483            // keyguard up, then we can turn on the screen
2484            // immediately.
2485            mKeyguardMediator.pokeWakelock();
2486        } else if (keyguardIsShowingTq()) {
2487            if (lidOpen) {
2488                // If we are opening the lid and not hiding the
2489                // keyguard, then we need to have it turn on the
2490                // screen once it is shown.
2491                mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
2492                        KeyEvent.KEYCODE_POWER, mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
2493            }
2494        } else {
2495            // Light up the keyboard if we are sliding up.
2496            if (lidOpen) {
2497                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
2498                        LocalPowerManager.BUTTON_EVENT);
2499            } else {
2500                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
2501                        LocalPowerManager.OTHER_EVENT);
2502            }
2503        }
2504    }
2505
2506    void setHdmiPlugged(boolean plugged) {
2507        if (mHdmiPlugged != plugged) {
2508            mHdmiPlugged = plugged;
2509            updateRotation(true);
2510            Intent intent = new Intent(ACTION_HDMI_PLUGGED);
2511            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2512            intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
2513            mContext.sendStickyBroadcast(intent);
2514        }
2515    }
2516
2517    void initializeHdmiState() {
2518        boolean plugged = false;
2519        // watch for HDMI plug messages if the hdmi switch exists
2520        if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
2521            mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
2522
2523            final String filename = "/sys/class/switch/hdmi/state";
2524            FileReader reader = null;
2525            try {
2526                reader = new FileReader(filename);
2527                char[] buf = new char[15];
2528                int n = reader.read(buf);
2529                if (n > 1) {
2530                    plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));
2531                }
2532            } catch (IOException ex) {
2533                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
2534            } catch (NumberFormatException ex) {
2535                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
2536            } finally {
2537                if (reader != null) {
2538                    try {
2539                        reader.close();
2540                    } catch (IOException ex) {
2541                    }
2542                }
2543            }
2544        }
2545        // This dance forces the code in setHdmiPlugged to run.
2546        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
2547        mHdmiPlugged = !plugged;
2548        setHdmiPlugged(!mHdmiPlugged);
2549    }
2550
2551    /**
2552     * @return Whether music is being played right now.
2553     */
2554    boolean isMusicActive() {
2555        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
2556        if (am == null) {
2557            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
2558            return false;
2559        }
2560        return am.isMusicActive();
2561    }
2562
2563    /**
2564     * Tell the audio service to adjust the volume appropriate to the event.
2565     * @param keycode
2566     */
2567    void handleVolumeKey(int stream, int keycode) {
2568        IAudioService audioService = getAudioService();
2569        if (audioService == null) {
2570            return;
2571        }
2572        try {
2573            // since audio is playing, we shouldn't have to hold a wake lock
2574            // during the call, but we do it as a precaution for the rare possibility
2575            // that the music stops right before we call this
2576            // TODO: Actually handle MUTE.
2577            mBroadcastWakeLock.acquire();
2578            audioService.adjustStreamVolume(stream,
2579                keycode == KeyEvent.KEYCODE_VOLUME_UP
2580                            ? AudioManager.ADJUST_RAISE
2581                            : AudioManager.ADJUST_LOWER,
2582                    0);
2583        } catch (RemoteException e) {
2584            Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
2585        } finally {
2586            mBroadcastWakeLock.release();
2587        }
2588    }
2589
2590    final Object mScreenshotLock = new Object();
2591    ServiceConnection mScreenshotConnection = null;
2592
2593    final Runnable mScreenshotTimeout = new Runnable() {
2594        @Override public void run() {
2595            synchronized (mScreenshotLock) {
2596                if (mScreenshotConnection != null) {
2597                    mContext.unbindService(mScreenshotConnection);
2598                    mScreenshotConnection = null;
2599                }
2600            }
2601        }
2602    };
2603
2604    // Assume this is called from the Handler thread.
2605    private void takeScreenshot() {
2606        synchronized (mScreenshotLock) {
2607            if (mScreenshotConnection != null) {
2608                return;
2609            }
2610            ComponentName cn = new ComponentName("com.android.systemui",
2611                    "com.android.systemui.screenshot.TakeScreenshotService");
2612            Intent intent = new Intent();
2613            intent.setComponent(cn);
2614            ServiceConnection conn = new ServiceConnection() {
2615                @Override
2616                public void onServiceConnected(ComponentName name, IBinder service) {
2617                    synchronized (mScreenshotLock) {
2618                        if (mScreenshotConnection != this) {
2619                            return;
2620                        }
2621                        Messenger messenger = new Messenger(service);
2622                        Message msg = Message.obtain(null, 1);
2623                        final ServiceConnection myConn = this;
2624                        Handler h = new Handler(mHandler.getLooper()) {
2625                            @Override
2626                            public void handleMessage(Message msg) {
2627                                synchronized (mScreenshotLock) {
2628                                    if (mScreenshotConnection == myConn) {
2629                                        mContext.unbindService(mScreenshotConnection);
2630                                        mScreenshotConnection = null;
2631                                        mHandler.removeCallbacks(mScreenshotTimeout);
2632                                    }
2633                                }
2634                            }
2635                        };
2636                        msg.replyTo = new Messenger(h);
2637                        msg.arg1 = msg.arg2 = 0;
2638                        if (mStatusBar != null && mStatusBar.isVisibleLw())
2639                            msg.arg1 = 1;
2640                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())
2641                            msg.arg2 = 1;
2642                        try {
2643                            messenger.send(msg);
2644                        } catch (RemoteException e) {
2645                        }
2646                    }
2647                }
2648                @Override
2649                public void onServiceDisconnected(ComponentName name) {}
2650            };
2651            if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
2652                mScreenshotConnection = conn;
2653                mHandler.postDelayed(mScreenshotTimeout, 10000);
2654            }
2655        }
2656    }
2657
2658    /** {@inheritDoc} */
2659    @Override
2660    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
2661        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
2662        final boolean canceled = event.isCanceled();
2663        final int keyCode = event.getKeyCode();
2664
2665        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
2666
2667        // If screen is off then we treat the case where the keyguard is open but hidden
2668        // the same as if it were open and in front.
2669        // This will prevent any keys other than the power button from waking the screen
2670        // when the keyguard is hidden by another activity.
2671        final boolean keyguardActive = (isScreenOn ?
2672                                        mKeyguardMediator.isShowingAndNotHidden() :
2673                                        mKeyguardMediator.isShowing());
2674
2675        if (!mSystemBooted) {
2676            // If we have not yet booted, don't let key events do anything.
2677            return 0;
2678        }
2679
2680        if (false) {
2681            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
2682                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
2683        }
2684
2685        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
2686                && event.getRepeatCount() == 0) {
2687            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
2688        }
2689
2690        // Basic policy based on screen state and keyguard.
2691        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
2692        //        is on or off, really.  We should care about whether the device is in an
2693        //        interactive state or is in suspend pretending to be "off".
2694        //        The primary screen might be turned off due to proximity sensor or
2695        //        because we are presenting media on an auxiliary screen or remotely controlling
2696        //        the device some other way (which is why we have an exemption here for injected
2697        //        events).
2698        int result;
2699        if (isScreenOn || isInjected) {
2700            // When the screen is on or if the key is injected pass the key to the application.
2701            result = ACTION_PASS_TO_USER;
2702        } else {
2703            // When the screen is off and the key is not injected, determine whether
2704            // to wake the device but don't pass the key to the application.
2705            result = 0;
2706
2707            final boolean isWakeKey = (policyFlags
2708                    & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
2709            if (down && isWakeKey) {
2710                if (keyguardActive) {
2711                    // If the keyguard is showing, let it decide what to do with the wake key.
2712                    mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode,
2713                            mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
2714                } else {
2715                    // Otherwise, wake the device ourselves.
2716                    result |= ACTION_POKE_USER_ACTIVITY;
2717                }
2718            }
2719        }
2720
2721        // Handle special keys.
2722        switch (keyCode) {
2723            case KeyEvent.KEYCODE_VOLUME_DOWN:
2724            case KeyEvent.KEYCODE_VOLUME_UP:
2725            case KeyEvent.KEYCODE_VOLUME_MUTE: {
2726                if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
2727                    if (down) {
2728                        if (isScreenOn && !mVolumeDownKeyTriggered
2729                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
2730                            mVolumeDownKeyTriggered = true;
2731                            mVolumeDownKeyTime = event.getDownTime();
2732                            mVolumeDownKeyConsumedByScreenshotChord = false;
2733                            cancelPendingPowerKeyAction();
2734                            interceptScreenshotChord();
2735                        }
2736                    } else {
2737                        mVolumeDownKeyTriggered = false;
2738                        cancelPendingScreenshotChordAction();
2739                    }
2740                } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
2741                    if (down) {
2742                        if (isScreenOn && !mVolumeUpKeyTriggered
2743                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
2744                            mVolumeUpKeyTriggered = true;
2745                            cancelPendingPowerKeyAction();
2746                            cancelPendingScreenshotChordAction();
2747                        }
2748                    } else {
2749                        mVolumeUpKeyTriggered = false;
2750                        cancelPendingScreenshotChordAction();
2751                    }
2752                }
2753                if (down) {
2754                    ITelephony telephonyService = getTelephonyService();
2755                    if (telephonyService != null) {
2756                        try {
2757                            if (telephonyService.isRinging()) {
2758                                // If an incoming call is ringing, either VOLUME key means
2759                                // "silence ringer".  We handle these keys here, rather than
2760                                // in the InCallScreen, to make sure we'll respond to them
2761                                // even if the InCallScreen hasn't come to the foreground yet.
2762                                // Look for the DOWN event here, to agree with the "fallback"
2763                                // behavior in the InCallScreen.
2764                                Log.i(TAG, "interceptKeyBeforeQueueing:"
2765                                      + " VOLUME key-down while ringing: Silence ringer!");
2766
2767                                // Silence the ringer.  (It's safe to call this
2768                                // even if the ringer has already been silenced.)
2769                                telephonyService.silenceRinger();
2770
2771                                // And *don't* pass this key thru to the current activity
2772                                // (which is probably the InCallScreen.)
2773                                result &= ~ACTION_PASS_TO_USER;
2774                                break;
2775                            }
2776                            if (telephonyService.isOffhook()
2777                                    && (result & ACTION_PASS_TO_USER) == 0) {
2778                                // If we are in call but we decided not to pass the key to
2779                                // the application, handle the volume change here.
2780                                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
2781                                break;
2782                            }
2783                        } catch (RemoteException ex) {
2784                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2785                        }
2786                    }
2787
2788                    if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
2789                        // If music is playing but we decided not to pass the key to the
2790                        // application, handle the volume change here.
2791                        handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
2792                        break;
2793                    }
2794                }
2795                break;
2796            }
2797
2798            case KeyEvent.KEYCODE_ENDCALL: {
2799                result &= ~ACTION_PASS_TO_USER;
2800                if (down) {
2801                    ITelephony telephonyService = getTelephonyService();
2802                    boolean hungUp = false;
2803                    if (telephonyService != null) {
2804                        try {
2805                            hungUp = telephonyService.endCall();
2806                        } catch (RemoteException ex) {
2807                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2808                        }
2809                    }
2810                    interceptPowerKeyDown(!isScreenOn || hungUp);
2811                } else {
2812                    if (interceptPowerKeyUp(canceled)) {
2813                        if ((mEndcallBehavior
2814                                & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
2815                            if (goHome()) {
2816                                break;
2817                            }
2818                        }
2819                        if ((mEndcallBehavior
2820                                & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
2821                            result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
2822                        }
2823                    }
2824                }
2825                break;
2826            }
2827
2828            case KeyEvent.KEYCODE_POWER: {
2829                result &= ~ACTION_PASS_TO_USER;
2830                if (down) {
2831                    if (isScreenOn && !mPowerKeyTriggered
2832                            && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
2833                        mPowerKeyTriggered = true;
2834                        mPowerKeyTime = event.getDownTime();
2835                        interceptScreenshotChord();
2836                    }
2837
2838                    ITelephony telephonyService = getTelephonyService();
2839                    boolean hungUp = false;
2840                    if (telephonyService != null) {
2841                        try {
2842                            if (telephonyService.isRinging()) {
2843                                // Pressing Power while there's a ringing incoming
2844                                // call should silence the ringer.
2845                                telephonyService.silenceRinger();
2846                            } else if ((mIncallPowerBehavior
2847                                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
2848                                    && telephonyService.isOffhook()) {
2849                                // Otherwise, if "Power button ends call" is enabled,
2850                                // the Power button will hang up any current active call.
2851                                hungUp = telephonyService.endCall();
2852                            }
2853                        } catch (RemoteException ex) {
2854                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2855                        }
2856                    }
2857                    interceptPowerKeyDown(!isScreenOn || hungUp
2858                            || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
2859                } else {
2860                    mPowerKeyTriggered = false;
2861                    cancelPendingScreenshotChordAction();
2862                    if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
2863                        result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
2864                    }
2865                    mPendingPowerKeyUpCanceled = false;
2866                }
2867                break;
2868            }
2869
2870            case KeyEvent.KEYCODE_MEDIA_PLAY:
2871            case KeyEvent.KEYCODE_MEDIA_PAUSE:
2872            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
2873                if (down) {
2874                    ITelephony telephonyService = getTelephonyService();
2875                    if (telephonyService != null) {
2876                        try {
2877                            if (!telephonyService.isIdle()) {
2878                                // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
2879                                // to avoid music playback.
2880                                break;
2881                            }
2882                        } catch (RemoteException ex) {
2883                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2884                        }
2885                    }
2886                }
2887            case KeyEvent.KEYCODE_HEADSETHOOK:
2888            case KeyEvent.KEYCODE_MUTE:
2889            case KeyEvent.KEYCODE_MEDIA_STOP:
2890            case KeyEvent.KEYCODE_MEDIA_NEXT:
2891            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
2892            case KeyEvent.KEYCODE_MEDIA_REWIND:
2893            case KeyEvent.KEYCODE_MEDIA_RECORD:
2894            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
2895                if ((result & ACTION_PASS_TO_USER) == 0) {
2896                    // Only do this if we would otherwise not pass it to the user. In that
2897                    // case, the PhoneWindow class will do the same thing, except it will
2898                    // only do it if the showing app doesn't process the key on its own.
2899                    mBroadcastWakeLock.acquire();
2900                    mHandler.post(new PassHeadsetKey(new KeyEvent(event)));
2901                }
2902                break;
2903            }
2904
2905            case KeyEvent.KEYCODE_CALL: {
2906                if (down) {
2907                    ITelephony telephonyService = getTelephonyService();
2908                    if (telephonyService != null) {
2909                        try {
2910                            if (telephonyService.isRinging()) {
2911                                Log.i(TAG, "interceptKeyBeforeQueueing:"
2912                                      + " CALL key-down while ringing: Answer the call!");
2913                                telephonyService.answerRingingCall();
2914
2915                                // And *don't* pass this key thru to the current activity
2916                                // (which is presumably the InCallScreen.)
2917                                result &= ~ACTION_PASS_TO_USER;
2918                            }
2919                        } catch (RemoteException ex) {
2920                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2921                        }
2922                    }
2923                }
2924                break;
2925            }
2926        }
2927        return result;
2928    }
2929
2930    /** {@inheritDoc} */
2931    @Override
2932    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
2933        int result = 0;
2934
2935        final boolean isWakeMotion = (policyFlags
2936                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
2937        if (isWakeMotion) {
2938            if (mKeyguardMediator.isShowing()) {
2939                // If the keyguard is showing, let it decide what to do with the wake motion.
2940                mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
2941            } else {
2942                // Otherwise, wake the device ourselves.
2943                result |= ACTION_POKE_USER_ACTIVITY;
2944            }
2945        }
2946        return result;
2947    }
2948
2949    class PassHeadsetKey implements Runnable {
2950        KeyEvent mKeyEvent;
2951
2952        PassHeadsetKey(KeyEvent keyEvent) {
2953            mKeyEvent = keyEvent;
2954        }
2955
2956        public void run() {
2957            if (ActivityManagerNative.isSystemReady()) {
2958                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
2959                intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
2960                mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
2961                        mHandler, Activity.RESULT_OK, null, null);
2962            }
2963        }
2964    }
2965
2966    BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
2967        public void onReceive(Context context, Intent intent) {
2968            mBroadcastWakeLock.release();
2969        }
2970    };
2971
2972    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
2973        public void onReceive(Context context, Intent intent) {
2974            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
2975                mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
2976                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
2977            } else {
2978                try {
2979                    IUiModeManager uiModeService = IUiModeManager.Stub.asInterface(
2980                            ServiceManager.getService(Context.UI_MODE_SERVICE));
2981                    mUiMode = uiModeService.getCurrentModeType();
2982                } catch (RemoteException e) {
2983                }
2984            }
2985            updateRotation(true);
2986            updateOrientationListenerLp();
2987        }
2988    };
2989
2990    /** {@inheritDoc} */
2991    public void screenTurnedOff(int why) {
2992        EventLog.writeEvent(70000, 0);
2993        synchronized (mLock) {
2994            mScreenOnEarly = false;
2995            mScreenOnFully = false;
2996        }
2997        mKeyguardMediator.onScreenTurnedOff(why);
2998        synchronized (mLock) {
2999            updateOrientationListenerLp();
3000            updateLockScreenTimeout();
3001        }
3002    }
3003
3004    /** {@inheritDoc} */
3005    public void screenTurningOn(final ScreenOnListener screenOnListener) {
3006        EventLog.writeEvent(70000, 1);
3007        if (false) {
3008            RuntimeException here = new RuntimeException("here");
3009            here.fillInStackTrace();
3010            Slog.i(TAG, "Screen turning on...", here);
3011        }
3012        if (screenOnListener != null) {
3013            mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
3014                @Override public void onShown(IBinder windowToken) {
3015                    if (windowToken != null) {
3016                        try {
3017                            mWindowManager.waitForWindowDrawn(windowToken,
3018                                    new IRemoteCallback.Stub() {
3019                                @Override public void sendResult(Bundle data) {
3020                                    Slog.i(TAG, "Lock screen displayed!");
3021                                    screenOnListener.onScreenOn();
3022                                    synchronized (mLock) {
3023                                        mScreenOnFully = true;
3024                                    }
3025                                }
3026                            });
3027                        } catch (RemoteException e) {
3028                        }
3029                    } else {
3030                        Slog.i(TAG, "No lock screen!");
3031                        screenOnListener.onScreenOn();
3032                        synchronized (mLock) {
3033                            mScreenOnFully = true;
3034                        }
3035                    }
3036                }
3037            });
3038        } else {
3039            synchronized (mLock) {
3040                mScreenOnFully = true;
3041            }
3042        }
3043        synchronized (mLock) {
3044            mScreenOnEarly = true;
3045            updateOrientationListenerLp();
3046            updateLockScreenTimeout();
3047        }
3048    }
3049
3050    /** {@inheritDoc} */
3051    public boolean isScreenOnEarly() {
3052        return mScreenOnEarly;
3053    }
3054
3055    /** {@inheritDoc} */
3056    public boolean isScreenOnFully() {
3057        return mScreenOnFully;
3058    }
3059
3060    /** {@inheritDoc} */
3061    public void enableKeyguard(boolean enabled) {
3062        mKeyguardMediator.setKeyguardEnabled(enabled);
3063    }
3064
3065    /** {@inheritDoc} */
3066    public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
3067        mKeyguardMediator.verifyUnlock(callback);
3068    }
3069
3070    private boolean keyguardIsShowingTq() {
3071        return mKeyguardMediator.isShowingAndNotHidden();
3072    }
3073
3074
3075    /** {@inheritDoc} */
3076    public boolean isKeyguardLocked() {
3077        return keyguardOn();
3078    }
3079
3080    /** {@inheritDoc} */
3081    public boolean isKeyguardSecure() {
3082        return mKeyguardMediator.isSecure();
3083    }
3084
3085    /** {@inheritDoc} */
3086    public boolean inKeyguardRestrictedKeyInputMode() {
3087        return mKeyguardMediator.isInputRestricted();
3088    }
3089
3090    public void dismissKeyguardLw() {
3091        if (!mKeyguardMediator.isSecure()) {
3092            if (mKeyguardMediator.isShowing()) {
3093                mHandler.post(new Runnable() {
3094                    public void run() {
3095                        mKeyguardMediator.keyguardDone(false, true);
3096                    }
3097                });
3098            }
3099        }
3100    }
3101
3102    void sendCloseSystemWindows() {
3103        sendCloseSystemWindows(mContext, null);
3104    }
3105
3106    void sendCloseSystemWindows(String reason) {
3107        sendCloseSystemWindows(mContext, reason);
3108    }
3109
3110    static void sendCloseSystemWindows(Context context, String reason) {
3111        if (ActivityManagerNative.isSystemReady()) {
3112            try {
3113                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
3114            } catch (RemoteException e) {
3115            }
3116        }
3117    }
3118
3119    @Override
3120    public int rotationForOrientationLw(int orientation, int lastRotation) {
3121        if (false) {
3122            Slog.v(TAG, "rotationForOrientationLw(orient="
3123                        + orientation + ", last=" + lastRotation
3124                        + "); user=" + mUserRotation + " "
3125                        + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
3126                            ? "USER_ROTATION_LOCKED" : "")
3127                        );
3128        }
3129
3130        synchronized (mLock) {
3131            int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1
3132            if (sensorRotation < 0) {
3133                sensorRotation = lastRotation;
3134            }
3135
3136            final int preferredRotation;
3137            if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) {
3138                // Ignore sensor when lid switch is open and rotation is forced.
3139                preferredRotation = mLidOpenRotation;
3140            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
3141                    && (mCarDockEnablesAccelerometer || mCarDockRotation >= 0)) {
3142                // Ignore sensor when in car dock unless explicitly enabled.
3143                // This case can override the behavior of NOSENSOR, and can also
3144                // enable 180 degree rotation while docked.
3145                preferredRotation = mCarDockEnablesAccelerometer
3146                        ? sensorRotation : mCarDockRotation;
3147            } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK
3148                    || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
3149                    || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
3150                    && (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
3151                // Ignore sensor when in desk dock unless explicitly enabled.
3152                // This case can override the behavior of NOSENSOR, and can also
3153                // enable 180 degree rotation while docked.
3154                preferredRotation = mDeskDockEnablesAccelerometer
3155                        ? sensorRotation : mDeskDockRotation;
3156            } else if (mHdmiPlugged) {
3157                // Ignore sensor when plugged into HDMI.
3158                // Note that the dock orientation overrides the HDMI orientation.
3159                preferredRotation = mHdmiRotation;
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