content: /*
   * Copyright (C) 2008 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.server.policy;
  
  import com.android.internal.app.AlertController;
  import com.android.internal.globalactions.Action;
  import com.android.internal.globalactions.ActionsAdapter;
  import com.android.internal.globalactions.ActionsDialog;
  import com.android.internal.globalactions.LongPressAction;
  import com.android.internal.globalactions.SinglePressAction;
  import com.android.internal.globalactions.ToggleAction;
  import com.android.internal.logging.MetricsLogger;
  import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
  import com.android.internal.R;
  import com.android.internal.telephony.TelephonyIntents;
  import com.android.internal.telephony.TelephonyProperties;
  import com.android.internal.util.EmergencyAffordanceManager;
  import com.android.internal.widget.LockPatternUtils;
  import com.android.server.policy.PowerAction;
  import com.android.server.policy.RestartAction;
  import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
  
  import android.app.ActivityManager;
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.pm.UserInfo;
  import android.database.ContentObserver;
  import android.graphics.drawable.Drawable;
  import android.media.AudioManager;
  import android.net.ConnectivityManager;
  import android.os.Build;
  import android.os.Handler;
  import android.os.Message;
  import android.os.RemoteException;
  import android.os.ServiceManager;
  import android.os.SystemProperties;
  import android.os.UserHandle;
  import android.os.UserManager;
  import android.os.Vibrator;
  import android.provider.Settings;
  import android.service.dreams.DreamService;
  import android.service.dreams.IDreamManager;
  import android.telephony.PhoneStateListener;
  import android.telephony.ServiceState;
  import android.telephony.TelephonyManager;
  import android.util.ArraySet;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.WindowManager;
  import android.view.WindowManagerGlobal;
  import android.widget.AdapterView;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * Helper to show the global actions dialog.  Each item is an {@link Action} that
   * may show depending on whether the keyguard is showing, and whether the device
   * is provisioned.
   */
  class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
  
      private static final String TAG = "LegacyGlobalActions";
  
      private static final boolean SHOW_SILENT_TOGGLE = true;
  
      /* Valid settings for global actions keys.
       * see config.xml config_globalActionList */
      private static final String GLOBAL_ACTION_KEY_POWER = "power";
      private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
      private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
      private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
      private static final String GLOBAL_ACTION_KEY_USERS = "users";
      private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
      private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
      private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
      private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
      private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
  
      private final Context mContext;
      private final WindowManagerFuncs mWindowManagerFuncs;
      private final AudioManager mAudioManager;
      private final IDreamManager mDreamManager;
      private final Runnable mOnDismiss;
  
      private ArrayList<Action> mItems;
      private ActionsDialog mDialog;
  
      private Action mSilentModeAction;
      private ToggleAction mAirplaneModeOn;
  
      private ActionsAdapter mAdapter;
  
      private boolean mKeyguardShowing = false;
      private boolean mDeviceProvisioned = false;
      private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
      private boolean mIsWaitingForEcmExit = false;
      private boolean mHasTelephony;
      private boolean mHasVibrator;
      private final boolean mShowSilentToggle;
      private final EmergencyAffordanceManager mEmergencyAffordanceManager;
  
      /**
       * @param context everything needs a context :(
       */
      public LegacyGlobalActions(Context context, WindowManagerFuncs windowManagerFuncs,
              Runnable onDismiss) {
          mContext = context;
          mWindowManagerFuncs = windowManagerFuncs;
          mOnDismiss = onDismiss;
          mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
          mDreamManager = IDreamManager.Stub.asInterface(
                  ServiceManager.getService(DreamService.DREAM_SERVICE));
  
          // receive broadcasts
          IntentFilter filter = new IntentFilter();
          filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
          filter.addAction(Intent.ACTION_SCREEN_OFF);
          filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
          context.registerReceiver(mBroadcastReceiver, filter);
  
          ConnectivityManager cm = (ConnectivityManager)
                  context.getSystemService(Context.CONNECTIVITY_SERVICE);
          mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
  
          // get notified of phone state changes
          TelephonyManager telephonyManager =
                  (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
          telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
          mContext.getContentResolver().registerContentObserver(
                  Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                  mAirplaneModeObserver);
          Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
          mHasVibrator = vibrator != null && vibrator.hasVibrator();
  
          mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
                  com.android.internal.R.bool.config_useFixedVolume);
  
          mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
      }
  
      /**
       * Show the global actions dialog (creating if necessary)
       * @param keyguardShowing True if keyguard is showing
       */
      public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
          mKeyguardShowing = keyguardShowing;
          mDeviceProvisioned = isDeviceProvisioned;
          if (mDialog != null) {
              mDialog.dismiss();
              mDialog = null;
              // Show delayed, so that the dismiss of the previous dialog completes
              mHandler.sendEmptyMessage(MESSAGE_SHOW);
          } else {
              handleShow();
          }
      }
  
      private void awakenIfNecessary() {
          if (mDreamManager != null) {
              try {
                  if (mDreamManager.isDreaming()) {
                      mDreamManager.awaken();
                  }
              } catch (RemoteException e) {
                  // we tried
              }
          }
      }
  
      private void handleShow() {
          awakenIfNecessary();
          mDialog = createDialog();
          prepareDialog();
  
          // If we only have 1 item and it's a simple press action, just do this action.
          if (mAdapter.getCount() == 1
                  && mAdapter.getItem(0) instanceof SinglePressAction
                  && !(mAdapter.getItem(0) instanceof LongPressAction)) {
              ((SinglePressAction) mAdapter.getItem(0)).onPress();
          } else {
              if (mDialog != null) {
                  WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
                  attrs.setTitle("LegacyGlobalActions");
                  mDialog.getWindow().setAttributes(attrs);
                  mDialog.show();
                  mDialog.getWindow().getDecorView().setSystemUiVisibility(
                          View.STATUS_BAR_DISABLE_EXPAND);
              }
          }
      }
  
      /**
       * Create the global actions dialog.
       * @return A new dialog.
       */
      private ActionsDialog createDialog() {
          // Simple toggle style if there's no vibrator, otherwise use a tri-state
          if (!mHasVibrator) {
              mSilentModeAction = new SilentModeToggleAction();
          } else {
              mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
          }
          mAirplaneModeOn = new ToggleAction(
                  R.drawable.ic_lock_airplane_mode,
                  R.drawable.ic_lock_airplane_mode_off,
                  R.string.global_actions_toggle_airplane_mode,
                  R.string.global_actions_airplane_mode_on_status,
                  R.string.global_actions_airplane_mode_off_status) {
  
              @Override
              public void onToggle(boolean on) {
                  if (mHasTelephony && Boolean.parseBoolean(
                          SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
                      mIsWaitingForEcmExit = true;
                      // Launch ECM exit dialog
                      Intent ecmDialogIntent =
                              new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
                      ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                      mContext.startActivity(ecmDialogIntent);
                  } else {
                      changeAirplaneModeSystemSetting(on);
                  }
              }
  
              @Override
              protected void changeStateFromPress(boolean buttonOn) {
                  if (!mHasTelephony) return;
  
                  // In ECM mode airplane state cannot be changed
                  if (!(Boolean.parseBoolean(
                          SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
                      mState = buttonOn ? State.TurningOn : State.TurningOff;
                      mAirplaneState = mState;
                  }
              }
  
              @Override
              public boolean showDuringKeyguard() {
                  return true;
              }
  
              @Override
              public boolean showBeforeProvisioning() {
                  return false;
              }
          };
          onAirplaneModeChanged();
  
          mItems = new ArrayList<Action>();
          String[] defaultActions = mContext.getResources().getStringArray(
                  com.android.internal.R.array.config_globalActionsList);
  
          ArraySet<String> addedKeys = new ArraySet<String>();
          for (int i = 0; i < defaultActions.length; i++) {
              String actionKey = defaultActions[i];
              if (addedKeys.contains(actionKey)) {
                  // If we already have added this, don't add it again.
                  continue;
              }
              if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
                  mItems.add(new PowerAction(mContext, mWindowManagerFuncs));
              } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
                  mItems.add(mAirplaneModeOn);
              } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
                  if (Settings.Global.getInt(mContext.getContentResolver(),
                          Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
                      mItems.add(new BugReportAction());
                  }
              } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
                  if (mShowSilentToggle) {
                      mItems.add(mSilentModeAction);
                  }
              } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
                  if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
                      addUsersToMenu(mItems);
                  }
              } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
                  mItems.add(getSettingsAction());
              } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
                  mItems.add(getLockdownAction());
              } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
                  mItems.add(getVoiceAssistAction());
              } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
                  mItems.add(getAssistAction());
              } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
                  mItems.add(new RestartAction(mContext, mWindowManagerFuncs));
              } else {
                  Log.e(TAG, "Invalid global action key " + actionKey);
              }
              // Add here so we don't add more than one.
              addedKeys.add(actionKey);
          }
  
          if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
              mItems.add(getEmergencyAction());
          }
  
          mAdapter = new ActionsAdapter(mContext, mItems,
                  () -> mDeviceProvisioned, () -> mKeyguardShowing);
  
          AlertController.AlertParams params = new AlertController.AlertParams(mContext);
          params.mAdapter = mAdapter;
          params.mOnClickListener = this;
          params.mForceInverseBackground = true;
  
          ActionsDialog dialog = new ActionsDialog(mContext, params);
          dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
  
          dialog.getListView().setItemsCanFocus(true);
          dialog.getListView().setLongClickable(true);
          dialog.getListView().setOnItemLongClickListener(
                  new AdapterView.OnItemLongClickListener() {
                      @Override
                      public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
                              long id) {
                          final Action action = mAdapter.getItem(position);
                          if (action instanceof LongPressAction) {
                              return ((LongPressAction) action).onLongPress();
                          }
                          return false;
                      }
          });
          dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  
          dialog.setOnDismissListener(this);
  
          return dialog;
      }
  
      private class BugReportAction extends SinglePressAction implements LongPressAction {
  
          public BugReportAction() {
              super(com.android.internal.R.drawable.ic_lock_bugreport, R.string.bugreport_title);
          }
  
          @Override
          public void onPress() {
              // don't actually trigger the bugreport if we are running stability
              // tests via monkey
              if (ActivityManager.isUserAMonkey()) {
                  return;
              }
              // Add a little delay before executing, to give the
              // dialog a chance to go away before it takes a
              // screenshot.
              mHandler.postDelayed(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          // Take an "interactive" bugreport.
                          MetricsLogger.action(mContext,
                                  MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
                          ActivityManager.getService().requestBugReport(
                                  ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
                      } catch (RemoteException e) {
                      }
                  }
              }, 500);
          }
  
          @Override
          public boolean onLongPress() {
              // don't actually trigger the bugreport if we are running stability
              // tests via monkey
              if (ActivityManager.isUserAMonkey()) {
                  return false;
              }
              try {
                  // Take a "full" bugreport.
                  MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
                  ActivityManager.getService().requestBugReport(
                          ActivityManager.BUGREPORT_OPTION_FULL);
              } catch (RemoteException e) {
              }
              return false;
          }
  
          @Override
          public boolean showDuringKeyguard() {
              return true;
          }
  
          @Override
          public boolean showBeforeProvisioning() {
              return false;
          }
  
          @Override
          public String getStatus() {
              return mContext.getString(
                      com.android.internal.R.string.bugreport_status,
                      Build.VERSION.RELEASE,
                      Build.ID);
          }
      }
  
      private Action getSettingsAction() {
          return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
                  R.string.global_action_settings) {
  
              @Override
              public void onPress() {
                  Intent intent = new Intent(Settings.ACTION_SETTINGS);
                  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                  mContext.startActivity(intent);
              }
  
              @Override
              public boolean showDuringKeyguard() {
                  return true;
              }
  
              @Override
              public boolean showBeforeProvisioning() {
                  return true;
              }
          };
      }
  
      private Action getEmergencyAction() {
          return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
                  R.string.global_action_emergency) {
              @Override
              public void onPress() {
                  mEmergencyAffordanceManager.performEmergencyCall();
              }
  
              @Override
              public boolean showDuringKeyguard() {
                  return true;
              }
  
              @Override
              public boolean showBeforeProvisioning() {
                  return true;
              }
          };
      }
  
      private Action getAssistAction() {
          return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
                  R.string.global_action_assist) {
              @Override
              public void onPress() {
                  Intent intent = new Intent(Intent.ACTION_ASSIST);
                  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                  mContext.startActivity(intent);
              }
  
              @Override
              public boolean showDuringKeyguard() {
                  return true;
              }
  
              @Override
              public boolean showBeforeProvisioning() {
                  return true;
              }
          };
      }
  
      private Action getVoiceAssistAction() {
          return new SinglePressAction(com.android.internal.R.drawable.ic_voice_search,
                  R.string.global_action_voice_assist) {
              @Override
              public void onPress() {
                  Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
                  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                  mContext.startActivity(intent);
              }
  
              @Override
              public boolean showDuringKeyguard() {
                  return true;
              }
  
              @Override
              public boolean showBeforeProvisioning() {
                  return true;
              }
          };
      }
  
      private Action getLockdownAction() {
          return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock,
                  R.string.global_action_lockdown) {
  
              @Override
              public void onPress() {
                  new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
                  try {
                      WindowManagerGlobal.getWindowManagerService().lockNow(null);
                  } catch (RemoteException e) {
                      Log.e(TAG, "Error while trying to lock device.", e);
                  }
              }
  
              @Override
              public boolean showDuringKeyguard() {
                  return true;
              }
  
              @Override
              public boolean showBeforeProvisioning() {
                  return false;
              }
          };
      }
  
      private UserInfo getCurrentUser() {
          try {
              return ActivityManager.getService().getCurrentUser();
          } catch (RemoteException re) {
              return null;
          }
      }
  
      private boolean isCurrentUserOwner() {
          UserInfo currentUser = getCurrentUser();
          return currentUser == null || currentUser.isPrimary();
      }
  
      private void addUsersToMenu(ArrayList<Action> items) {
          UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
          if (um.isUserSwitcherEnabled()) {
              List<UserInfo> users = um.getUsers();
              UserInfo currentUser = getCurrentUser();
              for (final UserInfo user : users) {
                  if (user.supportsSwitchToByUser()) {
                      boolean isCurrentUser = currentUser == null
                              ? user.id == 0 : (currentUser.id == user.id);
                      Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
                              : null;
                      SinglePressAction switchToUser = new SinglePressAction(
                              com.android.internal.R.drawable.ic_menu_cc, icon,
                              (user.name != null ? user.name : "Primary")
                              + (isCurrentUser ? " \u2714" : "")) {
                          @Override
                          public void onPress() {
                              try {
                                  ActivityManager.getService().switchUser(user.id);
                              } catch (RemoteException re) {
                                  Log.e(TAG, "Couldn't switch user " + re);
                              }
                          }
  
                          @Override
                          public boolean showDuringKeyguard() {
                              return true;
                          }
  
                          @Override
                          public boolean showBeforeProvisioning() {
                              return false;
                          }
                      };
                      items.add(switchToUser);
                  }
              }
          }
      }
  
      private void prepareDialog() {
          refreshSilentMode();
          mAirplaneModeOn.updateState(mAirplaneState);
          mAdapter.notifyDataSetChanged();
          mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
          if (mShowSilentToggle) {
              IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
              mContext.registerReceiver(mRingerModeReceiver, filter);
          }
      }
  
      private void refreshSilentMode() {
          if (!mHasVibrator) {
              final boolean silentModeOn =
                      mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
              ((ToggleAction)mSilentModeAction).updateState(
                      silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
          }
      }
  
      /** {@inheritDoc} */
      @Override
      public void onDismiss(DialogInterface dialog) {
          if (mOnDismiss != null) {
              mOnDismiss.run();
          }
          if (mShowSilentToggle) {
              try {
                  mContext.unregisterReceiver(mRingerModeReceiver);
              } catch (IllegalArgumentException ie) {
                  // ignore this
                  Log.w(TAG, ie);
              }
          }
      }
  
      /** {@inheritDoc} */
      @Override
      public void onClick(DialogInterface dialog, int which) {
          if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
              dialog.dismiss();
          }
          mAdapter.getItem(which).onPress();
      }
  
      // note: the scheme below made more sense when we were planning on having
      // 8 different things in the global actions dialog.  seems overkill with
      // only 3 items now, but may as well keep this flexible approach so it will
      // be easy should someone decide at the last minute to include something
      // else, such as 'enable wifi', or 'enable bluetooth'
  
      private class SilentModeToggleAction extends ToggleAction {
          public SilentModeToggleAction() {
              super(R.drawable.ic_audio_vol_mute,
                      R.drawable.ic_audio_vol,
                      R.string.global_action_toggle_silent_mode,
                      R.string.global_action_silent_mode_on_status,
                      R.string.global_action_silent_mode_off_status);
          }
  
          @Override
          public void onToggle(boolean on) {
              if (on) {
                  mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
              } else {
                  mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
              }
          }
  
          @Override
          public boolean showDuringKeyguard() {
              return true;
          }
  
          @Override
          public boolean showBeforeProvisioning() {
              return false;
          }
      }
  
      private static class SilentModeTriStateAction implements Action, View.OnClickListener {
  
          private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
  
          private final AudioManager mAudioManager;
          private final Handler mHandler;
          private final Context mContext;
  
          SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) {
              mAudioManager = audioManager;
              mHandler = handler;
              mContext = context;
          }
  
          private int ringerModeToIndex(int ringerMode) {
              // They just happen to coincide
              return ringerMode;
          }
  
          private int indexToRingerMode(int index) {
              // They just happen to coincide
              return index;
          }
  
          @Override
          public CharSequence getLabelForAccessibility(Context context) {
              return null;
          }
  
          @Override
          public View create(Context context, View convertView, ViewGroup parent,
                  LayoutInflater inflater) {
              View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
  
              int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
              for (int i = 0; i < 3; i++) {
                  View itemView = v.findViewById(ITEM_IDS[i]);
                  itemView.setSelected(selectedIndex == i);
                  // Set up click handler
                  itemView.setTag(i);
                  itemView.setOnClickListener(this);
              }
              return v;
          }
  
          @Override
          public void onPress() {
          }
  
          @Override
          public boolean showDuringKeyguard() {
              return true;
          }
  
          @Override
          public boolean showBeforeProvisioning() {
              return false;
          }
  
          @Override
          public boolean isEnabled() {
              return true;
          }
  
          void willCreate() {
          }
  
          @Override
          public void onClick(View v) {
              if (!(v.getTag() instanceof Integer)) return;
  
              int index = (Integer) v.getTag();
              mAudioManager.setRingerMode(indexToRingerMode(index));
              mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
          }
      }
  
      private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
              String action = intent.getAction();
              if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                      || Intent.ACTION_SCREEN_OFF.equals(action)) {
                  String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
                  if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
                      mHandler.sendEmptyMessage(MESSAGE_DISMISS);
                  }
              } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
                  // Airplane mode can be changed after ECM exits if airplane toggle button
                  // is pressed during ECM mode
                  if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
                          mIsWaitingForEcmExit) {
                      mIsWaitingForEcmExit = false;
                      changeAirplaneModeSystemSetting(true);
                  }
              }
          }
      };
  
      PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
          @Override
          public void onServiceStateChanged(ServiceState serviceState) {
              if (!mHasTelephony) return;
              final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
              mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
              mAirplaneModeOn.updateState(mAirplaneState);
              mAdapter.notifyDataSetChanged();
          }
      };
  
      private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
              if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
                  mHandler.sendEmptyMessage(MESSAGE_REFRESH);
              }
          }
      };
  
      private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
          @Override
          public void onChange(boolean selfChange) {
              onAirplaneModeChanged();
          }
      };
  
      private static final int MESSAGE_DISMISS = 0;
      private static final int MESSAGE_REFRESH = 1;
      private static final int MESSAGE_SHOW = 2;
      private static final int DIALOG_DISMISS_DELAY = 300; // ms
  
      private Handler mHandler = new Handler() {
          @Override
          public void handleMessage(Message msg) {
              switch (msg.what) {
              case MESSAGE_DISMISS:
                  if (mDialog != null) {
                      mDialog.dismiss();
                      mDialog = null;
                  }
                  break;
              case MESSAGE_REFRESH:
                  refreshSilentMode();
                  mAdapter.notifyDataSetChanged();
                  break;
              case MESSAGE_SHOW:
                  handleShow();
                  break;
              }
          }
      };
  
      private void onAirplaneModeChanged() {
          // Let the service state callbacks handle the state.
          if (mHasTelephony) return;
  
          boolean airplaneModeOn = Settings.Global.getInt(
                  mContext.getContentResolver(),
                  Settings.Global.AIRPLANE_MODE_ON,
                  0) == 1;
          mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
          mAirplaneModeOn.updateState(mAirplaneState);
      }
  
      /**
       * Change the airplane mode system setting
       */
      private void changeAirplaneModeSystemSetting(boolean on) {
          Settings.Global.putInt(
                  mContext.getContentResolver(),
                  Settings.Global.AIRPLANE_MODE_ON,
                  on ? 1 : 0);
          Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
          intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
          intent.putExtra("state", on);
          mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
          if (!mHasTelephony) {
              mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
          }
      }
  }
  