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