• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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