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