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