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