• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.wifi.calling;
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.SubscriptionManager;
35 import android.telephony.TelephonyManager;
36 import android.text.TextUtils;
37 import android.util.Log;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.view.ViewGroup;
41 import android.widget.Switch;
42 import android.widget.TextView;
43 
44 import com.android.ims.ImsConfig;
45 import com.android.ims.ImsManager;
46 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
47 import com.android.internal.telephony.Phone;
48 import com.android.settings.R;
49 import com.android.settings.SettingsActivity;
50 import com.android.settings.SettingsPreferenceFragment;
51 import com.android.settings.Utils;
52 import com.android.settings.widget.SwitchBar;
53 
54 /**
55  * This is the inner class of {@link WifiCallingSettings} fragment.
56  * The preference screen lets you enable/disable Wi-Fi Calling and change Wi-Fi Calling mode.
57  */
58 public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
59         implements SwitchBar.OnSwitchChangeListener,
60         Preference.OnPreferenceChangeListener {
61     private static final String TAG = "WifiCallingForSub";
62 
63     //String keys for preference lookup
64     private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
65     private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
66     private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
67 
68     private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
69 
70     public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
71 
72     protected static final String FRAGMENT_BUNDLE_SUBID = "subId";
73 
74     public static final int LAUCH_APP_ACTIVATE = 0;
75     public static final int LAUCH_APP_UPDATE = 1;
76 
77     //UI objects
78     private SwitchBar mSwitchBar;
79     private Switch mSwitch;
80     private ListPreference mButtonWfcMode;
81     private ListPreference mButtonWfcRoamingMode;
82     private Preference mUpdateAddress;
83     private TextView mEmptyView;
84 
85     private boolean mValidListener = false;
86     private boolean mEditableWfcMode = true;
87     private boolean mEditableWfcRoamingMode = true;
88 
89     private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
90     private ImsManager mImsManager;
91 
92     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
93         /*
94          * Enable/disable controls when in/out of a call and depending on
95          * TTY mode and TTY support over VoLTE.
96          * @see android.telephony.PhoneStateListener#onCallStateChanged(int,
97          * java.lang.String)
98          */
99         @Override
100         public void onCallStateChanged(int state, String incomingNumber) {
101             final SettingsActivity activity = (SettingsActivity) getActivity();
102             boolean isNonTtyOrTtyOnVolteEnabled = mImsManager.isNonTtyOrTtyOnVolteEnabled();
103             boolean isWfcEnabled = mSwitchBar.isChecked()
104                     && isNonTtyOrTtyOnVolteEnabled;
105 
106             mSwitchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE)
107                     && isNonTtyOrTtyOnVolteEnabled);
108 
109             boolean isWfcModeEditable = true;
110             boolean isWfcRoamingModeEditable = false;
111             final CarrierConfigManager configManager = (CarrierConfigManager)
112                     activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
113             if (configManager != null) {
114                 PersistableBundle b = configManager.getConfigForSubId(mSubId);
115                 if (b != null) {
116                     isWfcModeEditable = b.getBoolean(
117                             CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
118                     isWfcRoamingModeEditable = b.getBoolean(
119                             CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
120                 }
121             }
122 
123             Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
124             if (pref != null) {
125                 pref.setEnabled(isWfcEnabled && isWfcModeEditable
126                         && (state == TelephonyManager.CALL_STATE_IDLE));
127             }
128             Preference pref_roam =
129                     getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
130             if (pref_roam != null) {
131                 pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable
132                         && (state == TelephonyManager.CALL_STATE_IDLE));
133             }
134         }
135     };
136 
137     private final OnPreferenceClickListener mUpdateAddressListener =
138             new OnPreferenceClickListener() {
139                 /*
140                  * Launch carrier emergency address managemnent activity
141                  */
142                 @Override
143                 public boolean onPreferenceClick(Preference preference) {
144                     Intent carrierAppIntent = getCarrierActivityIntent();
145                     if (carrierAppIntent != null) {
146                         carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE);
147                         startActivity(carrierAppIntent);
148                     }
149                     return true;
150                 }
151             };
152 
153     @Override
onActivityCreated(Bundle savedInstanceState)154     public void onActivityCreated(Bundle savedInstanceState) {
155         super.onActivityCreated(savedInstanceState);
156 
157         final SettingsActivity activity = (SettingsActivity) getActivity();
158 
159         mEmptyView = getView().findViewById(android.R.id.empty);
160         setEmptyView(mEmptyView);
161         String emptyViewText = activity.getString(R.string.wifi_calling_off_explanation)
162                 + activity.getString(R.string.wifi_calling_off_explanation_2);
163         mEmptyView.setText(emptyViewText);
164 
165         mSwitchBar = getView().findViewById(R.id.switch_bar);
166         mSwitchBar.show();
167         mSwitch = mSwitchBar.getSwitch();
168     }
169 
170     @Override
onDestroyView()171     public void onDestroyView() {
172         super.onDestroyView();
173         mSwitchBar.hide();
174     }
175 
showAlert(Intent intent)176     private void showAlert(Intent intent) {
177         Context context = getActivity();
178 
179         CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE);
180         CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE);
181 
182         AlertDialog.Builder builder = new AlertDialog.Builder(context);
183         builder.setMessage(message)
184                 .setTitle(title)
185                 .setIcon(android.R.drawable.ic_dialog_alert)
186                 .setPositiveButton(android.R.string.ok, null);
187         AlertDialog dialog = builder.create();
188         dialog.show();
189     }
190 
191     private IntentFilter mIntentFilter;
192 
193     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
194         @Override
195         public void onReceive(Context context, Intent intent) {
196             String action = intent.getAction();
197             if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) {
198                 // If this fragment is active then we are immediately
199                 // showing alert on screen. There is no need to add
200                 // notification in this case.
201                 //
202                 // In order to communicate to ImsPhone that it should
203                 // not show notification, we are changing result code here.
204                 setResultCode(Activity.RESULT_CANCELED);
205 
206                 showAlert(intent);
207             }
208         }
209     };
210 
211     @Override
getMetricsCategory()212     public int getMetricsCategory() {
213         return MetricsEvent.WIFI_CALLING_FOR_SUB;
214     }
215 
216     @Override
getHelpResource()217     public int getHelpResource() {
218         // Return 0 to suppress help icon. The help will be populated by parent page.
219         return 0;
220     }
221 
222     @Override
onCreate(Bundle savedInstanceState)223     public void onCreate(Bundle savedInstanceState) {
224         super.onCreate(savedInstanceState);
225 
226         addPreferencesFromResource(R.xml.wifi_calling_settings);
227 
228         // SubId should always be specified when creating this fragment. Either through
229         // fragment.setArguments() or through savedInstanceState.
230         if (getArguments() != null && getArguments().containsKey(FRAGMENT_BUNDLE_SUBID)) {
231             mSubId = getArguments().getInt(FRAGMENT_BUNDLE_SUBID);
232         } else if (savedInstanceState != null) {
233             mSubId = savedInstanceState.getInt(
234                     FRAGMENT_BUNDLE_SUBID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
235         }
236 
237         mImsManager = ImsManager.getInstance(
238                 getActivity(), SubscriptionManager.getPhoneId(mSubId));
239 
240         mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
241         mButtonWfcMode.setOnPreferenceChangeListener(this);
242 
243         mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE);
244         mButtonWfcRoamingMode.setOnPreferenceChangeListener(this);
245 
246         mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS);
247         mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener);
248 
249         mIntentFilter = new IntentFilter();
250         mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
251     }
252 
253     @Override
onSaveInstanceState(Bundle outState)254     public void onSaveInstanceState(Bundle outState) {
255         outState.putInt(FRAGMENT_BUNDLE_SUBID, mSubId);
256         super.onSaveInstanceState(outState);
257     }
258 
259     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)260     public View onCreateView(LayoutInflater inflater, ViewGroup container,
261             Bundle savedInstanceState) {
262 
263         View view = inflater.inflate(
264                 R.layout.wifi_calling_settings_preferences, container, false);
265 
266         final ViewGroup prefs_container = view.findViewById(R.id.prefs_container);
267         Utils.prepareCustomPreferencesList(container, view, prefs_container, false);
268         View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState);
269         prefs_container.addView(prefs);
270 
271         return view;
272     }
273 
updateBody()274     private void updateBody() {
275         CarrierConfigManager configManager = (CarrierConfigManager)
276                 getSystemService(Context.CARRIER_CONFIG_SERVICE);
277         boolean isWifiOnlySupported = true;
278 
279         if (configManager != null) {
280             PersistableBundle b = configManager.getConfigForSubId(mSubId);
281             if (b != null) {
282                 mEditableWfcMode = b.getBoolean(
283                         CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
284                 mEditableWfcRoamingMode = b.getBoolean(
285                         CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
286                 isWifiOnlySupported = b.getBoolean(
287                         CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
288             }
289         }
290 
291         if (!isWifiOnlySupported) {
292             mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only);
293             mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only);
294             mButtonWfcRoamingMode.setEntries(
295                     R.array.wifi_calling_mode_choices_v2_without_wifi_only);
296             mButtonWfcRoamingMode.setEntryValues(
297                     R.array.wifi_calling_mode_values_without_wifi_only);
298         }
299 
300 
301         // NOTE: Buttons will be enabled/disabled in mPhoneStateListener
302         boolean wfcEnabled = mImsManager.isWfcEnabledByUser()
303                 && mImsManager.isNonTtyOrTtyOnVolteEnabled();
304         mSwitch.setChecked(wfcEnabled);
305         int wfcMode = mImsManager.getWfcMode(false);
306         int wfcRoamingMode = mImsManager.getWfcMode(true);
307         mButtonWfcMode.setValue(Integer.toString(wfcMode));
308         mButtonWfcRoamingMode.setValue(Integer.toString(wfcRoamingMode));
309         updateButtonWfcMode(wfcEnabled, wfcMode, wfcRoamingMode);
310     }
311 
312     @Override
onResume()313     public void onResume() {
314         super.onResume();
315 
316         final Context context = getActivity();
317 
318         updateBody();
319 
320         if (mImsManager.isWfcEnabledByPlatform()) {
321             TelephonyManager tm =
322                     (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
323             tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
324 
325             mSwitchBar.addOnSwitchChangeListener(this);
326 
327             mValidListener = true;
328         }
329 
330         context.registerReceiver(mIntentReceiver, mIntentFilter);
331 
332         Intent intent = getActivity().getIntent();
333         if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) {
334             showAlert(intent);
335         }
336     }
337 
338     @Override
onPause()339     public void onPause() {
340         super.onPause();
341 
342         final Context context = getActivity();
343 
344         if (mValidListener) {
345             mValidListener = false;
346 
347             TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
348             tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
349 
350             mSwitchBar.removeOnSwitchChangeListener(this);
351         }
352 
353         context.unregisterReceiver(mIntentReceiver);
354     }
355 
356     /**
357      * Listens to the state change of the switch.
358      */
359     @Override
onSwitchChanged(Switch switchView, boolean isChecked)360     public void onSwitchChanged(Switch switchView, boolean isChecked) {
361         Log.d(TAG, "onSwitchChanged(" + isChecked + ")");
362 
363         if (!isChecked) {
364             updateWfcMode(false);
365             return;
366         }
367 
368         // Call address management activity before turning on WFC
369         Intent carrierAppIntent = getCarrierActivityIntent();
370         if (carrierAppIntent != null) {
371             carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
372             startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
373         } else {
374             updateWfcMode(true);
375         }
376     }
377 
378     /*
379      * Get the Intent to launch carrier emergency address management activity.
380      * Return null when no activity found.
381      */
getCarrierActivityIntent()382     private Intent getCarrierActivityIntent() {
383         // Retrive component name from carrier config
384         CarrierConfigManager configManager =
385                 getActivity().getSystemService(CarrierConfigManager.class);
386         if (configManager == null) return null;
387 
388         PersistableBundle bundle = configManager.getConfigForSubId(mSubId);
389         if (bundle == null) return null;
390 
391         String carrierApp = bundle.getString(
392                 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
393         if (TextUtils.isEmpty(carrierApp)) return null;
394 
395         ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
396         if (componentName == null) return null;
397 
398         // Build and return intent
399         Intent intent = new Intent();
400         intent.setComponent(componentName);
401         return intent;
402     }
403 
404     /*
405      * Turn on/off WFC mode with ImsManager and update UI accordingly
406      */
updateWfcMode(boolean wfcEnabled)407     private void updateWfcMode(boolean wfcEnabled) {
408         Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")");
409         mImsManager.setWfcSetting(wfcEnabled);
410 
411         int wfcMode = mImsManager.getWfcMode(false);
412         int wfcRoamingMode = mImsManager.getWfcMode(true);
413         updateButtonWfcMode(wfcEnabled, wfcMode, wfcRoamingMode);
414         if (wfcEnabled) {
415             mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), wfcMode);
416         } else {
417             mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), -1);
418         }
419     }
420 
421     @Override
onActivityResult(int requestCode, int resultCode, Intent data)422     public void onActivityResult(int requestCode, int resultCode, Intent data) {
423         super.onActivityResult(requestCode, resultCode, data);
424 
425         final Context context = getActivity();
426 
427         if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
428             Log.d(TAG, "WFC emergency address activity result = " + resultCode);
429 
430             if (resultCode == Activity.RESULT_OK) {
431                 updateWfcMode(true);
432             }
433         }
434     }
435 
updateButtonWfcMode(boolean wfcEnabled, int wfcMode, int wfcRoamingMode)436     private void updateButtonWfcMode(boolean wfcEnabled,
437             int wfcMode, int wfcRoamingMode) {
438         mButtonWfcMode.setSummary(getWfcModeSummary(wfcMode));
439         mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode);
440         // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
441         mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode);
442 
443         final PreferenceScreen preferenceScreen = getPreferenceScreen();
444         boolean updateAddressEnabled = (getCarrierActivityIntent() != null);
445         if (wfcEnabled) {
446             if (mEditableWfcMode) {
447                 preferenceScreen.addPreference(mButtonWfcMode);
448             } else {
449                 // Don't show WFC (home) preference if it's not editable.
450                 preferenceScreen.removePreference(mButtonWfcMode);
451             }
452             if (mEditableWfcRoamingMode) {
453                 preferenceScreen.addPreference(mButtonWfcRoamingMode);
454             } else {
455                 // Don't show WFC roaming preference if it's not editable.
456                 preferenceScreen.removePreference(mButtonWfcRoamingMode);
457             }
458             if (updateAddressEnabled) {
459                 preferenceScreen.addPreference(mUpdateAddress);
460             } else {
461                 preferenceScreen.removePreference(mUpdateAddress);
462             }
463         } else {
464             preferenceScreen.removePreference(mButtonWfcMode);
465             preferenceScreen.removePreference(mButtonWfcRoamingMode);
466             preferenceScreen.removePreference(mUpdateAddress);
467         }
468     }
469 
470     @Override
onPreferenceChange(Preference preference, Object newValue)471     public boolean onPreferenceChange(Preference preference, Object newValue) {
472         if (preference == mButtonWfcMode) {
473             Log.d(TAG, "onPreferenceChange mButtonWfcMode " + newValue);
474             mButtonWfcMode.setValue((String) newValue);
475             int buttonMode = Integer.valueOf((String) newValue);
476             int currentWfcMode = mImsManager.getWfcMode(false);
477             if (buttonMode != currentWfcMode) {
478                 mImsManager.setWfcMode(buttonMode, false);
479                 mButtonWfcMode.setSummary(getWfcModeSummary(buttonMode));
480                 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
481             }
482             if (!mEditableWfcRoamingMode) {
483                 int currentWfcRoamingMode = mImsManager.getWfcMode(true);
484                 if (buttonMode != currentWfcRoamingMode) {
485                     mImsManager.setWfcMode(buttonMode, true);
486                     // mButtonWfcRoamingMode.setSummary is not needed; summary is selected value
487                 }
488             }
489         } else if (preference == mButtonWfcRoamingMode) {
490             mButtonWfcRoamingMode.setValue((String) newValue);
491             int buttonMode = Integer.valueOf((String) newValue);
492             int currentMode = mImsManager.getWfcMode(true);
493             if (buttonMode != currentMode) {
494                 mImsManager.setWfcMode(buttonMode, true);
495                 // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
496                 mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
497             }
498         }
499         return true;
500     }
501 
getWfcModeSummary(int wfcMode)502     private int getWfcModeSummary(int wfcMode) {
503         int resId = com.android.internal.R.string.wifi_calling_off_summary;
504         if (mImsManager.isWfcEnabledByUser()) {
505             switch (wfcMode) {
506                 case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
507                     resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
508                     break;
509                 case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
510                     resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary;
511                     break;
512                 case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
513                     resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
514                     break;
515                 default:
516                     Log.e(TAG, "Unexpected WFC mode value: " + wfcMode);
517             }
518         }
519         return resId;
520     }
521 }
522