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