PhoneWindowManager.java revision bc1aa7bbc753ebcd32da4507fa23215489b6d314
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.ProgressDialog;
24import android.app.UiModeManager;
25import android.content.ActivityNotFoundException;
26import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.ContentResolver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.ServiceConnection;
33import android.content.pm.ActivityInfo;
34import android.content.pm.PackageManager;
35import android.content.res.CompatibilityInfo;
36import android.content.res.Configuration;
37import android.content.res.Resources;
38import android.database.ContentObserver;
39import android.graphics.PixelFormat;
40import android.graphics.Rect;
41import android.graphics.RectF;
42import android.os.Binder;
43import android.os.Bundle;
44import android.os.Handler;
45import android.os.IBinder;
46import android.os.IRemoteCallback;
47import android.os.LocalPowerManager;
48import android.os.Message;
49import android.os.Messenger;
50import android.os.PowerManager;
51import android.os.RemoteException;
52import android.os.ServiceManager;
53import android.os.SystemClock;
54import android.os.SystemProperties;
55import android.os.UEventObserver;
56import android.os.Vibrator;
57import android.provider.Settings;
58
59import com.android.internal.R;
60import com.android.internal.app.ShutdownThread;
61import com.android.internal.policy.PolicyManager;
62import com.android.internal.statusbar.IStatusBarService;
63import com.android.internal.telephony.ITelephony;
64import com.android.internal.view.BaseInputHandler;
65import com.android.internal.widget.PointerLocationView;
66
67import android.util.DisplayMetrics;
68import android.util.EventLog;
69import android.util.Log;
70import android.util.Slog;
71import android.view.Gravity;
72import android.view.HapticFeedbackConstants;
73import android.view.IWindowManager;
74import android.view.InputChannel;
75import android.view.InputDevice;
76import android.view.InputQueue;
77import android.view.InputHandler;
78import android.view.KeyCharacterMap;
79import android.view.KeyEvent;
80import android.view.MotionEvent;
81import android.view.WindowOrientationListener;
82import android.view.Surface;
83import android.view.View;
84import android.view.ViewConfiguration;
85import android.view.Window;
86import android.view.WindowManager;
87import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
88import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
89import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
90import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
91import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
92import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
93import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
94import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
95import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
96import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
97import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
98import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
99import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
100import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
101import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
102import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
103import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
104import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
105import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
106import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
107import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
108import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
109import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
110import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
111import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
112import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
113import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
114import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
115import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
116import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
117import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
118import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
119import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
120import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
121import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
122import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
123import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
124import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
125import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
126import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
127import android.view.WindowManagerImpl;
128import android.view.WindowManagerPolicy;
129import android.view.KeyCharacterMap.FallbackAction;
130import android.view.accessibility.AccessibilityEvent;
131import android.view.animation.Animation;
132import android.view.animation.AnimationUtils;
133import android.media.IAudioService;
134import android.media.AudioManager;
135
136import java.io.File;
137import java.io.FileDescriptor;
138import java.io.FileReader;
139import java.io.IOException;
140import java.io.PrintWriter;
141import java.util.ArrayList;
142
143/**
144 * WindowManagerPolicy implementation for the Android phone UI.  This
145 * introduces a new method suffix, Lp, for an internal lock of the
146 * PhoneWindowManager.  This is used to protect some internal state, and
147 * can be acquired with either thw Lw and Li lock held, so has the restrictions
148 * of both of those when held.
149 */
150public class PhoneWindowManager implements WindowManagerPolicy {
151    static final String TAG = "WindowManager";
152    static final boolean DEBUG = false;
153    static final boolean localLOGV = false;
154    static final boolean DEBUG_LAYOUT = false;
155    static final boolean DEBUG_FALLBACK = false;
156    static final boolean SHOW_STARTING_ANIMATIONS = true;
157    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
158
159    static final int LONG_PRESS_POWER_NOTHING = 0;
160    static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
161    static final int LONG_PRESS_POWER_SHUT_OFF = 2;
162
163    // These need to match the documentation/constant in
164    // core/res/res/values/config.xml
165    static final int LONG_PRESS_HOME_NOTHING = 0;
166    static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
167    static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
168
169    // wallpaper is at the bottom, though the window manager may move it.
170    static final int WALLPAPER_LAYER = 2;
171    static final int APPLICATION_LAYER = 2;
172    static final int PHONE_LAYER = 3;
173    static final int SEARCH_BAR_LAYER = 4;
174    static final int SYSTEM_DIALOG_LAYER = 5;
175    // toasts and the plugged-in battery thing
176    static final int TOAST_LAYER = 6;
177    // SIM errors and unlock.  Not sure if this really should be in a high layer.
178    static final int PRIORITY_PHONE_LAYER = 7;
179    // like the ANR / app crashed dialogs
180    static final int SYSTEM_ALERT_LAYER = 8;
181    // system-level error dialogs
182    static final int SYSTEM_ERROR_LAYER = 9;
183    // on-screen keyboards and other such input method user interfaces go here.
184    static final int INPUT_METHOD_LAYER = 10;
185    // on-screen keyboards and other such input method user interfaces go here.
186    static final int INPUT_METHOD_DIALOG_LAYER = 11;
187    // the keyguard; nothing on top of these can take focus, since they are
188    // responsible for power management when displayed.
189    static final int KEYGUARD_LAYER = 12;
190    static final int KEYGUARD_DIALOG_LAYER = 13;
191    static final int STATUS_BAR_SUB_PANEL_LAYER = 14;
192    static final int STATUS_BAR_LAYER = 15;
193    static final int STATUS_BAR_PANEL_LAYER = 16;
194    // the on-screen volume indicator and controller shown when the user
195    // changes the device volume
196    static final int VOLUME_OVERLAY_LAYER = 17;
197    // things in here CAN NOT take focus, but are shown on top of everything else.
198    static final int SYSTEM_OVERLAY_LAYER = 18;
199    // the navigation bar, if available, shows atop most things
200    static final int NAVIGATION_BAR_LAYER = 19;
201    // the drag layer: input for drag-and-drop is associated with this window,
202    // which sits above all other focusable windows
203    static final int DRAG_LAYER = 20;
204    static final int SECURE_SYSTEM_OVERLAY_LAYER = 21;
205    static final int BOOT_PROGRESS_LAYER = 22;
206    // the (mouse) pointer layer
207    static final int POINTER_LAYER = 23;
208
209    static final int APPLICATION_MEDIA_SUBLAYER = -2;
210    static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
211    static final int APPLICATION_PANEL_SUBLAYER = 1;
212    static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
213
214    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
215    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
216    static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
217    static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
218
219    // Useful scan codes.
220    private static final int SW_LID = 0x00;
221    private static final int BTN_MOUSE = 0x110;
222
223    final Object mLock = new Object();
224
225    Context mContext;
226    IWindowManager mWindowManager;
227    LocalPowerManager mPowerManager;
228    IStatusBarService mStatusBarService;
229    Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
230
231    // Vibrator pattern for haptic feedback of a long press.
232    long[] mLongPressVibePattern;
233
234    // Vibrator pattern for haptic feedback of virtual key press.
235    long[] mVirtualKeyVibePattern;
236
237    // Vibrator pattern for a short vibration.
238    long[] mKeyboardTapVibePattern;
239
240    // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
241    long[] mSafeModeDisabledVibePattern;
242
243    // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
244    long[] mSafeModeEnabledVibePattern;
245
246    /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
247    boolean mEnableShiftMenuBugReports = false;
248
249    boolean mSafeMode;
250    WindowState mStatusBar = null;
251    boolean mStatusBarCanHide;
252    int mStatusBarHeight;
253    final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
254    WindowState mNavigationBar = null;
255    boolean mHasNavigationBar = false;
256    int mNavigationBarWidth = 0, mNavigationBarHeight = 0;
257
258    WindowState mKeyguard = null;
259    KeyguardViewMediator mKeyguardMediator;
260    GlobalActions mGlobalActions;
261    volatile boolean mPowerKeyHandled;
262    RecentApplicationsDialog mRecentAppsDialog;
263    Handler mHandler;
264
265    private static final int LID_ABSENT = -1;
266    private static final int LID_CLOSED = 0;
267    private static final int LID_OPEN = 1;
268
269    int mLidOpen = LID_ABSENT;
270
271    boolean mSystemReady;
272    boolean mSystemBooted;
273    boolean mHdmiPlugged;
274    int mUiMode = Configuration.UI_MODE_TYPE_NORMAL;
275    int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
276    int mLidOpenRotation;
277    int mCarDockRotation;
278    int mDeskDockRotation;
279
280    int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
281    int mUserRotation = Surface.ROTATION_0;
282
283    boolean mAllowAllRotations;
284    boolean mCarDockEnablesAccelerometer;
285    boolean mDeskDockEnablesAccelerometer;
286    int mLidKeyboardAccessibility;
287    int mLidNavigationAccessibility;
288    int mLongPressOnPowerBehavior = -1;
289    boolean mScreenOnEarly = false;
290    boolean mScreenOnFully = false;
291    boolean mOrientationSensorEnabled = false;
292    int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
293    static final int DEFAULT_ACCELEROMETER_ROTATION = 0;
294    int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION;
295    boolean mHasSoftInput = false;
296
297    int mPointerLocationMode = 0;
298    PointerLocationView mPointerLocationView = null;
299    InputChannel mPointerLocationInputChannel;
300
301    // The last window we were told about in focusChanged.
302    WindowState mFocusedWindow;
303
304    private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() {
305        @Override
306        public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
307            boolean handled = false;
308            try {
309                if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
310                    synchronized (mLock) {
311                        if (mPointerLocationView != null) {
312                            mPointerLocationView.addPointerEvent(event);
313                            handled = true;
314                        }
315                    }
316                }
317            } finally {
318                finishedCallback.finished(handled);
319            }
320        }
321    };
322
323    // The current size of the screen; really; (ir)regardless of whether the status
324    // bar can be hidden or not
325    int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
326    int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
327    // The current size of the screen; these may be different than (0,0)-(dw,dh)
328    // if the status bar can't be hidden; in that case it effectively carves out
329    // that area of the display from all other windows.
330    int mRestrictedScreenLeft, mRestrictedScreenTop;
331    int mRestrictedScreenWidth, mRestrictedScreenHeight;
332    // During layout, the current screen borders with all outer decoration
333    // (status bar, input method dock) accounted for.
334    int mCurLeft, mCurTop, mCurRight, mCurBottom;
335    // During layout, the frame in which content should be displayed
336    // to the user, accounting for all screen decoration except for any
337    // space they deem as available for other content.  This is usually
338    // the same as mCur*, but may be larger if the screen decor has supplied
339    // content insets.
340    int mContentLeft, mContentTop, mContentRight, mContentBottom;
341    // During layout, the current screen borders along which input method
342    // windows are placed.
343    int mDockLeft, mDockTop, mDockRight, mDockBottom;
344    // During layout, the layer at which the doc window is placed.
345    int mDockLayer;
346
347    static final Rect mTmpParentFrame = new Rect();
348    static final Rect mTmpDisplayFrame = new Rect();
349    static final Rect mTmpContentFrame = new Rect();
350    static final Rect mTmpVisibleFrame = new Rect();
351    static final Rect mTmpNavigationFrame = new Rect();
352
353    WindowState mTopFullscreenOpaqueWindowState;
354    WindowState mTopAppWindowState;
355    WindowState mLastTopAppWindowState;
356    boolean mTopIsFullscreen;
357    boolean mForceStatusBar;
358    boolean mHideLockScreen;
359    boolean mDismissKeyguard;
360    boolean mHomePressed;
361    Intent mHomeIntent;
362    Intent mCarDockIntent;
363    Intent mDeskDockIntent;
364    int mShortcutKeyPressed = -1;
365    boolean mConsumeShortcutKeyUp;
366
367    // support for activating the lock screen while the screen is on
368    boolean mAllowLockscreenWhenOn;
369    int mLockScreenTimeout;
370    boolean mLockScreenTimerActive;
371
372    // visual screen saver support
373    int mScreenSaverTimeout;
374    boolean mScreenSaverEnabled = false;
375
376    // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
377    int mEndcallBehavior;
378
379    // Behavior of POWER button while in-call and screen on.
380    // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.)
381    int mIncallPowerBehavior;
382
383    int mLandscapeRotation = 0;  // default landscape rotation
384    int mSeascapeRotation = 0;   // "other" landscape rotation, 180 degrees from mLandscapeRotation
385    int mPortraitRotation = 0;   // default portrait rotation
386    int mUpsideDownRotation = 0; // "other" portrait rotation
387
388    // Nothing to see here, move along...
389    int mFancyRotationAnimation;
390
391    // What we do when the user long presses on home
392    private int mLongPressOnHomeBehavior = -1;
393
394    // Screenshot trigger states
395    private boolean mVolumeDownTriggered;
396    private boolean mPowerDownTriggered;
397
398    ShortcutManager mShortcutManager;
399    PowerManager.WakeLock mBroadcastWakeLock;
400
401    final KeyCharacterMap.FallbackAction mFallbackAction = new KeyCharacterMap.FallbackAction();
402
403    private UEventObserver mHDMIObserver = new UEventObserver() {
404        @Override
405        public void onUEvent(UEventObserver.UEvent event) {
406            setHdmiPlugged("1".equals(event.get("SWITCH_STATE")));
407        }
408    };
409
410    class SettingsObserver extends ContentObserver {
411        SettingsObserver(Handler handler) {
412            super(handler);
413        }
414
415        void observe() {
416            ContentResolver resolver = mContext.getContentResolver();
417            resolver.registerContentObserver(Settings.System.getUriFor(
418                    Settings.System.END_BUTTON_BEHAVIOR), false, this);
419            resolver.registerContentObserver(Settings.Secure.getUriFor(
420                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this);
421            resolver.registerContentObserver(Settings.System.getUriFor(
422                    Settings.System.ACCELEROMETER_ROTATION), false, this);
423            resolver.registerContentObserver(Settings.System.getUriFor(
424                    Settings.System.USER_ROTATION), false, this);
425            resolver.registerContentObserver(Settings.System.getUriFor(
426                    Settings.System.SCREEN_OFF_TIMEOUT), false, this);
427            resolver.registerContentObserver(Settings.System.getUriFor(
428                    Settings.System.WINDOW_ORIENTATION_LISTENER_LOG), false, this);
429            resolver.registerContentObserver(Settings.System.getUriFor(
430                    Settings.System.POINTER_LOCATION), false, this);
431            resolver.registerContentObserver(Settings.Secure.getUriFor(
432                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
433            resolver.registerContentObserver(Settings.System.getUriFor(
434                    "fancy_rotation_anim"), false, this);
435            resolver.registerContentObserver(Settings.System.getUriFor(
436                    Settings.Secure.DREAM_TIMEOUT), false, this);
437            updateSettings();
438        }
439
440        @Override public void onChange(boolean selfChange) {
441            updateSettings();
442            try {
443                mWindowManager.setRotation(USE_LAST_ROTATION, false,
444                        mFancyRotationAnimation);
445            } catch (RemoteException e) {
446                // Ignore
447            }
448        }
449    }
450
451    class MyOrientationListener extends WindowOrientationListener {
452        MyOrientationListener(Context context) {
453            super(context);
454        }
455
456        @Override
457        public void onOrientationChanged(int rotation) {
458            // Send updates based on orientation value
459            if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation);
460            try {
461                mWindowManager.setRotation(rotation, false,
462                        mFancyRotationAnimation);
463            } catch (RemoteException e) {
464                // Ignore
465
466            }
467        }
468    }
469    MyOrientationListener mOrientationListener;
470
471    boolean useSensorForOrientationLp(int appOrientation) {
472        // The app says use the sensor.
473        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
474                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
475                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
476                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
477            return true;
478        }
479        // The user preference says we can rotate, and the app is willing to rotate.
480        if (mAccelerometerDefault != 0 &&
481                (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
482                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
483            return true;
484        }
485        // We're in a dock that has a rotation affinity, and the app is willing to rotate.
486        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR)
487                || (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
488            // Note we override the nosensor flag here.
489            if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
490                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
491                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
492                return true;
493            }
494        }
495        // Else, don't use the sensor.
496        return false;
497    }
498
499    /*
500     * We always let the sensor be switched on by default except when
501     * the user has explicitly disabled sensor based rotation or when the
502     * screen is switched off.
503     */
504    boolean needSensorRunningLp() {
505        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
506                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
507                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
508                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
509            // If the application has explicitly requested to follow the
510            // orientation, then we need to turn the sensor or.
511            return true;
512        }
513        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
514                (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
515            // enable accelerometer if we are docked in a dock that enables accelerometer
516            // orientation management,
517            return true;
518        }
519        if (mAccelerometerDefault == 0) {
520            // If the setting for using the sensor by default is enabled, then
521            // we will always leave it on.  Note that the user could go to
522            // a window that forces an orientation that does not use the
523            // sensor and in theory we could turn it off... however, when next
524            // turning it on we won't have a good value for the current
525            // orientation for a little bit, which can cause orientation
526            // changes to lag, so we'd like to keep it always on.  (It will
527            // still be turned off when the screen is off.)
528            return false;
529        }
530        return true;
531    }
532
533    /*
534     * Various use cases for invoking this function
535     * screen turning off, should always disable listeners if already enabled
536     * screen turned on and current app has sensor based orientation, enable listeners
537     * if not already enabled
538     * screen turned on and current app does not have sensor orientation, disable listeners if
539     * already enabled
540     * screen turning on and current app has sensor based orientation, enable listeners if needed
541     * screen turning on and current app has nosensor based orientation, do nothing
542     */
543    void updateOrientationListenerLp() {
544        if (!mOrientationListener.canDetectOrientation()) {
545            // If sensor is turned off or nonexistent for some reason
546            return;
547        }
548        //Could have been invoked due to screen turning on or off or
549        //change of the currently visible window's orientation
550        if (localLOGV) Log.v(TAG, "Screen status="+mScreenOnEarly+
551                ", current orientation="+mCurrentAppOrientation+
552                ", SensorEnabled="+mOrientationSensorEnabled);
553        boolean disable = true;
554        if (mScreenOnEarly) {
555            if (needSensorRunningLp()) {
556                disable = false;
557                //enable listener if not already enabled
558                if (!mOrientationSensorEnabled) {
559                    mOrientationListener.enable();
560                    if(localLOGV) Log.v(TAG, "Enabling listeners");
561                    mOrientationSensorEnabled = true;
562                }
563            }
564        }
565        //check if sensors need to be disabled
566        if (disable && mOrientationSensorEnabled) {
567            mOrientationListener.disable();
568            if(localLOGV) Log.v(TAG, "Disabling listeners");
569            mOrientationSensorEnabled = false;
570        }
571    }
572
573    private void interceptPowerKeyDown(boolean handled) {
574        mPowerKeyHandled = handled;
575        if (!handled) {
576            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
577        }
578    }
579
580    private boolean interceptPowerKeyUp(boolean canceled) {
581        if (!mPowerKeyHandled) {
582            mHandler.removeCallbacks(mPowerLongPress);
583            return !canceled;
584        } else {
585            mPowerKeyHandled = true;
586            return false;
587        }
588    }
589
590    private final Runnable mPowerLongPress = new Runnable() {
591        public void run() {
592            if (!mPowerKeyHandled) {
593                // The context isn't read
594                if (mLongPressOnPowerBehavior < 0) {
595                    mLongPressOnPowerBehavior = mContext.getResources().getInteger(
596                            com.android.internal.R.integer.config_longPressOnPowerBehavior);
597                }
598                switch (mLongPressOnPowerBehavior) {
599                case LONG_PRESS_POWER_NOTHING:
600                    break;
601                case LONG_PRESS_POWER_GLOBAL_ACTIONS:
602                    mPowerKeyHandled = true;
603                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
604                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
605                    showGlobalActionsDialog();
606                    break;
607                case LONG_PRESS_POWER_SHUT_OFF:
608                    mPowerKeyHandled = true;
609                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
610                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
611                    ShutdownThread.shutdown(mContext, true);
612                    break;
613                }
614            }
615        }
616    };
617
618    void showGlobalActionsDialog() {
619        if (mGlobalActions == null) {
620            mGlobalActions = new GlobalActions(mContext);
621        }
622        final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden();
623        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
624        if (keyguardShowing) {
625            // since it took two seconds of long press to bring this up,
626            // poke the wake lock so they have some time to see the dialog.
627            mKeyguardMediator.pokeWakelock();
628        }
629    }
630
631    boolean isDeviceProvisioned() {
632        return Settings.Secure.getInt(
633                mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
634    }
635
636    private void handleLongPressOnHome() {
637        // We can't initialize this in init() since the configuration hasn't been loaded yet.
638        if (mLongPressOnHomeBehavior < 0) {
639            mLongPressOnHomeBehavior
640                    = mContext.getResources().getInteger(R.integer.config_longPressOnHomeBehavior);
641            if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
642                    mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
643                mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
644            }
645        }
646
647        if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
648            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
649            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
650
651            // Eat the longpress so it won't dismiss the recent apps dialog when
652            // the user lets go of the home key
653            mHomePressed = false;
654        }
655
656        if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) {
657            showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
658        } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
659            try {
660                mStatusBarService.toggleRecentApps();
661            } catch (RemoteException e) {
662                Slog.e(TAG, "RemoteException when showing recent apps", e);
663            }
664        }
665    }
666
667    /**
668     * Create (if necessary) and launch the recent apps dialog, or hide it if it is
669     * already shown.
670     */
671    void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) {
672        mHandler.post(new Runnable() {
673            @Override
674            public void run() {
675                if (mRecentAppsDialog == null) {
676                    mRecentAppsDialog = new RecentApplicationsDialog(mContext);
677                }
678                if (mRecentAppsDialog.isShowing()) {
679                    if (dismissIfShown) {
680                        mRecentAppsDialog.dismiss();
681                    }
682                } else {
683                    mRecentAppsDialog.setHeldModifiers(heldModifiers);
684                    mRecentAppsDialog.show();
685                }
686            }
687        });
688    }
689
690    /** {@inheritDoc} */
691    public void init(Context context, IWindowManager windowManager,
692            LocalPowerManager powerManager) {
693        mContext = context;
694        mWindowManager = windowManager;
695        mPowerManager = powerManager;
696        mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
697        mHandler = new Handler();
698        mOrientationListener = new MyOrientationListener(mContext);
699        SettingsObserver settingsObserver = new SettingsObserver(mHandler);
700        settingsObserver.observe();
701        mShortcutManager = new ShortcutManager(context, mHandler);
702        mShortcutManager.observe();
703        mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
704        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
705        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
706                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
707        mCarDockIntent =  new Intent(Intent.ACTION_MAIN, null);
708        mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
709        mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
710                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
711        mDeskDockIntent =  new Intent(Intent.ACTION_MAIN, null);
712        mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
713        mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
714                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
715
716        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
717        mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
718                "PhoneWindowManager.mBroadcastWakeLock");
719        mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
720        mLidOpenRotation = readRotation(
721                com.android.internal.R.integer.config_lidOpenRotation);
722        mCarDockRotation = readRotation(
723                com.android.internal.R.integer.config_carDockRotation);
724        mDeskDockRotation = readRotation(
725                com.android.internal.R.integer.config_deskDockRotation);
726        mAllowAllRotations = mContext.getResources().getBoolean(
727                com.android.internal.R.bool.config_allowAllRotations);
728        mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
729                com.android.internal.R.bool.config_carDockEnablesAccelerometer);
730        mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
731                com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
732        mLidKeyboardAccessibility = mContext.getResources().getInteger(
733                com.android.internal.R.integer.config_lidKeyboardAccessibility);
734        mLidNavigationAccessibility = mContext.getResources().getInteger(
735                com.android.internal.R.integer.config_lidNavigationAccessibility);
736        // register for dock events
737        IntentFilter filter = new IntentFilter();
738        filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
739        filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE);
740        filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE);
741        filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE);
742        filter.addAction(Intent.ACTION_DOCK_EVENT);
743        Intent intent = context.registerReceiver(mDockReceiver, filter);
744        if (intent != null) {
745            // Retrieve current sticky dock event broadcast.
746            mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
747                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
748        }
749        mVibrator = new Vibrator();
750        mLongPressVibePattern = getLongIntArray(mContext.getResources(),
751                com.android.internal.R.array.config_longPressVibePattern);
752        mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
753                com.android.internal.R.array.config_virtualKeyVibePattern);
754        mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(),
755                com.android.internal.R.array.config_keyboardTapVibePattern);
756        mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
757                com.android.internal.R.array.config_safeModeDisabledVibePattern);
758        mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
759                com.android.internal.R.array.config_safeModeEnabledVibePattern);
760
761        // Controls rotation and the like.
762        initializeHdmiState();
763    }
764
765    public void setInitialDisplaySize(int width, int height) {
766        int shortSize;
767        if (width > height) {
768            shortSize = height;
769            mLandscapeRotation = Surface.ROTATION_0;
770            mSeascapeRotation = Surface.ROTATION_180;
771            if (mContext.getResources().getBoolean(
772                    com.android.internal.R.bool.config_reverseDefaultRotation)) {
773                mPortraitRotation = Surface.ROTATION_90;
774                mUpsideDownRotation = Surface.ROTATION_270;
775            } else {
776                mPortraitRotation = Surface.ROTATION_270;
777                mUpsideDownRotation = Surface.ROTATION_90;
778            }
779        } else {
780            shortSize = width;
781            mPortraitRotation = Surface.ROTATION_0;
782            mUpsideDownRotation = Surface.ROTATION_180;
783            if (mContext.getResources().getBoolean(
784                    com.android.internal.R.bool.config_reverseDefaultRotation)) {
785                mLandscapeRotation = Surface.ROTATION_270;
786                mSeascapeRotation = Surface.ROTATION_90;
787            } else {
788                mLandscapeRotation = Surface.ROTATION_90;
789                mSeascapeRotation = Surface.ROTATION_270;
790            }
791        }
792
793        // Determine whether the status bar can hide based on the size
794        // of the screen.  We assume sizes > 600dp are tablets where we
795        // will use the system bar.
796        int shortSizeDp = shortSize
797                * DisplayMetrics.DENSITY_DEFAULT
798                / DisplayMetrics.DENSITY_DEVICE;
799        mStatusBarCanHide = shortSizeDp < 600;
800        mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
801                mStatusBarCanHide
802                ? com.android.internal.R.dimen.status_bar_height
803                : com.android.internal.R.dimen.system_bar_height);
804
805        mHasNavigationBar = mContext.getResources().getBoolean(
806                com.android.internal.R.bool.config_showNavigationBar);
807        mNavigationBarHeight = mHasNavigationBar
808                ? mContext.getResources().getDimensionPixelSize(
809                    com.android.internal.R.dimen.navigation_bar_height)
810                : 0;
811        mNavigationBarWidth = mHasNavigationBar
812                ? mContext.getResources().getDimensionPixelSize(
813                    com.android.internal.R.dimen.navigation_bar_width)
814                : 0;
815    }
816
817    public void updateSettings() {
818        ContentResolver resolver = mContext.getContentResolver();
819        boolean updateRotation = false;
820        View addView = null;
821        View removeView = null;
822        synchronized (mLock) {
823            mEndcallBehavior = Settings.System.getInt(resolver,
824                    Settings.System.END_BUTTON_BEHAVIOR,
825                    Settings.System.END_BUTTON_BEHAVIOR_DEFAULT);
826            mIncallPowerBehavior = Settings.Secure.getInt(resolver,
827                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
828                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
829            mFancyRotationAnimation = Settings.System.getInt(resolver,
830                    "fancy_rotation_anim", 0) != 0 ? 0x80 : 0;
831            int accelerometerDefault = Settings.System.getInt(resolver,
832                    Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
833
834            // set up rotation lock state
835            mUserRotationMode = (accelerometerDefault == 0)
836                ? WindowManagerPolicy.USER_ROTATION_LOCKED
837                : WindowManagerPolicy.USER_ROTATION_FREE;
838            mUserRotation = Settings.System.getInt(resolver,
839                    Settings.System.USER_ROTATION,
840                    Surface.ROTATION_0);
841
842            if (mAccelerometerDefault != accelerometerDefault) {
843                mAccelerometerDefault = accelerometerDefault;
844                updateOrientationListenerLp();
845            }
846
847            mOrientationListener.setLogEnabled(
848                    Settings.System.getInt(resolver,
849                            Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, 0) != 0);
850
851            if (mSystemReady) {
852                int pointerLocation = Settings.System.getInt(resolver,
853                        Settings.System.POINTER_LOCATION, 0);
854                if (mPointerLocationMode != pointerLocation) {
855                    mPointerLocationMode = pointerLocation;
856                    if (pointerLocation != 0) {
857                        if (mPointerLocationView == null) {
858                            mPointerLocationView = new PointerLocationView(mContext);
859                            mPointerLocationView.setPrintCoords(false);
860                            addView = mPointerLocationView;
861                        }
862                    } else {
863                        removeView = mPointerLocationView;
864                        mPointerLocationView = null;
865                    }
866                }
867            }
868            // use screen off timeout setting as the timeout for the lockscreen
869            mLockScreenTimeout = Settings.System.getInt(resolver,
870                    Settings.System.SCREEN_OFF_TIMEOUT, 0);
871            String imId = Settings.Secure.getString(resolver,
872                    Settings.Secure.DEFAULT_INPUT_METHOD);
873            boolean hasSoftInput = imId != null && imId.length() > 0;
874            if (mHasSoftInput != hasSoftInput) {
875                mHasSoftInput = hasSoftInput;
876                updateRotation = true;
877            }
878
879            mScreenSaverTimeout = Settings.System.getInt(resolver,
880                    Settings.Secure.DREAM_TIMEOUT, 0);
881            mScreenSaverEnabled = true;
882            updateScreenSaverTimeoutLocked();
883        }
884        if (updateRotation) {
885            updateRotation(0);
886        }
887        if (addView != null) {
888            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
889                    WindowManager.LayoutParams.MATCH_PARENT,
890                    WindowManager.LayoutParams.MATCH_PARENT);
891            lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
892            lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
893                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
894                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
895                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
896            lp.format = PixelFormat.TRANSLUCENT;
897            lp.setTitle("PointerLocation");
898            WindowManager wm = (WindowManager)
899                    mContext.getSystemService(Context.WINDOW_SERVICE);
900            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
901            wm.addView(addView, lp);
902
903            if (mPointerLocationInputChannel == null) {
904                try {
905                    mPointerLocationInputChannel =
906                        mWindowManager.monitorInput("PointerLocationView");
907                    InputQueue.registerInputChannel(mPointerLocationInputChannel,
908                            mPointerLocationInputHandler, mHandler.getLooper().getQueue());
909                } catch (RemoteException ex) {
910                    Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.",
911                            ex);
912                }
913            }
914        }
915        if (removeView != null) {
916            if (mPointerLocationInputChannel != null) {
917                InputQueue.unregisterInputChannel(mPointerLocationInputChannel);
918                mPointerLocationInputChannel.dispose();
919                mPointerLocationInputChannel = null;
920            }
921
922            WindowManager wm = (WindowManager)
923                    mContext.getSystemService(Context.WINDOW_SERVICE);
924            wm.removeView(removeView);
925        }
926    }
927
928    private int readRotation(int resID) {
929        try {
930            int rotation = mContext.getResources().getInteger(resID);
931            switch (rotation) {
932                case 0:
933                    return Surface.ROTATION_0;
934                case 90:
935                    return Surface.ROTATION_90;
936                case 180:
937                    return Surface.ROTATION_180;
938                case 270:
939                    return Surface.ROTATION_270;
940            }
941        } catch (Resources.NotFoundException e) {
942            // fall through
943        }
944        return -1;
945    }
946
947    /** {@inheritDoc} */
948    public int checkAddPermission(WindowManager.LayoutParams attrs) {
949        int type = attrs.type;
950
951        if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
952                || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
953            return WindowManagerImpl.ADD_OKAY;
954        }
955        String permission = null;
956        switch (type) {
957            case TYPE_TOAST:
958                // XXX right now the app process has complete control over
959                // this...  should introduce a token to let the system
960                // monitor/control what they are doing.
961                break;
962            case TYPE_INPUT_METHOD:
963            case TYPE_WALLPAPER:
964                // The window manager will check these.
965                break;
966            case TYPE_PHONE:
967            case TYPE_PRIORITY_PHONE:
968            case TYPE_SYSTEM_ALERT:
969            case TYPE_SYSTEM_ERROR:
970            case TYPE_SYSTEM_OVERLAY:
971                permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
972                break;
973            default:
974                permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
975        }
976        if (permission != null) {
977            if (mContext.checkCallingOrSelfPermission(permission)
978                    != PackageManager.PERMISSION_GRANTED) {
979                return WindowManagerImpl.ADD_PERMISSION_DENIED;
980            }
981        }
982        return WindowManagerImpl.ADD_OKAY;
983    }
984
985    public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
986        switch (attrs.type) {
987            case TYPE_SYSTEM_OVERLAY:
988            case TYPE_SECURE_SYSTEM_OVERLAY:
989            case TYPE_TOAST:
990                // These types of windows can't receive input events.
991                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
992                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
993                attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
994                break;
995        }
996    }
997
998    void readLidState() {
999        try {
1000            int sw = mWindowManager.getSwitchState(SW_LID);
1001            if (sw > 0) {
1002                mLidOpen = LID_OPEN;
1003            } else if (sw == 0) {
1004                mLidOpen = LID_CLOSED;
1005            } else {
1006                mLidOpen = LID_ABSENT;
1007            }
1008        } catch (RemoteException e) {
1009            // Ignore
1010        }
1011    }
1012
1013    private int determineHiddenState(int mode, int hiddenValue, int visibleValue) {
1014        if (mLidOpen != LID_ABSENT) {
1015            switch (mode) {
1016                case 1:
1017                    return mLidOpen == LID_OPEN ? visibleValue : hiddenValue;
1018                case 2:
1019                    return mLidOpen == LID_OPEN ? hiddenValue : visibleValue;
1020            }
1021        }
1022        return visibleValue;
1023    }
1024
1025    /** {@inheritDoc} */
1026    public void adjustConfigurationLw(Configuration config) {
1027        readLidState();
1028
1029        mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN);
1030
1031        if (config.keyboard == Configuration.KEYBOARD_NOKEYS) {
1032            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
1033        } else {
1034            config.hardKeyboardHidden = determineHiddenState(mLidKeyboardAccessibility,
1035                    Configuration.HARDKEYBOARDHIDDEN_YES, Configuration.HARDKEYBOARDHIDDEN_NO);
1036        }
1037
1038        if (config.navigation == Configuration.NAVIGATION_NONAV) {
1039            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_YES;
1040        } else {
1041            config.navigationHidden = determineHiddenState(mLidNavigationAccessibility,
1042                    Configuration.NAVIGATIONHIDDEN_YES, Configuration.NAVIGATIONHIDDEN_NO);
1043        }
1044
1045        if (mHasSoftInput || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
1046            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
1047        } else {
1048            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES;
1049        }
1050    }
1051
1052    /** {@inheritDoc} */
1053    public int windowTypeToLayerLw(int type) {
1054        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
1055            return APPLICATION_LAYER;
1056        }
1057        switch (type) {
1058        case TYPE_STATUS_BAR:
1059            return STATUS_BAR_LAYER;
1060        case TYPE_STATUS_BAR_PANEL:
1061            return STATUS_BAR_PANEL_LAYER;
1062        case TYPE_STATUS_BAR_SUB_PANEL:
1063            return STATUS_BAR_SUB_PANEL_LAYER;
1064        case TYPE_SYSTEM_DIALOG:
1065            return SYSTEM_DIALOG_LAYER;
1066        case TYPE_SEARCH_BAR:
1067            return SEARCH_BAR_LAYER;
1068        case TYPE_PHONE:
1069            return PHONE_LAYER;
1070        case TYPE_KEYGUARD:
1071            return KEYGUARD_LAYER;
1072        case TYPE_KEYGUARD_DIALOG:
1073            return KEYGUARD_DIALOG_LAYER;
1074        case TYPE_SYSTEM_ALERT:
1075            return SYSTEM_ALERT_LAYER;
1076        case TYPE_SYSTEM_ERROR:
1077            return SYSTEM_ERROR_LAYER;
1078        case TYPE_INPUT_METHOD:
1079            return INPUT_METHOD_LAYER;
1080        case TYPE_INPUT_METHOD_DIALOG:
1081            return INPUT_METHOD_DIALOG_LAYER;
1082        case TYPE_VOLUME_OVERLAY:
1083            return VOLUME_OVERLAY_LAYER;
1084        case TYPE_SYSTEM_OVERLAY:
1085            return SYSTEM_OVERLAY_LAYER;
1086        case TYPE_SECURE_SYSTEM_OVERLAY:
1087            return SECURE_SYSTEM_OVERLAY_LAYER;
1088        case TYPE_PRIORITY_PHONE:
1089            return PRIORITY_PHONE_LAYER;
1090        case TYPE_TOAST:
1091            return TOAST_LAYER;
1092        case TYPE_WALLPAPER:
1093            return WALLPAPER_LAYER;
1094        case TYPE_DRAG:
1095            return DRAG_LAYER;
1096        case TYPE_POINTER:
1097            return POINTER_LAYER;
1098        case TYPE_NAVIGATION_BAR:
1099            return NAVIGATION_BAR_LAYER;
1100        case TYPE_BOOT_PROGRESS:
1101            return BOOT_PROGRESS_LAYER;
1102        }
1103        Log.e(TAG, "Unknown window type: " + type);
1104        return APPLICATION_LAYER;
1105    }
1106
1107    /** {@inheritDoc} */
1108    public int subWindowTypeToLayerLw(int type) {
1109        switch (type) {
1110        case TYPE_APPLICATION_PANEL:
1111        case TYPE_APPLICATION_ATTACHED_DIALOG:
1112            return APPLICATION_PANEL_SUBLAYER;
1113        case TYPE_APPLICATION_MEDIA:
1114            return APPLICATION_MEDIA_SUBLAYER;
1115        case TYPE_APPLICATION_MEDIA_OVERLAY:
1116            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
1117        case TYPE_APPLICATION_SUB_PANEL:
1118            return APPLICATION_SUB_PANEL_SUBLAYER;
1119        }
1120        Log.e(TAG, "Unknown sub-window type: " + type);
1121        return 0;
1122    }
1123
1124    public int getMaxWallpaperLayer() {
1125        return STATUS_BAR_LAYER;
1126    }
1127
1128    public boolean canStatusBarHide() {
1129        return mStatusBarCanHide;
1130    }
1131
1132    public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
1133        // Assumes that the navigation bar appears on the side of the display in landscape.
1134        if (fullWidth > fullHeight) {
1135            return fullWidth - mNavigationBarWidth;
1136        }
1137        return fullWidth;
1138    }
1139
1140    public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
1141        // Assumes the navigation bar appears on the bottom of the display in portrait.
1142        return fullHeight
1143            - (mStatusBarCanHide ? 0 : mStatusBarHeight)
1144            - ((fullWidth > fullHeight) ? 0 : mNavigationBarHeight);
1145    }
1146
1147    public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) {
1148        return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation);
1149    }
1150
1151    public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
1152        return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation);
1153    }
1154
1155    public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
1156        return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
1157    }
1158
1159    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
1160        return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
1161                && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
1162    }
1163
1164    /** {@inheritDoc} */
1165    public View addStartingWindow(IBinder appToken, String packageName, int theme,
1166            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
1167            int icon, int windowFlags) {
1168        if (!SHOW_STARTING_ANIMATIONS) {
1169            return null;
1170        }
1171        if (packageName == null) {
1172            return null;
1173        }
1174
1175        try {
1176            Context context = mContext;
1177            //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
1178            //        + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
1179            if (theme != context.getThemeResId() || labelRes != 0) {
1180                try {
1181                    context = context.createPackageContext(packageName, 0);
1182                    context.setTheme(theme);
1183                } catch (PackageManager.NameNotFoundException e) {
1184                    // Ignore
1185                }
1186            }
1187
1188            Window win = PolicyManager.makeNewWindow(context);
1189            if (win.getWindowStyle().getBoolean(
1190                    com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
1191                return null;
1192            }
1193
1194            Resources r = context.getResources();
1195            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
1196
1197            win.setType(
1198                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
1199            // Force the window flags: this is a fake window, so it is not really
1200            // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
1201            // flag because we do know that the next window will take input
1202            // focus, so we want to get the IME window up on top of us right away.
1203            win.setFlags(
1204                windowFlags|
1205                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
1206                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
1207                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
1208                windowFlags|
1209                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
1210                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
1211                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
1212
1213            if (!compatInfo.supportsScreen()) {
1214                win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW);
1215            }
1216
1217            win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
1218                    WindowManager.LayoutParams.MATCH_PARENT);
1219
1220            final WindowManager.LayoutParams params = win.getAttributes();
1221            params.token = appToken;
1222            params.packageName = packageName;
1223            params.windowAnimations = win.getWindowStyle().getResourceId(
1224                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
1225            params.privateFlags |=
1226                    WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
1227            params.setTitle("Starting " + packageName);
1228
1229            WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
1230            View view = win.getDecorView();
1231
1232            if (win.isFloating()) {
1233                // Whoops, there is no way to display an animation/preview
1234                // of such a thing!  After all that work...  let's skip it.
1235                // (Note that we must do this here because it is in
1236                // getDecorView() where the theme is evaluated...  maybe
1237                // we should peek the floating attribute from the theme
1238                // earlier.)
1239                return null;
1240            }
1241
1242            if (localLOGV) Log.v(
1243                TAG, "Adding starting window for " + packageName
1244                + " / " + appToken + ": "
1245                + (view.getParent() != null ? view : null));
1246
1247            wm.addView(view, params);
1248
1249            // Only return the view if it was successfully added to the
1250            // window manager... which we can tell by it having a parent.
1251            return view.getParent() != null ? view : null;
1252        } catch (WindowManagerImpl.BadTokenException e) {
1253            // ignore
1254            Log.w(TAG, appToken + " already running, starting window not displayed");
1255        } catch (RuntimeException e) {
1256            // don't crash if something else bad happens, for example a
1257            // failure loading resources because we are loading from an app
1258            // on external storage that has been unmounted.
1259            Log.w(TAG, appToken + " failed creating starting window", e);
1260        }
1261
1262        return null;
1263    }
1264
1265    /** {@inheritDoc} */
1266    public void removeStartingWindow(IBinder appToken, View window) {
1267        // RuntimeException e = new RuntimeException();
1268        // Log.i(TAG, "remove " + appToken + " " + window, e);
1269
1270        if (localLOGV) Log.v(
1271            TAG, "Removing starting window for " + appToken + ": " + window);
1272
1273        if (window != null) {
1274            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1275            wm.removeView(window);
1276        }
1277    }
1278
1279    /**
1280     * Preflight adding a window to the system.
1281     *
1282     * Currently enforces that three window types are singletons:
1283     * <ul>
1284     * <li>STATUS_BAR_TYPE</li>
1285     * <li>KEYGUARD_TYPE</li>
1286     * </ul>
1287     *
1288     * @param win The window to be added
1289     * @param attrs Information about the window to be added
1290     *
1291     * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
1292     */
1293    public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
1294        switch (attrs.type) {
1295            case TYPE_STATUS_BAR:
1296                mContext.enforceCallingOrSelfPermission(
1297                        android.Manifest.permission.STATUS_BAR_SERVICE,
1298                        "PhoneWindowManager");
1299                // TODO: Need to handle the race condition of the status bar proc
1300                // dying and coming back before the removeWindowLw cleanup has happened.
1301                if (mStatusBar != null) {
1302                    return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
1303                }
1304                mStatusBar = win;
1305                break;
1306            case TYPE_NAVIGATION_BAR:
1307                mContext.enforceCallingOrSelfPermission(
1308                        android.Manifest.permission.STATUS_BAR_SERVICE,
1309                        "PhoneWindowManager");
1310                mNavigationBar = win;
1311                if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
1312                break;
1313            case TYPE_STATUS_BAR_PANEL:
1314                mContext.enforceCallingOrSelfPermission(
1315                        android.Manifest.permission.STATUS_BAR_SERVICE,
1316                        "PhoneWindowManager");
1317                mStatusBarPanels.add(win);
1318                break;
1319            case TYPE_STATUS_BAR_SUB_PANEL:
1320                mContext.enforceCallingOrSelfPermission(
1321                        android.Manifest.permission.STATUS_BAR_SERVICE,
1322                        "PhoneWindowManager");
1323                mStatusBarPanels.add(win);
1324                break;
1325            case TYPE_KEYGUARD:
1326                if (mKeyguard != null) {
1327                    return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
1328                }
1329                mKeyguard = win;
1330                break;
1331        }
1332        return WindowManagerImpl.ADD_OKAY;
1333    }
1334
1335    /** {@inheritDoc} */
1336    public void removeWindowLw(WindowState win) {
1337        if (mStatusBar == win) {
1338            mStatusBar = null;
1339        } else if (mKeyguard == win) {
1340            mKeyguard = null;
1341        } else if (mNavigationBar == win) {
1342            mNavigationBar = null;
1343        } else {
1344            mStatusBarPanels.remove(win);
1345        }
1346    }
1347
1348    static final boolean PRINT_ANIM = false;
1349
1350    /** {@inheritDoc} */
1351    public int selectAnimationLw(WindowState win, int transit) {
1352        if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
1353              + ": transit=" + transit);
1354        if (transit == TRANSIT_PREVIEW_DONE) {
1355            if (win.hasAppShownWindows()) {
1356                if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
1357                return com.android.internal.R.anim.app_starting_exit;
1358            }
1359        }
1360
1361        return 0;
1362    }
1363
1364    public Animation createForceHideEnterAnimation() {
1365        return AnimationUtils.loadAnimation(mContext,
1366                com.android.internal.R.anim.lock_screen_behind_enter);
1367    }
1368
1369    static ITelephony getTelephonyService() {
1370        ITelephony telephonyService = ITelephony.Stub.asInterface(
1371                ServiceManager.checkService(Context.TELEPHONY_SERVICE));
1372        if (telephonyService == null) {
1373            Log.w(TAG, "Unable to find ITelephony interface.");
1374        }
1375        return telephonyService;
1376    }
1377
1378    static IAudioService getAudioService() {
1379        IAudioService audioService = IAudioService.Stub.asInterface(
1380                ServiceManager.checkService(Context.AUDIO_SERVICE));
1381        if (audioService == null) {
1382            Log.w(TAG, "Unable to find IAudioService interface.");
1383        }
1384        return audioService;
1385    }
1386
1387    boolean keyguardOn() {
1388        return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode();
1389    }
1390
1391    private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
1392            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
1393            WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
1394        };
1395
1396    /** {@inheritDoc} */
1397    @Override
1398    public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
1399        final boolean keyguardOn = keyguardOn();
1400        final int keyCode = event.getKeyCode();
1401        final int repeatCount = event.getRepeatCount();
1402        final int metaState = event.getMetaState();
1403        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
1404        final boolean canceled = event.isCanceled();
1405
1406        if (false) {
1407            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
1408                    + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
1409        }
1410
1411        // First we always handle the home key here, so applications
1412        // can never break it, although if keyguard is on, we do let
1413        // it handle it, because that gives us the correct 5 second
1414        // timeout.
1415        if (keyCode == KeyEvent.KEYCODE_HOME) {
1416            // If we have released the home key, and didn't do anything else
1417            // while it was pressed, then it is time to go home!
1418            if (mHomePressed && !down) {
1419                mHomePressed = false;
1420                if (!canceled) {
1421                    // If an incoming call is ringing, HOME is totally disabled.
1422                    // (The user is already on the InCallScreen at this point,
1423                    // and his ONLY options are to answer or reject the call.)
1424                    boolean incomingRinging = false;
1425                    try {
1426                        ITelephony telephonyService = getTelephonyService();
1427                        if (telephonyService != null) {
1428                            incomingRinging = telephonyService.isRinging();
1429                        }
1430                    } catch (RemoteException ex) {
1431                        Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
1432                    }
1433
1434                    if (incomingRinging) {
1435                        Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
1436                    } else {
1437                        launchHomeFromHotKey();
1438                    }
1439                } else {
1440                    Log.i(TAG, "Ignoring HOME; event canceled.");
1441                }
1442                return true;
1443            }
1444
1445            // If a system window has focus, then it doesn't make sense
1446            // right now to interact with applications.
1447            WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
1448            if (attrs != null) {
1449                final int type = attrs.type;
1450                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
1451                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
1452                    // the "app" is keyguard, so give it the key
1453                    return false;
1454                }
1455                final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
1456                for (int i=0; i<typeCount; i++) {
1457                    if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
1458                        // don't do anything, but also don't pass it to the app
1459                        return true;
1460                    }
1461                }
1462            }
1463
1464            if (down) {
1465                if (repeatCount == 0) {
1466                    mHomePressed = true;
1467                } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
1468                    if (!keyguardOn) {
1469                        handleLongPressOnHome();
1470                    }
1471                }
1472            }
1473            return true;
1474        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
1475            // Hijack modified menu keys for debugging features
1476            final int chordBug = KeyEvent.META_SHIFT_ON;
1477
1478            if (down && repeatCount == 0) {
1479                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
1480                    Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
1481                    mContext.sendOrderedBroadcast(intent, null);
1482                    return true;
1483                } else if (SHOW_PROCESSES_ON_ALT_MENU &&
1484                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
1485                    Intent service = new Intent();
1486                    service.setClassName(mContext, "com.android.server.LoadAverageService");
1487                    ContentResolver res = mContext.getContentResolver();
1488                    boolean shown = Settings.System.getInt(
1489                            res, Settings.System.SHOW_PROCESSES, 0) != 0;
1490                    if (!shown) {
1491                        mContext.startService(service);
1492                    } else {
1493                        mContext.stopService(service);
1494                    }
1495                    Settings.System.putInt(
1496                            res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
1497                    return true;
1498                }
1499            }
1500        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
1501            if (down) {
1502                if (repeatCount == 0) {
1503                    mShortcutKeyPressed = keyCode;
1504                    mConsumeShortcutKeyUp = false;
1505                }
1506            } else if (keyCode == mShortcutKeyPressed) {
1507                mShortcutKeyPressed = -1;
1508                if (mConsumeShortcutKeyUp) {
1509                    mConsumeShortcutKeyUp = false;
1510                    return true;
1511                }
1512            }
1513            return false;
1514        } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
1515            if (down && repeatCount == 0) {
1516                showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
1517            }
1518            return true;
1519        }
1520
1521        // Shortcuts are invoked through Search+key, so intercept those here
1522        // Any printing key that is chorded with Search should be consumed
1523        // even if no shortcut was invoked.  This prevents text from being
1524        // inadvertently inserted when using a keyboard that has built-in macro
1525        // shortcut keys (that emit Search+x) and some of them are not registered.
1526        if (mShortcutKeyPressed != -1) {
1527            final KeyCharacterMap kcm = event.getKeyCharacterMap();
1528            if (kcm.isPrintingKey(keyCode)) {
1529                mConsumeShortcutKeyUp = true;
1530                if (down && repeatCount == 0 && !keyguardOn) {
1531                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState);
1532                    if (shortcutIntent != null) {
1533                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1534                        try {
1535                            mContext.startActivity(shortcutIntent);
1536                        } catch (ActivityNotFoundException ex) {
1537                            Slog.w(TAG, "Dropping shortcut key combination because "
1538                                    + "the activity to which it is registered was not found: "
1539                                    + KeyEvent.keyCodeToString(mShortcutKeyPressed)
1540                                    + "+" + KeyEvent.keyCodeToString(keyCode), ex);
1541                        }
1542                    } else {
1543                        Slog.i(TAG, "Dropping unregistered shortcut key combination: "
1544                                + KeyEvent.keyCodeToString(mShortcutKeyPressed)
1545                                + "+" + KeyEvent.keyCodeToString(keyCode));
1546                    }
1547                }
1548                return true;
1549            }
1550        }
1551
1552        return false;
1553    }
1554
1555    /** {@inheritDoc} */
1556    @Override
1557    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
1558        // Note: This method is only called if the initial down was unhandled.
1559        if (DEBUG_FALLBACK) {
1560            Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
1561                    + ", flags=" + event.getFlags()
1562                    + ", keyCode=" + event.getKeyCode()
1563                    + ", scanCode=" + event.getScanCode()
1564                    + ", metaState=" + event.getMetaState()
1565                    + ", repeatCount=" + event.getRepeatCount()
1566                    + ", policyFlags=" + policyFlags);
1567        }
1568
1569        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
1570            final KeyCharacterMap kcm = event.getKeyCharacterMap();
1571            final int keyCode = event.getKeyCode();
1572            final int metaState = event.getMetaState();
1573            final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
1574                    && event.getRepeatCount() == 0;
1575
1576            if (initialDown) {
1577                // Invoke shortcuts using Meta as a fallback.
1578                if ((metaState & KeyEvent.META_META_ON) != 0) {
1579                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
1580                            metaState & ~(KeyEvent.META_META_ON
1581                                    | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
1582                    if (shortcutIntent != null) {
1583                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1584                        try {
1585                            mContext.startActivity(shortcutIntent);
1586                        } catch (ActivityNotFoundException ex) {
1587                            Slog.w(TAG, "Dropping shortcut key combination because "
1588                                    + "the activity to which it is registered was not found: "
1589                                    + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
1590                        }
1591                        return null;
1592                    }
1593                }
1594
1595                // Display task switcher for ALT-TAB or Meta-TAB.
1596                if (keyCode == KeyEvent.KEYCODE_TAB) {
1597                    final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
1598                    if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
1599                            || KeyEvent.metaStateHasModifiers(
1600                                    shiftlessModifiers, KeyEvent.META_META_ON)) {
1601                        showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/);
1602                        return null;
1603                    }
1604                }
1605            }
1606
1607            // Check for fallback actions specified by the key character map.
1608            if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) {
1609                if (DEBUG_FALLBACK) {
1610                    Slog.d(TAG, "Fallback: keyCode=" + mFallbackAction.keyCode
1611                            + " metaState=" + Integer.toHexString(mFallbackAction.metaState));
1612                }
1613
1614                int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
1615                KeyEvent fallbackEvent = KeyEvent.obtain(
1616                        event.getDownTime(), event.getEventTime(),
1617                        event.getAction(), mFallbackAction.keyCode,
1618                        event.getRepeatCount(), mFallbackAction.metaState,
1619                        event.getDeviceId(), event.getScanCode(),
1620                        flags, event.getSource(), null);
1621                int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
1622                if ((actions & ACTION_PASS_TO_USER) != 0) {
1623                    if (!interceptKeyBeforeDispatching(win, fallbackEvent, policyFlags)) {
1624                        if (DEBUG_FALLBACK) {
1625                            Slog.d(TAG, "Performing fallback.");
1626                        }
1627                        return fallbackEvent;
1628                    }
1629                }
1630                fallbackEvent.recycle();
1631            }
1632        }
1633
1634        if (DEBUG_FALLBACK) {
1635            Slog.d(TAG, "No fallback.");
1636        }
1637        return null;
1638    }
1639
1640    private boolean getFallbackAction(KeyCharacterMap kcm, int keyCode, int metaState,
1641            FallbackAction outFallbackAction) {
1642        // Consult the key character map for specific fallback actions.
1643        // For example, map NUMPAD_1 to MOVE_HOME when NUMLOCK is not pressed.
1644        return kcm.getFallbackAction(keyCode, metaState, outFallbackAction);
1645    }
1646
1647    /**
1648     * A home key -> launch home action was detected.  Take the appropriate action
1649     * given the situation with the keyguard.
1650     */
1651    void launchHomeFromHotKey() {
1652        if (mKeyguardMediator.isShowingAndNotHidden()) {
1653            // don't launch home if keyguard showing
1654        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
1655            // when in keyguard restricted mode, must first verify unlock
1656            // before launching home
1657            mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
1658                public void onKeyguardExitResult(boolean success) {
1659                    if (success) {
1660                        try {
1661                            ActivityManagerNative.getDefault().stopAppSwitches();
1662                        } catch (RemoteException e) {
1663                        }
1664                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1665                        startDockOrHome();
1666                    }
1667                }
1668            });
1669        } else {
1670            // no keyguard stuff to worry about, just launch home!
1671            try {
1672                ActivityManagerNative.getDefault().stopAppSwitches();
1673            } catch (RemoteException e) {
1674            }
1675            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
1676            startDockOrHome();
1677        }
1678    }
1679
1680    public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
1681        final int fl = attrs.flags;
1682
1683        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1684                == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1685            contentInset.set(mCurLeft, mCurTop,
1686                    (mRestrictedScreenLeft+mRestrictedScreenWidth) - mCurRight,
1687                    (mRestrictedScreenTop+mRestrictedScreenHeight) - mCurBottom);
1688        } else {
1689            contentInset.setEmpty();
1690        }
1691    }
1692
1693    /** {@inheritDoc} */
1694    public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotation) {
1695        mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
1696        mUnrestrictedScreenWidth = displayWidth;
1697        mUnrestrictedScreenHeight = displayHeight;
1698        mRestrictedScreenLeft = mRestrictedScreenTop = 0;
1699        mRestrictedScreenWidth = displayWidth;
1700        mRestrictedScreenHeight = displayHeight;
1701        mDockLeft = mContentLeft = mCurLeft = 0;
1702        mDockTop = mContentTop = mCurTop = 0;
1703        mDockRight = mContentRight = mCurRight = displayWidth;
1704        mDockBottom = mContentBottom = mCurBottom = displayHeight;
1705        mDockLayer = 0x10000000;
1706
1707        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
1708        final Rect pf = mTmpParentFrame;
1709        final Rect df = mTmpDisplayFrame;
1710        final Rect vf = mTmpVisibleFrame;
1711        pf.left = df.left = vf.left = mDockLeft;
1712        pf.top = df.top = vf.top = mDockTop;
1713        pf.right = df.right = vf.right = mDockRight;
1714        pf.bottom = df.bottom = vf.bottom = mDockBottom;
1715
1716        // decide where the status bar goes ahead of time
1717        if (mStatusBar != null) {
1718            Rect navr = null;
1719            if (mNavigationBar != null) {
1720                // Force the navigation bar to its appropriate place and
1721                // size.  We need to do this directly, instead of relying on
1722                // it to bubble up from the nav bar, because this needs to
1723                // change atomically with screen rotations.
1724                if (displayWidth < displayHeight) {
1725                    // Portrait screen; nav bar goes on bottom.
1726                    mTmpNavigationFrame.set(0, displayHeight-mNavigationBarHeight,
1727                            displayWidth, displayHeight);
1728                    if (mNavigationBar.isVisibleLw()) {
1729                        mDockBottom = mTmpNavigationFrame.top;
1730                        mRestrictedScreenHeight = mDockBottom - mDockTop;
1731                    }
1732                } else {
1733                    // Landscape screen; nav bar goes to the right.
1734                    mTmpNavigationFrame.set(displayWidth-mNavigationBarWidth, 0,
1735                            displayWidth, displayHeight);
1736                    if (mNavigationBar.isVisibleLw()) {
1737                        mDockRight = mTmpNavigationFrame.left;
1738                        mRestrictedScreenWidth = mDockRight - mDockLeft;
1739                    }
1740                }
1741                mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
1742                        mTmpNavigationFrame, mTmpNavigationFrame);
1743                if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
1744            }
1745            if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
1746                    mDockLeft, mDockTop, mDockRight, mDockBottom));
1747
1748            // apply navigation bar insets
1749            pf.left = df.left = vf.left = mDockLeft;
1750            pf.top = df.top = vf.top = mDockTop;
1751            pf.right = df.right = vf.right = mDockRight;
1752            pf.bottom = df.bottom = vf.bottom = mDockBottom;
1753
1754            mStatusBar.computeFrameLw(pf, df, vf, vf);
1755
1756            if (mStatusBar.isVisibleLw()) {
1757                // If the status bar is hidden, we don't want to cause
1758                // windows behind it to scroll.
1759                final Rect r = mStatusBar.getFrameLw();
1760                if (mStatusBarCanHide) {
1761                    // Status bar may go away, so the screen area it occupies
1762                    // is available to apps but just covering them when the
1763                    // status bar is visible.
1764                    if (mDockTop == r.top) mDockTop = r.bottom;
1765                    else if (mDockBottom == r.bottom) mDockBottom = r.top;
1766
1767                    mContentTop = mCurTop = mDockTop;
1768                    mContentBottom = mCurBottom = mDockBottom;
1769                    mContentLeft = mCurLeft = mDockLeft;
1770                    mContentRight = mCurRight = mDockRight;
1771
1772                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
1773                        String.format(
1774                            "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
1775                            mDockLeft, mDockTop, mDockRight, mDockBottom,
1776                            mContentLeft, mContentTop, mContentRight, mContentBottom,
1777                            mCurLeft, mCurTop, mCurRight, mCurBottom));
1778                } else {
1779                    // Status bar can't go away; the part of the screen it
1780                    // covers does not exist for anything behind it.
1781                    if (mRestrictedScreenTop == r.top) {
1782                        mRestrictedScreenTop = r.bottom;
1783                        mRestrictedScreenHeight -= (r.bottom-r.top);
1784                    } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
1785                        mRestrictedScreenHeight -= (r.bottom-r.top);
1786                    }
1787
1788                    mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
1789                    mContentBottom = mCurBottom = mDockBottom
1790                            = mRestrictedScreenTop + mRestrictedScreenHeight;
1791                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: ("
1792                            + mRestrictedScreenLeft + ","
1793                            + mRestrictedScreenTop + ","
1794                            + (mRestrictedScreenLeft + mRestrictedScreenWidth) + ","
1795                            + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")");
1796                }
1797            }
1798        }
1799    }
1800
1801    void setAttachedWindowFrames(WindowState win, int fl, int adjust,
1802            WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
1803        if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
1804            // Here's a special case: if this attached window is a panel that is
1805            // above the dock window, and the window it is attached to is below
1806            // the dock window, then the frames we computed for the window it is
1807            // attached to can not be used because the dock is effectively part
1808            // of the underlying window and the attached window is floating on top
1809            // of the whole thing.  So, we ignore the attached window and explicitly
1810            // compute the frames that would be appropriate without the dock.
1811            df.left = cf.left = vf.left = mDockLeft;
1812            df.top = cf.top = vf.top = mDockTop;
1813            df.right = cf.right = vf.right = mDockRight;
1814            df.bottom = cf.bottom = vf.bottom = mDockBottom;
1815        } else {
1816            // The effective display frame of the attached window depends on
1817            // whether it is taking care of insetting its content.  If not,
1818            // we need to use the parent's content frame so that the entire
1819            // window is positioned within that content.  Otherwise we can use
1820            // the display frame and let the attached window take care of
1821            // positioning its content appropriately.
1822            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1823                cf.set(attached.getDisplayFrameLw());
1824            } else {
1825                // If the window is resizing, then we want to base the content
1826                // frame on our attached content frame to resize...  however,
1827                // things can be tricky if the attached window is NOT in resize
1828                // mode, in which case its content frame will be larger.
1829                // Ungh.  So to deal with that, make sure the content frame
1830                // we end up using is not covering the IM dock.
1831                cf.set(attached.getContentFrameLw());
1832                if (attached.getSurfaceLayer() < mDockLayer) {
1833                    if (cf.left < mContentLeft) cf.left = mContentLeft;
1834                    if (cf.top < mContentTop) cf.top = mContentTop;
1835                    if (cf.right > mContentRight) cf.right = mContentRight;
1836                    if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
1837                }
1838            }
1839            df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
1840            vf.set(attached.getVisibleFrameLw());
1841        }
1842        // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
1843        // window should be positioned relative to its parent or the entire
1844        // screen.
1845        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
1846                ? attached.getFrameLw() : df);
1847    }
1848
1849    /** {@inheritDoc} */
1850    public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
1851            WindowState attached) {
1852        // we've already done the status bar
1853        if (win == mStatusBar || win == mNavigationBar) {
1854            return;
1855        }
1856
1857        final int fl = attrs.flags;
1858        final int sim = attrs.softInputMode;
1859
1860        final Rect pf = mTmpParentFrame;
1861        final Rect df = mTmpDisplayFrame;
1862        final Rect cf = mTmpContentFrame;
1863        final Rect vf = mTmpVisibleFrame;
1864
1865        final boolean hasNavBar = (mHasNavigationBar
1866                && mNavigationBar != null && mNavigationBar.isVisibleLw());
1867
1868        if (attrs.type == TYPE_INPUT_METHOD) {
1869            pf.left = df.left = cf.left = vf.left = mDockLeft;
1870            pf.top = df.top = cf.top = vf.top = mDockTop;
1871            pf.right = df.right = cf.right = vf.right = mDockRight;
1872            pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
1873            // IM dock windows always go to the bottom of the screen.
1874            attrs.gravity = Gravity.BOTTOM;
1875            mDockLayer = win.getSurfaceLayer();
1876        } else {
1877            final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1878
1879            if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1880                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1881                if (DEBUG_LAYOUT)
1882                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1883                            + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
1884                // This is the case for a normal activity window: we want it
1885                // to cover all of the screen space, and it can take care of
1886                // moving its contents to account for screen decorations that
1887                // intrude into that space.
1888                if (attached != null) {
1889                    // If this window is attached to another, our display
1890                    // frame is the same as the one we are attached to.
1891                    setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
1892                } else {
1893                    if (attrs.type == TYPE_STATUS_BAR_PANEL
1894                            || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
1895                        // Status bar panels are the only windows who can go on top of
1896                        // the status bar.  They are protected by the STATUS_BAR_SERVICE
1897                        // permission, so they have the same privileges as the status
1898                        // bar itself.
1899                        //
1900                        // However, they should still dodge the navigation bar if it exists.
1901
1902                        pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
1903                        pf.top = df.top = mUnrestrictedScreenTop;
1904                        pf.right = df.right = hasNavBar
1905                                            ? mRestrictedScreenLeft+mRestrictedScreenWidth
1906                                            : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
1907                        pf.bottom = df.bottom = hasNavBar
1908                                              ? mRestrictedScreenTop+mRestrictedScreenHeight
1909                                              : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
1910
1911                        if (DEBUG_LAYOUT) {
1912                            Log.v(TAG, String.format(
1913                                        "Laying out status bar window: (%d,%d - %d,%d)",
1914                                        pf.left, pf.top, pf.right, pf.bottom));
1915                        }
1916                    } else {
1917                        pf.left = df.left = mRestrictedScreenLeft;
1918                        pf.top = df.top = mRestrictedScreenTop;
1919                        pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
1920                        pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight;
1921                    }
1922                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1923                        cf.left = mDockLeft;
1924                        cf.top = mDockTop;
1925                        cf.right = mDockRight;
1926                        cf.bottom = mDockBottom;
1927                    } else {
1928                        cf.left = mContentLeft;
1929                        cf.top = mContentTop;
1930                        cf.right = mContentRight;
1931                        cf.bottom = mContentBottom;
1932                    }
1933                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1934                        vf.left = mCurLeft;
1935                        vf.top = mCurTop;
1936                        vf.right = mCurRight;
1937                        vf.bottom = mCurBottom;
1938                    } else {
1939                        vf.set(cf);
1940                    }
1941                }
1942            } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
1943                if (DEBUG_LAYOUT)
1944                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
1945                // A window that has requested to fill the entire screen just
1946                // gets everything, period.
1947                if (attrs.type == TYPE_STATUS_BAR_PANEL
1948                        || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
1949                    pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
1950                    pf.top = df.top = cf.top = mUnrestrictedScreenTop;
1951                    pf.right = df.right = cf.right = hasNavBar
1952                                        ? mRestrictedScreenLeft+mRestrictedScreenWidth
1953                                        : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
1954                    pf.bottom = df.bottom = cf.bottom = hasNavBar
1955                                          ? mRestrictedScreenTop+mRestrictedScreenHeight
1956                                          : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
1957
1958                    if (DEBUG_LAYOUT) {
1959                        Log.v(TAG, String.format(
1960                                    "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
1961                                    pf.left, pf.top, pf.right, pf.bottom));
1962                    }
1963                } else if (attrs.type == TYPE_NAVIGATION_BAR) {
1964                    // The navigation bar has Real Ultimate Power.
1965                    pf.left = df.left = mUnrestrictedScreenLeft;
1966                    pf.top = df.top = mUnrestrictedScreenTop;
1967                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
1968                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
1969                    if (DEBUG_LAYOUT) {
1970                        Log.v(TAG, String.format(
1971                                    "Laying out navigation bar window: (%d,%d - %d,%d)",
1972                                    pf.left, pf.top, pf.right, pf.bottom));
1973                    }
1974                } else if (attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
1975                        && ((fl & FLAG_FULLSCREEN) != 0)) {
1976                    // Fullscreen secure system overlays get what they ask for.
1977                    pf.left = df.left = mUnrestrictedScreenLeft;
1978                    pf.top = df.top = mUnrestrictedScreenTop;
1979                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
1980                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
1981                } else {
1982                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
1983                    pf.top = df.top = cf.top = mRestrictedScreenTop;
1984                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
1985                    pf.bottom = df.bottom = cf.bottom
1986                            = mRestrictedScreenTop+mRestrictedScreenHeight;
1987                }
1988                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1989                    vf.left = mCurLeft;
1990                    vf.top = mCurTop;
1991                    vf.right = mCurRight;
1992                    vf.bottom = mCurBottom;
1993                } else {
1994                    vf.set(cf);
1995                }
1996            } else if (attached != null) {
1997                if (DEBUG_LAYOUT)
1998                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
1999                // A child window should be placed inside of the same visible
2000                // frame that its parent had.
2001                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
2002            } else {
2003                if (DEBUG_LAYOUT)
2004                    Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
2005                // Otherwise, a normal window must be placed inside the content
2006                // of all screen decorations.
2007                if (attrs.type == TYPE_STATUS_BAR_PANEL) {
2008                    // Status bar panels are the only windows who can go on top of
2009                    // the status bar.  They are protected by the STATUS_BAR_SERVICE
2010                    // permission, so they have the same privileges as the status
2011                    // bar itself.
2012                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
2013                    pf.top = df.top = cf.top = mRestrictedScreenTop;
2014                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
2015                    pf.bottom = df.bottom = cf.bottom
2016                            = mRestrictedScreenTop+mRestrictedScreenHeight;
2017                } else {
2018                    pf.left = mContentLeft;
2019                    pf.top = mContentTop;
2020                    pf.right = mContentRight;
2021                    pf.bottom = mContentBottom;
2022                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2023                        df.left = cf.left = mDockLeft;
2024                        df.top = cf.top = mDockTop;
2025                        df.right = cf.right = mDockRight;
2026                        df.bottom = cf.bottom = mDockBottom;
2027                    } else {
2028                        df.left = cf.left = mContentLeft;
2029                        df.top = cf.top = mContentTop;
2030                        df.right = cf.right = mContentRight;
2031                        df.bottom = cf.bottom = mContentBottom;
2032                    }
2033                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2034                        vf.left = mCurLeft;
2035                        vf.top = mCurTop;
2036                        vf.right = mCurRight;
2037                        vf.bottom = mCurBottom;
2038                    } else {
2039                        vf.set(cf);
2040                    }
2041                }
2042            }
2043        }
2044
2045        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
2046            df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
2047            df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2048        }
2049
2050        if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
2051                + ": sim=#" + Integer.toHexString(sim)
2052                + " attach=" + attached + " type=" + attrs.type
2053                + String.format(" flags=0x%08x", fl)
2054                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2055                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
2056
2057        win.computeFrameLw(pf, df, cf, vf);
2058
2059        // Dock windows carve out the bottom of the screen, so normal windows
2060        // can't appear underneath them.
2061        if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
2062            int top = win.getContentFrameLw().top;
2063            top += win.getGivenContentInsetsLw().top;
2064            if (mContentBottom > top) {
2065                mContentBottom = top;
2066            }
2067            top = win.getVisibleFrameLw().top;
2068            top += win.getGivenVisibleInsetsLw().top;
2069            if (mCurBottom > top) {
2070                mCurBottom = top;
2071            }
2072            if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom="
2073                    + mDockBottom + " mContentBottom="
2074                    + mContentBottom + " mCurBottom=" + mCurBottom);
2075        }
2076    }
2077
2078    /** {@inheritDoc} */
2079    public int finishLayoutLw() {
2080        return 0;
2081    }
2082
2083    /** {@inheritDoc} */
2084    public void beginAnimationLw(int displayWidth, int displayHeight) {
2085        mTopFullscreenOpaqueWindowState = null;
2086        mTopAppWindowState = null;
2087        mForceStatusBar = false;
2088
2089        mHideLockScreen = false;
2090        mAllowLockscreenWhenOn = false;
2091        mDismissKeyguard = false;
2092    }
2093
2094    /** {@inheritDoc} */
2095    public void animatingWindowLw(WindowState win,
2096                                WindowManager.LayoutParams attrs) {
2097        if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
2098                + win.isVisibleOrBehindKeyguardLw());
2099        if (mTopFullscreenOpaqueWindowState == null &&
2100                win.isVisibleOrBehindKeyguardLw()) {
2101            if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2102                mForceStatusBar = true;
2103            }
2104            if (attrs.type >= FIRST_APPLICATION_WINDOW
2105                    && attrs.type <= LAST_APPLICATION_WINDOW
2106                    && attrs.x == 0 && attrs.y == 0
2107                    && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
2108                    && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
2109                if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
2110                mTopFullscreenOpaqueWindowState = win;
2111                if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
2112                    if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
2113                    mHideLockScreen = true;
2114                }
2115                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
2116                    if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
2117                    mDismissKeyguard = true;
2118                }
2119                if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2120                    mAllowLockscreenWhenOn = true;
2121                }
2122            }
2123        }
2124        if (mTopAppWindowState == null && win.isVisibleOrBehindKeyguardLw()) {
2125            if (attrs.type >= FIRST_APPLICATION_WINDOW
2126                    && attrs.type <= LAST_APPLICATION_WINDOW) {
2127                mTopAppWindowState = win;
2128            }
2129        }
2130    }
2131
2132    /** {@inheritDoc} */
2133    public int finishAnimationLw() {
2134        int changes = 0;
2135        boolean topIsFullscreen = false;
2136
2137        final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null)
2138                ? mTopFullscreenOpaqueWindowState.getAttrs()
2139                : null;
2140
2141        if (mStatusBar != null) {
2142            if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar
2143                    + " top=" + mTopFullscreenOpaqueWindowState);
2144            if (mForceStatusBar) {
2145                if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced");
2146                if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
2147            } else if (mTopFullscreenOpaqueWindowState != null) {
2148                if (localLOGV) {
2149                    Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
2150                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
2151                    Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2152                            + " lp.flags=0x" + Integer.toHexString(lp.flags));
2153                }
2154                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
2155                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2156                // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
2157                // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
2158                // case though.
2159                if (topIsFullscreen) {
2160                    if (mStatusBarCanHide) {
2161                        if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
2162                        if (mStatusBar.hideLw(true)) {
2163                            changes |= FINISH_LAYOUT_REDO_LAYOUT;
2164
2165                            mHandler.post(new Runnable() { public void run() {
2166                                if (mStatusBarService != null) {
2167                                    try {
2168                                        mStatusBarService.collapse();
2169                                    } catch (RemoteException ex) {}
2170                                }
2171                            }});
2172                        }
2173                    } else if (DEBUG_LAYOUT) {
2174                        Log.v(TAG, "Preventing status bar from hiding by policy");
2175                    }
2176                } else {
2177                    if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: top is not fullscreen");
2178                    if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
2179                }
2180            }
2181        }
2182
2183        mTopIsFullscreen = topIsFullscreen;
2184
2185        if (mTopAppWindowState != null && mTopAppWindowState != mLastTopAppWindowState) {
2186            mLastTopAppWindowState = mTopAppWindowState;
2187
2188            final boolean topNeedsMenu = (mTopAppWindowState.getAttrs().flags
2189                    & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
2190
2191            mHandler.post(new Runnable() {
2192                    public void run() {
2193                        if (mStatusBarService == null) {
2194                            // This is the one that can not go away, but it doesn't come up
2195                            // before the window manager does, so don't fail if it doesn't
2196                            // exist. This works as long as no fullscreen windows come up
2197                            // before the status bar service does.
2198                            mStatusBarService = IStatusBarService.Stub.asInterface(
2199                                    ServiceManager.getService("statusbar"));
2200                        }
2201                        final IStatusBarService sbs = mStatusBarService;
2202                        if (mStatusBarService != null) {
2203                            try {
2204                                sbs.topAppWindowChanged(topNeedsMenu);
2205                            } catch (RemoteException e) {
2206                                // This should be impossible because we're in the same process.
2207                                mStatusBarService = null;
2208                            }
2209                        }
2210                    }
2211                });
2212        }
2213
2214        // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
2215        // when the screen is locked
2216        if (mKeyguard != null) {
2217            if (localLOGV) Log.v(TAG, "finishAnimationLw::mHideKeyguard="+mHideLockScreen);
2218            if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
2219                if (mKeyguard.hideLw(true)) {
2220                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2221                            | FINISH_LAYOUT_REDO_CONFIG
2222                            | FINISH_LAYOUT_REDO_WALLPAPER;
2223                }
2224                if (mKeyguardMediator.isShowing()) {
2225                    mHandler.post(new Runnable() {
2226                        public void run() {
2227                            mKeyguardMediator.keyguardDone(false, false);
2228                        }
2229                    });
2230                }
2231            } else if (mHideLockScreen) {
2232                if (mKeyguard.hideLw(true)) {
2233                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2234                            | FINISH_LAYOUT_REDO_CONFIG
2235                            | FINISH_LAYOUT_REDO_WALLPAPER;
2236                }
2237                mKeyguardMediator.setHidden(true);
2238            } else {
2239                if (mKeyguard.showLw(true)) {
2240                    changes |= FINISH_LAYOUT_REDO_LAYOUT
2241                            | FINISH_LAYOUT_REDO_CONFIG
2242                            | FINISH_LAYOUT_REDO_WALLPAPER;
2243                }
2244                mKeyguardMediator.setHidden(false);
2245            }
2246        }
2247
2248        updateSystemUiVisibility();
2249
2250        // update since mAllowLockscreenWhenOn might have changed
2251        updateLockScreenTimeout();
2252        return changes;
2253    }
2254
2255    public boolean allowAppAnimationsLw() {
2256        if (mKeyguard != null && mKeyguard.isVisibleLw()) {
2257            // If keyguard is currently visible, no reason to animate
2258            // behind it.
2259            return false;
2260        }
2261        if (false) {
2262            // Don't do this on the tablet, since the system bar never completely
2263            // covers the screen, and with all its transparency this will
2264            // incorrectly think it does cover it when it doesn't.  We'll revisit
2265            // this later when we re-do the phone status bar.
2266            if (mStatusBar != null && mStatusBar.isVisibleLw()) {
2267                RectF rect = new RectF(mStatusBar.getShownFrameLw());
2268                for (int i=mStatusBarPanels.size()-1; i>=0; i--) {
2269                    WindowState w = mStatusBarPanels.get(i);
2270                    if (w.isVisibleLw()) {
2271                        rect.union(w.getShownFrameLw());
2272                    }
2273                }
2274                final int insetw = mRestrictedScreenWidth/10;
2275                final int inseth = mRestrictedScreenHeight/10;
2276                if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw,
2277                            mRestrictedScreenHeight-inseth)) {
2278                    // All of the status bar windows put together cover the
2279                    // screen, so the app can't be seen.  (Note this test doesn't
2280                    // work if the rects of these windows are at off offsets or
2281                    // sizes, causing gaps in the rect union we have computed.)
2282                    return false;
2283                }
2284            }
2285        }
2286        return true;
2287    }
2288
2289    public void focusChanged(WindowState lastFocus, WindowState newFocus) {
2290        mFocusedWindow = newFocus;
2291        updateSystemUiVisibility();
2292    }
2293
2294    /** {@inheritDoc} */
2295    public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
2296        // lid changed state
2297        mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED;
2298        boolean awakeNow = mKeyguardMediator.doLidChangeTq(lidOpen);
2299        updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2300        if (awakeNow) {
2301            // If the lid is opening and we don't have to keep the
2302            // keyguard up, then we can turn on the screen
2303            // immediately.
2304            mKeyguardMediator.pokeWakelock();
2305        } else if (keyguardIsShowingTq()) {
2306            if (lidOpen) {
2307                // If we are opening the lid and not hiding the
2308                // keyguard, then we need to have it turn on the
2309                // screen once it is shown.
2310                mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
2311                        KeyEvent.KEYCODE_POWER);
2312            }
2313        } else {
2314            // Light up the keyboard if we are sliding up.
2315            if (lidOpen) {
2316                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
2317                        LocalPowerManager.BUTTON_EVENT);
2318            } else {
2319                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
2320                        LocalPowerManager.OTHER_EVENT);
2321            }
2322        }
2323    }
2324
2325    void setHdmiPlugged(boolean plugged) {
2326        if (mHdmiPlugged != plugged) {
2327            mHdmiPlugged = plugged;
2328            updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2329            Intent intent = new Intent(ACTION_HDMI_PLUGGED);
2330            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2331            intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
2332            mContext.sendStickyBroadcast(intent);
2333        }
2334    }
2335
2336    void initializeHdmiState() {
2337        boolean plugged = false;
2338        // watch for HDMI plug messages if the hdmi switch exists
2339        if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
2340            mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
2341
2342            final String filename = "/sys/class/switch/hdmi/state";
2343            FileReader reader = null;
2344            try {
2345                reader = new FileReader(filename);
2346                char[] buf = new char[15];
2347                int n = reader.read(buf);
2348                if (n > 1) {
2349                    plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));
2350                }
2351            } catch (IOException ex) {
2352                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
2353            } catch (NumberFormatException ex) {
2354                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
2355            } finally {
2356                if (reader != null) {
2357                    try {
2358                        reader.close();
2359                    } catch (IOException ex) {
2360                    }
2361                }
2362            }
2363        }
2364        // This dance forces the code in setHdmiPlugged to run.
2365        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
2366        mHdmiPlugged = !plugged;
2367        setHdmiPlugged(!mHdmiPlugged);
2368    }
2369
2370    /**
2371     * @return Whether music is being played right now.
2372     */
2373    boolean isMusicActive() {
2374        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
2375        if (am == null) {
2376            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
2377            return false;
2378        }
2379        return am.isMusicActive();
2380    }
2381
2382    /**
2383     * Tell the audio service to adjust the volume appropriate to the event.
2384     * @param keycode
2385     */
2386    void handleVolumeKey(int stream, int keycode) {
2387        IAudioService audioService = getAudioService();
2388        if (audioService == null) {
2389            return;
2390        }
2391        try {
2392            // since audio is playing, we shouldn't have to hold a wake lock
2393            // during the call, but we do it as a precaution for the rare possibility
2394            // that the music stops right before we call this
2395            // TODO: Actually handle MUTE.
2396            mBroadcastWakeLock.acquire();
2397            audioService.adjustStreamVolume(stream,
2398                keycode == KeyEvent.KEYCODE_VOLUME_UP
2399                            ? AudioManager.ADJUST_RAISE
2400                            : AudioManager.ADJUST_LOWER,
2401                    0);
2402        } catch (RemoteException e) {
2403            Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
2404        } finally {
2405            mBroadcastWakeLock.release();
2406        }
2407    }
2408
2409    final Object mScreenshotLock = new Object();
2410    ServiceConnection mScreenshotConnection = null;
2411    Runnable mScreenshotTimeout = null;
2412
2413    void finishScreenshotLSS(ServiceConnection conn) {
2414        if (mScreenshotConnection == conn) {
2415            mContext.unbindService(conn);
2416            mScreenshotConnection = null;
2417            if (mScreenshotTimeout != null) {
2418                mHandler.removeCallbacks(mScreenshotTimeout);
2419                mScreenshotTimeout = null;
2420            }
2421        }
2422    }
2423
2424    private void takeScreenshot() {
2425        mHandler.post(new Runnable() {
2426            @Override
2427            public void run() {
2428                synchronized (mScreenshotLock) {
2429                    if (mScreenshotConnection != null) {
2430                        return;
2431                    }
2432                    ComponentName cn = new ComponentName("com.android.systemui",
2433                            "com.android.systemui.screenshot.TakeScreenshotService");
2434                    Intent intent = new Intent();
2435                    intent.setComponent(cn);
2436                    ServiceConnection conn = new ServiceConnection() {
2437                        @Override
2438                        public void onServiceConnected(ComponentName name, IBinder service) {
2439                            synchronized (mScreenshotLock) {
2440                                if (mScreenshotConnection != this) {
2441                                    return;
2442                                }
2443                                Messenger messenger = new Messenger(service);
2444                                Message msg = Message.obtain(null, 1);
2445                                final ServiceConnection myConn = this;
2446                                Handler h = new Handler(mHandler.getLooper()) {
2447                                    @Override
2448                                    public void handleMessage(Message msg) {
2449                                        synchronized (mScreenshotLock) {
2450                                            finishScreenshotLSS(myConn);
2451                                        }
2452                                    }
2453                                };
2454                                msg.replyTo = new Messenger(h);
2455                                try {
2456                                    messenger.send(msg);
2457                                } catch (RemoteException e) {
2458                                }
2459                            }
2460                        }
2461                        @Override
2462                        public void onServiceDisconnected(ComponentName name) {}
2463                    };
2464                    if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
2465                        mScreenshotConnection = conn;
2466                        mScreenshotTimeout = new Runnable() {
2467                            @Override public void run() {
2468                                synchronized (mScreenshotLock) {
2469                                    if (mScreenshotConnection != null) {
2470                                        finishScreenshotLSS(mScreenshotConnection);
2471                                    }
2472                                }
2473                            }
2474
2475                        };
2476                        mHandler.postDelayed(mScreenshotTimeout, 10000);
2477                    }
2478                }
2479            }
2480        });
2481    }
2482
2483    /** {@inheritDoc} */
2484    @Override
2485    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
2486        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
2487        final boolean canceled = event.isCanceled();
2488        final int keyCode = event.getKeyCode();
2489
2490        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
2491
2492        // If screen is off then we treat the case where the keyguard is open but hidden
2493        // the same as if it were open and in front.
2494        // This will prevent any keys other than the power button from waking the screen
2495        // when the keyguard is hidden by another activity.
2496        final boolean keyguardActive = (isScreenOn ?
2497                                        mKeyguardMediator.isShowingAndNotHidden() :
2498                                        mKeyguardMediator.isShowing());
2499
2500        if (!mSystemBooted) {
2501            // If we have not yet booted, don't let key events do anything.
2502            return 0;
2503        }
2504
2505        if (false) {
2506            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
2507                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
2508        }
2509
2510        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
2511                && event.getRepeatCount() == 0) {
2512            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
2513        }
2514
2515        // Basic policy based on screen state and keyguard.
2516        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
2517        //        is on or off, really.  We should care about whether the device is in an
2518        //        interactive state or is in suspend pretending to be "off".
2519        //        The primary screen might be turned off due to proximity sensor or
2520        //        because we are presenting media on an auxiliary screen or remotely controlling
2521        //        the device some other way (which is why we have an exemption here for injected
2522        //        events).
2523        int result;
2524        if (isScreenOn || isInjected) {
2525            // When the screen is on or if the key is injected pass the key to the application.
2526            result = ACTION_PASS_TO_USER;
2527        } else {
2528            // When the screen is off and the key is not injected, determine whether
2529            // to wake the device but don't pass the key to the application.
2530            result = 0;
2531
2532            final boolean isWakeKey = (policyFlags
2533                    & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
2534            if (down && isWakeKey) {
2535                if (keyguardActive) {
2536                    // If the keyguard is showing, let it decide what to do with the wake key.
2537                    mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
2538                } else {
2539                    // Otherwise, wake the device ourselves.
2540                    result |= ACTION_POKE_USER_ACTIVITY;
2541                }
2542            }
2543        }
2544
2545        // Handle special keys.
2546        switch (keyCode) {
2547            case KeyEvent.KEYCODE_VOLUME_DOWN:
2548                if (down) {
2549                    if (isScreenOn) {
2550                        // If the power key down was already triggered, take the screenshot
2551                        if (mPowerDownTriggered) {
2552                            // Dismiss the power-key longpress
2553                            mHandler.removeCallbacks(mPowerLongPress);
2554                            mPowerKeyHandled = true;
2555
2556                            // Take the screenshot
2557                            takeScreenshot();
2558
2559                            // Prevent the event from being passed through to the current activity
2560                            result &= ~ACTION_PASS_TO_USER;
2561                            break;
2562                        }
2563                        mVolumeDownTriggered = true;
2564                    }
2565                } else {
2566                    mVolumeDownTriggered = false;
2567                }
2568            case KeyEvent.KEYCODE_VOLUME_UP:
2569            case KeyEvent.KEYCODE_VOLUME_MUTE: {
2570                if (down) {
2571                    ITelephony telephonyService = getTelephonyService();
2572                    if (telephonyService != null) {
2573                        try {
2574                            if (telephonyService.isRinging()) {
2575                                // If an incoming call is ringing, either VOLUME key means
2576                                // "silence ringer".  We handle these keys here, rather than
2577                                // in the InCallScreen, to make sure we'll respond to them
2578                                // even if the InCallScreen hasn't come to the foreground yet.
2579                                // Look for the DOWN event here, to agree with the "fallback"
2580                                // behavior in the InCallScreen.
2581                                Log.i(TAG, "interceptKeyBeforeQueueing:"
2582                                      + " VOLUME key-down while ringing: Silence ringer!");
2583
2584                                // Silence the ringer.  (It's safe to call this
2585                                // even if the ringer has already been silenced.)
2586                                telephonyService.silenceRinger();
2587
2588                                // And *don't* pass this key thru to the current activity
2589                                // (which is probably the InCallScreen.)
2590                                result &= ~ACTION_PASS_TO_USER;
2591                                break;
2592                            }
2593                            if (telephonyService.isOffhook()
2594                                    && (result & ACTION_PASS_TO_USER) == 0) {
2595                                // If we are in call but we decided not to pass the key to
2596                                // the application, handle the volume change here.
2597                                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
2598                                break;
2599                            }
2600                        } catch (RemoteException ex) {
2601                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2602                        }
2603                    }
2604
2605                    if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
2606                        // If music is playing but we decided not to pass the key to the
2607                        // application, handle the volume change here.
2608                        handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
2609                        break;
2610                    }
2611                }
2612                break;
2613            }
2614
2615            case KeyEvent.KEYCODE_ENDCALL: {
2616                result &= ~ACTION_PASS_TO_USER;
2617                if (down) {
2618                    ITelephony telephonyService = getTelephonyService();
2619                    boolean hungUp = false;
2620                    if (telephonyService != null) {
2621                        try {
2622                            hungUp = telephonyService.endCall();
2623                        } catch (RemoteException ex) {
2624                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2625                        }
2626                    }
2627                    interceptPowerKeyDown(!isScreenOn || hungUp);
2628                } else {
2629                    if (interceptPowerKeyUp(canceled)) {
2630                        if ((mEndcallBehavior
2631                                & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
2632                            if (goHome()) {
2633                                break;
2634                            }
2635                        }
2636                        if ((mEndcallBehavior
2637                                & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
2638                            result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
2639                        }
2640                    }
2641                }
2642                break;
2643            }
2644
2645            case KeyEvent.KEYCODE_POWER: {
2646                result &= ~ACTION_PASS_TO_USER;
2647                if (down) {
2648                    if (isScreenOn) {
2649                        // If the volume down key has been triggered, then just take the screenshot
2650                        if (mVolumeDownTriggered) {
2651                            // Take the screenshot
2652                            takeScreenshot();
2653                            mPowerKeyHandled = true;
2654
2655                            // Prevent the event from being passed through to the current activity
2656                            break;
2657                        }
2658                        mPowerDownTriggered = true;
2659                    }
2660
2661                    ITelephony telephonyService = getTelephonyService();
2662                    boolean hungUp = false;
2663                    if (telephonyService != null) {
2664                        try {
2665                            if (telephonyService.isRinging()) {
2666                                // Pressing Power while there's a ringing incoming
2667                                // call should silence the ringer.
2668                                telephonyService.silenceRinger();
2669                            } else if ((mIncallPowerBehavior
2670                                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
2671                                    && telephonyService.isOffhook()) {
2672                                // Otherwise, if "Power button ends call" is enabled,
2673                                // the Power button will hang up any current active call.
2674                                hungUp = telephonyService.endCall();
2675                            }
2676                        } catch (RemoteException ex) {
2677                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2678                        }
2679                    }
2680                    interceptPowerKeyDown(!isScreenOn || hungUp);
2681                } else {
2682                    mPowerDownTriggered = false;
2683                    if (interceptPowerKeyUp(canceled)) {
2684                        result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
2685                    }
2686                }
2687                break;
2688            }
2689
2690            case KeyEvent.KEYCODE_MEDIA_PLAY:
2691            case KeyEvent.KEYCODE_MEDIA_PAUSE:
2692            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
2693                if (down) {
2694                    ITelephony telephonyService = getTelephonyService();
2695                    if (telephonyService != null) {
2696                        try {
2697                            if (!telephonyService.isIdle()) {
2698                                // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
2699                                // to avoid music playback.
2700                                break;
2701                            }
2702                        } catch (RemoteException ex) {
2703                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2704                        }
2705                    }
2706                }
2707            case KeyEvent.KEYCODE_HEADSETHOOK:
2708            case KeyEvent.KEYCODE_MUTE:
2709            case KeyEvent.KEYCODE_MEDIA_STOP:
2710            case KeyEvent.KEYCODE_MEDIA_NEXT:
2711            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
2712            case KeyEvent.KEYCODE_MEDIA_REWIND:
2713            case KeyEvent.KEYCODE_MEDIA_RECORD:
2714            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
2715                if ((result & ACTION_PASS_TO_USER) == 0) {
2716                    // Only do this if we would otherwise not pass it to the user. In that
2717                    // case, the PhoneWindow class will do the same thing, except it will
2718                    // only do it if the showing app doesn't process the key on its own.
2719                    mBroadcastWakeLock.acquire();
2720                    mHandler.post(new PassHeadsetKey(new KeyEvent(event)));
2721                }
2722                break;
2723            }
2724
2725            case KeyEvent.KEYCODE_CALL: {
2726                if (down) {
2727                    ITelephony telephonyService = getTelephonyService();
2728                    if (telephonyService != null) {
2729                        try {
2730                            if (telephonyService.isRinging()) {
2731                                Log.i(TAG, "interceptKeyBeforeQueueing:"
2732                                      + " CALL key-down while ringing: Answer the call!");
2733                                telephonyService.answerRingingCall();
2734
2735                                // And *don't* pass this key thru to the current activity
2736                                // (which is presumably the InCallScreen.)
2737                                result &= ~ACTION_PASS_TO_USER;
2738                            }
2739                        } catch (RemoteException ex) {
2740                            Log.w(TAG, "ITelephony threw RemoteException", ex);
2741                        }
2742                    }
2743                }
2744                break;
2745            }
2746        }
2747        return result;
2748    }
2749
2750    /** {@inheritDoc} */
2751    @Override
2752    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
2753        int result = 0;
2754
2755        final boolean isWakeMotion = (policyFlags
2756                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
2757        if (isWakeMotion) {
2758            if (mKeyguardMediator.isShowing()) {
2759                // If the keyguard is showing, let it decide what to do with the wake motion.
2760                mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
2761            } else {
2762                // Otherwise, wake the device ourselves.
2763                result |= ACTION_POKE_USER_ACTIVITY;
2764            }
2765        }
2766        return result;
2767    }
2768
2769    class PassHeadsetKey implements Runnable {
2770        KeyEvent mKeyEvent;
2771
2772        PassHeadsetKey(KeyEvent keyEvent) {
2773            mKeyEvent = keyEvent;
2774        }
2775
2776        public void run() {
2777            if (ActivityManagerNative.isSystemReady()) {
2778                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
2779                intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
2780                mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
2781                        mHandler, Activity.RESULT_OK, null, null);
2782            }
2783        }
2784    }
2785
2786    BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
2787        public void onReceive(Context context, Intent intent) {
2788            mBroadcastWakeLock.release();
2789        }
2790    };
2791
2792    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
2793        public void onReceive(Context context, Intent intent) {
2794            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
2795                mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
2796                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
2797            } else {
2798                try {
2799                    IUiModeManager uiModeService = IUiModeManager.Stub.asInterface(
2800                            ServiceManager.getService(Context.UI_MODE_SERVICE));
2801                    mUiMode = uiModeService.getCurrentModeType();
2802                } catch (RemoteException e) {
2803                }
2804            }
2805            updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
2806            updateOrientationListenerLp();
2807        }
2808    };
2809
2810    /** {@inheritDoc} */
2811    public void screenTurnedOff(int why) {
2812        EventLog.writeEvent(70000, 0);
2813        synchronized (mLock) {
2814            mScreenOnEarly = false;
2815            mScreenOnFully = false;
2816        }
2817        mKeyguardMediator.onScreenTurnedOff(why);
2818        synchronized (mLock) {
2819            updateOrientationListenerLp();
2820            updateLockScreenTimeout();
2821            updateScreenSaverTimeoutLocked();
2822        }
2823    }
2824
2825    /** {@inheritDoc} */
2826    public void screenTurningOn(final ScreenOnListener screenOnListener) {
2827        EventLog.writeEvent(70000, 1);
2828        //Slog.i(TAG, "Screen turning on...");
2829        mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
2830            @Override public void onShown(IBinder windowToken) {
2831                if (windowToken != null) {
2832                    try {
2833                        mWindowManager.waitForWindowDrawn(windowToken, new IRemoteCallback.Stub() {
2834                            @Override public void sendResult(Bundle data) {
2835                                Slog.i(TAG, "Lock screen displayed!");
2836                                screenOnListener.onScreenOn();
2837                                synchronized (mLock) {
2838                                    mScreenOnFully = true;
2839                                }
2840                            }
2841                        });
2842                    } catch (RemoteException e) {
2843                    }
2844                } else {
2845                    Slog.i(TAG, "No lock screen!");
2846                    screenOnListener.onScreenOn();
2847                    synchronized (mLock) {
2848                        mScreenOnFully = true;
2849                    }
2850                }
2851            }
2852        });
2853        synchronized (mLock) {
2854            mScreenOnEarly = true;
2855            updateOrientationListenerLp();
2856            updateLockScreenTimeout();
2857            updateScreenSaverTimeoutLocked();
2858        }
2859    }
2860
2861    /** {@inheritDoc} */
2862    public boolean isScreenOnEarly() {
2863        return mScreenOnEarly;
2864    }
2865
2866    /** {@inheritDoc} */
2867    public boolean isScreenOnFully() {
2868        return mScreenOnFully;
2869    }
2870
2871    /** {@inheritDoc} */
2872    public void enableKeyguard(boolean enabled) {
2873        mKeyguardMediator.setKeyguardEnabled(enabled);
2874    }
2875
2876    /** {@inheritDoc} */
2877    public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
2878        mKeyguardMediator.verifyUnlock(callback);
2879    }
2880
2881    private boolean keyguardIsShowingTq() {
2882        return mKeyguardMediator.isShowingAndNotHidden();
2883    }
2884
2885
2886    /** {@inheritDoc} */
2887    public boolean isKeyguardLocked() {
2888        return keyguardOn();
2889    }
2890
2891    /** {@inheritDoc} */
2892    public boolean isKeyguardSecure() {
2893        return mKeyguardMediator.isSecure();
2894    }
2895
2896    /** {@inheritDoc} */
2897    public boolean inKeyguardRestrictedKeyInputMode() {
2898        return mKeyguardMediator.isInputRestricted();
2899    }
2900
2901    void sendCloseSystemWindows() {
2902        sendCloseSystemWindows(mContext, null);
2903    }
2904
2905    void sendCloseSystemWindows(String reason) {
2906        sendCloseSystemWindows(mContext, reason);
2907    }
2908
2909    static void sendCloseSystemWindows(Context context, String reason) {
2910        if (ActivityManagerNative.isSystemReady()) {
2911            try {
2912                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
2913            } catch (RemoteException e) {
2914            }
2915        }
2916    }
2917
2918    public int rotationForOrientationLw(int orientation, int lastRotation,
2919            boolean displayEnabled) {
2920
2921        if (false) {
2922            Slog.v(TAG, "rotationForOrientationLw(orient="
2923                        + orientation + ", last=" + lastRotation
2924                        + "); user=" + mUserRotation + " "
2925                        + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
2926                            ? "USER_ROTATION_LOCKED" : "")
2927                        );
2928        }
2929
2930        synchronized (mLock) {
2931            switch (orientation) {
2932                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
2933                    //always return portrait if orientation set to portrait
2934                    return mPortraitRotation;
2935                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
2936                    //always return landscape if orientation set to landscape
2937                    return mLandscapeRotation;
2938                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
2939                    //always return portrait if orientation set to portrait
2940                    return mUpsideDownRotation;
2941                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
2942                    //always return seascape if orientation set to reverse landscape
2943                    return mSeascapeRotation;
2944                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
2945                    //return either landscape rotation based on the sensor
2946                    return getCurrentLandscapeRotation(lastRotation);
2947                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
2948                    return getCurrentPortraitRotation(lastRotation);
2949            }
2950
2951            // case for nosensor meaning ignore sensor and consider only lid
2952            // or orientation sensor disabled
2953            //or case.unspecified
2954            if (mHdmiPlugged) {
2955                return mLandscapeRotation;
2956            } else if (mLidOpen == LID_OPEN) {
2957                return mLidOpenRotation;
2958            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
2959                return mCarDockRotation;
2960            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
2961                return mDeskDockRotation;
2962            } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
2963                return mUserRotation;
2964            } else {
2965                if (useSensorForOrientationLp(orientation)) {
2966                    // Disable 180 degree rotation unless allowed by default for the device
2967                    // or explicitly requested by the application.
2968                    int rotation = mOrientationListener.getCurrentRotation(lastRotation);
2969                    if (rotation == Surface.ROTATION_180
2970                            && !mAllowAllRotations
2971                            && orientation != ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR) {
2972                        return lastRotation;
2973                    }
2974                    return rotation;
2975                }
2976                return Surface.ROTATION_0;
2977            }
2978        }
2979    }
2980
2981    public int getLockedRotationLw() {
2982        synchronized (mLock) {
2983            if (false) {
2984                // Not yet working.
2985                if (mHdmiPlugged) {
2986                    return Surface.ROTATION_0;
2987                } else if (mLidOpen == LID_OPEN) {
2988                    return mLidOpenRotation;
2989                } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
2990                    return mCarDockRotation;
2991                } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
2992                    return mDeskDockRotation;
2993                } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
2994                    return mUserRotation;
2995                }
2996            }
2997            return -1;
2998        }
2999    }
3000
3001    private int getCurrentLandscapeRotation(int lastRotation) {
3002        // if the user has locked rotation, we ignore the sensor
3003        if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
3004            if (isLandscapeOrSeascape(mUserRotation)) {
3005                return mUserRotation;
3006            } else {
3007                // it seems odd to obey the sensor at all if rotation lock is enabled
3008                return mLandscapeRotation;
3009            }
3010        }
3011
3012        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
3013        if (isLandscapeOrSeascape(sensorRotation)) {
3014            return sensorRotation;
3015        }
3016        // try to preserve the old rotation if it was landscape
3017        if (isLandscapeOrSeascape(lastRotation)) {
3018            return lastRotation;
3019        }
3020        // default to one of the primary landscape rotation
3021        return mLandscapeRotation;
3022    }
3023
3024    private boolean isLandscapeOrSeascape(int sensorRotation) {
3025        return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation;
3026    }
3027
3028    private int getCurrentPortraitRotation(int lastRotation) {
3029        // if the user has locked rotation, we ignore the sensor
3030        if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
3031            if (isAnyPortrait(mUserRotation)) {
3032                return mUserRotation;
3033            } else {
3034                // it seems odd to obey the sensor at all if rotation lock is enabled
3035                return mPortraitRotation;
3036            }
3037        }
3038
3039        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
3040        if (isAnyPortrait(sensorRotation)) {
3041            return sensorRotation;
3042        }
3043        // try to preserve the old rotation if it was portrait
3044        if (isAnyPortrait(lastRotation)) {
3045            return lastRotation;
3046        }
3047        // default to one of the primary portrait rotations
3048        return mPortraitRotation;
3049    }
3050
3051    private boolean isAnyPortrait(int sensorRotation) {
3052        return sensorRotation == mPortraitRotation || sensorRotation == mUpsideDownRotation;
3053    }
3054
3055
3056    // User rotation: to be used when all else fails in assigning an orientation to the device
3057    public void setUserRotationMode(int mode, int rot) {
3058        ContentResolver res = mContext.getContentResolver();
3059
3060        // mUserRotationMode and mUserRotation will be assigned by the content observer
3061        if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
3062            Settings.System.putInt(res,
3063                    Settings.System.USER_ROTATION,
3064                    rot);
3065            Settings.System.putInt(res,
3066                    Settings.System.ACCELEROMETER_ROTATION,
3067                    0);
3068        } else {
3069            Settings.System.putInt(res,
3070                    Settings.System.ACCELEROMETER_ROTATION,
3071                    1);
3072        }
3073    }
3074
3075    public boolean detectSafeMode() {
3076        try {
3077            int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
3078            int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
3079            int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
3080            int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE);
3081            int volumeDownState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_VOLUME_DOWN);
3082            mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
3083                    || volumeDownState > 0;
3084            performHapticFeedbackLw(null, mSafeMode
3085                    ? HapticFeedbackConstants.SAFE_MODE_ENABLED
3086                    : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
3087            if (mSafeMode) {
3088                Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
3089                        + " dpad=" + dpadState + " trackball=" + trackballState + ")");
3090            } else {
3091                Log.i(TAG, "SAFE MODE not enabled");
3092            }
3093            return mSafeMode;
3094        } catch (RemoteException e) {
3095            // Doom! (it's also local)
3096            throw new RuntimeException("window manager dead");
3097        }
3098    }
3099
3100    static long[] getLongIntArray(Resources r, int resid) {
3101        int[] ar = r.getIntArray(resid);
3102        if (ar == null) {
3103            return null;
3104        }
3105        long[] out = new long[ar.length];
3106        for (int i=0; i<ar.length; i++) {
3107            out[i] = ar[i];
3108        }
3109        return out;
3110    }
3111
3112    /** {@inheritDoc} */
3113    public void systemReady() {
3114        // tell the keyguard
3115        mKeyguardMediator.onSystemReady();
3116        android.os.SystemProperties.set("dev.bootcomplete", "1");
3117        synchronized (mLock) {
3118            updateOrientationListenerLp();
3119            mSystemReady = true;
3120            mHandler.post(new Runnable() {
3121                public void run() {
3122                    updateSettings();
3123                }
3124            });
3125        }
3126    }
3127
3128    /** {@inheritDoc} */
3129    public void systemBooted() {
3130        synchronized (mLock) {
3131            mSystemBooted = true;
3132        }
3133    }
3134
3135    ProgressDialog mBootMsgDialog = null;
3136
3137    /** {@inheritDoc} */
3138    public void showBootMessage(final CharSequence msg, final boolean always) {
3139        mHandler.post(new Runnable() {
3140            @Override public void run() {
3141                if (mBootMsgDialog == null) {
3142                    mBootMsgDialog = new ProgressDialog(mContext) {
3143                        // This dialog will consume all events coming in to
3144                        // it, to avoid it trying to do things too early in boot.
3145                        @Override public boolean dispatchKeyEvent(KeyEvent event) {
3146                            return true;
3147                        }
3148                        @Override public boolean dispatchKeyShortcutEvent(KeyEvent event) {
3149                            return true;
3150                        }
3151                        @Override public boolean dispatchTouchEvent(MotionEvent ev) {
3152                            return true;
3153                        }
3154                        @Override public boolean dispatchTrackballEvent(MotionEvent ev) {
3155                            return true;
3156                        }
3157                        @Override public boolean dispatchGenericMotionEvent(MotionEvent ev) {
3158                            return true;
3159                        }
3160                        @Override public boolean dispatchPopulateAccessibilityEvent(
3161                                AccessibilityEvent event) {
3162                            return true;
3163                        }
3164                    };
3165                    mBootMsgDialog.setTitle(R.string.android_upgrading_title);
3166                    mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
3167                    mBootMsgDialog.setIndeterminate(true);
3168                    mBootMsgDialog.getWindow().setType(
3169                            WindowManager.LayoutParams.TYPE_BOOT_PROGRESS);
3170                    mBootMsgDialog.getWindow().addFlags(
3171                            WindowManager.LayoutParams.FLAG_DIM_BEHIND
3172                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
3173                    mBootMsgDialog.getWindow().setDimAmount(1);
3174                    mBootMsgDialog.setCancelable(false);
3175                    mBootMsgDialog.show();
3176                }
3177                mBootMsgDialog.setMessage(msg);
3178            }
3179        });
3180    }
3181
3182    /** {@inheritDoc} */
3183    public void hideBootMessages() {
3184        mHandler.post(new Runnable() {
3185            @Override public void run() {
3186                if (mBootMsgDialog != null) {
3187                    mBootMsgDialog.dismiss();
3188                    mBootMsgDialog = null;
3189                }
3190            }
3191        });
3192    }
3193
3194    /** {@inheritDoc} */
3195    public void userActivity() {
3196        synchronized (mScreenLockTimeout) {
3197            if (mLockScreenTimerActive) {
3198                // reset the timer
3199                mHandler.removeCallbacks(mScreenLockTimeout);
3200                mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
3201            }
3202        }
3203
3204        if (mStatusBarService != null) {
3205            try {
3206                mStatusBarService.userActivity();
3207            } catch (RemoteException ex) {}
3208        }
3209
3210        synchronized (mLock) {
3211            updateScreenSaverTimeoutLocked();
3212        }
3213    }
3214
3215    Runnable mScreenSaverActivator = null;
3216    /*new Runnable() {
3217        public void run() {
3218            synchronized (this) {
3219                if (!(mScreenSaverEnabled && mScreenOn)) {
3220                    Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?");
3221                    return;
3222                }
3223
3224                if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland");
3225                try {
3226                    String component = Settings.System.getString(
3227                            mContext.getContentResolver(), Settings.Secure.DREAM_COMPONENT);
3228                    if (component != null) {
3229                        ComponentName cn = ComponentName.unflattenFromString(component);
3230                        Intent intent = new Intent(Intent.ACTION_MAIN)
3231                            .setComponent(cn)
3232                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
3233                                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
3234                                | Intent.FLAG_ACTIVITY_NO_USER_ACTION
3235                                | Intent.FLAG_ACTIVITY_SINGLE_TOP);
3236                        mContext.startActivity(intent);
3237                    } else {
3238                        Log.e(TAG, "Couldn't start screen saver: none selected");
3239                    }
3240                } catch (android.content.ActivityNotFoundException exc) {
3241                    // no screensaver? give up
3242                    Log.e(TAG, "Couldn't start screen saver: none installed");
3243                }
3244            }
3245        }
3246    };
3247    */
3248
3249    // Must call while holding mLock
3250    private void updateScreenSaverTimeoutLocked() {
3251        if (mScreenSaverActivator == null) return;
3252
3253        synchronized (mScreenSaverActivator) {
3254            mHandler.removeCallbacks(mScreenSaverActivator);
3255            if (mScreenSaverEnabled && mScreenOnEarly && mScreenSaverTimeout > 0) {
3256                if (localLOGV)
3257                    Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now");
3258                mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout);
3259            } else {
3260                if (localLOGV) {
3261                    if (mScreenSaverTimeout == 0)
3262                        Log.v(TAG, "screen saver disabled by user");
3263                    else if (!mScreenOnEarly)
3264                        Log.v(TAG, "screen saver disabled while screen off");
3265                    else
3266                        Log.v(TAG, "screen saver disabled by wakelock");
3267                }
3268            }
3269        }
3270    }
3271
3272    Runnable mScreenLockTimeout = new Runnable() {
3273        public void run() {
3274            synchronized (this) {
3275                if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
3276                mKeyguardMediator.doKeyguardTimeout();
3277                mLockScreenTimerActive = false;
3278            }
3279        }
3280    };
3281
3282    private void updateLockScreenTimeout() {
3283        synchronized (mScreenLockTimeout) {
3284            boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && mKeyguardMediator.isSecure());
3285            if (mLockScreenTimerActive != enable) {
3286                if (enable) {
3287                    if (localLOGV) Log.v(TAG, "setting lockscreen timer");
3288                    mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
3289                } else {
3290                    if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
3291                    mHandler.removeCallbacks(mScreenLockTimeout);
3292                }
3293                mLockScreenTimerActive = enable;
3294            }
3295        }
3296    }
3297
3298    /** {@inheritDoc} */
3299    public void enableScreenAfterBoot() {
3300        readLidState();
3301        updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
3302    }
3303
3304    void updateRotation(int animFlags) {
3305        mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN);
3306        int rotation = Surface.ROTATION_0;
3307        if (mHdmiPlugged) {
3308            rotation = Surface.ROTATION_0;
3309        } else if (mLidOpen == LID_OPEN) {
3310            rotation = mLidOpenRotation;
3311        } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
3312            rotation = mCarDockRotation;
3313        } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
3314            rotation = mDeskDockRotation;
3315        }
3316        //if lid is closed orientation will be portrait
3317        try {
3318            //set orientation on WindowManager
3319            mWindowManager.setRotation(rotation, true,
3320                    mFancyRotationAnimation | animFlags);
3321        } catch (RemoteException e) {
3322            // Ignore
3323        }
3324    }
3325
3326    /**
3327     * Return an Intent to launch the currently active dock as home.  Returns
3328     * null if the standard home should be launched.
3329     * @return
3330     */
3331    Intent createHomeDockIntent() {
3332        Intent intent;
3333
3334        // What home does is based on the mode, not the dock state.  That
3335        // is, when in car mode you should be taken to car home regardless
3336        // of whether we are actually in a car dock.
3337        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
3338            intent = mCarDockIntent;
3339        } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) {
3340            intent = mDeskDockIntent;
3341        } else {
3342            return null;
3343        }
3344
3345        ActivityInfo ai = intent.resolveActivityInfo(
3346                mContext.getPackageManager(), PackageManager.GET_META_DATA);
3347        if (ai == null) {
3348            return null;
3349        }
3350
3351        if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
3352            intent = new Intent(intent);
3353            intent.setClassName(ai.packageName, ai.name);
3354            return intent;
3355        }
3356
3357        return null;
3358    }
3359
3360    void startDockOrHome() {
3361        Intent dock = createHomeDockIntent();
3362        if (dock != null) {
3363            try {
3364                mContext.startActivity(dock);
3365                return;
3366            } catch (ActivityNotFoundException e) {
3367            }
3368        }
3369        mContext.startActivity(mHomeIntent);
3370    }
3371
3372    /**
3373     * goes to the home screen
3374     * @return whether it did anything
3375     */
3376    boolean goHome() {
3377        if (false) {
3378            // This code always brings home to the front.
3379            try {
3380                ActivityManagerNative.getDefault().stopAppSwitches();
3381            } catch (RemoteException e) {
3382            }
3383            sendCloseSystemWindows();
3384            startDockOrHome();
3385        } else {
3386            // This code brings home to the front or, if it is already
3387            // at the front, puts the device to sleep.
3388            try {
3389                if (SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1) {
3390                    /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry.
3391                    Log.d(TAG, "UTS-TEST-MODE");
3392                } else {
3393                    ActivityManagerNative.getDefault().stopAppSwitches();
3394                    sendCloseSystemWindows();
3395                    Intent dock = createHomeDockIntent();
3396                    if (dock != null) {
3397                        int result = ActivityManagerNative.getDefault()
3398                                .startActivity(null, dock,
3399                                        dock.resolveTypeIfNeeded(mContext.getContentResolver()),
3400                                        null, 0, null, null, 0, true /* onlyIfNeeded*/, false,
3401                                        null, null, false);
3402                        if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
3403                            return false;
3404                        }
3405                    }
3406                }
3407                int result = ActivityManagerNative.getDefault()
3408                        .startActivity(null, mHomeIntent,
3409                                mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
3410                                null, 0, null, null, 0, true /* onlyIfNeeded*/, false,
3411                                null, null, false);
3412                if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
3413                    return false;
3414                }
3415            } catch (RemoteException ex) {
3416                // bummer, the activity manager, which is in this process, is dead
3417            }
3418        }
3419        return true;
3420    }
3421
3422    public void setCurrentOrientationLw(int newOrientation) {
3423        synchronized (mLock) {
3424            if (newOrientation != mCurrentAppOrientation) {
3425                mCurrentAppOrientation = newOrientation;
3426                updateOrientationListenerLp();
3427            }
3428        }
3429    }
3430
3431    public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
3432        final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(),
3433                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0;
3434        if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) {
3435            return false;
3436        }
3437        long[] pattern = null;
3438        switch (effectId) {
3439            case HapticFeedbackConstants.LONG_PRESS:
3440                pattern = mLongPressVibePattern;
3441                break;
3442            case HapticFeedbackConstants.VIRTUAL_KEY:
3443                pattern = mVirtualKeyVibePattern;
3444                break;
3445            case HapticFeedbackConstants.KEYBOARD_TAP:
3446                pattern = mKeyboardTapVibePattern;
3447                break;
3448            case HapticFeedbackConstants.SAFE_MODE_DISABLED:
3449                pattern = mSafeModeDisabledVibePattern;
3450                break;
3451            case HapticFeedbackConstants.SAFE_MODE_ENABLED:
3452                pattern = mSafeModeEnabledVibePattern;
3453                break;
3454            default:
3455                return false;
3456        }
3457        if (pattern.length == 1) {
3458            // One-shot vibration
3459            mVibrator.vibrate(pattern[0]);
3460        } else {
3461            // Pattern vibration
3462            mVibrator.vibrate(pattern, -1);
3463        }
3464        return true;
3465    }
3466
3467    public void screenOnStartedLw() {
3468        // The window manager has just grabbed a wake lock. This is our cue to disable the screen
3469        // saver.
3470        synchronized (mLock) {
3471            mScreenSaverEnabled = false;
3472        }
3473    }
3474
3475    public void screenOnStoppedLw() {
3476        if (mPowerManager.isScreenOn()) {
3477            if (!mKeyguardMediator.isShowingAndNotHidden()) {
3478                long curTime = SystemClock.uptimeMillis();
3479                mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
3480            }
3481
3482            synchronized (mLock) {
3483                // even if the keyguard is up, now that all the wakelocks have been released, we
3484                // should re-enable the screen saver
3485                mScreenSaverEnabled = true;
3486                updateScreenSaverTimeoutLocked();
3487            }
3488        }
3489    }
3490
3491    public boolean allowKeyRepeat() {
3492        // disable key repeat when screen is off
3493        return mScreenOnEarly;
3494    }
3495
3496    private void updateSystemUiVisibility() {
3497        // If there is no window focused, there will be nobody to handle the events
3498        // anyway, so just hang on in whatever state we're in until things settle down.
3499        if (mFocusedWindow != null) {
3500            final WindowManager.LayoutParams params = mFocusedWindow.getAttrs();
3501            final int visibility = params.systemUiVisibility | params.subtreeSystemUiVisibility;
3502            mHandler.post(new Runnable() {
3503                    public void run() {
3504                        if (mStatusBarService == null) {
3505                            mStatusBarService = IStatusBarService.Stub.asInterface(
3506                                    ServiceManager.getService("statusbar"));
3507                        }
3508                        if (mStatusBarService != null) {
3509                            // need to assume status bar privileges to invoke lights on
3510                            long origId = Binder.clearCallingIdentity();
3511                            try {
3512                                mStatusBarService.setSystemUiVisibility(visibility);
3513                            } catch (RemoteException e) {
3514                                // not much to be done
3515                                mStatusBarService = null;
3516                            } finally {
3517                                Binder.restoreCallingIdentity(origId);
3518                            }
3519                        }
3520                    }
3521                });
3522        }
3523    }
3524
3525    public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
3526        pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
3527                pw.print(" mSystemReady="); pw.print(mSystemReady);
3528                pw.print(" mSystemBooted="); pw.println(mSystemBooted);
3529        pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
3530                pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
3531                pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
3532        pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
3533                pw.print(" mDockMode="); pw.print(mDockMode);
3534                pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
3535                pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation);
3536        pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode);
3537                pw.print(" mUserRotation="); pw.print(mUserRotation);
3538                pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations);
3539        pw.print(prefix); pw.print("mAccelerometerDefault="); pw.print(mAccelerometerDefault);
3540                pw.print(" mCurrentAppOrientation="); pw.println(mCurrentAppOrientation);
3541        pw.print(prefix); pw.print("mCarDockEnablesAccelerometer=");
3542                pw.print(mCarDockEnablesAccelerometer);
3543                pw.print(" mDeskDockEnablesAccelerometer=");
3544                pw.println(mDeskDockEnablesAccelerometer);
3545        pw.print(prefix); pw.print("mLidKeyboardAccessibility=");
3546                pw.print(mLidKeyboardAccessibility);
3547                pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility);
3548                pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
3549        pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
3550                pw.print(" mScreenOnFully="); pw.print(mScreenOnFully);
3551                pw.print(" mOrientationSensorEnabled="); pw.print(mOrientationSensorEnabled);
3552                pw.print(" mHasSoftInput="); pw.println(mHasSoftInput);
3553        pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
3554                pw.print(","); pw.print(mUnrestrictedScreenTop);
3555                pw.print(") "); pw.print(mUnrestrictedScreenWidth);
3556                pw.print("x"); pw.println(mUnrestrictedScreenHeight);
3557        pw.print(prefix); pw.print("mRestrictedScreen=("); pw.print(mRestrictedScreenLeft);
3558                pw.print(","); pw.print(mRestrictedScreenTop);
3559                pw.print(") "); pw.print(mRestrictedScreenWidth);
3560                pw.print("x"); pw.println(mRestrictedScreenHeight);
3561        pw.print(prefix); pw.print("mCur=("); pw.print(mCurLeft);
3562                pw.print(","); pw.print(mCurTop);
3563                pw.print(")-("); pw.print(mCurRight);
3564                pw.print(","); pw.print(mCurBottom); pw.println(")");
3565        pw.print(prefix); pw.print("mContent=("); pw.print(mContentLeft);
3566                pw.print(","); pw.print(mContentTop);
3567                pw.print(")-("); pw.print(mContentRight);
3568                pw.print(","); pw.print(mContentBottom); pw.println(")");
3569        pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft);
3570                pw.print(","); pw.print(mDockTop);
3571                pw.print(")-("); pw.print(mDockRight);
3572                pw.print(","); pw.print(mDockBottom); pw.println(")");
3573        pw.print(prefix); pw.print("mDockLayer="); pw.println(mDockLayer);
3574        pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3575                pw.println(mTopFullscreenOpaqueWindowState);
3576        pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3577                pw.print(" mForceStatusBar="); pw.print(mForceStatusBar);
3578                pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
3579        pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
3580                pw.print(" mHomePressed="); pw.println(mHomePressed);
3581        pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
3582                pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
3583                pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
3584        pw.print(prefix); pw.print("mEndcallBehavior="); pw.print(mEndcallBehavior);
3585                pw.print(" mIncallPowerBehavior="); pw.print(mIncallPowerBehavior);
3586                pw.print(" mLongPressOnHomeBehavior="); pw.println(mLongPressOnHomeBehavior);
3587        pw.print(prefix); pw.print("mLandscapeRotation="); pw.print(mLandscapeRotation);
3588                pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
3589        pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
3590                pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
3591    }
3592}
3593