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