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