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