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.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.os.Bundle;
26 import android.os.PersistableBundle;
27 import android.support.v7.preference.ListPreference;
28 import android.support.v7.preference.Preference;
29 import android.support.v7.preference.PreferenceScreen;
30 import android.telephony.CarrierConfigManager;
31 import android.telephony.PhoneStateListener;
32 import android.telephony.TelephonyManager;
33 import android.util.Log;
34 import android.widget.Switch;
35 import android.widget.TextView;
36 
37 import com.android.ims.ImsConfig;
38 import com.android.ims.ImsManager;
39 import com.android.internal.logging.MetricsLogger;
40 import com.android.internal.logging.MetricsProto.MetricsEvent;
41 import com.android.internal.telephony.Phone;
42 import com.android.settings.widget.SwitchBar;
43 
44 /**
45  * "Wi-Fi Calling settings" screen.  This preference screen lets you
46  * enable/disable Wi-Fi Calling and change Wi-Fi Calling mode.
47  */
48 public class WifiCallingSettings extends SettingsPreferenceFragment
49         implements SwitchBar.OnSwitchChangeListener,
50         Preference.OnPreferenceChangeListener {
51 
52     private static final String TAG = "WifiCallingSettings";
53 
54     //String keys for preference lookup
55     private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
56 
57     //UI objects
58     private SwitchBar mSwitchBar;
59     private Switch mSwitch;
60     private ListPreference mButtonWfcMode;
61     private TextView mEmptyView;
62 
63     private boolean mValidListener = false;
64     private boolean mEditableWfcMode = true;
65 
66     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
67         /*
68          * Enable/disable controls when in/out of a call and depending on
69          * TTY mode and TTY support over VoLTE.
70          * @see android.telephony.PhoneStateListener#onCallStateChanged(int,
71          * java.lang.String)
72          */
73         @Override
74         public void onCallStateChanged(int state, String incomingNumber) {
75             final SettingsActivity activity = (SettingsActivity) getActivity();
76             boolean isNonTtyOrTtyOnVolteEnabled = ImsManager
77                     .isNonTtyOrTtyOnVolteEnabled(activity);
78             final SwitchBar switchBar = activity.getSwitchBar();
79             boolean isWfcEnabled = switchBar.getSwitch().isChecked()
80                     && isNonTtyOrTtyOnVolteEnabled;
81 
82             switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE)
83                     && isNonTtyOrTtyOnVolteEnabled);
84 
85             Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
86             if (pref != null) {
87                 pref.setEnabled(isWfcEnabled
88                         && (state == TelephonyManager.CALL_STATE_IDLE));
89             }
90         }
91     };
92 
93     @Override
onActivityCreated(Bundle savedInstanceState)94     public void onActivityCreated(Bundle savedInstanceState) {
95         super.onActivityCreated(savedInstanceState);
96 
97         final SettingsActivity activity = (SettingsActivity) getActivity();
98 
99         mSwitchBar = activity.getSwitchBar();
100         mSwitch = mSwitchBar.getSwitch();
101         mSwitchBar.show();
102 
103         mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
104         setEmptyView(mEmptyView);
105         mEmptyView.setText(R.string.wifi_calling_off_explanation);
106     }
107 
108     @Override
onDestroyView()109     public void onDestroyView() {
110         super.onDestroyView();
111         mSwitchBar.hide();
112     }
113 
showAlert(Intent intent)114     private void showAlert(Intent intent) {
115         Context context = getActivity();
116 
117         CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE);
118         CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE);
119 
120         AlertDialog.Builder builder = new AlertDialog.Builder(context);
121         builder.setMessage(message)
122                 .setTitle(title)
123                 .setIcon(android.R.drawable.ic_dialog_alert)
124                 .setPositiveButton(android.R.string.ok, null);
125         AlertDialog dialog = builder.create();
126         dialog.show();
127     }
128 
129     private IntentFilter mIntentFilter;
130 
131     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
132         @Override
133         public void onReceive(Context context, Intent intent) {
134             String action = intent.getAction();
135             if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) {
136                 // If this fragment is active then we are immediately
137                 // showing alert on screen. There is no need to add
138                 // notification in this case.
139                 //
140                 // In order to communicate to ImsPhone that it should
141                 // not show notification, we are changing result code here.
142                 setResultCode(Activity.RESULT_CANCELED);
143 
144                 // UX requirement is to disable WFC in case of "permanent" registration failures.
145                 mSwitch.setChecked(false);
146 
147                 showAlert(intent);
148             }
149         }
150     };
151 
152     @Override
getMetricsCategory()153     protected int getMetricsCategory() {
154         return MetricsEvent.WIFI_CALLING;
155     }
156 
157     @Override
onCreate(Bundle savedInstanceState)158     public void onCreate(Bundle savedInstanceState) {
159         super.onCreate(savedInstanceState);
160 
161         addPreferencesFromResource(R.xml.wifi_calling_settings);
162 
163         mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
164         mButtonWfcMode.setOnPreferenceChangeListener(this);
165 
166         mIntentFilter = new IntentFilter();
167         mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
168 
169         CarrierConfigManager configManager = (CarrierConfigManager)
170                 getSystemService(Context.CARRIER_CONFIG_SERVICE);
171         boolean isWifiOnlySupported = true;
172         if (configManager != null) {
173             PersistableBundle b = configManager.getConfig();
174             if (b != null) {
175                 mEditableWfcMode = b.getBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
176                 isWifiOnlySupported = b.getBoolean(
177                         CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
178             }
179         }
180 
181         if (!isWifiOnlySupported) {
182             mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only);
183             mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only);
184         }
185     }
186 
187     @Override
onResume()188     public void onResume() {
189         super.onResume();
190 
191         final Context context = getActivity();
192 
193         if (ImsManager.isWfcEnabledByPlatform(context)) {
194             TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
195             tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
196 
197             mSwitchBar.addOnSwitchChangeListener(this);
198 
199             mValidListener = true;
200         }
201 
202         // NOTE: Buttons will be enabled/disabled in mPhoneStateListener
203         boolean wfcEnabled = ImsManager.isWfcEnabledByUser(context)
204                 && ImsManager.isNonTtyOrTtyOnVolteEnabled(context);
205         mSwitch.setChecked(wfcEnabled);
206         int wfcMode = ImsManager.getWfcMode(context);
207         mButtonWfcMode.setValue(Integer.toString(wfcMode));
208         updateButtonWfcMode(context, wfcEnabled, wfcMode);
209 
210         context.registerReceiver(mIntentReceiver, mIntentFilter);
211 
212         Intent intent = getActivity().getIntent();
213         if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) {
214             showAlert(intent);
215         }
216     }
217 
218     @Override
onPause()219     public void onPause() {
220         super.onPause();
221 
222         final Context context = getActivity();
223 
224         if (mValidListener) {
225             mValidListener = false;
226 
227             TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
228             tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
229 
230             mSwitchBar.removeOnSwitchChangeListener(this);
231         }
232 
233         context.unregisterReceiver(mIntentReceiver);
234     }
235 
236     /**
237      * Listens to the state change of the switch.
238      */
239     @Override
onSwitchChanged(Switch switchView, boolean isChecked)240     public void onSwitchChanged(Switch switchView, boolean isChecked) {
241         final Context context = getActivity();
242 
243         ImsManager.setWfcSetting(context, isChecked);
244 
245         int wfcMode = ImsManager.getWfcMode(context);
246         updateButtonWfcMode(context, isChecked, wfcMode);
247         if (isChecked) {
248             MetricsLogger.action(getActivity(), getMetricsCategory(), wfcMode);
249         } else {
250             MetricsLogger.action(getActivity(), getMetricsCategory(), -1);
251         }
252     }
253 
updateButtonWfcMode(Context context, boolean wfcEnabled, int wfcMode)254     private void updateButtonWfcMode(Context context, boolean wfcEnabled, int wfcMode) {
255         mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode));
256         mButtonWfcMode.setEnabled(wfcEnabled);
257 
258         final PreferenceScreen preferenceScreen = getPreferenceScreen();
259         if (wfcEnabled) {
260             preferenceScreen.addPreference(mButtonWfcMode);
261         } else {
262             preferenceScreen.removePreference(mButtonWfcMode);
263         }
264         preferenceScreen.setEnabled(mEditableWfcMode);
265     }
266 
267     @Override
onPreferenceChange(Preference preference, Object newValue)268     public boolean onPreferenceChange(Preference preference, Object newValue) {
269         final Context context = getActivity();
270         if (preference == mButtonWfcMode) {
271             mButtonWfcMode.setValue((String) newValue);
272             int buttonMode = Integer.valueOf((String) newValue);
273             int currentMode = ImsManager.getWfcMode(context);
274             if (buttonMode != currentMode) {
275                 ImsManager.setWfcMode(context, buttonMode);
276                 mButtonWfcMode.setSummary(getWfcModeSummary(context, buttonMode));
277                 MetricsLogger.action(getActivity(), getMetricsCategory(), buttonMode);
278             }
279         }
280         return true;
281     }
282 
getWfcModeSummary(Context context, int wfcMode)283     static int getWfcModeSummary(Context context, int wfcMode) {
284         int resId = com.android.internal.R.string.wifi_calling_off_summary;
285         if (ImsManager.isWfcEnabledByUser(context)) {
286             switch (wfcMode) {
287                 case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
288                     resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
289                     break;
290                 case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
291                     resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary;
292                     break;
293                 case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
294                     resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
295                     break;
296                 default:
297                     Log.e(TAG, "Unexpected WFC mode value: " + wfcMode);
298             }
299         }
300         return resId;
301     }
302 }
303