/*
|
* 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;
|
}
|
}
|
}
|