1 /* 2 * Copyright (C) 2015 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 17 package com.android.settings; 18 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; 39 40 import com.android.ims.ImsConfig; 41 import com.android.ims.ImsManager; 42 import com.android.internal.logging.MetricsLogger; 43 import com.android.internal.logging.MetricsProto.MetricsEvent; 44 import com.android.internal.telephony.Phone; 45 import com.android.settings.widget.SwitchBar; 46 47 /** 48 * "Wi-Fi Calling settings" screen. This preference screen lets you 49 * enable/disable Wi-Fi Calling and change Wi-Fi Calling mode. 50 */ 51 public class WifiCallingSettings extends SettingsPreferenceFragment 52 implements SwitchBar.OnSwitchChangeListener, 53 Preference.OnPreferenceChangeListener { 54 55 private static final String TAG = "WifiCallingSettings"; 56 57 //String keys for preference lookup 58 private static final String BUTTON_WFC_MODE = "wifi_calling_mode"; 59 private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key"; 60 61 private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1; 62 63 public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP"; 64 65 public static final int LAUCH_APP_ACTIVATE = 0; 66 public static final int LAUCH_APP_UPDATE = 1; 67 68 //UI objects 69 private SwitchBar mSwitchBar; 70 private Switch mSwitch; 71 private ListPreference mButtonWfcMode; 72 private Preference mUpdateAddress; 73 private TextView mEmptyView; 74 75 private boolean mValidListener = false; 76 private boolean mEditableWfcMode = true; 77 78 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 79 /* 80 * Enable/disable controls when in/out of a call and depending on 81 * TTY mode and TTY support over VoLTE. 82 * @see android.telephony.PhoneStateListener#onCallStateChanged(int, 83 * java.lang.String) 84 */ 85 @Override 86 public void onCallStateChanged(int state, String incomingNumber) { 87 final SettingsActivity activity = (SettingsActivity) getActivity(); 88 boolean isNonTtyOrTtyOnVolteEnabled = ImsManager 89 .isNonTtyOrTtyOnVolteEnabled(activity); 90 final SwitchBar switchBar = activity.getSwitchBar(); 91 boolean isWfcEnabled = switchBar.getSwitch().isChecked() 92 && isNonTtyOrTtyOnVolteEnabled; 93 94 switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE) 95 && isNonTtyOrTtyOnVolteEnabled); 96 97 Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE); 98 if (pref != null) { 99 pref.setEnabled(isWfcEnabled && getEditableWfcMode(activity) 100 && (state == TelephonyManager.CALL_STATE_IDLE)); 101 } 102 } 103 }; 104 getEditableWfcMode(Context context)105 private static boolean getEditableWfcMode(Context context) { 106 CarrierConfigManager configManager = (CarrierConfigManager) 107 context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 108 if (configManager != null) { 109 PersistableBundle b = configManager.getConfig(); 110 if (b != null) { 111 return b.getBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); 112 } 113 } 114 return true; 115 } 116 117 private final OnPreferenceClickListener mUpdateAddressListener = 118 new OnPreferenceClickListener() { 119 /* 120 * Launch carrier emergency address managemnent activity 121 */ 122 @Override 123 public boolean onPreferenceClick(Preference preference) { 124 final Context context = getActivity(); 125 Intent carrierAppIntent = getCarrierActivityIntent(context); 126 if (carrierAppIntent != null) { 127 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE); 128 startActivity(carrierAppIntent); 129 } 130 return true; 131 } 132 }; 133 134 @Override onActivityCreated(Bundle savedInstanceState)135 public void onActivityCreated(Bundle savedInstanceState) { 136 super.onActivityCreated(savedInstanceState); 137 138 final SettingsActivity activity = (SettingsActivity) getActivity(); 139 140 mSwitchBar = activity.getSwitchBar(); 141 mSwitch = mSwitchBar.getSwitch(); 142 mSwitchBar.show(); 143 144 mEmptyView = (TextView) getView().findViewById(android.R.id.empty); 145 setEmptyView(mEmptyView); 146 mEmptyView.setText(R.string.wifi_calling_off_explanation); 147 } 148 149 @Override onDestroyView()150 public void onDestroyView() { 151 super.onDestroyView(); 152 mSwitchBar.hide(); 153 } 154 showAlert(Intent intent)155 private void showAlert(Intent intent) { 156 Context context = getActivity(); 157 158 CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE); 159 CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE); 160 161 AlertDialog.Builder builder = new AlertDialog.Builder(context); 162 builder.setMessage(message) 163 .setTitle(title) 164 .setIcon(android.R.drawable.ic_dialog_alert) 165 .setPositiveButton(android.R.string.ok, null); 166 AlertDialog dialog = builder.create(); 167 dialog.show(); 168 } 169 170 private IntentFilter mIntentFilter; 171 172 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 173 @Override 174 public void onReceive(Context context, Intent intent) { 175 String action = intent.getAction(); 176 if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) { 177 // If this fragment is active then we are immediately 178 // showing alert on screen. There is no need to add 179 // notification in this case. 180 // 181 // In order to communicate to ImsPhone that it should 182 // not show notification, we are changing result code here. 183 setResultCode(Activity.RESULT_CANCELED); 184 185 // UX requirement is to disable WFC in case of "permanent" registration failures. 186 mSwitch.setChecked(false); 187 188 showAlert(intent); 189 } 190 } 191 }; 192 193 @Override getMetricsCategory()194 protected int getMetricsCategory() { 195 return MetricsEvent.WIFI_CALLING; 196 } 197 198 @Override onCreate(Bundle savedInstanceState)199 public void onCreate(Bundle savedInstanceState) { 200 super.onCreate(savedInstanceState); 201 202 addPreferencesFromResource(R.xml.wifi_calling_settings); 203 204 mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE); 205 mButtonWfcMode.setOnPreferenceChangeListener(this); 206 207 mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS); 208 mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener); 209 210 mIntentFilter = new IntentFilter(); 211 mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR); 212 213 CarrierConfigManager configManager = (CarrierConfigManager) 214 getSystemService(Context.CARRIER_CONFIG_SERVICE); 215 boolean isWifiOnlySupported = true; 216 if (configManager != null) { 217 PersistableBundle b = configManager.getConfig(); 218 if (b != null) { 219 mEditableWfcMode = b.getBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL); 220 isWifiOnlySupported = b.getBoolean( 221 CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true); 222 } 223 } 224 225 if (!isWifiOnlySupported) { 226 mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only); 227 mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only); 228 } 229 } 230 231 @Override onResume()232 public void onResume() { 233 super.onResume(); 234 235 final Context context = getActivity(); 236 237 if (ImsManager.isWfcEnabledByPlatform(context)) { 238 TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 239 tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 240 241 mSwitchBar.addOnSwitchChangeListener(this); 242 243 mValidListener = true; 244 } 245 246 // NOTE: Buttons will be enabled/disabled in mPhoneStateListener 247 boolean wfcEnabled = ImsManager.isWfcEnabledByUser(context) 248 && ImsManager.isNonTtyOrTtyOnVolteEnabled(context); 249 mSwitch.setChecked(wfcEnabled); 250 int wfcMode = ImsManager.getWfcMode(context); 251 mButtonWfcMode.setValue(Integer.toString(wfcMode)); 252 updateButtonWfcMode(context, wfcEnabled, wfcMode); 253 254 context.registerReceiver(mIntentReceiver, mIntentFilter); 255 256 Intent intent = getActivity().getIntent(); 257 if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) { 258 showAlert(intent); 259 } 260 } 261 262 @Override onPause()263 public void onPause() { 264 super.onPause(); 265 266 final Context context = getActivity(); 267 268 if (mValidListener) { 269 mValidListener = false; 270 271 TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 272 tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 273 274 mSwitchBar.removeOnSwitchChangeListener(this); 275 } 276 277 context.unregisterReceiver(mIntentReceiver); 278 } 279 280 /** 281 * Listens to the state change of the switch. 282 */ 283 @Override onSwitchChanged(Switch switchView, boolean isChecked)284 public void onSwitchChanged(Switch switchView, boolean isChecked) { 285 final Context context = getActivity(); 286 Log.d(TAG, "onSwitchChanged(" + isChecked + ")"); 287 288 if (!isChecked) { 289 updateWfcMode(context, false); 290 return; 291 } 292 293 // Call address management activity before turning on WFC 294 Intent carrierAppIntent = getCarrierActivityIntent(context); 295 if (carrierAppIntent != null) { 296 carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE); 297 startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS); 298 } else { 299 updateWfcMode(context, true); 300 } 301 } 302 303 /* 304 * Get the Intent to launch carrier emergency address management activity. 305 * Return null when no activity found. 306 */ getCarrierActivityIntent(Context context)307 private static Intent getCarrierActivityIntent(Context context) { 308 // Retrive component name from carrirt config 309 CarrierConfigManager configManager = context.getSystemService(CarrierConfigManager.class); 310 if (configManager == null) return null; 311 312 PersistableBundle bundle = configManager.getConfig(); 313 if (bundle == null) return null; 314 315 String carrierApp = bundle.getString( 316 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING); 317 if (TextUtils.isEmpty(carrierApp)) return null; 318 319 ComponentName componentName = ComponentName.unflattenFromString(carrierApp); 320 if (componentName == null) return null; 321 322 // Build and return intent 323 Intent intent = new Intent(); 324 intent.setComponent(componentName); 325 return intent; 326 } 327 328 /* 329 * Turn on/off WFC mode with ImsManager and update UI accordingly 330 */ updateWfcMode(Context context, boolean wfcEnabled)331 private void updateWfcMode(Context context, boolean wfcEnabled) { 332 Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")"); 333 ImsManager.setWfcSetting(context, wfcEnabled); 334 335 int wfcMode = ImsManager.getWfcMode(context); 336 updateButtonWfcMode(context, wfcEnabled, wfcMode); 337 if (wfcEnabled) { 338 MetricsLogger.action(getActivity(), getMetricsCategory(), wfcMode); 339 } else { 340 MetricsLogger.action(getActivity(), getMetricsCategory(), -1); 341 } 342 } 343 344 @Override onActivityResult(int requestCode, int resultCode, Intent data)345 public void onActivityResult(int requestCode, int resultCode, Intent data) { 346 super.onActivityResult(requestCode, resultCode, data); 347 348 final Context context = getActivity(); 349 350 if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) { 351 Log.d(TAG, "WFC emergency address activity result = " + resultCode); 352 353 if (resultCode == Activity.RESULT_OK) { 354 updateWfcMode(context, true); 355 } 356 } 357 } 358 updateButtonWfcMode(Context context, boolean wfcEnabled, int wfcMode)359 private void updateButtonWfcMode(Context context, boolean wfcEnabled, int wfcMode) { 360 mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode)); 361 mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode); 362 363 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 364 boolean updateAddressEnabled = (getCarrierActivityIntent(context) != null); 365 if (wfcEnabled) { 366 if (mEditableWfcMode) { 367 preferenceScreen.addPreference(mButtonWfcMode); 368 } else { 369 // Don't show WFC mode preference if it's not editable. 370 preferenceScreen.removePreference(mButtonWfcMode); 371 } 372 if (updateAddressEnabled) { 373 preferenceScreen.addPreference(mUpdateAddress); 374 } else { 375 preferenceScreen.removePreference(mUpdateAddress); 376 } 377 } else { 378 preferenceScreen.removePreference(mButtonWfcMode); 379 preferenceScreen.removePreference(mUpdateAddress); 380 } 381 } 382 383 @Override onPreferenceChange(Preference preference, Object newValue)384 public boolean onPreferenceChange(Preference preference, Object newValue) { 385 final Context context = getActivity(); 386 if (preference == mButtonWfcMode) { 387 mButtonWfcMode.setValue((String) newValue); 388 int buttonMode = Integer.valueOf((String) newValue); 389 int currentMode = ImsManager.getWfcMode(context); 390 if (buttonMode != currentMode) { 391 ImsManager.setWfcMode(context, buttonMode); 392 mButtonWfcMode.setSummary(getWfcModeSummary(context, buttonMode)); 393 MetricsLogger.action(getActivity(), getMetricsCategory(), buttonMode); 394 } 395 } 396 return true; 397 } 398 getWfcModeSummary(Context context, int wfcMode)399 static int getWfcModeSummary(Context context, int wfcMode) { 400 int resId = com.android.internal.R.string.wifi_calling_off_summary; 401 if (ImsManager.isWfcEnabledByUser(context)) { 402 switch (wfcMode) { 403 case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: 404 resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; 405 break; 406 case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: 407 resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary; 408 break; 409 case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: 410 resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary; 411 break; 412 default: 413 Log.e(TAG, "Unexpected WFC mode value: " + wfcMode); 414 } 415 } 416 return resId; 417 } 418 } 419