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