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