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