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