GlobalActions.java revision 258848d2ae04f447ff1c18023fa76b139fcc0862
1/* 2 * Copyright (C) 2008 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 com.android.internal.telephony.TelephonyIntents; 20import com.android.internal.telephony.TelephonyProperties; 21import com.android.internal.R; 22 23import android.app.ActivityManagerNative; 24import android.app.AlertDialog; 25import android.content.BroadcastReceiver; 26import android.content.Context; 27import android.content.DialogInterface; 28import android.content.Intent; 29import android.content.IntentFilter; 30import android.content.pm.UserInfo; 31import android.database.ContentObserver; 32import android.graphics.drawable.Drawable; 33import android.media.AudioManager; 34import android.net.ConnectivityManager; 35import android.os.Handler; 36import android.os.IBinder; 37import android.os.Message; 38import android.os.RemoteException; 39import android.os.ServiceManager; 40import android.os.SystemProperties; 41import android.os.UserManager; 42import android.os.Vibrator; 43import android.provider.Settings; 44import android.telephony.PhoneStateListener; 45import android.telephony.ServiceState; 46import android.telephony.TelephonyManager; 47import android.util.Log; 48import android.view.IWindowManager; 49import android.view.LayoutInflater; 50import android.view.View; 51import android.view.ViewGroup; 52import android.view.WindowManager; 53import android.view.WindowManagerPolicy.WindowManagerFuncs; 54import android.widget.AdapterView; 55import android.widget.BaseAdapter; 56import android.widget.ImageView; 57import android.widget.ImageView.ScaleType; 58import android.widget.TextView; 59 60import java.util.ArrayList; 61import java.util.List; 62 63/** 64 * Helper to show the global actions dialog. Each item is an {@link Action} that 65 * may show depending on whether the keyguard is showing, and whether the device 66 * is provisioned. 67 */ 68class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { 69 70 private static final String TAG = "GlobalActions"; 71 72 private static final boolean SHOW_SILENT_TOGGLE = true; 73 74 private final Context mContext; 75 private final WindowManagerFuncs mWindowManagerFuncs; 76 private final AudioManager mAudioManager; 77 78 private ArrayList<Action> mItems; 79 private AlertDialog mDialog; 80 81 private Action mSilentModeAction; 82 private ToggleAction mAirplaneModeOn; 83 84 private MyAdapter mAdapter; 85 86 private boolean mKeyguardShowing = false; 87 private boolean mDeviceProvisioned = false; 88 private ToggleAction.State mAirplaneState = ToggleAction.State.Off; 89 private boolean mIsWaitingForEcmExit = false; 90 private boolean mHasTelephony; 91 private boolean mHasVibrator; 92 93 private IWindowManager mIWindowManager; 94 95 /** 96 * @param context everything needs a context :( 97 */ 98 public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) { 99 mContext = context; 100 mWindowManagerFuncs = windowManagerFuncs; 101 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 102 103 // receive broadcasts 104 IntentFilter filter = new IntentFilter(); 105 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 106 filter.addAction(Intent.ACTION_SCREEN_OFF); 107 filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 108 context.registerReceiver(mBroadcastReceiver, filter); 109 110 // get notified of phone state changes 111 TelephonyManager telephonyManager = 112 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 113 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); 114 ConnectivityManager cm = (ConnectivityManager) 115 context.getSystemService(Context.CONNECTIVITY_SERVICE); 116 mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); 117 mContext.getContentResolver().registerContentObserver( 118 Settings.System.getUriFor(Settings.System.AIRPLANE_MODE_ON), true, 119 mAirplaneModeObserver); 120 Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); 121 mHasVibrator = vibrator != null && vibrator.hasVibrator(); 122 } 123 124 /** 125 * Show the global actions dialog (creating if necessary) 126 * @param keyguardShowing True if keyguard is showing 127 */ 128 public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { 129 mKeyguardShowing = keyguardShowing; 130 mDeviceProvisioned = isDeviceProvisioned; 131 if (mDialog != null) { 132 mDialog.dismiss(); 133 mDialog = null; 134 // Show delayed, so that the dismiss of the previous dialog completes 135 mHandler.sendEmptyMessage(MESSAGE_SHOW); 136 } else { 137 handleShow(); 138 } 139 } 140 141 private void handleShow() { 142 mDialog = createDialog(); 143 prepareDialog(); 144 145 mDialog.show(); 146 mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND); 147 } 148 149 /** 150 * Create the global actions dialog. 151 * @return A new dialog. 152 */ 153 private AlertDialog createDialog() { 154 // Simple toggle style if there's no vibrator, otherwise use a tri-state 155 if (!mHasVibrator) { 156 mSilentModeAction = new SilentModeToggleAction(); 157 } else { 158 mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler); 159 } 160 mAirplaneModeOn = new ToggleAction( 161 R.drawable.ic_lock_airplane_mode, 162 R.drawable.ic_lock_airplane_mode_off, 163 R.string.global_actions_toggle_airplane_mode, 164 R.string.global_actions_airplane_mode_on_status, 165 R.string.global_actions_airplane_mode_off_status) { 166 167 void onToggle(boolean on) { 168 if (mHasTelephony && Boolean.parseBoolean( 169 SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { 170 mIsWaitingForEcmExit = true; 171 // Launch ECM exit dialog 172 Intent ecmDialogIntent = 173 new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null); 174 ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 175 mContext.startActivity(ecmDialogIntent); 176 } else { 177 changeAirplaneModeSystemSetting(on); 178 } 179 } 180 181 @Override 182 protected void changeStateFromPress(boolean buttonOn) { 183 if (!mHasTelephony) return; 184 185 // In ECM mode airplane state cannot be changed 186 if (!(Boolean.parseBoolean( 187 SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) { 188 mState = buttonOn ? State.TurningOn : State.TurningOff; 189 mAirplaneState = mState; 190 } 191 } 192 193 public boolean showDuringKeyguard() { 194 return true; 195 } 196 197 public boolean showBeforeProvisioning() { 198 return false; 199 } 200 }; 201 onAirplaneModeChanged(); 202 203 mItems = new ArrayList<Action>(); 204 205 // first: power off 206 mItems.add( 207 new SinglePressAction( 208 com.android.internal.R.drawable.ic_lock_power_off, 209 R.string.global_action_power_off) { 210 211 public void onPress() { 212 // shutdown by making sure radio and power are handled accordingly. 213 mWindowManagerFuncs.shutdown(); 214 } 215 216 public boolean onLongPress() { 217 mWindowManagerFuncs.rebootSafeMode(); 218 return true; 219 } 220 221 public boolean showDuringKeyguard() { 222 return true; 223 } 224 225 public boolean showBeforeProvisioning() { 226 return true; 227 } 228 }); 229 230 // next: airplane mode 231 mItems.add(mAirplaneModeOn); 232 233 // next: bug report, if enabled 234 if (Settings.Secure.getInt(mContext.getContentResolver(), 235 Settings.Secure.BUGREPORT_IN_POWER_MENU, 0) != 0) { 236 mItems.add( 237 new SinglePressAction(0, R.string.global_action_bug_report) { 238 239 public void onPress() { 240 AlertDialog.Builder builder = new AlertDialog.Builder(mContext); 241 builder.setTitle(com.android.internal.R.string.bugreport_title); 242 builder.setMessage(com.android.internal.R.string.bugreport_message); 243 builder.setNegativeButton(com.android.internal.R.string.cancel, null); 244 builder.setPositiveButton(com.android.internal.R.string.report, 245 new DialogInterface.OnClickListener() { 246 @Override 247 public void onClick(DialogInterface dialog, int which) { 248 // Add a little delay before executing, to give the 249 // dialog a chance to go away before it takes a 250 // screenshot. 251 mHandler.postDelayed(new Runnable() { 252 @Override public void run() { 253 SystemProperties.set("ctl.start", "bugreport"); 254 } 255 }, 500); 256 } 257 }); 258 AlertDialog dialog = builder.create(); 259 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); 260 dialog.show(); 261 } 262 263 public boolean onLongPress() { 264 return false; 265 } 266 267 public boolean showDuringKeyguard() { 268 return true; 269 } 270 271 public boolean showBeforeProvisioning() { 272 return false; 273 } 274 }); 275 } 276 277 // last: silent mode 278 if (SHOW_SILENT_TOGGLE) { 279 mItems.add(mSilentModeAction); 280 } 281 282 List<UserInfo> users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)) 283 .getUsers(); 284 if (users.size() > 1) { 285 UserInfo currentUser; 286 try { 287 currentUser = ActivityManagerNative.getDefault().getCurrentUser(); 288 } catch (RemoteException re) { 289 currentUser = null; 290 } 291 for (final UserInfo user : users) { 292 boolean isCurrentUser = currentUser == null 293 ? user.id == 0 : (currentUser.id == user.id); 294 Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath) 295 : null; 296 SinglePressAction switchToUser = new SinglePressAction( 297 com.android.internal.R.drawable.ic_menu_cc, icon, 298 (user.name != null ? user.name : "Primary") 299 + (isCurrentUser ? " \u2714" : "")) { 300 public void onPress() { 301 try { 302 ActivityManagerNative.getDefault().switchUser(user.id); 303 getWindowManager().lockNow(); 304 } catch (RemoteException re) { 305 Log.e(TAG, "Couldn't switch user " + re); 306 } 307 } 308 309 public boolean showDuringKeyguard() { 310 return true; 311 } 312 313 public boolean showBeforeProvisioning() { 314 return false; 315 } 316 }; 317 mItems.add(switchToUser); 318 } 319 } 320 321 mAdapter = new MyAdapter(); 322 323 final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); 324 325 ab.setAdapter(mAdapter, this) 326 .setInverseBackgroundForced(true); 327 328 final AlertDialog dialog = ab.create(); 329 dialog.getListView().setItemsCanFocus(true); 330 dialog.getListView().setLongClickable(true); 331 dialog.getListView().setOnItemLongClickListener( 332 new AdapterView.OnItemLongClickListener() { 333 @Override 334 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, 335 long id) { 336 return mAdapter.getItem(position).onLongPress(); 337 } 338 }); 339 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); 340 341 dialog.setOnDismissListener(this); 342 343 return dialog; 344 } 345 346 private void prepareDialog() { 347 refreshSilentMode(); 348 mAirplaneModeOn.updateState(mAirplaneState); 349 mAdapter.notifyDataSetChanged(); 350 if (mKeyguardShowing) { 351 mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 352 } else { 353 mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); 354 } 355 if (SHOW_SILENT_TOGGLE) { 356 IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); 357 mContext.registerReceiver(mRingerModeReceiver, filter); 358 } 359 } 360 361 private void refreshSilentMode() { 362 if (!mHasVibrator) { 363 final boolean silentModeOn = 364 mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; 365 ((ToggleAction)mSilentModeAction).updateState( 366 silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); 367 } 368 } 369 370 /** {@inheritDoc} */ 371 public void onDismiss(DialogInterface dialog) { 372 if (SHOW_SILENT_TOGGLE) { 373 mContext.unregisterReceiver(mRingerModeReceiver); 374 } 375 } 376 377 /** {@inheritDoc} */ 378 public void onClick(DialogInterface dialog, int which) { 379 if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) { 380 dialog.dismiss(); 381 } 382 mAdapter.getItem(which).onPress(); 383 } 384 385 /** 386 * The adapter used for the list within the global actions dialog, taking 387 * into account whether the keyguard is showing via 388 * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned 389 * via {@link GlobalActions#mDeviceProvisioned}. 390 */ 391 private class MyAdapter extends BaseAdapter { 392 393 public int getCount() { 394 int count = 0; 395 396 for (int i = 0; i < mItems.size(); i++) { 397 final Action action = mItems.get(i); 398 399 if (mKeyguardShowing && !action.showDuringKeyguard()) { 400 continue; 401 } 402 if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { 403 continue; 404 } 405 count++; 406 } 407 return count; 408 } 409 410 @Override 411 public boolean isEnabled(int position) { 412 return getItem(position).isEnabled(); 413 } 414 415 @Override 416 public boolean areAllItemsEnabled() { 417 return false; 418 } 419 420 public Action getItem(int position) { 421 422 int filteredPos = 0; 423 for (int i = 0; i < mItems.size(); i++) { 424 final Action action = mItems.get(i); 425 if (mKeyguardShowing && !action.showDuringKeyguard()) { 426 continue; 427 } 428 if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { 429 continue; 430 } 431 if (filteredPos == position) { 432 return action; 433 } 434 filteredPos++; 435 } 436 437 throw new IllegalArgumentException("position " + position 438 + " out of range of showable actions" 439 + ", filtered count=" + getCount() 440 + ", keyguardshowing=" + mKeyguardShowing 441 + ", provisioned=" + mDeviceProvisioned); 442 } 443 444 445 public long getItemId(int position) { 446 return position; 447 } 448 449 public View getView(int position, View convertView, ViewGroup parent) { 450 Action action = getItem(position); 451 return action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); 452 } 453 } 454 455 // note: the scheme below made more sense when we were planning on having 456 // 8 different things in the global actions dialog. seems overkill with 457 // only 3 items now, but may as well keep this flexible approach so it will 458 // be easy should someone decide at the last minute to include something 459 // else, such as 'enable wifi', or 'enable bluetooth' 460 461 /** 462 * What each item in the global actions dialog must be able to support. 463 */ 464 private interface Action { 465 View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater); 466 467 void onPress(); 468 469 public boolean onLongPress(); 470 471 /** 472 * @return whether this action should appear in the dialog when the keygaurd 473 * is showing. 474 */ 475 boolean showDuringKeyguard(); 476 477 /** 478 * @return whether this action should appear in the dialog before the 479 * device is provisioned. 480 */ 481 boolean showBeforeProvisioning(); 482 483 boolean isEnabled(); 484 } 485 486 /** 487 * A single press action maintains no state, just responds to a press 488 * and takes an action. 489 */ 490 private static abstract class SinglePressAction implements Action { 491 private final int mIconResId; 492 private final Drawable mIcon; 493 private final int mMessageResId; 494 private final CharSequence mMessage; 495 496 protected SinglePressAction(int iconResId, int messageResId) { 497 mIconResId = iconResId; 498 mMessageResId = messageResId; 499 mMessage = null; 500 mIcon = null; 501 } 502 503 protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) { 504 mIconResId = iconResId; 505 mMessageResId = 0; 506 mMessage = message; 507 mIcon = icon; 508 } 509 510 protected SinglePressAction(int iconResId, CharSequence message) { 511 mIconResId = iconResId; 512 mMessageResId = 0; 513 mMessage = message; 514 mIcon = null; 515 } 516 517 public boolean isEnabled() { 518 return true; 519 } 520 521 abstract public void onPress(); 522 523 public boolean onLongPress() { 524 return false; 525 } 526 527 public View create( 528 Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { 529 View v = inflater.inflate(R.layout.global_actions_item, parent, false); 530 531 ImageView icon = (ImageView) v.findViewById(R.id.icon); 532 TextView messageView = (TextView) v.findViewById(R.id.message); 533 534 v.findViewById(R.id.status).setVisibility(View.GONE); 535 if (mIcon != null) { 536 icon.setImageDrawable(mIcon); 537 icon.setScaleType(ScaleType.CENTER_CROP); 538 } else if (mIconResId != 0) { 539 icon.setImageDrawable(context.getResources().getDrawable(mIconResId)); 540 } 541 if (mMessage != null) { 542 messageView.setText(mMessage); 543 } else { 544 messageView.setText(mMessageResId); 545 } 546 547 return v; 548 } 549 } 550 551 /** 552 * A toggle action knows whether it is on or off, and displays an icon 553 * and status message accordingly. 554 */ 555 private static abstract class ToggleAction implements Action { 556 557 enum State { 558 Off(false), 559 TurningOn(true), 560 TurningOff(true), 561 On(false); 562 563 private final boolean inTransition; 564 565 State(boolean intermediate) { 566 inTransition = intermediate; 567 } 568 569 public boolean inTransition() { 570 return inTransition; 571 } 572 } 573 574 protected State mState = State.Off; 575 576 // prefs 577 protected int mEnabledIconResId; 578 protected int mDisabledIconResid; 579 protected int mMessageResId; 580 protected int mEnabledStatusMessageResId; 581 protected int mDisabledStatusMessageResId; 582 583 /** 584 * @param enabledIconResId The icon for when this action is on. 585 * @param disabledIconResid The icon for when this action is off. 586 * @param essage The general information message, e.g 'Silent Mode' 587 * @param enabledStatusMessageResId The on status message, e.g 'sound disabled' 588 * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled' 589 */ 590 public ToggleAction(int enabledIconResId, 591 int disabledIconResid, 592 int message, 593 int enabledStatusMessageResId, 594 int disabledStatusMessageResId) { 595 mEnabledIconResId = enabledIconResId; 596 mDisabledIconResid = disabledIconResid; 597 mMessageResId = message; 598 mEnabledStatusMessageResId = enabledStatusMessageResId; 599 mDisabledStatusMessageResId = disabledStatusMessageResId; 600 } 601 602 /** 603 * Override to make changes to resource IDs just before creating the 604 * View. 605 */ 606 void willCreate() { 607 608 } 609 610 public View create(Context context, View convertView, ViewGroup parent, 611 LayoutInflater inflater) { 612 willCreate(); 613 614 View v = inflater.inflate(R 615 .layout.global_actions_item, parent, false); 616 617 ImageView icon = (ImageView) v.findViewById(R.id.icon); 618 TextView messageView = (TextView) v.findViewById(R.id.message); 619 TextView statusView = (TextView) v.findViewById(R.id.status); 620 final boolean enabled = isEnabled(); 621 622 if (messageView != null) { 623 messageView.setText(mMessageResId); 624 messageView.setEnabled(enabled); 625 } 626 627 boolean on = ((mState == State.On) || (mState == State.TurningOn)); 628 if (icon != null) { 629 icon.setImageDrawable(context.getResources().getDrawable( 630 (on ? mEnabledIconResId : mDisabledIconResid))); 631 icon.setEnabled(enabled); 632 } 633 634 if (statusView != null) { 635 statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); 636 statusView.setVisibility(View.VISIBLE); 637 statusView.setEnabled(enabled); 638 } 639 v.setEnabled(enabled); 640 641 return v; 642 } 643 644 public final void onPress() { 645 if (mState.inTransition()) { 646 Log.w(TAG, "shouldn't be able to toggle when in transition"); 647 return; 648 } 649 650 final boolean nowOn = !(mState == State.On); 651 onToggle(nowOn); 652 changeStateFromPress(nowOn); 653 } 654 655 public boolean onLongPress() { 656 return false; 657 } 658 659 public boolean isEnabled() { 660 return !mState.inTransition(); 661 } 662 663 /** 664 * Implementations may override this if their state can be in on of the intermediate 665 * states until some notification is received (e.g airplane mode is 'turning off' until 666 * we know the wireless connections are back online 667 * @param buttonOn Whether the button was turned on or off 668 */ 669 protected void changeStateFromPress(boolean buttonOn) { 670 mState = buttonOn ? State.On : State.Off; 671 } 672 673 abstract void onToggle(boolean on); 674 675 public void updateState(State state) { 676 mState = state; 677 } 678 } 679 680 private class SilentModeToggleAction extends ToggleAction { 681 public SilentModeToggleAction() { 682 super(R.drawable.ic_audio_vol_mute, 683 R.drawable.ic_audio_vol, 684 R.string.global_action_toggle_silent_mode, 685 R.string.global_action_silent_mode_on_status, 686 R.string.global_action_silent_mode_off_status); 687 } 688 689 void onToggle(boolean on) { 690 if (on) { 691 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT); 692 } else { 693 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); 694 } 695 } 696 697 public boolean showDuringKeyguard() { 698 return true; 699 } 700 701 public boolean showBeforeProvisioning() { 702 return false; 703 } 704 } 705 706 private static class SilentModeTriStateAction implements Action, View.OnClickListener { 707 708 private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 }; 709 710 private final AudioManager mAudioManager; 711 private final Handler mHandler; 712 private final Context mContext; 713 714 SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) { 715 mAudioManager = audioManager; 716 mHandler = handler; 717 mContext = context; 718 } 719 720 private int ringerModeToIndex(int ringerMode) { 721 // They just happen to coincide 722 return ringerMode; 723 } 724 725 private int indexToRingerMode(int index) { 726 // They just happen to coincide 727 return index; 728 } 729 730 public View create(Context context, View convertView, ViewGroup parent, 731 LayoutInflater inflater) { 732 View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false); 733 734 int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode()); 735 for (int i = 0; i < 3; i++) { 736 View itemView = v.findViewById(ITEM_IDS[i]); 737 itemView.setSelected(selectedIndex == i); 738 // Set up click handler 739 itemView.setTag(i); 740 itemView.setOnClickListener(this); 741 } 742 return v; 743 } 744 745 public void onPress() { 746 } 747 748 public boolean onLongPress() { 749 return false; 750 } 751 752 public boolean showDuringKeyguard() { 753 return true; 754 } 755 756 public boolean showBeforeProvisioning() { 757 return false; 758 } 759 760 public boolean isEnabled() { 761 return true; 762 } 763 764 void willCreate() { 765 } 766 767 public void onClick(View v) { 768 if (!(v.getTag() instanceof Integer)) return; 769 770 int index = (Integer) v.getTag(); 771 mAudioManager.setRingerMode(indexToRingerMode(index)); 772 mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY); 773 } 774 } 775 776 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 777 public void onReceive(Context context, Intent intent) { 778 String action = intent.getAction(); 779 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) 780 || Intent.ACTION_SCREEN_OFF.equals(action)) { 781 String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); 782 if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { 783 mHandler.sendEmptyMessage(MESSAGE_DISMISS); 784 } 785 } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) { 786 // Airplane mode can be changed after ECM exits if airplane toggle button 787 // is pressed during ECM mode 788 if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) && 789 mIsWaitingForEcmExit) { 790 mIsWaitingForEcmExit = false; 791 changeAirplaneModeSystemSetting(true); 792 } 793 } 794 } 795 }; 796 797 PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 798 @Override 799 public void onServiceStateChanged(ServiceState serviceState) { 800 if (!mHasTelephony) return; 801 final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF; 802 mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off; 803 mAirplaneModeOn.updateState(mAirplaneState); 804 mAdapter.notifyDataSetChanged(); 805 } 806 }; 807 808 private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() { 809 @Override 810 public void onReceive(Context context, Intent intent) { 811 if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 812 mHandler.sendEmptyMessage(MESSAGE_REFRESH); 813 } 814 } 815 }; 816 817 private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) { 818 @Override 819 public void onChange(boolean selfChange) { 820 onAirplaneModeChanged(); 821 } 822 }; 823 824 private static final int MESSAGE_DISMISS = 0; 825 private static final int MESSAGE_REFRESH = 1; 826 private static final int MESSAGE_SHOW = 2; 827 private static final int DIALOG_DISMISS_DELAY = 300; // ms 828 829 private Handler mHandler = new Handler() { 830 public void handleMessage(Message msg) { 831 switch (msg.what) { 832 case MESSAGE_DISMISS: 833 if (mDialog != null) { 834 mDialog.dismiss(); 835 } 836 break; 837 case MESSAGE_REFRESH: 838 refreshSilentMode(); 839 mAdapter.notifyDataSetChanged(); 840 break; 841 case MESSAGE_SHOW: 842 handleShow(); 843 break; 844 } 845 } 846 }; 847 848 private void onAirplaneModeChanged() { 849 // Let the service state callbacks handle the state. 850 if (mHasTelephony) return; 851 852 boolean airplaneModeOn = Settings.System.getInt( 853 mContext.getContentResolver(), 854 Settings.System.AIRPLANE_MODE_ON, 855 0) == 1; 856 mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off; 857 mAirplaneModeOn.updateState(mAirplaneState); 858 } 859 860 /** 861 * Change the airplane mode system setting 862 */ 863 private void changeAirplaneModeSystemSetting(boolean on) { 864 Settings.System.putInt( 865 mContext.getContentResolver(), 866 Settings.System.AIRPLANE_MODE_ON, 867 on ? 1 : 0); 868 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 869 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 870 intent.putExtra("state", on); 871 mContext.sendBroadcast(intent); 872 if (!mHasTelephony) { 873 mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off; 874 } 875 } 876 877 private IWindowManager getWindowManager() { 878 if (mIWindowManager == null) { 879 IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE); 880 mIWindowManager = IWindowManager.Stub.asInterface(b); 881 } 882 return mIWindowManager; 883 } 884} 885