Home | History | Annotate | Download | only in settings
      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.nano.MetricsProto.MetricsEvent;
     43 import com.android.internal.telephony.Phone;
     44 import com.android.settings.widget.SwitchBar;
     45 
     46 /**
     47  * "Wi-Fi Calling settings" screen.  This preference screen lets you
     48  * enable/disable Wi-Fi Calling and change Wi-Fi Calling mode.
     49  */
     50 public class WifiCallingSettings extends SettingsPreferenceFragment
     51         implements SwitchBar.OnSwitchChangeListener,
     52         Preference.OnPreferenceChangeListener {
     53 
     54     private static final String TAG = "WifiCallingSettings";
     55 
     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";
     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 ListPreference mButtonWfcRoamingMode;
     73     private Preference mUpdateAddress;
     74     private TextView mEmptyView;
     75 
     76     private boolean mValidListener = false;
     77     private boolean mEditableWfcMode = true;
     78     private boolean mEditableWfcRoamingMode = true;
     79 
     80     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
     81         /*
     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,
     85          * java.lang.String)
     86          */
     87         @Override
     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;
     95 
     96             switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE)
     97                     && isNonTtyOrTtyOnVolteEnabled);
     98 
     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();
    105                 if (b != null) {
    106                     isWfcModeEditable = b.getBoolean(
    107                             CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
    108                     isWfcRoamingModeEditable = b.getBoolean(
    109                             CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
    110                 }
    111             }
    112 
    113             Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
    114             if (pref != null) {
    115                 pref.setEnabled(isWfcEnabled && isWfcModeEditable
    116                         && (state == TelephonyManager.CALL_STATE_IDLE));
    117             }
    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));
    122             }
    123         }
    124     };
    125 
    126     private final OnPreferenceClickListener mUpdateAddressListener =
    127             new OnPreferenceClickListener() {
    128                 /*
    129                  * Launch carrier emergency address managemnent activity
    130                  */
    131                 @Override
    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);
    138                     }
    139                     return true;
    140                 }
    141     };
    142 
    143     @Override
    144     public void onActivityCreated(Bundle savedInstanceState) {
    145         super.onActivityCreated(savedInstanceState);
    146 
    147         final SettingsActivity activity = (SettingsActivity) getActivity();
    148 
    149         mSwitchBar = activity.getSwitchBar();
    150         mSwitch = mSwitchBar.getSwitch();
    151         mSwitchBar.show();
    152 
    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);
    158     }
    159 
    160     @Override
    161     public void onDestroyView() {
    162         super.onDestroyView();
    163         mSwitchBar.hide();
    164     }
    165 
    166     private void showAlert(Intent intent) {
    167         Context context = getActivity();
    168 
    169         CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE);
    170         CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE);
    171 
    172         AlertDialog.Builder builder = new AlertDialog.Builder(context);
    173         builder.setMessage(message)
    174                 .setTitle(title)
    175                 .setIcon(android.R.drawable.ic_dialog_alert)
    176                 .setPositiveButton(android.R.string.ok, null);
    177         AlertDialog dialog = builder.create();
    178         dialog.show();
    179     }
    180 
    181     private IntentFilter mIntentFilter;
    182 
    183     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    184         @Override
    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.
    191                 //
    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);
    195 
    196                 // UX requirement is to disable WFC in case of "permanent" registration failures.
    197                 mSwitch.setChecked(false);
    198 
    199                 showAlert(intent);
    200             }
    201         }
    202     };
    203 
    204     @Override
    205     public int getMetricsCategory() {
    206         return MetricsEvent.WIFI_CALLING;
    207     }
    208 
    209     @Override
    210     public void onCreate(Bundle savedInstanceState) {
    211         super.onCreate(savedInstanceState);
    212 
    213         addPreferencesFromResource(R.xml.wifi_calling_settings);
    214 
    215         mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
    216         mButtonWfcMode.setOnPreferenceChangeListener(this);
    217 
    218         mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE);
    219         mButtonWfcRoamingMode.setOnPreferenceChangeListener(this);
    220 
    221         mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS);
    222         mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener);
    223 
    224         mIntentFilter = new IntentFilter();
    225         mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
    226 
    227         CarrierConfigManager configManager = (CarrierConfigManager)
    228                 getSystemService(Context.CARRIER_CONFIG_SERVICE);
    229         boolean isWifiOnlySupported = true;
    230         if (configManager != null) {
    231             PersistableBundle b = configManager.getConfig();
    232             if (b != null) {
    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);
    238             }
    239         }
    240 
    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);
    248         }
    249     }
    250 
    251     @Override
    252     public void onResume() {
    253         super.onResume();
    254 
    255         final Context context = getActivity();
    256 
    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);
    266 
    267         if (ImsManager.isWfcEnabledByPlatform(context)) {
    268             TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    269             tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
    270 
    271             mSwitchBar.addOnSwitchChangeListener(this);
    272 
    273             mValidListener = true;
    274         }
    275 
    276         context.registerReceiver(mIntentReceiver, mIntentFilter);
    277 
    278         Intent intent = getActivity().getIntent();
    279         if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) {
    280             showAlert(intent);
    281         }
    282     }
    283 
    284     @Override
    285     public void onPause() {
    286         super.onPause();
    287 
    288         final Context context = getActivity();
    289 
    290         if (mValidListener) {
    291             mValidListener = false;
    292 
    293             TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    294             tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
    295 
    296             mSwitchBar.removeOnSwitchChangeListener(this);
    297         }
    298 
    299         context.unregisterReceiver(mIntentReceiver);
    300     }
    301 
    302     /**
    303      * Listens to the state change of the switch.
    304      */
    305     @Override
    306     public void onSwitchChanged(Switch switchView, boolean isChecked) {
    307         final Context context = getActivity();
    308         Log.d(TAG, "onSwitchChanged(" + isChecked + ")");
    309 
    310         if (!isChecked) {
    311             updateWfcMode(context, false);
    312             return;
    313         }
    314 
    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);
    320         } else {
    321             updateWfcMode(context, true);
    322         }
    323     }
    324 
    325     /*
    326      * Get the Intent to launch carrier emergency address management activity.
    327      * Return null when no activity found.
    328      */
    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;
    333 
    334         PersistableBundle bundle = configManager.getConfig();
    335         if (bundle == null) return null;
    336 
    337         String carrierApp = bundle.getString(
    338                 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
    339         if (TextUtils.isEmpty(carrierApp)) return null;
    340 
    341         ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
    342         if (componentName == null) return null;
    343 
    344         // Build and return intent
    345         Intent intent = new Intent();
    346         intent.setComponent(componentName);
    347         return intent;
    348     }
    349 
    350     /*
    351      * Turn on/off WFC mode with ImsManager and update UI accordingly
    352      */
    353     private void updateWfcMode(Context context, boolean wfcEnabled) {
    354         Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")");
    355         ImsManager.setWfcSetting(context, wfcEnabled);
    356 
    357         int wfcMode = ImsManager.getWfcMode(context, false);
    358         int wfcRoamingMode = ImsManager.getWfcMode(context, true);
    359         updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode);
    360         if (wfcEnabled) {
    361             mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), wfcMode);
    362         } else {
    363             mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), -1);
    364         }
    365     }
    366 
    367     @Override
    368     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    369         super.onActivityResult(requestCode, resultCode, data);
    370 
    371         final Context context = getActivity();
    372 
    373         if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
    374             Log.d(TAG, "WFC emergency address activity result = " + resultCode);
    375 
    376             if (resultCode == Activity.RESULT_OK) {
    377                 updateWfcMode(context, true);
    378             }
    379         }
    380     }
    381 
    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);
    388 
    389         final PreferenceScreen preferenceScreen = getPreferenceScreen();
    390         boolean updateAddressEnabled = (getCarrierActivityIntent(context) != null);
    391         if (wfcEnabled) {
    392             if (mEditableWfcMode) {
    393                 preferenceScreen.addPreference(mButtonWfcMode);
    394             } else {
    395                 // Don't show WFC (home) preference if it's not editable.
    396                 preferenceScreen.removePreference(mButtonWfcMode);
    397             }
    398             if (mEditableWfcRoamingMode) {
    399                 preferenceScreen.addPreference(mButtonWfcRoamingMode);
    400             } else {
    401                 // Don't show WFC roaming preference if it's not editable.
    402                 preferenceScreen.removePreference(mButtonWfcRoamingMode);
    403             }
    404             if (updateAddressEnabled) {
    405                 preferenceScreen.addPreference(mUpdateAddress);
    406             } else {
    407                 preferenceScreen.removePreference(mUpdateAddress);
    408             }
    409         } else {
    410             preferenceScreen.removePreference(mButtonWfcMode);
    411             preferenceScreen.removePreference(mButtonWfcRoamingMode);
    412             preferenceScreen.removePreference(mUpdateAddress);
    413         }
    414     }
    415 
    416     @Override
    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);
    427             }
    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
    433                 }
    434             }
    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);
    443             }
    444         }
    445         return true;
    446     }
    447 
    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)) {
    451             switch (wfcMode) {
    452                 case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
    453                     resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
    454                     break;
    455                 case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
    456                     resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary;
    457                     break;
    458                 case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
    459                     resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
    460                     break;
    461                 default:
    462                     Log.e(TAG, "Unexpected WFC mode value: " + wfcMode);
    463             }
    464         }
    465         return resId;
    466     }
    467 }
    468