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