/* * Copyright (C) 2015 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.settings; import android.app.Activity; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.PersistableBundle; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.PreferenceScreen; import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.widget.Switch; import android.widget.TextView; import com.android.ims.ImsConfig; import com.android.ims.ImsManager; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.telephony.Phone; import com.android.settings.widget.SwitchBar; /** * "Wi-Fi Calling settings" screen. This preference screen lets you * enable/disable Wi-Fi Calling and change Wi-Fi Calling mode. */ public class WifiCallingSettings extends SettingsPreferenceFragment implements SwitchBar.OnSwitchChangeListener, Preference.OnPreferenceChangeListener { private static final String TAG = "WifiCallingSettings"; //String keys for preference lookup private static final String BUTTON_WFC_MODE = "wifi_calling_mode"; private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode"; private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key"; private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1; public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP"; public static final int LAUCH_APP_ACTIVATE = 0; public static final int LAUCH_APP_UPDATE = 1; //UI objects private SwitchBar mSwitchBar; private Switch mSwitch; private ListPreference mButtonWfcMode; private ListPreference mButtonWfcRoamingMode; private Preference mUpdateAddress; private TextView mEmptyView; private boolean mValidListener = false; private boolean mEditableWfcMode = true; private boolean mEditableWfcRoamingMode = true; private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { /* * Enable/disable controls when in/out of a call and depending on * TTY mode and TTY support over VoLTE. * @see android.telephony.PhoneStateListener#onCallStateChanged(int, * java.lang.String) */ @Override public void onCallStateChanged(int state, String incomingNumber) { final SettingsActivity activity = (SettingsActivity) getActivity(); boolean isNonTtyOrTtyOnVolteEnabled = ImsManager .isNonTtyOrTtyOnVolteEnabled(activity); final SwitchBar switchBar = activity.getSwitchBar(); boolean isWfcEnabled = switchBar.getSwitch().isChecked() && isNonTtyOrTtyOnVolteEnabled; switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE) && isNonTtyOrTtyOnVolteEnabled); boolean isWfcModeEditable = true; boolean isWfcRoamingModeEditable = false; final CarrierConfigManager configManager = (CarrierConfigManager) activity.getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configManager != null) { PersistableBundle b = configManager.getConfig(); if (b != null) { isWfcModeEditable = b.getBoolean( CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); isWfcRoamingModeEditable = b.getBoolean( CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL); } } Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE); if (pref != null) { pref.setEnabled(isWfcEnabled && isWfcModeEditable && (state == TelephonyManager.CALL_STATE_IDLE)); } Preference pref_roam = getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE); if (pref_roam != null) { pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable && (state == TelephonyManager.CALL_STATE_IDLE)); } } }; private final OnPreferenceClickListener mUpdateAddressListener = new OnPreferenceClickListener() { /* * Launch carrier emergency address managemnent activity */ @Override public boolean onPreferenceClick(Preference preference) { final Context context = getActivity(); Intent carrierAppIntent = getCarrierActivityIntent(context); if (carrierAppIntent != null) { carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE); startActivity(carrierAppIntent); } return true; } }; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final SettingsActivity activity = (SettingsActivity) getActivity(); mSwitchBar = activity.getSwitchBar(); mSwitch = mSwitchBar.getSwitch(); mSwitchBar.show(); mEmptyView = (TextView) getView().findViewById(android.R.id.empty); setEmptyView(mEmptyView); mEmptyView.setText(R.string.wifi_calling_off_explanation); } @Override public void onDestroyView() { super.onDestroyView(); mSwitchBar.hide(); } private void showAlert(Intent intent) { Context context = getActivity(); CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE); CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE); AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage(message) .setTitle(title) .setIcon(android.R.drawable.ic_dialog_alert) .setPositiveButton(android.R.string.ok, null); AlertDialog dialog = builder.create(); dialog.show(); } private IntentFilter mIntentFilter; private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) { // If this fragment is active then we are immediately // showing alert on screen. There is no need to add // notification in this case. // // In order to communicate to ImsPhone that it should // not show notification, we are changing result code here. setResultCode(Activity.RESULT_CANCELED); // UX requirement is to disable WFC in case of "permanent" registration failures. mSwitch.setChecked(false); showAlert(intent); } } }; @Override protected int getMetricsCategory() { return MetricsEvent.WIFI_CALLING; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.wifi_calling_settings); mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE); mButtonWfcMode.setOnPreferenceChangeListener(this); mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE); mButtonWfcRoamingMode.setOnPreferenceChangeListener(this); mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS); mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener); mIntentFilter = new IntentFilter(); mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR); CarrierConfigManager configManager = (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE); boolean isWifiOnlySupported = true; if (configManager != null) { PersistableBundle b = configManager.getConfig(); if (b != null) { mEditableWfcMode = b.getBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); mEditableWfcRoamingMode = b.getBoolean( CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL); isWifiOnlySupported = b.getBoolean( CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true); } } if (!isWifiOnlySupported) { mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only); mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only); mButtonWfcRoamingMode.setEntries( R.array.wifi_calling_mode_choices_v2_without_wifi_only); mButtonWfcRoamingMode.setEntryValues( R.array.wifi_calling_mode_values_without_wifi_only); } } @Override public void onResume() { super.onResume(); final Context context = getActivity(); // NOTE: Buttons will be enabled/disabled in mPhoneStateListener boolean wfcEnabled = ImsManager.isWfcEnabledByUser(context) && ImsManager.isNonTtyOrTtyOnVolteEnabled(context); mSwitch.setChecked(wfcEnabled); int wfcMode = ImsManager.getWfcMode(context, false); int wfcRoamingMode = ImsManager.getWfcMode(context, true); mButtonWfcMode.setValue(Integer.toString(wfcMode)); mButtonWfcRoamingMode.setValue(Integer.toString(wfcRoamingMode)); updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode); if (ImsManager.isWfcEnabledByPlatform(context)) { TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); mSwitchBar.addOnSwitchChangeListener(this); mValidListener = true; } context.registerReceiver(mIntentReceiver, mIntentFilter); Intent intent = getActivity().getIntent(); if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) { showAlert(intent); } } @Override public void onPause() { super.onPause(); final Context context = getActivity(); if (mValidListener) { mValidListener = false; TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); mSwitchBar.removeOnSwitchChangeListener(this); } context.unregisterReceiver(mIntentReceiver); } /** * Listens to the state change of the switch. */ @Override public void onSwitchChanged(Switch switchView, boolean isChecked) { final Context context = getActivity(); Log.d(TAG, "onSwitchChanged(" + isChecked + ")"); if (!isChecked) { updateWfcMode(context, false); return; } // Call address management activity before turning on WFC Intent carrierAppIntent = getCarrierActivityIntent(context); if (carrierAppIntent != null) { carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE); startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS); } else { updateWfcMode(context, true); } } /* * Get the Intent to launch carrier emergency address management activity. * Return null when no activity found. */ private static Intent getCarrierActivityIntent(Context context) { // Retrive component name from carrirt config CarrierConfigManager configManager = context.getSystemService(CarrierConfigManager.class); if (configManager == null) return null; PersistableBundle bundle = configManager.getConfig(); if (bundle == null) return null; String carrierApp = bundle.getString( CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING); if (TextUtils.isEmpty(carrierApp)) return null; ComponentName componentName = ComponentName.unflattenFromString(carrierApp); if (componentName == null) return null; // Build and return intent Intent intent = new Intent(); intent.setComponent(componentName); return intent; } /* * Turn on/off WFC mode with ImsManager and update UI accordingly */ private void updateWfcMode(Context context, boolean wfcEnabled) { Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")"); ImsManager.setWfcSetting(context, wfcEnabled); int wfcMode = ImsManager.getWfcMode(context, false); int wfcRoamingMode = ImsManager.getWfcMode(context, true); updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode); if (wfcEnabled) { MetricsLogger.action(getActivity(), getMetricsCategory(), wfcMode); } else { MetricsLogger.action(getActivity(), getMetricsCategory(), -1); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); final Context context = getActivity(); if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) { Log.d(TAG, "WFC emergency address activity result = " + resultCode); if (resultCode == Activity.RESULT_OK) { updateWfcMode(context, true); } } } private void updateButtonWfcMode(Context context, boolean wfcEnabled, int wfcMode, int wfcRoamingMode) { mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode)); mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode); // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value. mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode); final PreferenceScreen preferenceScreen = getPreferenceScreen(); boolean updateAddressEnabled = (getCarrierActivityIntent(context) != null); if (wfcEnabled) { if (mEditableWfcMode) { preferenceScreen.addPreference(mButtonWfcMode); } else { // Don't show WFC (home) preference if it's not editable. preferenceScreen.removePreference(mButtonWfcMode); } if (mEditableWfcRoamingMode) { preferenceScreen.addPreference(mButtonWfcRoamingMode); } else { // Don't show WFC roaming preference if it's not editable. preferenceScreen.removePreference(mButtonWfcRoamingMode); } if (updateAddressEnabled) { preferenceScreen.addPreference(mUpdateAddress); } else { preferenceScreen.removePreference(mUpdateAddress); } } else { preferenceScreen.removePreference(mButtonWfcMode); preferenceScreen.removePreference(mButtonWfcRoamingMode); preferenceScreen.removePreference(mUpdateAddress); } } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final Context context = getActivity(); if (preference == mButtonWfcMode) { mButtonWfcMode.setValue((String) newValue); int buttonMode = Integer.valueOf((String) newValue); int currentWfcMode = ImsManager.getWfcMode(context, false); if (buttonMode != currentWfcMode) { ImsManager.setWfcMode(context, buttonMode, false); mButtonWfcMode.setSummary(getWfcModeSummary(context, buttonMode)); MetricsLogger.action(getActivity(), getMetricsCategory(), buttonMode); } if (!mEditableWfcRoamingMode) { int currentWfcRoamingMode = ImsManager.getWfcMode(context, true); if (buttonMode != currentWfcRoamingMode) { ImsManager.setWfcMode(context, buttonMode, true); // mButtonWfcRoamingMode.setSummary is not needed; summary is selected value } } } else if (preference == mButtonWfcRoamingMode) { mButtonWfcRoamingMode.setValue((String) newValue); int buttonMode = Integer.valueOf((String) newValue); int currentMode = ImsManager.getWfcMode(context, true); if (buttonMode != currentMode) { ImsManager.setWfcMode(context, buttonMode, true); // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value. MetricsLogger.action(getActivity(), getMetricsCategory(), buttonMode); } } return true; } static int getWfcModeSummary(Context context, int wfcMode) { int resId = com.android.internal.R.string.wifi_calling_off_summary; if (ImsManager.isWfcEnabledByUser(context)) { switch (wfcMode) { case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; break; case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary; break; case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary; break; default: Log.e(TAG, "Unexpected WFC mode value: " + wfcMode); } } return resId; } }