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