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