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