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