2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.BroadcastReceiver;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.os.Bundle;
27 import android.os.PersistableBundle;
28 import android.support.v7.preference.ListPreference;
29 import android.support.v7.preference.Preference;
30 import android.support.v7.preference.Preference.OnPreferenceClickListener;
31 import android.support.v7.preference.PreferenceScreen;
32 import android.telephony.CarrierConfigManager;
33 import android.telephony.PhoneStateListener;
34 import android.telephony.TelephonyManager;
35 import android.text.TextUtils;
36 import android.util.Log;
37 import android.widget.Switch;
38 import android.widget.TextView;
40 import com.android.ims.ImsConfig;
41 import com.android.ims.ImsManager;
42 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
43 import com.android.internal.telephony.Phone;
44 import com.android.settings.widget.SwitchBar;
47 * "Wi-Fi Calling settings" screen. This preference screen lets you
48 * enable/disable Wi-Fi Calling and change Wi-Fi Calling mode.
50 public class WifiCallingSettings extends SettingsPreferenceFragment
51 implements SwitchBar.OnSwitchChangeListener,
52 Preference.OnPreferenceChangeListener {
54 private static final String TAG = "WifiCallingSettings";
56 //String keys for preference lookup
57 private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
58 private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
59 private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
61 private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
63 public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
65 public static final int LAUCH_APP_ACTIVATE = 0;
66 public static final int LAUCH_APP_UPDATE = 1;
69 private SwitchBar mSwitchBar;
70 private Switch mSwitch;
71 private ListPreference mButtonWfcMode;
72 private ListPreference mButtonWfcRoamingMode;
73 private Preference mUpdateAddress;
74 private TextView mEmptyView;
76 private boolean mValidListener = false;
77 private boolean mEditableWfcMode = true;
78 private boolean mEditableWfcRoamingMode = true;
80 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
82 * Enable/disable controls when in/out of a call and depending on
83 * TTY mode and TTY support over VoLTE.
84 * @see android.telephony.PhoneStateListener#onCallStateChanged(int,
88 public void onCallStateChanged(int state, String incomingNumber) {
89 final SettingsActivity activity = (SettingsActivity) getActivity();
90 boolean isNonTtyOrTtyOnVolteEnabled = ImsManager
91 .isNonTtyOrTtyOnVolteEnabled(activity);
92 final SwitchBar switchBar = activity.getSwitchBar();
93 boolean isWfcEnabled = switchBar.getSwitch().isChecked()
94 && isNonTtyOrTtyOnVolteEnabled;
96 switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE)
97 && isNonTtyOrTtyOnVolteEnabled);
99 boolean isWfcModeEditable = true;
100 boolean isWfcRoamingModeEditable = false;
101 final CarrierConfigManager configManager = (CarrierConfigManager)
102 activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
103 if (configManager != null) {
104 PersistableBundle b = configManager.getConfig();
106 isWfcModeEditable = b.getBoolean(
107 CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
108 isWfcRoamingModeEditable = b.getBoolean(
109 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
113 Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
115 pref.setEnabled(isWfcEnabled && isWfcModeEditable
116 && (state == TelephonyManager.CALL_STATE_IDLE));
118 Preference pref_roam = getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
119 if (pref_roam != null) {
120 pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable
121 && (state == TelephonyManager.CALL_STATE_IDLE));
126 private final OnPreferenceClickListener mUpdateAddressListener =
127 new OnPreferenceClickListener() {
129 * Launch carrier emergency address managemnent activity
132 public boolean onPreferenceClick(Preference preference) {
133 final Context context = getActivity();
134 Intent carrierAppIntent = getCarrierActivityIntent(context);
135 if (carrierAppIntent != null) {
136 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE);
137 startActivity(carrierAppIntent);
144 public void onActivityCreated(Bundle savedInstanceState) {
145 super.onActivityCreated(savedInstanceState);
147 final SettingsActivity activity = (SettingsActivity) getActivity();
149 mSwitchBar = activity.getSwitchBar();
150 mSwitch = mSwitchBar.getSwitch();
153 mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
154 setEmptyView(mEmptyView);
155 String emptyViewText = activity.getString(R.string.wifi_calling_off_explanation)
156 + activity.getString(R.string.wifi_calling_off_explanation_2);
157 mEmptyView.setText(emptyViewText);
161 public void onDestroyView() {
162 super.onDestroyView();
166 private void showAlert(Intent intent) {
167 Context context = getActivity();
169 CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE);
170 CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE);
172 AlertDialog.Builder builder = new AlertDialog.Builder(context);
173 builder.setMessage(message)
175 .setIcon(android.R.drawable.ic_dialog_alert)
176 .setPositiveButton(android.R.string.ok, null);
177 AlertDialog dialog = builder.create();
181 private IntentFilter mIntentFilter;
183 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
185 public void onReceive(Context context, Intent intent) {
186 String action = intent.getAction();
187 if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) {
188 // If this fragment is active then we are immediately
189 // showing alert on screen. There is no need to add
190 // notification in this case.
192 // In order to communicate to ImsPhone that it should
193 // not show notification, we are changing result code here.
194 setResultCode(Activity.RESULT_CANCELED);
196 // UX requirement is to disable WFC in case of "permanent" registration failures.
197 mSwitch.setChecked(false);
205 public int getMetricsCategory() {
206 return MetricsEvent.WIFI_CALLING;
210 public void onCreate(Bundle savedInstanceState) {
211 super.onCreate(savedInstanceState);
213 addPreferencesFromResource(R.xml.wifi_calling_settings);
215 mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
216 mButtonWfcMode.setOnPreferenceChangeListener(this);
218 mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE);
219 mButtonWfcRoamingMode.setOnPreferenceChangeListener(this);
221 mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS);
222 mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener);
224 mIntentFilter = new IntentFilter();
225 mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
227 CarrierConfigManager configManager = (CarrierConfigManager)
228 getSystemService(Context.CARRIER_CONFIG_SERVICE);
229 boolean isWifiOnlySupported = true;
230 if (configManager != null) {
231 PersistableBundle b = configManager.getConfig();
233 mEditableWfcMode = b.getBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
234 mEditableWfcRoamingMode = b.getBoolean(
235 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
236 isWifiOnlySupported = b.getBoolean(
237 CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
241 if (!isWifiOnlySupported) {
242 mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only);
243 mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only);
244 mButtonWfcRoamingMode.setEntries(
245 R.array.wifi_calling_mode_choices_v2_without_wifi_only);
246 mButtonWfcRoamingMode.setEntryValues(
247 R.array.wifi_calling_mode_values_without_wifi_only);
252 public void onResume() {
255 final Context context = getActivity();
257 // NOTE: Buttons will be enabled/disabled in mPhoneStateListener
258 boolean wfcEnabled = ImsManager.isWfcEnabledByUser(context)
259 && ImsManager.isNonTtyOrTtyOnVolteEnabled(context);
260 mSwitch.setChecked(wfcEnabled);
261 int wfcMode = ImsManager.getWfcMode(context, false);
262 int wfcRoamingMode = ImsManager.getWfcMode(context, true);
263 mButtonWfcMode.setValue(Integer.toString(wfcMode));
264 mButtonWfcRoamingMode.setValue(Integer.toString(wfcRoamingMode));
265 updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode);
267 if (ImsManager.isWfcEnabledByPlatform(context)) {
268 TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
269 tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
271 mSwitchBar.addOnSwitchChangeListener(this);
273 mValidListener = true;
276 context.registerReceiver(mIntentReceiver, mIntentFilter);
278 Intent intent = getActivity().getIntent();
279 if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) {
285 public void onPause() {
288 final Context context = getActivity();
290 if (mValidListener) {
291 mValidListener = false;
293 TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
294 tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
296 mSwitchBar.removeOnSwitchChangeListener(this);
299 context.unregisterReceiver(mIntentReceiver);
303 * Listens to the state change of the switch.
306 public void onSwitchChanged(Switch switchView, boolean isChecked) {
307 final Context context = getActivity();
308 Log.d(TAG, "onSwitchChanged(" + isChecked + ")");
311 updateWfcMode(context, false);
315 // Call address management activity before turning on WFC
316 Intent carrierAppIntent = getCarrierActivityIntent(context);
317 if (carrierAppIntent != null) {
318 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
319 startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
321 updateWfcMode(context, true);
326 * Get the Intent to launch carrier emergency address management activity.
327 * Return null when no activity found.
329 private static Intent getCarrierActivityIntent(Context context) {
330 // Retrive component name from carrirt config
331 CarrierConfigManager configManager = context.getSystemService(CarrierConfigManager.class);
332 if (configManager == null) return null;
334 PersistableBundle bundle = configManager.getConfig();
335 if (bundle == null) return null;
337 String carrierApp = bundle.getString(
338 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
339 if (TextUtils.isEmpty(carrierApp)) return null;
341 ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
342 if (componentName == null) return null;
344 // Build and return intent
345 Intent intent = new Intent();
346 intent.setComponent(componentName);
351 * Turn on/off WFC mode with ImsManager and update UI accordingly
353 private void updateWfcMode(Context context, boolean wfcEnabled) {
354 Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")");
355 ImsManager.setWfcSetting(context, wfcEnabled);
357 int wfcMode = ImsManager.getWfcMode(context, false);
358 int wfcRoamingMode = ImsManager.getWfcMode(context, true);
359 updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode);
361 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), wfcMode);
363 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), -1);
368 public void onActivityResult(int requestCode, int resultCode, Intent data) {
369 super.onActivityResult(requestCode, resultCode, data);
371 final Context context = getActivity();
373 if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
374 Log.d(TAG, "WFC emergency address activity result = " + resultCode);
376 if (resultCode == Activity.RESULT_OK) {
377 updateWfcMode(context, true);
382 private void updateButtonWfcMode(Context context, boolean wfcEnabled,
383 int wfcMode, int wfcRoamingMode) {
384 mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode));
385 mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode);
386 // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
387 mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode);
389 final PreferenceScreen preferenceScreen = getPreferenceScreen();
390 boolean updateAddressEnabled = (getCarrierActivityIntent(context) != null);
392 if (mEditableWfcMode) {
393 preferenceScreen.addPreference(mButtonWfcMode);
395 // Don't show WFC (home) preference if it's not editable.
396 preferenceScreen.removePreference(mButtonWfcMode);
398 if (mEditableWfcRoamingMode) {
399 preferenceScreen.addPreference(mButtonWfcRoamingMode);
401 // Don't show WFC roaming preference if it's not editable.
402 preferenceScreen.removePreference(mButtonWfcRoamingMode);
404 if (updateAddressEnabled) {
405 preferenceScreen.addPreference(mUpdateAddress);
407 preferenceScreen.removePreference(mUpdateAddress);
410 preferenceScreen.removePreference(mButtonWfcMode);
411 preferenceScreen.removePreference(mButtonWfcRoamingMode);
412 preferenceScreen.removePreference(mUpdateAddress);
417 public boolean onPreferenceChange(Preference preference, Object newValue) {
418 final Context context = getActivity();
419 if (preference == mButtonWfcMode) {
420 mButtonWfcMode.setValue((String) newValue);
421 int buttonMode = Integer.valueOf((String) newValue);
422 int currentWfcMode = ImsManager.getWfcMode(context, false);
423 if (buttonMode != currentWfcMode) {
424 ImsManager.setWfcMode(context, buttonMode, false);
425 mButtonWfcMode.setSummary(getWfcModeSummary(context, buttonMode));
426 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
428 if (!mEditableWfcRoamingMode) {
429 int currentWfcRoamingMode = ImsManager.getWfcMode(context, true);
430 if (buttonMode != currentWfcRoamingMode) {
431 ImsManager.setWfcMode(context, buttonMode, true);
432 // mButtonWfcRoamingMode.setSummary is not needed; summary is selected value
435 } else if (preference == mButtonWfcRoamingMode) {
436 mButtonWfcRoamingMode.setValue((String) newValue);
437 int buttonMode = Integer.valueOf((String) newValue);
438 int currentMode = ImsManager.getWfcMode(context, true);
439 if (buttonMode != currentMode) {
440 ImsManager.setWfcMode(context, buttonMode, true);
441 // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
442 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
448 public static int getWfcModeSummary(Context context, int wfcMode) {
449 int resId = com.android.internal.R.string.wifi_calling_off_summary;
450 if (ImsManager.isWfcEnabledByUser(context)) {
452 case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
453 resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
455 case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
456 resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary;
458 case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
459 resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
462 Log.e(TAG, "Unexpected WFC mode value: " + wfcMode);