1/* 2 * Copyright (C) 2006-2007 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.IStatusBar; 23import android.content.BroadcastReceiver; 24import android.content.ContentQueryMap; 25import android.content.ContentResolver; 26import android.content.ContentValues; 27import android.content.Context; 28import android.content.Intent; 29import android.content.pm.ActivityInfo; 30import android.content.pm.PackageManager; 31import android.content.res.Configuration; 32import android.content.res.Resources; 33import android.database.Cursor; 34import android.graphics.Rect; 35import android.os.Handler; 36import android.os.IBinder; 37import android.os.LocalPowerManager; 38import android.os.PowerManager; 39import android.os.RemoteException; 40import android.os.ServiceManager; 41import android.os.SystemClock; 42import android.provider.Settings; 43import static android.provider.Settings.System.END_BUTTON_BEHAVIOR; 44 45import com.android.internal.policy.PolicyManager; 46import com.android.internal.telephony.ITelephony; 47import android.util.Config; 48import android.util.EventLog; 49import android.util.Log; 50import android.view.HapticFeedbackConstants; 51import android.view.IWindowManager; 52import android.view.KeyEvent; 53import android.view.MotionEvent; 54import android.view.OrientationListener; 55import android.view.RawInputEvent; 56import android.view.Surface; 57import android.view.View; 58import android.view.ViewConfiguration; 59import android.view.Window; 60import android.view.WindowManager; 61import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 62import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; 63import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 64import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 65import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; 66import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; 67import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 68import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; 69import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; 70import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; 71import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; 72import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; 73import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; 74import static android.view.WindowManager.LayoutParams.TYPE_PHONE; 75import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; 76import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; 77import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 78import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; 79import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 80import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 81import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; 82import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 83import android.view.WindowManagerImpl; 84import android.view.WindowManagerPolicy; 85import android.view.WindowManagerPolicy.WindowState; 86import android.media.IAudioService; 87import android.media.AudioManager; 88 89import java.util.Observable; 90import java.util.Observer; 91 92/** 93 * WindowManagerPolicy implementation for the Android MID UI. 94 */ 95public class MidWindowManager implements WindowManagerPolicy { 96 private static final String TAG = "MidWindowManager"; 97 private static final boolean DEBUG = false; 98 private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; 99 private static final boolean SHOW_STARTING_ANIMATIONS = true; 100 101 private static final int APPLICATION_LAYER = 1; 102 private static final int PHONE_LAYER = 2; 103 private static final int SEARCH_BAR_LAYER = 3; 104 private static final int STATUS_BAR_PANEL_LAYER = 4; 105 // toasts and the plugged-in battery thing 106 private static final int TOAST_LAYER = 5; 107 private static final int STATUS_BAR_LAYER = 6; 108 // SIM errors and unlock. Not sure if this really should be in a high layer. 109 private static final int PRIORITY_PHONE_LAYER = 7; 110 // like the ANR / app crashed dialogs 111 private static final int SYSTEM_ALERT_LAYER = 8; 112 // system-level error dialogs 113 private static final int SYSTEM_ERROR_LAYER = 9; 114 // the keyguard; nothing on top of these can take focus, since they are 115 // responsible for power management when displayed. 116 private static final int KEYGUARD_LAYER = 10; 117 private static final int KEYGUARD_DIALOG_LAYER = 11; 118 // things in here CAN NOT take focus, but are shown on top of everything else. 119 private static final int SYSTEM_OVERLAY_LAYER = 12; 120 121 static final int APPLICATION_MEDIA_SUBLAYER = -2; 122 static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; 123 static final int APPLICATION_PANEL_SUBLAYER = 1; 124 static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; 125 126 private static final boolean SINGLE_PRESS_OFF = false; 127 128 private static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; 129 130 static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; 131 static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; 132 static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; 133 134 private Context mContext; 135 private IWindowManager mWindowManager; 136 private LocalPowerManager mPowerManager; 137 138 boolean mSafeMode; 139 private WindowState mStatusBar = null; 140 private WindowState mSearchBar = null; 141 private WindowState mKeyguard = null; 142 private boolean mFirstConnect = true; 143 private GlobalActions mGlobalActions; 144 private boolean mShouldTurnOffOnKeyUp; 145 private RecentApplicationsDialog mRecentAppsDialog; 146 private Handler mHandler; 147 148 private boolean mLidOpen; 149 private boolean mScreenOn = false; 150 private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 151 152 private int mW, mH; 153 private int mCurLeft, mCurTop, mCurRight, mCurBottom; 154 155 static final Rect mTmpParentFrame = new Rect(); 156 static final Rect mTmpDisplayFrame = new Rect(); 157 static final Rect mTmpVisibleFrame = new Rect(); 158 159 private WindowState mTopFullscreenOpaqueWindowState; 160 private boolean mForceStatusBar; 161 private boolean mHomePressed; 162 private Intent mHomeIntent; 163 private boolean mSearchKeyPressed; 164 private boolean mConsumeSearchKeyUp; 165 166 private static final int ENDCALL_HOME = 0x1; 167 private static final int ENDCALL_SLEEPS = 0x2; 168 private static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; 169 private int mEndcallBehavior; 170 171 private ShortcutManager mShortcutManager; 172 private PowerManager.WakeLock mBroadcastWakeLock; 173 174 /* 175 * Various use cases for invoking this function 176 * screen turning off, should always disable listeners if already enabled 177 * screen turned on and current app has sensor based orientation, enable listeners 178 * if not already enabled 179 * screen turned on and current app does not have sensor orientation, disable listeners if 180 * already enabled 181 * screen turning on and current app has sensor based orientation, enable listeners if needed 182 * screen turning on and current app has nosensor based orientation, do nothing 183 */ 184 185 private Runnable mEndCallLongPress = new Runnable() { 186 public void run() { 187 mShouldTurnOffOnKeyUp = false; 188 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); 189 showGlobalActionsDialog(); 190 } 191 }; 192 193 private void showGlobalActionsDialog() { 194 if (mGlobalActions == null) { 195 mGlobalActions = new GlobalActions(mContext, mPowerManager); 196 } 197 mGlobalActions.showDialog(false, isDeviceProvisioned()); 198 } 199 200 private boolean isDeviceProvisioned() { 201 return Settings.System.getInt( 202 mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0; 203 } 204 205 /** 206 * When a home-key longpress expires, close other system windows and launch the recent apps 207 */ 208 private Runnable mHomeLongPress = new Runnable() { 209 public void run() { 210 /* 211 * Eat the longpress so it won't dismiss the recent apps dialog when 212 * the user lets go of the home key 213 */ 214 mHomePressed = false; 215 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); 216 showRecentAppsDialog(); 217 } 218 }; 219 220 /** 221 * Create (if necessary) and launch the recent apps dialog 222 */ 223 private void showRecentAppsDialog() { 224 if (mRecentAppsDialog == null) { 225 mRecentAppsDialog = new RecentApplicationsDialog(mContext); 226 } 227 mRecentAppsDialog.show(); 228 } 229 230 /** {@inheritDoc} */ 231 public void init(Context context, IWindowManager windowManager, 232 LocalPowerManager powerManager) { 233 mContext = context; 234 mWindowManager = windowManager; 235 mPowerManager = powerManager; 236 mHandler = new Handler(); 237 mShortcutManager = new ShortcutManager(context, mHandler); 238 mShortcutManager.observe(); 239 mHomeIntent = new Intent(Intent.ACTION_MAIN, null); 240 mHomeIntent.addCategory(Intent.CATEGORY_HOME); 241 mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 242 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 243 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 244 mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 245 "MidWindowManager.mBroadcastWakeLock"); 246 } 247 248 /** {@inheritDoc} */ 249 public int checkAddPermission(WindowManager.LayoutParams attrs) { 250 int type = attrs.type; 251 if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW 252 || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { 253 return WindowManagerImpl.ADD_OKAY; 254 } 255 String permission = null; 256 switch (type) { 257 case TYPE_TOAST: 258 // XXX right now the app process has complete control over 259 // this... should introduce a token to let the system 260 // monitor/control what they are doing. 261 break; 262 case TYPE_PHONE: 263 case TYPE_PRIORITY_PHONE: 264 case TYPE_SYSTEM_ALERT: 265 case TYPE_SYSTEM_ERROR: 266 case TYPE_SYSTEM_OVERLAY: 267 permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW; 268 break; 269 default: 270 permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; 271 } 272 if (permission != null) { 273 if (mContext.checkCallingOrSelfPermission(permission) 274 != PackageManager.PERMISSION_GRANTED) { 275 return WindowManagerImpl.ADD_PERMISSION_DENIED; 276 } 277 } 278 return WindowManagerImpl.ADD_OKAY; 279 } 280 281 public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) { 282 switch (attrs.type) { 283 case TYPE_SYSTEM_OVERLAY: 284 case TYPE_TOAST: 285 // These types of windows can't receive input events. 286 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 287 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 288 break; 289 } 290 } 291 292 /** {@inheritDoc} */ 293 public void adjustConfigurationLw(Configuration config) { 294 mPowerManager.setKeyboardVisibility(true); 295 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; 296 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 297 LocalPowerManager.OTHER_EVENT); 298 } 299 300 public boolean isCheekPressedAgainstScreen(MotionEvent ev) { 301 return false; 302 } 303 304 /** {@inheritDoc} */ 305 public int windowTypeToLayerLw(int type) { 306 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { 307 return APPLICATION_LAYER; 308 } 309 switch (type) { 310 case TYPE_APPLICATION_PANEL: 311 return APPLICATION_LAYER; 312 case TYPE_APPLICATION_SUB_PANEL: 313 return APPLICATION_LAYER; 314 case TYPE_STATUS_BAR: 315 return STATUS_BAR_LAYER; 316 case TYPE_STATUS_BAR_PANEL: 317 return STATUS_BAR_PANEL_LAYER; 318 case TYPE_SEARCH_BAR: 319 return SEARCH_BAR_LAYER; 320 case TYPE_PHONE: 321 return PHONE_LAYER; 322 case TYPE_KEYGUARD: 323 return KEYGUARD_LAYER; 324 case TYPE_KEYGUARD_DIALOG: 325 return KEYGUARD_DIALOG_LAYER; 326 case TYPE_SYSTEM_ALERT: 327 return SYSTEM_ALERT_LAYER; 328 case TYPE_SYSTEM_ERROR: 329 return SYSTEM_ERROR_LAYER; 330 case TYPE_SYSTEM_OVERLAY: 331 return SYSTEM_OVERLAY_LAYER; 332 case TYPE_PRIORITY_PHONE: 333 return PRIORITY_PHONE_LAYER; 334 case TYPE_TOAST: 335 return TOAST_LAYER; 336 } 337 Log.e(TAG, "Unknown window type: " + type); 338 return APPLICATION_LAYER; 339 } 340 341 /** {@inheritDoc} */ 342 public int subWindowTypeToLayerLw(int type) { 343 switch (type) { 344 case TYPE_APPLICATION_PANEL: 345 return APPLICATION_PANEL_SUBLAYER; 346 case TYPE_APPLICATION_MEDIA: 347 return APPLICATION_MEDIA_SUBLAYER; 348 case TYPE_APPLICATION_MEDIA_OVERLAY: 349 return APPLICATION_MEDIA_OVERLAY_SUBLAYER; 350 case TYPE_APPLICATION_SUB_PANEL: 351 return APPLICATION_SUB_PANEL_SUBLAYER; 352 } 353 Log.e(TAG, "Unknown sub-window type: " + type); 354 return 0; 355 } 356 357 /** {@inheritDoc} */ 358 public View addStartingWindow(IBinder appToken, String packageName, 359 int theme, CharSequence nonLocalizedLabel, 360 int labelRes, int icon) { 361 if (!SHOW_STARTING_ANIMATIONS) { 362 return null; 363 } 364 if (packageName == null) { 365 return null; 366 } 367 368 Context context = mContext; 369 boolean setTheme = false; 370 //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel=" 371 // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); 372 if (theme != 0 || labelRes != 0) { 373 try { 374 context = context.createPackageContext(packageName, 0); 375 if (theme != 0) { 376 context.setTheme(theme); 377 setTheme = true; 378 } 379 } catch (PackageManager.NameNotFoundException e) { 380 } 381 } 382 if (!setTheme) { 383 context.setTheme(com.android.internal.R.style.Theme); 384 } 385 386 Window win = PolicyManager.makeNewWindow(context); 387 Resources r = context.getResources(); 388 win.setTitle(r.getText(labelRes, nonLocalizedLabel)); 389 390 win.setType( 391 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 392 win.setFlags( 393 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 394 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, 395 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 396 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); 397 398 win.setLayout(WindowManager.LayoutParams.FILL_PARENT, 399 WindowManager.LayoutParams.FILL_PARENT); 400 401 final WindowManager.LayoutParams params = win.getAttributes(); 402 params.token = appToken; 403 params.packageName = packageName; 404 params.windowAnimations = win.getWindowStyle().getResourceId( 405 com.android.internal.R.styleable.Window_windowAnimationStyle, 0); 406 params.setTitle("Starting " + packageName); 407 408 try { 409 WindowManagerImpl wm = (WindowManagerImpl) 410 context.getSystemService(Context.WINDOW_SERVICE); 411 View view = win.getDecorView(); 412 413 if (win.isFloating()) { 414 // Whoops, there is no way to display an animation/preview 415 // of such a thing! After all that work... let's skip it. 416 // (Note that we must do this here because it is in 417 // getDecorView() where the theme is evaluated... maybe 418 // we should peek the floating attribute from the theme 419 // earlier.) 420 return null; 421 } 422 423 if (localLOGV) Log.v( 424 TAG, "Adding starting window for " + packageName 425 + " / " + appToken + ": " 426 + (view.getParent() != null ? view : null)); 427 428 wm.addView(view, params); 429 430 // Only return the view if it was successfully added to the 431 // window manager... which we can tell by it having a parent. 432 return view.getParent() != null ? view : null; 433 } catch (WindowManagerImpl.BadTokenException e) { 434 // ignore 435 Log.w(TAG, appToken + " already running, starting window not displayed"); 436 } 437 438 return null; 439 } 440 441 /** {@inheritDoc} */ 442 public void removeStartingWindow(IBinder appToken, View window) { 443 // RuntimeException e = new RuntimeException(); 444 // Log.i(TAG, "remove " + appToken + " " + window, e); 445 446 if (localLOGV) Log.v( 447 TAG, "Removing starting window for " + appToken + ": " + window); 448 449 if (window != null) { 450 WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); 451 wm.removeView(window); 452 } 453 } 454 455 /** 456 * Preflight adding a window to the system. 457 * 458 * Currently enforces that three window types are singletons: 459 * <ul> 460 * <li>STATUS_BAR_TYPE</li> 461 * <li>SEARCH_BAR_TYPE</li> 462 * <li>KEYGUARD_TYPE</li> 463 * </ul> 464 * 465 * @param win The window to be added 466 * @param attrs Information about the window to be added 467 * 468 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON 469 */ 470 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { 471 switch (attrs.type) { 472 case TYPE_STATUS_BAR: 473 if (mStatusBar != null) { 474 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; 475 } 476 mStatusBar = win; 477 break; 478 case TYPE_SEARCH_BAR: 479 if (mSearchBar != null) { 480 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; 481 } 482 mSearchBar = win; 483 break; 484 case TYPE_KEYGUARD: 485 if (mKeyguard != null) { 486 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; 487 } 488 mKeyguard = win; 489 break; 490 } 491 return WindowManagerImpl.ADD_OKAY; 492 } 493 494 /** {@inheritDoc} */ 495 public void removeWindowLw(WindowState win) { 496 if (mStatusBar == win) { 497 mStatusBar = null; 498 } 499 else if (mSearchBar == win) { 500 mSearchBar = null; 501 } 502 else if (mKeyguard == win) { 503 mKeyguard = null; 504 } 505 } 506 507 private static final boolean PRINT_ANIM = false; 508 509 /** {@inheritDoc} */ 510 public int selectAnimationLw(WindowState win, int transit) { 511 if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win 512 + ": transit=" + transit); 513 if (transit == TRANSIT_PREVIEW_DONE) { 514 if (win.hasAppShownWindows()) { 515 if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); 516 return com.android.internal.R.anim.app_starting_exit; 517 } 518 } 519 520 return 0; 521 } 522 523 private static IAudioService getAudioInterface() { 524 return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); 525 } 526 527 /** {@inheritDoc} */ 528 public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, 529 int repeatCount) { 530 if (false) { 531 Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount=" 532 + repeatCount); 533 } 534 535 // Clear a pending HOME longpress if the user releases Home 536 // TODO: This could probably be inside the next bit of logic, but that code 537 // turned out to be a bit fragile so I'm doing it here explicitly, for now. 538 if ((code == KeyEvent.KEYCODE_HOME) && !down) { 539 mHandler.removeCallbacks(mHomeLongPress); 540 } 541 542 // If the HOME button is currently being held, then we do special 543 // chording with it. 544 if (mHomePressed) { 545 546 // If we have released the home key, and didn't do anything else 547 // while it was pressed, then it is time to go home! 548 if (code == KeyEvent.KEYCODE_HOME) { 549 if (!down) { 550 mHomePressed = false; 551 launchHomeFromHotKey(); 552 } 553 } 554 555 return true; 556 } 557 558 // First we always handle the home key here, so applications 559 // can never break it, although if keyguard is on, we do let 560 // it handle it, because that gives us the correct 5 second 561 // timeout. 562 if (code == KeyEvent.KEYCODE_HOME) { 563 564 // If a system window has focus, then it doesn't make sense 565 // right now to interact with applications. 566 WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; 567 if (attrs != null) { 568 int type = attrs.type; 569 if (type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW 570 && type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { 571 // Only do this once, so home-key-longpress doesn't close itself 572 if (repeatCount == 0 && down) { 573 sendCloseSystemWindows(); 574 } 575 return false; 576 } 577 } 578 579 if (down && repeatCount == 0) { 580 mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); 581 mHomePressed = true; 582 } 583 return true; 584 } else if (code == KeyEvent.KEYCODE_MENU) { 585 // Hijack modified menu keys for debugging features 586 final int chordBug = KeyEvent.META_SHIFT_ON; 587 final int chordProcess = KeyEvent.META_ALT_ON; 588 589 if (down && repeatCount == 0) { 590 if ((metaKeys & chordBug) == chordBug) { 591 Intent intent = new Intent(Intent.ACTION_BUG_REPORT); 592 mContext.sendOrderedBroadcast(intent, null); 593 return true; 594 } else if ((metaKeys & chordProcess) == chordProcess) { 595 Intent service = new Intent(); 596 service.setClassName(mContext, "com.android.server.LoadAverageService"); 597 ContentResolver res = mContext.getContentResolver(); 598 boolean shown = Settings.System.getInt( 599 res, Settings.System.SHOW_PROCESSES, 0) != 0; 600 if (!shown) { 601 mContext.startService(service); 602 } else { 603 mContext.stopService(service); 604 } 605 Settings.System.putInt( 606 res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1); 607 return true; 608 } 609 } 610 } else if (code == KeyEvent.KEYCODE_NOTIFICATION) { 611 if (down) { 612 // this key doesn't exist on current hardware, but if a device 613 // didn't have a touchscreen, it would want one of these to open 614 // the status bar. 615 IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); 616 if (sbs != null) { 617 try { 618 sbs.toggle(); 619 } catch (RemoteException e) { 620 // we're screwed anyway, since it's in this process 621 throw new RuntimeException(e); 622 } 623 } 624 } 625 return true; 626 } else if (code == KeyEvent.KEYCODE_SEARCH) { 627 if (down) { 628 if (repeatCount == 0) { 629 mSearchKeyPressed = true; 630 } 631 } else { 632 mSearchKeyPressed = false; 633 634 if (mConsumeSearchKeyUp) { 635 // Consume the up-event 636 mConsumeSearchKeyUp = false; 637 return true; 638 } 639 } 640 } 641 642 // Shortcuts are invoked through Search+key, so intercept those here 643 if (mSearchKeyPressed) { 644 if (down && repeatCount == 0) { 645 Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys); 646 if (shortcutIntent != null) { 647 shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 648 mContext.startActivity(shortcutIntent); 649 650 /* 651 * We launched an app, so the up-event of the search key 652 * should be consumed 653 */ 654 mConsumeSearchKeyUp = true; 655 return true; 656 } 657 } 658 } 659 660 return false; 661 } 662 663 /** 664 * A home key -> launch home action was detected. Take the appropriate action 665 * given the situation with the keyguard. 666 */ 667 private void launchHomeFromHotKey() { 668 // no keyguard stuff to worry about, just launch home! 669 try { 670 ActivityManagerNative.getDefault().stopAppSwitches(); 671 } catch (RemoteException e) { 672 } 673 mContext.startActivity(mHomeIntent); 674 sendCloseSystemWindows(); 675 } 676 677 public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect coveredInset) { 678 final int fl = attrs.flags; 679 680 if ((fl & 681 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) 682 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { 683 coveredInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); 684 } else { 685 coveredInset.setEmpty(); 686 } 687 } 688 689 /** {@inheritDoc} */ 690 public void beginLayoutLw(int displayWidth, int displayHeight) { 691 mW = displayWidth; 692 mH = displayHeight; 693 mCurLeft = 0; 694 mCurTop = 0; 695 mCurRight = displayWidth; 696 mCurBottom = displayHeight; 697 698 // decide where the status bar goes ahead of time 699 if (mStatusBar != null) { 700 final Rect pf = mTmpParentFrame; 701 final Rect df = mTmpDisplayFrame; 702 final Rect vf = mTmpVisibleFrame; 703 pf.left = df.left = vf.left = 0; 704 pf.top = df.top = vf.top = 0; 705 pf.right = df.right = vf.right = displayWidth; 706 pf.bottom = df.bottom = vf.bottom = displayHeight; 707 708 mStatusBar.computeFrameLw(pf, df, vf, vf); 709 mCurTop = mStatusBar.getFrameLw().bottom; 710 } 711 } 712 713 /** {@inheritDoc} */ 714 public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { 715 // we've already done the status bar 716 if (win == mStatusBar) { 717 return; 718 } 719 720 final int fl = attrs.flags; 721 722 final Rect pf = mTmpParentFrame; 723 final Rect df = mTmpDisplayFrame; 724 final Rect vf = mTmpVisibleFrame; 725 726 if ((fl & 727 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) 728 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { 729 df.left = 0; 730 df.top = 0; 731 df.right = mW; 732 df.bottom = mH; 733 vf.left = mCurLeft; 734 vf.top = mCurTop; 735 vf.right = mCurRight; 736 vf.bottom = mCurBottom; 737 } else if ((fl & FLAG_LAYOUT_IN_SCREEN) == 0) { 738 // Make sure this window doesn't intrude into the status bar. 739 df.left = vf.left = mCurLeft; 740 df.top = vf.top = mCurTop; 741 df.right = vf.right = mCurRight; 742 df.bottom = vf.bottom = mCurBottom; 743 } else { 744 df.left = vf.left = 0; 745 df.top = vf.top = 0; 746 df.right = vf.right = mW; 747 df.bottom = vf.bottom = mH; 748 } 749 750 if (attached != null && (fl & (FLAG_LAYOUT_IN_SCREEN)) == 0) { 751 pf.set(attached.getFrameLw()); 752 } else { 753 pf.set(df); 754 } 755 756 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { 757 df.left = df.top = vf.left = vf.top = -10000; 758 df.right = df.bottom = vf.right = vf.bottom = 10000; 759 } 760 761 win.computeFrameLw(pf, df, vf, vf); 762 } 763 764 /** {@inheritDoc} */ 765 public boolean finishLayoutLw() { 766 return false; 767 } 768 769 /** {@inheritDoc} */ 770 public void beginAnimationLw(int displayWidth, int displayHeight) { 771 mTopFullscreenOpaqueWindowState = null; 772 mForceStatusBar = false; 773 } 774 775 /** {@inheritDoc} */ 776 public void animatingWindowLw(WindowState win, 777 WindowManager.LayoutParams attrs) { 778 if (mTopFullscreenOpaqueWindowState == null 779 && attrs.type >= FIRST_APPLICATION_WINDOW 780 && attrs.type <= LAST_APPLICATION_WINDOW 781 && win.fillsScreenLw(mW, mH, true, false) 782 && win.isDisplayedLw()) { 783 mTopFullscreenOpaqueWindowState = win; 784 } else if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { 785 mForceStatusBar = true; 786 } 787 } 788 789 /** {@inheritDoc} */ 790 public boolean finishAnimationLw() { 791 if (mStatusBar != null) { 792 if (mForceStatusBar) { 793 mStatusBar.showLw(true); 794 } else if (mTopFullscreenOpaqueWindowState != null) { 795 WindowManager.LayoutParams lp = 796 mTopFullscreenOpaqueWindowState.getAttrs(); 797 boolean hideStatusBar = 798 (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; 799 if (hideStatusBar) { 800 mStatusBar.hideLw(true); 801 } else { 802 mStatusBar.showLw(true); 803 } 804 } 805 } 806 return false; 807 } 808 809 /** {@inheritDoc} */ 810 public boolean preprocessInputEventTq(RawInputEvent event) { 811 return false; 812 } 813 814 815 /** {@inheritDoc} */ 816 public boolean isAppSwitchKeyTqTiLwLi(int keycode) { 817 return keycode == KeyEvent.KEYCODE_HOME 818 || keycode == KeyEvent.KEYCODE_ENDCALL; 819 } 820 821 /** {@inheritDoc} */ 822 public boolean isMovementKeyTi(int keycode) { 823 switch (keycode) { 824 case KeyEvent.KEYCODE_DPAD_UP: 825 case KeyEvent.KEYCODE_DPAD_DOWN: 826 case KeyEvent.KEYCODE_DPAD_LEFT: 827 case KeyEvent.KEYCODE_DPAD_RIGHT: 828 return true; 829 } 830 return false; 831 } 832 833 /** 834 * @return Whether music is being played right now. 835 */ 836 private boolean isMusicActive() { 837 final IAudioService audio = getAudioInterface(); 838 if (audio == null) { 839 Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); 840 return false; 841 } 842 try { 843 return audio.isMusicActive(); 844 } catch (RemoteException e) { 845 Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e); 846 return false; 847 } 848 } 849 850 /** 851 * Tell the audio service to adjust the volume appropriate to the event. 852 * @param keycode 853 */ 854 private void sendVolToMusic(int keycode) { 855 final IAudioService audio = getAudioInterface(); 856 if (audio == null) { 857 Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); 858 return; 859 } 860 try { 861 // since audio is playing, we shouldn't have to hold a wake lock 862 // during the call, but we do it as a precaution for the rare possibility 863 // that the music stops right before we call this 864 mBroadcastWakeLock.acquire(); 865 audio.adjustStreamVolume( 866 AudioManager.STREAM_MUSIC, 867 keycode == KeyEvent.KEYCODE_VOLUME_UP 868 ? AudioManager.ADJUST_RAISE 869 : AudioManager.ADJUST_LOWER, 870 0); 871 } catch (RemoteException e) { 872 Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e); 873 } finally { 874 mBroadcastWakeLock.release(); 875 } 876 } 877 878 /** {@inheritDoc} */ 879 public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { 880 int result = ACTION_PASS_TO_USER | ACTION_POKE_USER_ACTIVITY; 881 return result; 882 } 883 884 class PassHeadsetKey implements Runnable { 885 KeyEvent mKeyEvent; 886 887 PassHeadsetKey(KeyEvent keyEvent) { 888 mKeyEvent = keyEvent; 889 } 890 891 public void run() { 892 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 893 intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent); 894 mContext.sendOrderedBroadcast(intent, null, mBroadcastDone, 895 mHandler, Activity.RESULT_OK, null, null); 896 } 897 } 898 899 private BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { 900 public void onReceive(Context context, Intent intent) { 901 mBroadcastWakeLock.release(); 902 } 903 }; 904 905 /** {@inheritDoc} */ 906 public boolean isWakeRelMovementTq(int device, int classes, 907 RawInputEvent event) { 908 // if it's tagged with one of the wake bits, it wakes up the device 909 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); 910 } 911 912 /** {@inheritDoc} */ 913 public boolean isWakeAbsMovementTq(int device, int classes, 914 RawInputEvent event) { 915 // if it's tagged with one of the wake bits, it wakes up the device 916 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); 917 } 918 919 /** 920 * Given the current state of the world, should this key wake up the device? 921 */ 922 protected boolean isWakeKeyTq(RawInputEvent event) { 923 // There are not key maps for trackball devices, but we'd still 924 // like to have pressing it wake the device up, so force it here. 925 int keycode = event.keycode; 926 int flags = event.flags; 927 if (keycode == RawInputEvent.BTN_MOUSE) { 928 flags |= WindowManagerPolicy.FLAG_WAKE; 929 } 930 return (flags 931 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; 932 } 933 934 /** {@inheritDoc} */ 935 public void screenTurnedOff(int why) { 936 EventLog.writeEvent(70000, 0); 937 mScreenOn = false; 938 } 939 940 /** {@inheritDoc} */ 941 public void screenTurnedOn() { 942 EventLog.writeEvent(70000, 1); 943 mScreenOn = true; 944 } 945 946 /** {@inheritDoc} */ 947 public void enableKeyguard(boolean enabled) { 948 } 949 950 /** {@inheritDoc} */ 951 public void exitKeyguardSecurely(OnKeyguardExitResult callback) { 952 } 953 954 /** {@inheritDoc} */ 955 public boolean keyguardIsShowingTq() { 956 return false; 957 } 958 959 /** {@inheritDoc} */ 960 public boolean inKeyguardRestrictedKeyInputMode() { 961 return false; 962 } 963 964 /** 965 * Callback from {@link KeyguardViewMediator} 966 */ 967 public void onKeyguardShow() { 968 sendCloseSystemWindows(); 969 } 970 971 private void sendCloseSystemWindows() { 972 sendCloseSystemWindows(null); 973 } 974 975 private void sendCloseSystemWindows(String reason) { 976 try { 977 ActivityManagerNative.getDefault().closeSystemDialogs(reason); 978 } catch (RemoteException e) { 979 } 980 } 981 982 public int rotationForOrientationLw(int orientation, int lastRotation, 983 boolean displayEnabled) { 984 // get rid of rotation for now. Always rotation of 0 985 return Surface.ROTATION_0; 986 } 987 988 public boolean detectSafeMode() { 989 try { 990 int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); 991 mSafeMode = menuState > 0; 992 Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode); 993 return mSafeMode; 994 } catch (RemoteException e) { 995 // Doom! (it's also local) 996 throw new RuntimeException("window manager dead"); 997 } 998 } 999 1000 /** {@inheritDoc} */ 1001 public void systemReady() { 1002 try { 1003 if (mSafeMode) { 1004 // If the user is holding the menu key code, then we are 1005 // going to boot into safe mode. 1006 ActivityManagerNative.getDefault().enterSafeMode(); 1007 } else { 1008 // tell the keyguard 1009 android.os.SystemProperties.set("dev.bootcomplete", "1"); 1010 } 1011 } catch (RemoteException e) { 1012 } 1013 } 1014 1015 /** {@inheritDoc} */ 1016 public void enableScreenAfterBoot() { 1017 updateRotation(); 1018 } 1019 1020 private void updateRotation() { 1021 mPowerManager.setKeyboardVisibility(true); 1022 int rotation = Surface.ROTATION_0; 1023 try { 1024 //set orientation on WindowManager 1025 mWindowManager.setRotation(rotation, true, 0); 1026 } catch (RemoteException e) { 1027 } 1028 1029 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 1030 LocalPowerManager.OTHER_EVENT); 1031 } 1032 1033 /** 1034 * goes to the home screen 1035 * @return whether it did anything 1036 */ 1037 boolean goHome() { 1038 if (false) { 1039 // This code always brings home to the front. 1040 try { 1041 ActivityManagerNative.getDefault().stopAppSwitches(); 1042 } catch (RemoteException e) { 1043 } 1044 mContext.startActivity(mHomeIntent); 1045 } else { 1046 // This code brings home to the front or, if it is already 1047 // at the front, puts the device to sleep. 1048 try { 1049 ActivityManagerNative.getDefault().stopAppSwitches(); 1050 int result = ActivityManagerNative.getDefault() 1051 .startActivity(null, mHomeIntent, 1052 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 1053 null, 0, null, null, 0, true /* onlyIfNeeded*/, false); 1054 if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { 1055 return false; 1056 } 1057 } catch (RemoteException ex) { 1058 // bummer, the activity manager, which is in this process, is dead 1059 } 1060 } 1061 sendCloseSystemWindows(); 1062 return true; 1063 } 1064 1065 public void setCurrentOrientationLw(int newOrientation) { 1066 if(newOrientation != mCurrentAppOrientation) { 1067 mCurrentAppOrientation = newOrientation; 1068 } 1069 } 1070 1071 public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { 1072 return false; 1073 } 1074 1075 public void screenOnStoppedLw() { 1076 } 1077} 1078