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