PhoneWindowManager.java revision 38014763a2ceec005682066da01849adf95839bd
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.Handler;
38import android.os.IBinder;
39import android.os.LocalPowerManager;
40import android.os.Looper;
41import android.os.PowerManager;
42import android.os.RemoteException;
43import android.os.ServiceManager;
44import android.os.SystemClock;
45import android.os.SystemProperties;
46import android.os.Vibrator;
47import android.provider.Settings;
48
49import com.android.internal.R;
50import com.android.internal.policy.PolicyManager;
51import com.android.internal.statusbar.IStatusBarService;
52import com.android.internal.telephony.ITelephony;
53import com.android.internal.view.BaseInputHandler;
54import com.android.internal.widget.PointerLocationView;
55
56import android.util.Config;
57import android.util.EventLog;
58import android.util.Log;
59import android.util.Slog;
60import android.view.Display;
61import android.view.Gravity;
62import android.view.HapticFeedbackConstants;
63import android.view.IWindowManager;
64import android.view.InputChannel;
65import android.view.InputQueue;
66import android.view.InputHandler;
67import android.view.KeyEvent;
68import android.view.MotionEvent;
69import android.view.WindowOrientationListener;
70import android.view.Surface;
71import android.view.View;
72import android.view.ViewConfiguration;
73import android.view.Window;
74import android.view.WindowManager;
75import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
76import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
77import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
78import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
79import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
80import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
81import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
82import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
83import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
84import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
85import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
86import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
87import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
88import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
89import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
90import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
91import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
92import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
93import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
94import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
95import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
96import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
97import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
98import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
99import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
100import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
101import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
102import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
103import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
104import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
105import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
106import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
107import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
108import android.view.WindowManagerImpl;
109import android.view.WindowManagerPolicy;
110import android.view.animation.Animation;
111import android.view.animation.AnimationUtils;
112import android.media.IAudioService;
113import android.media.AudioManager;
114
115import java.util.ArrayList;
116
117/**
118 * WindowManagerPolicy implementation for the Android phone UI.  This
119 * introduces a new method suffix, Lp, for an internal lock of the
120 * PhoneWindowManager.  This is used to protect some internal state, and
121 * can be acquired with either thw Lw and Li lock held, so has the restrictions
122 * of both of those when held.
123 */
124public class PhoneWindowManager implements WindowManagerPolicy {
125    static final String TAG = "WindowManager";
126    static final boolean DEBUG = false;
127    static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
128    static final boolean DEBUG_LAYOUT = false;
129    static final boolean SHOW_STARTING_ANIMATIONS = true;
130    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
131
132    // wallpaper is at the bottom, though the window manager may move it.
133    static final int WALLPAPER_LAYER = 2;
134    static final int APPLICATION_LAYER = 2;
135    static final int PHONE_LAYER = 3;
136    static final int SEARCH_BAR_LAYER = 4;
137    static final int STATUS_BAR_PANEL_LAYER = 5;
138    static final int SYSTEM_DIALOG_LAYER = 6;
139    // toasts and the plugged-in battery thing
140    static final int TOAST_LAYER = 7;
141    static final int STATUS_BAR_LAYER = 8;
142    // SIM errors and unlock.  Not sure if this really should be in a high layer.
143    static final int PRIORITY_PHONE_LAYER = 9;
144    // like the ANR / app crashed dialogs
145    static final int SYSTEM_ALERT_LAYER = 10;
146    // system-level error dialogs
147    static final int SYSTEM_ERROR_LAYER = 11;
148    // on-screen keyboards and other such input method user interfaces go here.
149    static final int INPUT_METHOD_LAYER = 12;
150    // on-screen keyboards and other such input method user interfaces go here.
151    static final int INPUT_METHOD_DIALOG_LAYER = 13;
152    // the keyguard; nothing on top of these can take focus, since they are
153    // responsible for power management when displayed.
154    static final int KEYGUARD_LAYER = 14;
155    static final int KEYGUARD_DIALOG_LAYER = 15;
156    // the drag layer: input for drag-and-drop is associated with this window,
157    // which sits above all other focusable windows
158    static final int DRAG_LAYER = 16;
159    // things in here CAN NOT take focus, but are shown on top of everything else.
160    static final int SYSTEM_OVERLAY_LAYER = 17;
161
162    static final int APPLICATION_MEDIA_SUBLAYER = -2;
163    static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
164    static final int APPLICATION_PANEL_SUBLAYER = 1;
165    static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
166
167    // Debugging: set this to have the system act like there is no hard keyboard.
168    static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
169
170    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
171    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
172    static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
173    static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
174
175    // Useful scan codes.
176    private static final int SW_LID = 0x00;
177    private static final int BTN_MOUSE = 0x110;
178
179    final Object mLock = new Object();
180
181    Context mContext;
182    IWindowManager mWindowManager;
183    LocalPowerManager mPowerManager;
184    IStatusBarService mStatusBarService;
185    Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
186
187    // Vibrator pattern for haptic feedback of a long press.
188    long[] mLongPressVibePattern;
189
190    // Vibrator pattern for haptic feedback of virtual key press.
191    long[] mVirtualKeyVibePattern;
192
193    // Vibrator pattern for a short vibration.
194    long[] mKeyboardTapVibePattern;
195
196    // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
197    long[] mSafeModeDisabledVibePattern;
198
199    // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
200    long[] mSafeModeEnabledVibePattern;
201
202    /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
203    boolean mEnableShiftMenuBugReports = false;
204
205    boolean mSafeMode;
206    WindowState mStatusBar = null;
207    boolean mStatusBarCanHide;
208    final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
209    WindowState mKeyguard = null;
210    KeyguardViewMediator mKeyguardMediator;
211    GlobalActions mGlobalActions;
212    boolean mShouldTurnOffOnKeyUp;
213    RecentApplicationsDialog mRecentAppsDialog;
214    Handler mHandler;
215
216    boolean mSystemReady;
217    boolean mLidOpen;
218    int mUiMode = Configuration.UI_MODE_TYPE_NORMAL;
219    int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
220    int mLidOpenRotation;
221    int mCarDockRotation;
222    int mDeskDockRotation;
223    boolean mCarDockEnablesAccelerometer;
224    boolean mDeskDockEnablesAccelerometer;
225    int mLidKeyboardAccessibility;
226    int mLidNavigationAccessibility;
227    boolean mScreenOn = false;
228    boolean mOrientationSensorEnabled = false;
229    int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
230    static final int DEFAULT_ACCELEROMETER_ROTATION = 0;
231    int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION;
232    boolean mHasSoftInput = false;
233
234    int mPointerLocationMode = 0;
235    PointerLocationView mPointerLocationView = null;
236    InputChannel mPointerLocationInputChannel;
237
238    private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() {
239        @Override
240        public void handleMotion(MotionEvent event, Runnable finishedCallback) {
241            finishedCallback.run();
242
243            synchronized (mLock) {
244                if (mPointerLocationView != null) {
245                    mPointerLocationView.addTouchEvent(event);
246                }
247            }
248        }
249    };
250
251    // The current size of the screen.
252    int mW, mH;
253    // During layout, the current screen borders with all outer decoration
254    // (status bar, input method dock) accounted for.
255    int mCurLeft, mCurTop, mCurRight, mCurBottom;
256    // During layout, the frame in which content should be displayed
257    // to the user, accounting for all screen decoration except for any
258    // space they deem as available for other content.  This is usually
259    // the same as mCur*, but may be larger if the screen decor has supplied
260    // content insets.
261    int mContentLeft, mContentTop, mContentRight, mContentBottom;
262    // During layout, the current screen borders along with input method
263    // windows are placed.
264    int mDockLeft, mDockTop, mDockRight, mDockBottom;
265    // During layout, the layer at which the doc window is placed.
266    int mDockLayer;
267
268    static final Rect mTmpParentFrame = new Rect();
269    static final Rect mTmpDisplayFrame = new Rect();
270    static final Rect mTmpContentFrame = new Rect();
271    static final Rect mTmpVisibleFrame = new Rect();
272
273    WindowState mTopFullscreenOpaqueWindowState;
274    boolean mTopIsFullscreen;
275    boolean mForceStatusBar;
276    boolean mHideLockScreen;
277    boolean mDismissKeyguard;
278    boolean mHomePressed;
279    Intent mHomeIntent;
280    Intent mCarDockIntent;
281    Intent mDeskDockIntent;
282    boolean mSearchKeyPressed;
283    boolean mConsumeSearchKeyUp;
284
285    // support for activating the lock screen while the screen is on
286    boolean mAllowLockscreenWhenOn;
287    int mLockScreenTimeout;
288    boolean mLockScreenTimerActive;
289
290    // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
291    int mEndcallBehavior;
292
293    // Behavior of POWER button while in-call and screen on.
294    // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.)
295    int mIncallPowerBehavior;
296
297    int mLandscapeRotation = -1; // default landscape rotation
298    int mSeascapeRotation = -1; // "other" landscape rotation, 180 degrees from mLandscapeRotation
299    int mPortraitRotation = -1; // default portrait rotation
300    int mUpsideDownRotation = -1; // "other" portrait rotation
301
302    // Nothing to see here, move along...
303    int mFancyRotationAnimation;
304
305    // Enable 3D recents based on config settings.
306    private Boolean mUse3dRecents;
307
308    ShortcutManager mShortcutManager;
309    PowerManager.WakeLock mBroadcastWakeLock;
310
311    class SettingsObserver extends ContentObserver {
312        SettingsObserver(Handler handler) {
313            super(handler);
314        }
315
316        void observe() {
317            ContentResolver resolver = mContext.getContentResolver();
318            resolver.registerContentObserver(Settings.System.getUriFor(
319                    Settings.System.END_BUTTON_BEHAVIOR), false, this);
320            resolver.registerContentObserver(Settings.Secure.getUriFor(
321                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this);
322            resolver.registerContentObserver(Settings.System.getUriFor(
323                    Settings.System.ACCELEROMETER_ROTATION), false, this);
324            resolver.registerContentObserver(Settings.System.getUriFor(
325                    Settings.System.SCREEN_OFF_TIMEOUT), false, this);
326            resolver.registerContentObserver(Settings.System.getUriFor(
327                    Settings.System.POINTER_LOCATION), false, this);
328            resolver.registerContentObserver(Settings.Secure.getUriFor(
329                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
330            resolver.registerContentObserver(Settings.System.getUriFor(
331                    "fancy_rotation_anim"), false, this);
332            updateSettings();
333        }
334
335        @Override public void onChange(boolean selfChange) {
336            updateSettings();
337            try {
338                mWindowManager.setRotation(USE_LAST_ROTATION, false,
339                        mFancyRotationAnimation);
340            } catch (RemoteException e) {
341                // Ignore
342            }
343        }
344    }
345
346    class MyOrientationListener extends WindowOrientationListener {
347        MyOrientationListener(Context context) {
348            super(context);
349        }
350
351        @Override
352        public void onOrientationChanged(int rotation) {
353            // Send updates based on orientation value
354            if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation);
355            try {
356                mWindowManager.setRotation(rotation, false,
357                        mFancyRotationAnimation);
358            } catch (RemoteException e) {
359                // Ignore
360
361            }
362        }
363    }
364    MyOrientationListener mOrientationListener;
365
366    boolean useSensorForOrientationLp(int appOrientation) {
367        // The app says use the sensor.
368        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
369                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
370                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
371                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
372            return true;
373        }
374        // The user preference says we can rotate, and the app is willing to rotate.
375        if (mAccelerometerDefault != 0 &&
376                (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
377                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
378            return true;
379        }
380        // We're in a dock that has a rotation affinity, and the app is willing to rotate.
381        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR)
382                || (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
383            // Note we override the nosensor flag here.
384            if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
385                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
386                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
387                return true;
388            }
389        }
390        // Else, don't use the sensor.
391        return false;
392    }
393
394    /*
395     * We always let the sensor be switched on by default except when
396     * the user has explicitly disabled sensor based rotation or when the
397     * screen is switched off.
398     */
399    boolean needSensorRunningLp() {
400        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
401                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
402                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
403                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
404            // If the application has explicitly requested to follow the
405            // orientation, then we need to turn the sensor or.
406            return true;
407        }
408        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
409                (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
410            // enable accelerometer if we are docked in a dock that enables accelerometer
411            // orientation management,
412            return true;
413        }
414        if (mAccelerometerDefault == 0) {
415            // If the setting for using the sensor by default is enabled, then
416            // we will always leave it on.  Note that the user could go to
417            // a window that forces an orientation that does not use the
418            // sensor and in theory we could turn it off... however, when next
419            // turning it on we won't have a good value for the current
420            // orientation for a little bit, which can cause orientation
421            // changes to lag, so we'd like to keep it always on.  (It will
422            // still be turned off when the screen is off.)
423            return false;
424        }
425        return true;
426    }
427
428    /*
429     * Various use cases for invoking this function
430     * screen turning off, should always disable listeners if already enabled
431     * screen turned on and current app has sensor based orientation, enable listeners
432     * if not already enabled
433     * screen turned on and current app does not have sensor orientation, disable listeners if
434     * already enabled
435     * screen turning on and current app has sensor based orientation, enable listeners if needed
436     * screen turning on and current app has nosensor based orientation, do nothing
437     */
438    void updateOrientationListenerLp() {
439        if (!mOrientationListener.canDetectOrientation()) {
440            // If sensor is turned off or nonexistent for some reason
441            return;
442        }
443        //Could have been invoked due to screen turning on or off or
444        //change of the currently visible window's orientation
445        if (localLOGV) Log.v(TAG, "Screen status="+mScreenOn+
446                ", current orientation="+mCurrentAppOrientation+
447                ", SensorEnabled="+mOrientationSensorEnabled);
448        boolean disable = true;
449        if (mScreenOn) {
450            if (needSensorRunningLp()) {
451                disable = false;
452                //enable listener if not already enabled
453                if (!mOrientationSensorEnabled) {
454                    mOrientationListener.enable();
455                    if(localLOGV) Log.v(TAG, "Enabling listeners");
456                    mOrientationSensorEnabled = true;
457                }
458            }
459        }
460        //check if sensors need to be disabled
461        if (disable && mOrientationSensorEnabled) {
462            mOrientationListener.disable();
463            if(localLOGV) Log.v(TAG, "Disabling listeners");
464            mOrientationSensorEnabled = false;
465        }
466    }
467
468    Runnable mPowerLongPress = new Runnable() {
469        public void run() {
470            mShouldTurnOffOnKeyUp = false;
471            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
472            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
473            showGlobalActionsDialog();
474        }
475    };
476
477    void showGlobalActionsDialog() {
478        if (mGlobalActions == null) {
479            mGlobalActions = new GlobalActions(mContext);
480        }
481        final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden();
482        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
483        if (keyguardShowing) {
484            // since it took two seconds of long press to bring this up,
485            // poke the wake lock so they have some time to see the dialog.
486            mKeyguardMediator.pokeWakelock();
487        }
488    }
489
490    boolean isDeviceProvisioned() {
491        return Settings.Secure.getInt(
492                mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
493    }
494
495    /**
496     * When a home-key longpress expires, close other system windows and launch the recent apps
497     */
498    Runnable mHomeLongPress = new Runnable() {
499        public void run() {
500            /*
501             * Eat the longpress so it won't dismiss the recent apps dialog when
502             * the user lets go of the home key
503             */
504            mHomePressed = false;
505            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
506            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
507            showRecentAppsDialog();
508        }
509    };
510
511    /**
512     * Create (if necessary) and launch the recent apps dialog
513     */
514    void showRecentAppsDialog() {
515        // We can't initialize this in init() since the configuration hasn't been loaded yet.
516        if (mUse3dRecents == null) {
517            mUse3dRecents = mContext.getResources().getBoolean(R.bool.config_enableRecentApps3D);
518        }
519
520        // Use 3d Recents dialog
521        if (mUse3dRecents) {
522            try {
523                Intent intent = new Intent();
524                intent.setClassName("com.android.systemui",
525                        "com.android.systemui.statusbar.RecentApplicationsActivity");
526                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
527                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
528                mContext.startActivity(intent);
529                return;
530            } catch (ActivityNotFoundException e) {
531                Log.e(TAG, "Failed to launch RecentAppsIntent", e);
532            }
533        }
534
535        // Fallback to dialog if we fail to launch the above.
536        if (mRecentAppsDialog == null) {
537            mRecentAppsDialog = new RecentApplicationsDialog(mContext);
538        }
539        mRecentAppsDialog.show();
540    }
541
542    /** {@inheritDoc} */
543    public void init(Context context, IWindowManager windowManager,
544            LocalPowerManager powerManager) {
545        mContext = context;
546        mWindowManager = windowManager;
547        mPowerManager = powerManager;
548        mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
549        mHandler = new Handler();
550        mOrientationListener = new MyOrientationListener(mContext);
551        SettingsObserver settingsObserver = new SettingsObserver(mHandler);
552        settingsObserver.observe();
553        mShortcutManager = new ShortcutManager(context, mHandler);
554        mShortcutManager.observe();
555        mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
556        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
557        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
558                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
559        mCarDockIntent =  new Intent(Intent.ACTION_MAIN, null);
560        mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
561        mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
562                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
563        mDeskDockIntent =  new Intent(Intent.ACTION_MAIN, null);
564        mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
565        mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
566                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
567
568        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
569        mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
570                "PhoneWindowManager.mBroadcastWakeLock");
571        mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
572        mLidOpenRotation = readRotation(
573                com.android.internal.R.integer.config_lidOpenRotation);
574        mCarDockRotation = readRotation(
575                com.android.internal.R.integer.config_carDockRotation);
576        mDeskDockRotation = readRotation(
577                com.android.internal.R.integer.config_deskDockRotation);
578        mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
579                com.android.internal.R.bool.config_carDockEnablesAccelerometer);
580        mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
581                com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
582        mLidKeyboardAccessibility = mContext.getResources().getInteger(
583                com.android.internal.R.integer.config_lidKeyboardAccessibility);
584        mLidNavigationAccessibility = mContext.getResources().getInteger(
585                com.android.internal.R.integer.config_lidNavigationAccessibility);
586        // register for dock events
587        IntentFilter filter = new IntentFilter();
588        filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
589        filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE);
590        filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE);
591        filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE);
592        filter.addAction(Intent.ACTION_DOCK_EVENT);
593        Intent intent = context.registerReceiver(mDockReceiver, filter);
594        if (intent != null) {
595            // Retrieve current sticky dock event broadcast.
596            mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
597                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
598        }
599        mVibrator = new Vibrator();
600        mLongPressVibePattern = getLongIntArray(mContext.getResources(),
601                com.android.internal.R.array.config_longPressVibePattern);
602        mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
603                com.android.internal.R.array.config_virtualKeyVibePattern);
604        mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(),
605                com.android.internal.R.array.config_keyboardTapVibePattern);
606        mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
607                com.android.internal.R.array.config_safeModeDisabledVibePattern);
608        mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
609                com.android.internal.R.array.config_safeModeEnabledVibePattern);
610
611        // Note: the Configuration is not stable here, so we cannot load mStatusBarCanHide from
612        // config_statusBarCanHide because the latter depends on the screen size
613    }
614
615    public void updateSettings() {
616        ContentResolver resolver = mContext.getContentResolver();
617        boolean updateRotation = false;
618        View addView = null;
619        View removeView = null;
620        synchronized (mLock) {
621            mEndcallBehavior = Settings.System.getInt(resolver,
622                    Settings.System.END_BUTTON_BEHAVIOR,
623                    Settings.System.END_BUTTON_BEHAVIOR_DEFAULT);
624            mIncallPowerBehavior = Settings.Secure.getInt(resolver,
625                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
626                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
627            mFancyRotationAnimation = Settings.System.getInt(resolver,
628                    "fancy_rotation_anim", 0) != 0 ? 0x80 : 0;
629            int accelerometerDefault = Settings.System.getInt(resolver,
630                    Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
631            if (mAccelerometerDefault != accelerometerDefault) {
632                mAccelerometerDefault = accelerometerDefault;
633                updateOrientationListenerLp();
634            }
635            if (mSystemReady) {
636                int pointerLocation = Settings.System.getInt(resolver,
637                        Settings.System.POINTER_LOCATION, 0);
638                if (mPointerLocationMode != pointerLocation) {
639                    mPointerLocationMode = pointerLocation;
640                    if (pointerLocation != 0) {
641                        if (mPointerLocationView == null) {
642                            mPointerLocationView = new PointerLocationView(mContext);
643                            mPointerLocationView.setPrintCoords(false);
644                            addView = mPointerLocationView;
645                        }
646                    } else {
647                        removeView = mPointerLocationView;
648                        mPointerLocationView = null;
649                    }
650                }
651            }
652            // use screen off timeout setting as the timeout for the lockscreen
653            mLockScreenTimeout = Settings.System.getInt(resolver,
654                    Settings.System.SCREEN_OFF_TIMEOUT, 0);
655            String imId = Settings.Secure.getString(resolver,
656                    Settings.Secure.DEFAULT_INPUT_METHOD);
657            boolean hasSoftInput = imId != null && imId.length() > 0;
658            if (mHasSoftInput != hasSoftInput) {
659                mHasSoftInput = hasSoftInput;
660                updateRotation = true;
661            }
662        }
663        if (updateRotation) {
664            updateRotation(0);
665        }
666        if (addView != null) {
667            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
668                    WindowManager.LayoutParams.MATCH_PARENT,
669                    WindowManager.LayoutParams.MATCH_PARENT);
670            lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
671            lp.flags =
672                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
673                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
674                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
675            lp.format = PixelFormat.TRANSLUCENT;
676            lp.setTitle("PointerLocation");
677            WindowManagerImpl wm = (WindowManagerImpl)
678                    mContext.getSystemService(Context.WINDOW_SERVICE);
679            wm.addView(addView, lp);
680
681            if (mPointerLocationInputChannel == null) {
682                try {
683                    mPointerLocationInputChannel =
684                        mWindowManager.monitorInput("PointerLocationView");
685                    InputQueue.registerInputChannel(mPointerLocationInputChannel,
686                            mPointerLocationInputHandler, mHandler.getLooper().getQueue());
687                } catch (RemoteException ex) {
688                    Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.",
689                            ex);
690                }
691            }
692        }
693        if (removeView != null) {
694            if (mPointerLocationInputChannel != null) {
695                InputQueue.unregisterInputChannel(mPointerLocationInputChannel);
696                mPointerLocationInputChannel.dispose();
697                mPointerLocationInputChannel = null;
698            }
699
700            WindowManagerImpl wm = (WindowManagerImpl)
701                    mContext.getSystemService(Context.WINDOW_SERVICE);
702            wm.removeView(removeView);
703        }
704    }
705
706    private int readRotation(int resID) {
707        try {
708            int rotation = mContext.getResources().getInteger(resID);
709            switch (rotation) {
710                case 0:
711                    return Surface.ROTATION_0;
712                case 90:
713                    return Surface.ROTATION_90;
714                case 180:
715                    return Surface.ROTATION_180;
716                case 270:
717                    return Surface.ROTATION_270;
718            }
719        } catch (Resources.NotFoundException e) {
720            // fall through
721        }
722        return -1;
723    }
724
725    /** {@inheritDoc} */
726    public int checkAddPermission(WindowManager.LayoutParams attrs) {
727        int type = attrs.type;
728
729        if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
730                || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
731            return WindowManagerImpl.ADD_OKAY;
732        }
733        String permission = null;
734        switch (type) {
735            case TYPE_TOAST:
736                // XXX right now the app process has complete control over
737                // this...  should introduce a token to let the system
738                // monitor/control what they are doing.
739                break;
740            case TYPE_INPUT_METHOD:
741            case TYPE_WALLPAPER:
742                // The window manager will check these.
743                break;
744            case TYPE_PHONE:
745            case TYPE_PRIORITY_PHONE:
746            case TYPE_SYSTEM_ALERT:
747            case TYPE_SYSTEM_ERROR:
748            case TYPE_SYSTEM_OVERLAY:
749                permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
750                break;
751            default:
752                permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
753        }
754        if (permission != null) {
755            if (mContext.checkCallingOrSelfPermission(permission)
756                    != PackageManager.PERMISSION_GRANTED) {
757                return WindowManagerImpl.ADD_PERMISSION_DENIED;
758            }
759        }
760        return WindowManagerImpl.ADD_OKAY;
761    }
762
763    public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
764        switch (attrs.type) {
765            case TYPE_SYSTEM_OVERLAY:
766            case TYPE_TOAST:
767                // These types of windows can't receive input events.
768                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
769                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
770                break;
771        }
772    }
773
774    void readLidState() {
775        try {
776            int sw = mWindowManager.getSwitchState(SW_LID);
777            if (sw >= 0) {
778                mLidOpen = sw == 0;
779            }
780        } catch (RemoteException e) {
781            // Ignore
782        }
783    }
784
785    private int determineHiddenState(boolean lidOpen,
786            int mode, int hiddenValue, int visibleValue) {
787        switch (mode) {
788            case 1:
789                return lidOpen ? visibleValue : hiddenValue;
790            case 2:
791                return lidOpen ? hiddenValue : visibleValue;
792        }
793        return visibleValue;
794    }
795
796    /** {@inheritDoc} */
797    public void adjustConfigurationLw(Configuration config) {
798        readLidState();
799        final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen;
800        mPowerManager.setKeyboardVisibility(lidOpen);
801        config.hardKeyboardHidden = determineHiddenState(lidOpen,
802                mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES,
803                Configuration.HARDKEYBOARDHIDDEN_NO);
804        config.navigationHidden = determineHiddenState(lidOpen,
805                mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES,
806                Configuration.NAVIGATIONHIDDEN_NO);
807        config.keyboardHidden = (config.hardKeyboardHidden
808                        == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput)
809                ? Configuration.KEYBOARDHIDDEN_NO
810                : Configuration.KEYBOARDHIDDEN_YES;
811    }
812
813    /** {@inheritDoc} */
814    public int windowTypeToLayerLw(int type) {
815        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
816            return APPLICATION_LAYER;
817        }
818        switch (type) {
819        case TYPE_STATUS_BAR:
820            return STATUS_BAR_LAYER;
821        case TYPE_STATUS_BAR_PANEL:
822            return STATUS_BAR_PANEL_LAYER;
823        case TYPE_SYSTEM_DIALOG:
824            return SYSTEM_DIALOG_LAYER;
825        case TYPE_SEARCH_BAR:
826            return SEARCH_BAR_LAYER;
827        case TYPE_PHONE:
828            return PHONE_LAYER;
829        case TYPE_KEYGUARD:
830            return KEYGUARD_LAYER;
831        case TYPE_KEYGUARD_DIALOG:
832            return KEYGUARD_DIALOG_LAYER;
833        case TYPE_SYSTEM_ALERT:
834            return SYSTEM_ALERT_LAYER;
835        case TYPE_SYSTEM_ERROR:
836            return SYSTEM_ERROR_LAYER;
837        case TYPE_INPUT_METHOD:
838            return INPUT_METHOD_LAYER;
839        case TYPE_INPUT_METHOD_DIALOG:
840            return INPUT_METHOD_DIALOG_LAYER;
841        case TYPE_SYSTEM_OVERLAY:
842            return SYSTEM_OVERLAY_LAYER;
843        case TYPE_PRIORITY_PHONE:
844            return PRIORITY_PHONE_LAYER;
845        case TYPE_TOAST:
846            return TOAST_LAYER;
847        case TYPE_WALLPAPER:
848            return WALLPAPER_LAYER;
849        case TYPE_DRAG:
850            return DRAG_LAYER;
851        }
852        Log.e(TAG, "Unknown window type: " + type);
853        return APPLICATION_LAYER;
854    }
855
856    /** {@inheritDoc} */
857    public int subWindowTypeToLayerLw(int type) {
858        switch (type) {
859        case TYPE_APPLICATION_PANEL:
860        case TYPE_APPLICATION_ATTACHED_DIALOG:
861            return APPLICATION_PANEL_SUBLAYER;
862        case TYPE_APPLICATION_MEDIA:
863            return APPLICATION_MEDIA_SUBLAYER;
864        case TYPE_APPLICATION_MEDIA_OVERLAY:
865            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
866        case TYPE_APPLICATION_SUB_PANEL:
867            return APPLICATION_SUB_PANEL_SUBLAYER;
868        }
869        Log.e(TAG, "Unknown sub-window type: " + type);
870        return 0;
871    }
872
873    public int getMaxWallpaperLayer() {
874        return STATUS_BAR_LAYER;
875    }
876
877    public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
878        return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
879    }
880
881    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
882        return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
883                && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
884    }
885
886    /** {@inheritDoc} */
887    public View addStartingWindow(IBinder appToken, String packageName,
888                                  int theme, CharSequence nonLocalizedLabel,
889                                  int labelRes, int icon) {
890        if (!SHOW_STARTING_ANIMATIONS) {
891            return null;
892        }
893        if (packageName == null) {
894            return null;
895        }
896
897        try {
898            Context context = mContext;
899            boolean setTheme = false;
900            //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
901            //        + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
902            if (theme != 0 || labelRes != 0) {
903                try {
904                    context = context.createPackageContext(packageName, 0);
905                    if (theme != 0) {
906                        context.setTheme(theme);
907                        setTheme = true;
908                    }
909                } catch (PackageManager.NameNotFoundException e) {
910                    // Ignore
911                }
912            }
913            if (!setTheme) {
914                context.setTheme(com.android.internal.R.style.Theme);
915            }
916
917            Window win = PolicyManager.makeNewWindow(context);
918            if (win.getWindowStyle().getBoolean(
919                    com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
920                return null;
921            }
922
923            Resources r = context.getResources();
924            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
925
926            win.setType(
927                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
928            // Force the window flags: this is a fake window, so it is not really
929            // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
930            // flag because we do know that the next window will take input
931            // focus, so we want to get the IME window up on top of us right away.
932            win.setFlags(
933                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
934                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
935                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
936                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
937                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
938                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
939
940            win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
941                                WindowManager.LayoutParams.MATCH_PARENT);
942
943            final WindowManager.LayoutParams params = win.getAttributes();
944            params.token = appToken;
945            params.packageName = packageName;
946            params.windowAnimations = win.getWindowStyle().getResourceId(
947                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
948            params.setTitle("Starting " + packageName);
949
950            WindowManagerImpl wm = (WindowManagerImpl)
951                    context.getSystemService(Context.WINDOW_SERVICE);
952            View view = win.getDecorView();
953
954            if (win.isFloating()) {
955                // Whoops, there is no way to display an animation/preview
956                // of such a thing!  After all that work...  let's skip it.
957                // (Note that we must do this here because it is in
958                // getDecorView() where the theme is evaluated...  maybe
959                // we should peek the floating attribute from the theme
960                // earlier.)
961                return null;
962            }
963
964            if (localLOGV) Log.v(
965                TAG, "Adding starting window for " + packageName
966                + " / " + appToken + ": "
967                + (view.getParent() != null ? view : null));
968
969            wm.addView(view, params);
970
971            // Only return the view if it was successfully added to the
972            // window manager... which we can tell by it having a parent.
973            return view.getParent() != null ? view : null;
974        } catch (WindowManagerImpl.BadTokenException e) {
975            // ignore
976            Log.w(TAG, appToken + " already running, starting window not displayed");
977        } catch (RuntimeException e) {
978            // don't crash if something else bad happens, for example a
979            // failure loading resources because we are loading from an app
980            // on external storage that has been unmounted.
981            Log.w(TAG, appToken + " failed creating starting window", e);
982        }
983
984        return null;
985    }
986
987    /** {@inheritDoc} */
988    public void removeStartingWindow(IBinder appToken, View window) {
989        // RuntimeException e = new RuntimeException();
990        // Log.i(TAG, "remove " + appToken + " " + window, e);
991
992        if (localLOGV) Log.v(
993            TAG, "Removing starting window for " + appToken + ": " + window);
994
995        if (window != null) {
996            WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE);
997            wm.removeView(window);
998        }
999    }
1000
1001    /**
1002     * Preflight adding a window to the system.
1003     *
1004     * Currently enforces that three window types are singletons:
1005     * <ul>
1006     * <li>STATUS_BAR_TYPE</li>
1007     * <li>KEYGUARD_TYPE</li>
1008     * </ul>
1009     *
1010     * @param win The window to be added
1011     * @param attrs Information about the window to be added
1012     *
1013     * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
1014     */
1015    public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
1016        switch (attrs.type) {
1017            case TYPE_STATUS_BAR:
1018                mContext.enforceCallingOrSelfPermission(
1019                        android.Manifest.permission.STATUS_BAR_SERVICE,
1020                        "PhoneWindowManager");
1021                // TODO: Need to handle the race condition of the status bar proc
1022                // dying and coming back before the removeWindowLw cleanup has happened.
1023                if (mStatusBar != null) {
1024                    return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
1025                }
1026                mStatusBar = win;
1027
1028                // The Configuration will be stable by now, so we can load this
1029                mStatusBarCanHide = mContext.getResources().getBoolean(
1030                        com.android.internal.R.bool.config_statusBarCanHide);
1031
1032                break;
1033            case TYPE_STATUS_BAR_PANEL:
1034                mContext.enforceCallingOrSelfPermission(
1035                        android.Manifest.permission.STATUS_BAR_SERVICE,
1036                        "PhoneWindowManager");
1037                mStatusBarPanels.add(win);
1038                break;
1039            case TYPE_KEYGUARD:
1040                if (mKeyguard != null) {
1041                    return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
1042                }
1043                mKeyguard = win;
1044                break;
1045        }
1046        return WindowManagerImpl.ADD_OKAY;
1047    }
1048
1049    /** {@inheritDoc} */
1050    public void removeWindowLw(WindowState win) {
1051        if (mStatusBar == win) {
1052            mStatusBar = null;
1053        }
1054        else if (mKeyguard == win) {
1055            mKeyguard = null;
1056        } else {
1057            mStatusBarPanels.remove(win);
1058        }
1059    }
1060
1061    static final boolean PRINT_ANIM = false;
1062
1063    /** {@inheritDoc} */
1064    public int selectAnimationLw(WindowState win, int transit) {
1065        if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
1066              + ": transit=" + transit);
1067        if (transit == TRANSIT_PREVIEW_DONE) {
1068            if (win.hasAppShownWindows()) {
1069                if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
1070                return com.android.internal.R.anim.app_starting_exit;
1071            }
1072        }
1073
1074        return 0;
1075    }
1076
1077    public Animation createForceHideEnterAnimation() {
1078        return AnimationUtils.loadAnimation(mContext,
1079                com.android.internal.R.anim.lock_screen_behind_enter);
1080    }
1081
1082    static ITelephony getPhoneInterface() {
1083        return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
1084    }
1085
1086    static IAudioService getAudioInterface() {
1087        return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
1088    }
1089
1090    boolean keyguardOn() {
1091        return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode();
1092    }
1093
1094    private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
1095            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
1096            WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
1097        };
1098
1099    /** {@inheritDoc} */
1100    @Override
1101    public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
1102            int keyCode, int metaState, int repeatCount, int policyFlags) {
1103        final boolean keyguardOn = keyguardOn();
1104        final boolean down = (action == KeyEvent.ACTION_DOWN);
1105        final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
1106
1107        if (false) {
1108            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
1109                    + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
1110        }
1111
1112        // Clear a pending HOME longpress if the user releases Home
1113        // TODO: This could probably be inside the next bit of logic, but that code
1114        // turned out to be a bit fragile so I'm doing it here explicitly, for now.
1115        if ((keyCode == KeyEvent.KEYCODE_HOME) && !down) {
1116            mHandler.removeCallbacks(mHomeLongPress);
1117        }
1118
1119        // If the HOME button is currently being held, then we do special
1120        // chording with it.
1121        if (mHomePressed) {
1122
1123            // If we have released the home key, and didn't do anything else
1124            // while it was pressed, then it is time to go home!
1125            if (keyCode == KeyEvent.KEYCODE_HOME) {
1126                if (!down) {
1127                    mHomePressed = false;
1128
1129                    if (! canceled) {
1130                        // If an incoming call is ringing, HOME is totally disabled.
1131                        // (The user is already on the InCallScreen at this point,
1132                        // and his ONLY options are to answer or reject the call.)
1133                        boolean incomingRinging = false;
1134                        try {
1135                            ITelephony phoneServ = getPhoneInterface();
1136                            if (phoneServ != null) {
1137                                incomingRinging = phoneServ.isRinging();
1138                            } else {
1139                                Log.w(TAG, "Unable to find ITelephony interface");
1140                            }
1141                        } catch (RemoteException ex) {
1142                            Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
1143                        }
1144
1145                        if (incomingRinging) {
1146                            Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
1147                        } else {
1148                            launchHomeFromHotKey();
1149                        }
1150                    } else {
1151                        Log.i(TAG, "Ignoring HOME; event canceled.");
1152                    }
1153                }
1154            }
1155
1156            return true;
1157        }
1158
1159        // First we always handle the home key here, so applications
1160        // can never break it, although if keyguard is on, we do let
1161        // it handle it, because that gives us the correct 5 second
1162        // timeout.
1163        if (keyCode == KeyEvent.KEYCODE_HOME) {
1164
1165            // If a system window has focus, then it doesn't make sense
1166            // right now to interact with applications.
1167            WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
1168            if (attrs != null) {
1169                final int type = attrs.type;
1170                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
1171                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
1172                    // the "app" is keyguard, so give it the key
1173                    return false;
1174                }
1175                final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
1176                for (int i=0; i<typeCount; i++) {
1177                    if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
1178                        // don't do anything, but also don't pass it to the app
1179                        return true;
1180                    }
1181                }
1182            }
1183
1184            if (down && repeatCount == 0) {
1185                if (!keyguardOn) {
1186                    mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
1187                }
1188                mHomePressed = true;
1189            }
1190            return true;
1191        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
1192            // Hijack modified menu keys for debugging features
1193            final int chordBug = KeyEvent.META_SHIFT_ON;
1194
1195            if (down && repeatCount == 0) {
1196                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
1197                    Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
1198                    mContext.sendOrderedBroadcast(intent, null);
1199                    return true;
1200                } else if (SHOW_PROCESSES_ON_ALT_MENU &&
1201                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
1202                    Intent service = new Intent();
1203                    service.setClassName(mContext, "com.android.server.LoadAverageService");
1204                    ContentResolver res = mContext.getContentResolver();
1205                    boolean shown = Settings.System.getInt(
1206                            res, Settings.System.SHOW_PROCESSES, 0) != 0;
1207                    if (!shown) {
1208                        mContext.startService(service);
1209                    } else {
1210                        mContext.stopService(service);
1211                    }
1212                    Settings.System.putInt(
1213                            res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
1214                    return true;
1215                }
1216            }
1217        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
1218            if (down) {
1219                if (repeatCount == 0) {
1220                    mSearchKeyPressed = true;
1221                }
1222            } else {
1223                mSearchKeyPressed = false;
1224
1225                if (mConsumeSearchKeyUp) {
1226                    // Consume the up-event
1227                    mConsumeSearchKeyUp = false;
1228                    return true;
1229                }
1230            }
1231        }
1232
1233        // Shortcuts are invoked through Search+key, so intercept those here
1234        if (mSearchKeyPressed) {
1235            if (down && repeatCount == 0 && !keyguardOn) {
1236                Intent shortcutIntent = mShortcutManager.getIntent(keyCode, metaState);
1237                if (shortcutIntent != null) {
1238                    shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1239                    mContext.startActivity(shortcutIntent);
1240
1241                    /*
1242                     * We launched an app, so the up-event of the search key
1243                     * should be consumed
1244                     */
1245                    mConsumeSearchKeyUp = true;
1246                    return true;
1247                }
1248            }
1249        }
1250
1251        return false;
1252    }
1253
1254    /**
1255     * A home key -> launch home action was detected.  Take the appropriate action
1256     * given the situation with the keyguard.
1257     */
1258    void launchHomeFromHotKey() {
1259        if (mKeyguardMediator.isShowingAndNotHidden()) {
1260            // don't launch home if keyguard showing
1261        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
1262            // when in keyguard restricted mode, must first verify unlock
1263            // before launching home
1264            mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
1265                public void onKeyguardExitResult(boolean success) {
1266                    if (success) {
1267                        try {
1268                            ActivityManagerNative.getDefault().stopAppSwitches();
1269                        } catch (RemoteException e) {
1270                        }
1271                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1272                        startDockOrHome();
1273                    }
1274                }
1275            });
1276        } else {
1277            // no keyguard stuff to worry about, just launch home!
1278            try {
1279                ActivityManagerNative.getDefault().stopAppSwitches();
1280            } catch (RemoteException e) {
1281            }
1282            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1283            startDockOrHome();
1284        }
1285    }
1286
1287    public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
1288        final int fl = attrs.flags;
1289
1290        if (mStatusBarCanHide && (fl &
1291                (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1292                == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1293            contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom);
1294        } else {
1295            contentInset.setEmpty();
1296        }
1297    }
1298
1299    /** {@inheritDoc} */
1300    public void beginLayoutLw(int displayWidth, int displayHeight) {
1301        mW = displayWidth;
1302        mH = displayHeight;
1303        mDockLeft = mContentLeft = mCurLeft = 0;
1304        mDockTop = mContentTop = mCurTop = 0;
1305        mDockRight = mContentRight = mCurRight = displayWidth;
1306        mDockBottom = mContentBottom = mCurBottom = displayHeight;
1307        mDockLayer = 0x10000000;
1308
1309        // decide where the status bar goes ahead of time
1310        if (mStatusBar != null) {
1311            final Rect pf = mTmpParentFrame;
1312            final Rect df = mTmpDisplayFrame;
1313            final Rect vf = mTmpVisibleFrame;
1314            pf.left = df.left = vf.left = 0;
1315            pf.top = df.top = vf.top = 0;
1316            pf.right = df.right = vf.right = displayWidth;
1317            pf.bottom = df.bottom = vf.bottom = displayHeight;
1318
1319            mStatusBar.computeFrameLw(pf, df, vf, vf);
1320            if (mStatusBar.isVisibleLw()) {
1321                // If the status bar is hidden, we don't want to cause
1322                // windows behind it to scroll.
1323                final Rect r = mStatusBar.getFrameLw();
1324                if (mDockTop == r.top) mDockTop = r.bottom;
1325                else if (mDockBottom == r.bottom) mDockBottom = r.top;
1326                mContentTop = mCurTop = mDockTop;
1327                mContentBottom = mCurBottom = mDockBottom;
1328                if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockTop=" + mDockTop
1329                        + " mContentTop=" + mContentTop
1330                        + " mCurTop=" + mCurTop
1331                        + " mDockBottom=" + mDockBottom
1332                        + " mContentBottom=" + mContentBottom
1333                        + " mCurBottom=" + mCurBottom);
1334            }
1335        }
1336    }
1337
1338    void setAttachedWindowFrames(WindowState win, int fl, int sim,
1339            WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
1340        if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
1341            // Here's a special case: if this attached window is a panel that is
1342            // above the dock window, and the window it is attached to is below
1343            // the dock window, then the frames we computed for the window it is
1344            // attached to can not be used because the dock is effectively part
1345            // of the underlying window and the attached window is floating on top
1346            // of the whole thing.  So, we ignore the attached window and explicitly
1347            // compute the frames that would be appropriate without the dock.
1348            df.left = cf.left = vf.left = mDockLeft;
1349            df.top = cf.top = vf.top = mDockTop;
1350            df.right = cf.right = vf.right = mDockRight;
1351            df.bottom = cf.bottom = vf.bottom = mDockBottom;
1352        } else {
1353            // The effective display frame of the attached window depends on
1354            // whether it is taking care of insetting its content.  If not,
1355            // we need to use the parent's content frame so that the entire
1356            // window is positioned within that content.  Otherwise we can use
1357            // the display frame and let the attached window take care of
1358            // positioning its content appropriately.
1359            if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1360                cf.set(attached.getDisplayFrameLw());
1361            } else {
1362                // If the window is resizing, then we want to base the content
1363                // frame on our attached content frame to resize...  however,
1364                // things can be tricky if the attached window is NOT in resize
1365                // mode, in which case its content frame will be larger.
1366                // Ungh.  So to deal with that, make sure the content frame
1367                // we end up using is not covering the IM dock.
1368                cf.set(attached.getContentFrameLw());
1369                if (attached.getSurfaceLayer() < mDockLayer) {
1370                    if (cf.left < mContentLeft) cf.left = mContentLeft;
1371                    if (cf.top < mContentTop) cf.top = mContentTop;
1372                    if (cf.right > mContentRight) cf.right = mContentRight;
1373                    if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
1374                }
1375            }
1376            df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
1377            vf.set(attached.getVisibleFrameLw());
1378        }
1379        // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
1380        // window should be positioned relative to its parent or the entire
1381        // screen.
1382        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
1383                ? attached.getFrameLw() : df);
1384    }
1385
1386    /** {@inheritDoc} */
1387    public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
1388            WindowState attached) {
1389        // we've already done the status bar
1390        if (win == mStatusBar) {
1391            return;
1392        }
1393
1394        if (false) {
1395            if ("com.google.android.youtube".equals(attrs.packageName)
1396                    && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
1397                Log.i(TAG, "GOTCHA!");
1398            }
1399        }
1400
1401        final int fl = attrs.flags;
1402        final int sim = attrs.softInputMode;
1403
1404        final Rect pf = mTmpParentFrame;
1405        final Rect df = mTmpDisplayFrame;
1406        final Rect cf = mTmpContentFrame;
1407        final Rect vf = mTmpVisibleFrame;
1408
1409        if (attrs.type == TYPE_INPUT_METHOD) {
1410            pf.left = df.left = cf.left = vf.left = mDockLeft;
1411            pf.top = df.top = cf.top = vf.top = mDockTop;
1412            pf.right = df.right = cf.right = vf.right = mDockRight;
1413            pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
1414            // IM dock windows always go to the bottom of the screen.
1415            attrs.gravity = Gravity.BOTTOM;
1416            mDockLayer = win.getSurfaceLayer();
1417        } else {
1418            if (mStatusBarCanHide && (fl &
1419                    (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1420                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1421                // This is the case for a normal activity window: we want it
1422                // to cover all of the screen space, and it can take care of
1423                // moving its contents to account for screen decorations that
1424                // intrude into that space.
1425                if (attached != null) {
1426                    // If this window is attached to another, our display
1427                    // frame is the same as the one we are attached to.
1428                    setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
1429                } else {
1430                    pf.left = df.left = 0;
1431                    pf.top = df.top = 0;
1432                    pf.right = df.right = mW;
1433                    pf.bottom = df.bottom = mH;
1434                    if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1435                        cf.left = mDockLeft;
1436                        cf.top = mDockTop;
1437                        cf.right = mDockRight;
1438                        cf.bottom = mDockBottom;
1439                    } else {
1440                        cf.left = mContentLeft;
1441                        cf.top = mContentTop;
1442                        cf.right = mContentRight;
1443                        cf.bottom = mContentBottom;
1444                    }
1445                    vf.left = mCurLeft;
1446                    vf.top = mCurTop;
1447                    vf.right = mCurRight;
1448                    vf.bottom = mCurBottom;
1449                }
1450            } else if (mStatusBarCanHide && (fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
1451                // A window that has requested to fill the entire screen just
1452                // gets everything, period.
1453                pf.left = df.left = cf.left = 0;
1454                pf.top = df.top = cf.top = 0;
1455                pf.right = df.right = cf.right = mW;
1456                pf.bottom = df.bottom = cf.bottom = mH;
1457                vf.left = mCurLeft;
1458                vf.top = mCurTop;
1459                vf.right = mCurRight;
1460                vf.bottom = mCurBottom;
1461            } else if (attached != null) {
1462                // A child window should be placed inside of the same visible
1463                // frame that its parent had.
1464                setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf);
1465            } else {
1466                // Otherwise, a normal window must be placed inside the content
1467                // of all screen decorations.
1468                pf.left = mContentLeft;
1469                pf.top = mContentTop;
1470                pf.right = mContentRight;
1471                pf.bottom = mContentBottom;
1472                if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1473                    df.left = cf.left = mDockLeft;
1474                    df.top = cf.top = mDockTop;
1475                    df.right = cf.right = mDockRight;
1476                    df.bottom = cf.bottom = mDockBottom;
1477                } else {
1478                    df.left = cf.left = mContentLeft;
1479                    df.top = cf.top = mContentTop;
1480                    df.right = cf.right = mContentRight;
1481                    df.bottom = cf.bottom = mContentBottom;
1482                }
1483                vf.left = mCurLeft;
1484                vf.top = mCurTop;
1485                vf.right = mCurRight;
1486                vf.bottom = mCurBottom;
1487            }
1488        }
1489
1490        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
1491            df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
1492            df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
1493        }
1494
1495        if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
1496                + ": sim=#" + Integer.toHexString(sim)
1497                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
1498                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
1499
1500        if (false) {
1501            if ("com.google.android.youtube".equals(attrs.packageName)
1502                    && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
1503                if (true || localLOGV) Log.v(TAG, "Computing frame of " + win +
1504                        ": sim=#" + Integer.toHexString(sim)
1505                        + " pf=" + pf.toShortString() + " df=" + df.toShortString()
1506                        + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
1507            }
1508        }
1509
1510        win.computeFrameLw(pf, df, cf, vf);
1511
1512        // Dock windows carve out the bottom of the screen, so normal windows
1513        // can't appear underneath them.
1514        if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
1515            int top = win.getContentFrameLw().top;
1516            top += win.getGivenContentInsetsLw().top;
1517            if (mContentBottom > top) {
1518                mContentBottom = top;
1519            }
1520            top = win.getVisibleFrameLw().top;
1521            top += win.getGivenVisibleInsetsLw().top;
1522            if (mCurBottom > top) {
1523                mCurBottom = top;
1524            }
1525            if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom="
1526                    + mDockBottom + " mContentBottom="
1527                    + mContentBottom + " mCurBottom=" + mCurBottom);
1528        }
1529    }
1530
1531    /** {@inheritDoc} */
1532    public int finishLayoutLw() {
1533        return 0;
1534    }
1535
1536    /** {@inheritDoc} */
1537    public void beginAnimationLw(int displayWidth, int displayHeight) {
1538        mTopFullscreenOpaqueWindowState = null;
1539        mForceStatusBar = false;
1540
1541        mHideLockScreen = false;
1542        mAllowLockscreenWhenOn = false;
1543        mDismissKeyguard = false;
1544    }
1545
1546    /** {@inheritDoc} */
1547    public void animatingWindowLw(WindowState win,
1548                                WindowManager.LayoutParams attrs) {
1549        if (mTopFullscreenOpaqueWindowState == null &&
1550                win.isVisibleOrBehindKeyguardLw()) {
1551            if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
1552                mForceStatusBar = true;
1553            }
1554            if (attrs.type >= FIRST_APPLICATION_WINDOW
1555                    && attrs.type <= LAST_APPLICATION_WINDOW
1556                    && attrs.x == 0 && attrs.y == 0
1557                    && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
1558                    && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
1559                if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
1560                mTopFullscreenOpaqueWindowState = win;
1561                if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
1562                    if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
1563                    mHideLockScreen = true;
1564                }
1565                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
1566                    if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
1567                    mDismissKeyguard = true;
1568                }
1569                if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
1570                    mAllowLockscreenWhenOn = true;
1571                }
1572            }
1573        }
1574    }
1575
1576    /** {@inheritDoc} */
1577    public int finishAnimationLw() {
1578        int changes = 0;
1579
1580        boolean topIsFullscreen = false;
1581        if (mStatusBar != null) {
1582            if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar
1583                    + " top=" + mTopFullscreenOpaqueWindowState);
1584            if (mForceStatusBar) {
1585                if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
1586                if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
1587            } else if (mTopFullscreenOpaqueWindowState != null) {
1588                final WindowManager.LayoutParams lp = mTopFullscreenOpaqueWindowState.getAttrs();
1589                if (localLOGV) {
1590                    Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
1591                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
1592                    Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
1593                            + " lp.flags=0x" + Integer.toHexString(lp.flags));
1594                }
1595                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
1596                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
1597                // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
1598                // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
1599                // case though.
1600                if (topIsFullscreen) {
1601                    if (mStatusBarCanHide) {
1602                        if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
1603                        if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
1604                    } else if (localLOGV) {
1605                        Log.v(TAG, "Preventing status bar from hiding by policy");
1606                    }
1607                } else {
1608                    if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
1609                    if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
1610                }
1611            }
1612        }
1613
1614        if (topIsFullscreen != mTopIsFullscreen) {
1615            final boolean topIsFullscreenF = topIsFullscreen;
1616            mTopIsFullscreen = topIsFullscreen;
1617            mHandler.post(new Runnable() {
1618                    public void run() {
1619                        if (mStatusBarService == null) {
1620                            // This is the one that can not go away, but it doesn't come up
1621                            // before the window manager does, so don't fail if it doesn't
1622                            // exist. This works as long as no fullscreen windows come up
1623                            // before the status bar service does.
1624                            mStatusBarService = IStatusBarService.Stub.asInterface(
1625                                    ServiceManager.getService("statusbar"));
1626                        }
1627                        final IStatusBarService sbs = mStatusBarService;
1628                        if (mStatusBarService != null) {
1629                            try {
1630                                sbs.setActiveWindowIsFullscreen(topIsFullscreenF);
1631                            } catch (RemoteException e) {
1632                                // This should be impossible because we're in the same process.
1633                                mStatusBarService = null;
1634                            }
1635                        }
1636                    }
1637                });
1638        }
1639
1640        // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
1641        // when the screen is locked
1642        if (mKeyguard != null) {
1643            if (localLOGV) Log.v(TAG, "finishAnimationLw::mHideKeyguard="+mHideLockScreen);
1644            if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
1645                if (mKeyguard.hideLw(true)) {
1646                    changes |= FINISH_LAYOUT_REDO_LAYOUT
1647                            | FINISH_LAYOUT_REDO_CONFIG
1648                            | FINISH_LAYOUT_REDO_WALLPAPER;
1649                }
1650                if (mKeyguardMediator.isShowing()) {
1651                    mHandler.post(new Runnable() {
1652                        public void run() {
1653                            mKeyguardMediator.keyguardDone(false, false);
1654                        }
1655                    });
1656                }
1657            } else if (mHideLockScreen) {
1658                if (mKeyguard.hideLw(true)) {
1659                    changes |= FINISH_LAYOUT_REDO_LAYOUT
1660                            | FINISH_LAYOUT_REDO_CONFIG
1661                            | FINISH_LAYOUT_REDO_WALLPAPER;
1662                }
1663                mKeyguardMediator.setHidden(true);
1664            } else {
1665                if (mKeyguard.showLw(true)) {
1666                    changes |= FINISH_LAYOUT_REDO_LAYOUT
1667                            | FINISH_LAYOUT_REDO_CONFIG
1668                            | FINISH_LAYOUT_REDO_WALLPAPER;
1669                }
1670                mKeyguardMediator.setHidden(false);
1671            }
1672        }
1673
1674        // update since mAllowLockscreenWhenOn might have changed
1675        updateLockScreenTimeout();
1676        return changes;
1677    }
1678
1679    public boolean allowAppAnimationsLw() {
1680        if (mKeyguard != null && mKeyguard.isVisibleLw()) {
1681            // If keyguard is currently visible, no reason to animate
1682            // behind it.
1683            return false;
1684        }
1685        if (mStatusBar != null && mStatusBar.isVisibleLw()) {
1686            Rect rect = new Rect(mStatusBar.getShownFrameLw());
1687            for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
1688                WindowState w = mStatusBarPanels.get(i);
1689                if (w.isVisibleLw()) {
1690                    rect.union(w.getShownFrameLw());
1691                }
1692            }
1693            final int insetw = mW/10;
1694            final int inseth = mH/10;
1695            if (rect.contains(insetw, inseth, mW-insetw, mH-inseth)) {
1696                // All of the status bar windows put together cover the
1697                // screen, so the app can't be seen.  (Note this test doesn't
1698                // work if the rects of these windows are at off offsets or
1699                // sizes, causing gaps in the rect union we have computed.)
1700                return false;
1701            }
1702        }
1703        return true;
1704    }
1705
1706    /** {@inheritDoc} */
1707    public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
1708        // lid changed state
1709        mLidOpen = lidOpen;
1710        boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen);
1711        updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
1712        if (awakeNow) {
1713            // If the lid opening and we don't have to keep the
1714            // keyguard up, then we can turn on the screen
1715            // immediately.
1716            mKeyguardMediator.pokeWakelock();
1717        } else if (keyguardIsShowingTq()) {
1718            if (mLidOpen) {
1719                // If we are opening the lid and not hiding the
1720                // keyguard, then we need to have it turn on the
1721                // screen once it is shown.
1722                mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
1723                        KeyEvent.KEYCODE_POWER);
1724            }
1725        } else {
1726            // Light up the keyboard if we are sliding up.
1727            if (mLidOpen) {
1728                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
1729                        LocalPowerManager.BUTTON_EVENT);
1730            } else {
1731                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
1732                        LocalPowerManager.OTHER_EVENT);
1733            }
1734        }
1735    }
1736
1737    /**
1738     * @return Whether a telephone call is in progress right now.
1739     */
1740    boolean isInCall() {
1741        final ITelephony phone = getPhoneInterface();
1742        if (phone == null) {
1743            Log.w(TAG, "couldn't get ITelephony reference");
1744            return false;
1745        }
1746        try {
1747            return phone.isOffhook();
1748        } catch (RemoteException e) {
1749            Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
1750            return false;
1751        }
1752    }
1753
1754    /**
1755     * @return Whether music is being played right now.
1756     */
1757    boolean isMusicActive() {
1758        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
1759        if (am == null) {
1760            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
1761            return false;
1762        }
1763        return am.isMusicActive();
1764    }
1765
1766    /**
1767     * Tell the audio service to adjust the volume appropriate to the event.
1768     * @param keycode
1769     */
1770    void handleVolumeKey(int stream, int keycode) {
1771        final IAudioService audio = getAudioInterface();
1772        if (audio == null) {
1773            Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
1774            return;
1775        }
1776        try {
1777            // since audio is playing, we shouldn't have to hold a wake lock
1778            // during the call, but we do it as a precaution for the rare possibility
1779            // that the music stops right before we call this
1780            mBroadcastWakeLock.acquire();
1781            audio.adjustStreamVolume(stream,
1782                keycode == KeyEvent.KEYCODE_VOLUME_UP
1783                            ? AudioManager.ADJUST_RAISE
1784                            : AudioManager.ADJUST_LOWER,
1785                    0);
1786        } catch (RemoteException e) {
1787            Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
1788        } finally {
1789            mBroadcastWakeLock.release();
1790        }
1791    }
1792
1793    static boolean isMediaKey(int code) {
1794        if (code == KeyEvent.KEYCODE_HEADSETHOOK ||
1795                code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
1796                code == KeyEvent.KEYCODE_MEDIA_STOP ||
1797                code == KeyEvent.KEYCODE_MEDIA_NEXT ||
1798                code == KeyEvent.KEYCODE_MEDIA_PREVIOUS ||
1799                code == KeyEvent.KEYCODE_MEDIA_REWIND ||
1800                code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
1801            return true;
1802        }
1803        return false;
1804    }
1805
1806    /** {@inheritDoc} */
1807    @Override
1808    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
1809            int policyFlags, boolean isScreenOn) {
1810        int result = ACTION_PASS_TO_USER;
1811
1812        final boolean isWakeKey = (policyFlags
1813                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
1814
1815        // If screen is off then we treat the case where the keyguard is open but hidden
1816        // the same as if it were open and in front.
1817        // This will prevent any keys other than the power button from waking the screen
1818        // when the keyguard is hidden by another activity.
1819        final boolean keyguardActive = (isScreenOn ?
1820                                        mKeyguardMediator.isShowingAndNotHidden() :
1821                                        mKeyguardMediator.isShowing());
1822
1823        if (false) {
1824            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
1825                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
1826        }
1827
1828        if (keyguardActive) {
1829            if (isScreenOn) {
1830                // when the screen is on, always give the event to the keyguard
1831                result |= ACTION_PASS_TO_USER;
1832            } else {
1833                // otherwise, don't pass it to the user
1834                result &= ~ACTION_PASS_TO_USER;
1835
1836                if (isWakeKey && down) {
1837
1838                    // tell the mediator about a wake key, it may decide to
1839                    // turn on the screen depending on whether the key is
1840                    // appropriate.
1841                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode)
1842                            && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
1843                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
1844                        // when keyguard is showing and screen off, we need
1845                        // to handle the volume key for calls and  music here
1846                        if (isInCall()) {
1847                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
1848                        } else if (isMusicActive()) {
1849                            handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
1850                        }
1851                    }
1852                }
1853            }
1854        } else if (!isScreenOn) {
1855            // If we are in-call with screen off and keyguard is not showing,
1856            // then handle the volume key ourselves.
1857            // This is necessary because the phone app will disable the keyguard
1858            // when the proximity sensor is in use.
1859            if (isInCall() &&
1860                     (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
1861                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
1862                result &= ~ACTION_PASS_TO_USER;
1863                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
1864            }
1865            if (isWakeKey) {
1866                // a wake key has a sole purpose of waking the device; don't pass
1867                // it to the user
1868                result |= ACTION_POKE_USER_ACTIVITY;
1869                result &= ~ACTION_PASS_TO_USER;
1870            }
1871        }
1872
1873        if (keyCode == KeyEvent.KEYCODE_ENDCALL
1874                || keyCode == KeyEvent.KEYCODE_POWER) {
1875            if (down) {
1876                boolean handled = false;
1877                boolean hungUp = false;
1878                // key repeats are generated by the window manager, and we don't see them
1879                // here, so unless the driver is doing something it shouldn't be, we know
1880                // this is the real press event.
1881                ITelephony phoneServ = getPhoneInterface();
1882                if (phoneServ != null) {
1883                    try {
1884                        if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
1885                            handled = hungUp = phoneServ.endCall();
1886                        } else if (keyCode == KeyEvent.KEYCODE_POWER) {
1887                            if (phoneServ.isRinging()) {
1888                                // Pressing Power while there's a ringing incoming
1889                                // call should silence the ringer.
1890                                phoneServ.silenceRinger();
1891                                handled = true;
1892                            } else if (phoneServ.isOffhook() &&
1893                                       ((mIncallPowerBehavior
1894                                         & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
1895                                        != 0)) {
1896                                // Otherwise, if "Power button ends call" is enabled,
1897                                // the Power button will hang up any current active call.
1898                                handled = hungUp = phoneServ.endCall();
1899                            }
1900                        }
1901                    } catch (RemoteException ex) {
1902                        Log.w(TAG, "ITelephony threw RemoteException" + ex);
1903                    }
1904                } else {
1905                    Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
1906                }
1907
1908                if (!isScreenOn
1909                        || (handled && keyCode != KeyEvent.KEYCODE_POWER)
1910                        || (handled && hungUp && keyCode == KeyEvent.KEYCODE_POWER)) {
1911                    mShouldTurnOffOnKeyUp = false;
1912                } else {
1913                    // only try to turn off the screen if we didn't already hang up
1914                    mShouldTurnOffOnKeyUp = true;
1915                    mHandler.postDelayed(mPowerLongPress,
1916                            ViewConfiguration.getGlobalActionKeyTimeout());
1917                    result &= ~ACTION_PASS_TO_USER;
1918                }
1919            } else {
1920                mHandler.removeCallbacks(mPowerLongPress);
1921                if (mShouldTurnOffOnKeyUp) {
1922                    mShouldTurnOffOnKeyUp = false;
1923                    boolean gohome, sleeps;
1924                    if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
1925                        gohome = (mEndcallBehavior
1926                                  & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
1927                        sleeps = (mEndcallBehavior
1928                                  & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
1929                    } else {
1930                        gohome = false;
1931                        sleeps = true;
1932                    }
1933                    if (keyguardActive
1934                            || (sleeps && !gohome)
1935                            || (gohome && !goHome() && sleeps)) {
1936                        // they must already be on the keyguad or home screen,
1937                        // go to sleep instead
1938                        Log.d(TAG, "I'm tired mEndcallBehavior=0x"
1939                                + Integer.toHexString(mEndcallBehavior));
1940                        result &= ~ACTION_POKE_USER_ACTIVITY;
1941                        result |= ACTION_GO_TO_SLEEP;
1942                    }
1943                    result &= ~ACTION_PASS_TO_USER;
1944                }
1945            }
1946        } else if (isMediaKey(keyCode)) {
1947            // This key needs to be handled even if the screen is off.
1948            // If others need to be handled while it's off, this is a reasonable
1949            // pattern to follow.
1950            if ((result & ACTION_PASS_TO_USER) == 0) {
1951                // Only do this if we would otherwise not pass it to the user. In that
1952                // case, the PhoneWindow class will do the same thing, except it will
1953                // only do it if the showing app doesn't process the key on its own.
1954                long when = whenNanos / 1000000;
1955                KeyEvent keyEvent = new KeyEvent(when, when,
1956                        down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
1957                        keyCode, 0);
1958                mBroadcastWakeLock.acquire();
1959                mHandler.post(new PassHeadsetKey(keyEvent));
1960            }
1961        } else if (keyCode == KeyEvent.KEYCODE_CALL) {
1962            // If an incoming call is ringing, answer it!
1963            // (We handle this key here, rather than in the InCallScreen, to make
1964            // sure we'll respond to the key even if the InCallScreen hasn't come to
1965            // the foreground yet.)
1966
1967            // We answer the call on the DOWN event, to agree with
1968            // the "fallback" behavior in the InCallScreen.
1969            if (down) {
1970                try {
1971                    ITelephony phoneServ = getPhoneInterface();
1972                    if (phoneServ != null) {
1973                        if (phoneServ.isRinging()) {
1974                            Log.i(TAG, "interceptKeyTq:"
1975                                  + " CALL key-down while ringing: Answer the call!");
1976                            phoneServ.answerRingingCall();
1977
1978                            // And *don't* pass this key thru to the current activity
1979                            // (which is presumably the InCallScreen.)
1980                            result &= ~ACTION_PASS_TO_USER;
1981                        }
1982                    } else {
1983                        Log.w(TAG, "CALL button: Unable to find ITelephony interface");
1984                    }
1985                } catch (RemoteException ex) {
1986                    Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
1987                }
1988            }
1989        } else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
1990                   || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
1991            // If an incoming call is ringing, either VOLUME key means
1992            // "silence ringer".  We handle these keys here, rather than
1993            // in the InCallScreen, to make sure we'll respond to them
1994            // even if the InCallScreen hasn't come to the foreground yet.
1995
1996            // Look for the DOWN event here, to agree with the "fallback"
1997            // behavior in the InCallScreen.
1998            if (down) {
1999                try {
2000                    ITelephony phoneServ = getPhoneInterface();
2001                    if (phoneServ != null) {
2002                        if (phoneServ.isRinging()) {
2003                            Log.i(TAG, "interceptKeyTq:"
2004                                  + " VOLUME key-down while ringing: Silence ringer!");
2005                            // Silence the ringer.  (It's safe to call this
2006                            // even if the ringer has already been silenced.)
2007                            phoneServ.silenceRinger();
2008
2009                            // And *don't* pass this key thru to the current activity
2010                            // (which is probably the InCallScreen.)
2011                            result &= ~ACTION_PASS_TO_USER;
2012                        }
2013                    } else {
2014                        Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
2015                    }
2016                } catch (RemoteException ex) {
2017                    Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
2018                }
2019            }
2020        }
2021
2022        return result;
2023    }
2024
2025    class PassHeadsetKey implements Runnable {
2026        KeyEvent mKeyEvent;
2027
2028        PassHeadsetKey(KeyEvent keyEvent) {
2029            mKeyEvent = keyEvent;
2030        }
2031
2032        public void run() {
2033            if (ActivityManagerNative.isSystemReady()) {
2034                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
2035                intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
2036                mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
2037                        mHandler, Activity.RESULT_OK, null, null);
2038            }
2039        }
2040    }
2041
2042    BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
2043        public void onReceive(Context context, Intent intent) {
2044            mBroadcastWakeLock.release();
2045        }
2046    };
2047
2048    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
2049        public void onReceive(Context context, Intent intent) {
2050            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
2051                mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
2052                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
2053            } else {
2054                try {
2055                    IUiModeManager uiModeService = IUiModeManager.Stub.asInterface(
2056                            ServiceManager.getService(Context.UI_MODE_SERVICE));
2057                    mUiMode = uiModeService.getCurrentModeType();
2058                } catch (RemoteException e) {
2059                }
2060            }
2061            updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2062            updateOrientationListenerLp();
2063        }
2064    };
2065
2066    /** {@inheritDoc} */
2067    public void screenTurnedOff(int why) {
2068        EventLog.writeEvent(70000, 0);
2069        mKeyguardMediator.onScreenTurnedOff(why);
2070        synchronized (mLock) {
2071            mScreenOn = false;
2072            updateOrientationListenerLp();
2073            updateLockScreenTimeout();
2074        }
2075    }
2076
2077    /** {@inheritDoc} */
2078    public void screenTurnedOn() {
2079        EventLog.writeEvent(70000, 1);
2080        mKeyguardMediator.onScreenTurnedOn();
2081        synchronized (mLock) {
2082            mScreenOn = true;
2083            updateOrientationListenerLp();
2084            updateLockScreenTimeout();
2085        }
2086    }
2087
2088    /** {@inheritDoc} */
2089    public boolean isScreenOn() {
2090        return mScreenOn;
2091    }
2092
2093    /** {@inheritDoc} */
2094    public void enableKeyguard(boolean enabled) {
2095        mKeyguardMediator.setKeyguardEnabled(enabled);
2096    }
2097
2098    /** {@inheritDoc} */
2099    public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
2100        mKeyguardMediator.verifyUnlock(callback);
2101    }
2102
2103    private boolean keyguardIsShowingTq() {
2104        return mKeyguardMediator.isShowingAndNotHidden();
2105    }
2106
2107    /** {@inheritDoc} */
2108    public boolean inKeyguardRestrictedKeyInputMode() {
2109        return mKeyguardMediator.isInputRestricted();
2110    }
2111
2112    void sendCloseSystemWindows() {
2113        sendCloseSystemWindows(mContext, null);
2114    }
2115
2116    void sendCloseSystemWindows(String reason) {
2117        sendCloseSystemWindows(mContext, reason);
2118    }
2119
2120    static void sendCloseSystemWindows(Context context, String reason) {
2121        if (ActivityManagerNative.isSystemReady()) {
2122            try {
2123                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
2124            } catch (RemoteException e) {
2125            }
2126        }
2127    }
2128
2129    public int rotationForOrientationLw(int orientation, int lastRotation,
2130            boolean displayEnabled) {
2131
2132        if (mPortraitRotation < 0) {
2133            // Initialize the rotation angles for each orientation once.
2134            Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
2135                    .getDefaultDisplay();
2136            if (d.getWidth() > d.getHeight()) {
2137                mPortraitRotation = Surface.ROTATION_90;
2138                mLandscapeRotation = Surface.ROTATION_0;
2139                mUpsideDownRotation = Surface.ROTATION_270;
2140                mSeascapeRotation = Surface.ROTATION_180;
2141            } else {
2142                mPortraitRotation = Surface.ROTATION_0;
2143                mLandscapeRotation = Surface.ROTATION_90;
2144                mUpsideDownRotation = Surface.ROTATION_180;
2145                mSeascapeRotation = Surface.ROTATION_270;
2146            }
2147        }
2148
2149        synchronized (mLock) {
2150            switch (orientation) {
2151                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
2152                    //always return portrait if orientation set to portrait
2153                    return mPortraitRotation;
2154                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
2155                    //always return landscape if orientation set to landscape
2156                    return mLandscapeRotation;
2157                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
2158                    //always return portrait if orientation set to portrait
2159                    return mUpsideDownRotation;
2160                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
2161                    //always return seascape if orientation set to reverse landscape
2162                    return mSeascapeRotation;
2163                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
2164                    //return either landscape rotation based on the sensor
2165                    mOrientationListener.setAllow180Rotation(false);
2166                    return getCurrentLandscapeRotation(lastRotation);
2167                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
2168                    mOrientationListener.setAllow180Rotation(true);
2169                    return getCurrentPortraitRotation(lastRotation);
2170            }
2171
2172            mOrientationListener.setAllow180Rotation(
2173                    orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
2174
2175            // case for nosensor meaning ignore sensor and consider only lid
2176            // or orientation sensor disabled
2177            //or case.unspecified
2178            if (mLidOpen) {
2179                return mLidOpenRotation;
2180            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
2181                return mCarDockRotation;
2182            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
2183                return mDeskDockRotation;
2184            } else {
2185                if (useSensorForOrientationLp(orientation)) {
2186                    return mOrientationListener.getCurrentRotation(lastRotation);
2187                }
2188                return Surface.ROTATION_0;
2189            }
2190        }
2191    }
2192
2193    private int getCurrentLandscapeRotation(int lastRotation) {
2194        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
2195        if (isLandscapeOrSeascape(sensorRotation)) {
2196            return sensorRotation;
2197        }
2198        // try to preserve the old rotation if it was landscape
2199        if (isLandscapeOrSeascape(lastRotation)) {
2200            return lastRotation;
2201        }
2202        // default to one of the primary landscape rotation
2203        return mLandscapeRotation;
2204    }
2205
2206    private boolean isLandscapeOrSeascape(int sensorRotation) {
2207        return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation;
2208    }
2209
2210    private int getCurrentPortraitRotation(int lastRotation) {
2211        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
2212        if (isAnyPortrait(sensorRotation)) {
2213            return sensorRotation;
2214        }
2215        // try to preserve the old rotation if it was portrait
2216        if (isAnyPortrait(lastRotation)) {
2217            return lastRotation;
2218        }
2219        // default to one of the primary portrait rotations
2220        return mPortraitRotation;
2221    }
2222
2223    private boolean isAnyPortrait(int sensorRotation) {
2224        return sensorRotation == mPortraitRotation || sensorRotation == mUpsideDownRotation;
2225    }
2226
2227    public boolean detectSafeMode() {
2228        try {
2229            int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
2230            int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
2231            int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
2232            int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE);
2233            mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0;
2234            performHapticFeedbackLw(null, mSafeMode
2235                    ? HapticFeedbackConstants.SAFE_MODE_ENABLED
2236                    : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
2237            if (mSafeMode) {
2238                Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
2239                        + " dpad=" + dpadState + " trackball=" + trackballState + ")");
2240            } else {
2241                Log.i(TAG, "SAFE MODE not enabled");
2242            }
2243            return mSafeMode;
2244        } catch (RemoteException e) {
2245            // Doom! (it's also local)
2246            throw new RuntimeException("window manager dead");
2247        }
2248    }
2249
2250    static long[] getLongIntArray(Resources r, int resid) {
2251        int[] ar = r.getIntArray(resid);
2252        if (ar == null) {
2253            return null;
2254        }
2255        long[] out = new long[ar.length];
2256        for (int i=0; i<ar.length; i++) {
2257            out[i] = ar[i];
2258        }
2259        return out;
2260    }
2261
2262    /** {@inheritDoc} */
2263    public void systemReady() {
2264        // tell the keyguard
2265        mKeyguardMediator.onSystemReady();
2266        android.os.SystemProperties.set("dev.bootcomplete", "1");
2267        synchronized (mLock) {
2268            updateOrientationListenerLp();
2269            mSystemReady = true;
2270            mHandler.post(new Runnable() {
2271                public void run() {
2272                    updateSettings();
2273                }
2274            });
2275        }
2276    }
2277
2278    /** {@inheritDoc} */
2279    public void userActivity() {
2280        synchronized (mScreenLockTimeout) {
2281            if (mLockScreenTimerActive) {
2282                // reset the timer
2283                mHandler.removeCallbacks(mScreenLockTimeout);
2284                mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
2285            }
2286        }
2287    }
2288
2289    Runnable mScreenLockTimeout = new Runnable() {
2290        public void run() {
2291            synchronized (this) {
2292                if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
2293                mKeyguardMediator.doKeyguardTimeout();
2294                mLockScreenTimerActive = false;
2295            }
2296        }
2297    };
2298
2299    private void updateLockScreenTimeout() {
2300        synchronized (mScreenLockTimeout) {
2301            boolean enable = (mAllowLockscreenWhenOn && mScreenOn && mKeyguardMediator.isSecure());
2302            if (mLockScreenTimerActive != enable) {
2303                if (enable) {
2304                    if (localLOGV) Log.v(TAG, "setting lockscreen timer");
2305                    mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
2306                } else {
2307                    if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
2308                    mHandler.removeCallbacks(mScreenLockTimeout);
2309                }
2310                mLockScreenTimerActive = enable;
2311            }
2312        }
2313    }
2314
2315    /** {@inheritDoc} */
2316    public void enableScreenAfterBoot() {
2317        readLidState();
2318        updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2319    }
2320
2321    void updateRotation(int animFlags) {
2322        mPowerManager.setKeyboardVisibility(mLidOpen);
2323        int rotation = Surface.ROTATION_0;
2324        if (mLidOpen) {
2325            rotation = mLidOpenRotation;
2326        } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
2327            rotation = mCarDockRotation;
2328        } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
2329            rotation = mDeskDockRotation;
2330        }
2331        //if lid is closed orientation will be portrait
2332        try {
2333            //set orientation on WindowManager
2334            mWindowManager.setRotation(rotation, true,
2335                    mFancyRotationAnimation | animFlags);
2336        } catch (RemoteException e) {
2337            // Ignore
2338        }
2339    }
2340
2341    /**
2342     * Return an Intent to launch the currently active dock as home.  Returns
2343     * null if the standard home should be launched.
2344     * @return
2345     */
2346    Intent createHomeDockIntent() {
2347        Intent intent;
2348
2349        // What home does is based on the mode, not the dock state.  That
2350        // is, when in car mode you should be taken to car home regardless
2351        // of whether we are actually in a car dock.
2352        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
2353            intent = mCarDockIntent;
2354        } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) {
2355            intent = mDeskDockIntent;
2356        } else {
2357            return null;
2358        }
2359
2360        ActivityInfo ai = intent.resolveActivityInfo(
2361                mContext.getPackageManager(), PackageManager.GET_META_DATA);
2362        if (ai == null) {
2363            return null;
2364        }
2365
2366        if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
2367            intent = new Intent(intent);
2368            intent.setClassName(ai.packageName, ai.name);
2369            return intent;
2370        }
2371
2372        return null;
2373    }
2374
2375    void startDockOrHome() {
2376        Intent dock = createHomeDockIntent();
2377        if (dock != null) {
2378            try {
2379                mContext.startActivity(dock);
2380                return;
2381            } catch (ActivityNotFoundException e) {
2382            }
2383        }
2384        mContext.startActivity(mHomeIntent);
2385    }
2386
2387    /**
2388     * goes to the home screen
2389     * @return whether it did anything
2390     */
2391    boolean goHome() {
2392        if (false) {
2393            // This code always brings home to the front.
2394            try {
2395                ActivityManagerNative.getDefault().stopAppSwitches();
2396            } catch (RemoteException e) {
2397            }
2398            sendCloseSystemWindows();
2399            startDockOrHome();
2400        } else {
2401            // This code brings home to the front or, if it is already
2402            // at the front, puts the device to sleep.
2403            try {
2404                if (SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1) {
2405                    /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry.
2406                    Log.d(TAG, "UTS-TEST-MODE");
2407                } else {
2408                    ActivityManagerNative.getDefault().stopAppSwitches();
2409                    sendCloseSystemWindows();
2410                    Intent dock = createHomeDockIntent();
2411                    if (dock != null) {
2412                        int result = ActivityManagerNative.getDefault()
2413                                .startActivity(null, dock,
2414                                        dock.resolveTypeIfNeeded(mContext.getContentResolver()),
2415                                        null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
2416                        if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
2417                            return false;
2418                        }
2419                    }
2420                }
2421                int result = ActivityManagerNative.getDefault()
2422                        .startActivity(null, mHomeIntent,
2423                                mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
2424                                null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
2425                if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
2426                    return false;
2427                }
2428            } catch (RemoteException ex) {
2429                // bummer, the activity manager, which is in this process, is dead
2430            }
2431        }
2432        return true;
2433    }
2434
2435    public void setCurrentOrientationLw(int newOrientation) {
2436        synchronized (mLock) {
2437            if (newOrientation != mCurrentAppOrientation) {
2438                mCurrentAppOrientation = newOrientation;
2439                updateOrientationListenerLp();
2440            }
2441        }
2442    }
2443
2444    public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
2445        final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(),
2446                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0;
2447        if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) {
2448            return false;
2449        }
2450        long[] pattern = null;
2451        switch (effectId) {
2452            case HapticFeedbackConstants.LONG_PRESS:
2453                pattern = mLongPressVibePattern;
2454                break;
2455            case HapticFeedbackConstants.VIRTUAL_KEY:
2456                pattern = mVirtualKeyVibePattern;
2457                break;
2458            case HapticFeedbackConstants.KEYBOARD_TAP:
2459                pattern = mKeyboardTapVibePattern;
2460                break;
2461            case HapticFeedbackConstants.SAFE_MODE_DISABLED:
2462                pattern = mSafeModeDisabledVibePattern;
2463                break;
2464            case HapticFeedbackConstants.SAFE_MODE_ENABLED:
2465                pattern = mSafeModeEnabledVibePattern;
2466                break;
2467            default:
2468                return false;
2469        }
2470        if (pattern.length == 1) {
2471            // One-shot vibration
2472            mVibrator.vibrate(pattern[0]);
2473        } else {
2474            // Pattern vibration
2475            mVibrator.vibrate(pattern, -1);
2476        }
2477        return true;
2478    }
2479
2480    public void screenOnStoppedLw() {
2481        if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) {
2482            long curTime = SystemClock.uptimeMillis();
2483            mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
2484        }
2485    }
2486
2487    public boolean allowKeyRepeat() {
2488        // disable key repeat when screen is off
2489        return mScreenOn;
2490    }
2491}
2492