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