1 /*
2  * Copyright (C) 2018 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.network.telephony;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.content.pm.ResolveInfo;
23 import android.os.Looper;
24 import android.os.PersistableBundle;
25 import android.provider.Settings;
26 import android.telecom.PhoneAccountHandle;
27 import android.telecom.TelecomManager;
28 import android.telephony.CarrierConfigManager;
29 import android.telephony.PhoneStateListener;
30 import android.telephony.SubscriptionManager;
31 import android.telephony.TelephonyManager;
32 import android.telephony.ims.ImsMmTelManager;
33 import android.util.Log;
34 
35 import androidx.annotation.VisibleForTesting;
36 import androidx.preference.Preference;
37 import androidx.preference.PreferenceScreen;
38 
39 import com.android.settings.R;
40 import com.android.settings.network.ims.WifiCallingQueryImsState;
41 import com.android.settingslib.core.lifecycle.LifecycleObserver;
42 import com.android.settingslib.core.lifecycle.events.OnStart;
43 import com.android.settingslib.core.lifecycle.events.OnStop;
44 
45 import java.util.List;
46 
47 /**
48  * Preference controller for "Wifi Calling"
49  */
50 public class WifiCallingPreferenceController extends TelephonyBasePreferenceController implements
51         LifecycleObserver, OnStart, OnStop {
52 
53     private static final String TAG = "WifiCallingPreference";
54 
55     @VisibleForTesting
56     Integer mCallState;
57     @VisibleForTesting
58     CarrierConfigManager mCarrierConfigManager;
59     private ImsMmTelManager mImsMmTelManager;
60     @VisibleForTesting
61     PhoneAccountHandle mSimCallManager;
62     private PhoneCallStateListener mPhoneStateListener;
63     private Preference mPreference;
64 
WifiCallingPreferenceController(Context context, String key)65     public WifiCallingPreferenceController(Context context, String key) {
66         super(context, key);
67         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
68         mPhoneStateListener = new PhoneCallStateListener();
69     }
70 
71     @Override
getAvailabilityStatus(int subId)72     public int getAvailabilityStatus(int subId) {
73         return SubscriptionManager.isValidSubscriptionId(subId)
74                 && isWifiCallingEnabled(mContext, subId)
75                 ? AVAILABLE
76                 : UNSUPPORTED_ON_DEVICE;
77     }
78 
79     @Override
onStart()80     public void onStart() {
81         mPhoneStateListener.register(mContext, mSubId);
82     }
83 
84     @Override
onStop()85     public void onStop() {
86         mPhoneStateListener.unregister();
87     }
88 
89     @Override
displayPreference(PreferenceScreen screen)90     public void displayPreference(PreferenceScreen screen) {
91         super.displayPreference(screen);
92         mPreference = screen.findPreference(getPreferenceKey());
93         final Intent intent = mPreference.getIntent();
94         if (intent != null) {
95             intent.putExtra(Settings.EXTRA_SUB_ID, mSubId);
96         }
97     }
98 
99     @Override
updateState(Preference preference)100     public void updateState(Preference preference) {
101         super.updateState(preference);
102         if ((mCallState == null) || (preference == null)) {
103             Log.d(TAG, "Skip update under mCallState=" + mCallState);
104             return;
105         }
106         CharSequence summaryText = null;
107         if (mSimCallManager != null) {
108             final Intent intent = MobileNetworkUtils.buildPhoneAccountConfigureIntent(mContext,
109                     mSimCallManager);
110             if (intent == null) {
111                 // Do nothing in this case since preference is invisible
112                 return;
113             }
114             final PackageManager pm = mContext.getPackageManager();
115             final List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0);
116             preference.setTitle(resolutions.get(0).loadLabel(pm));
117             preference.setIntent(intent);
118         } else {
119             final String title = SubscriptionManager.getResourcesForSubId(mContext, mSubId)
120                     .getString(R.string.wifi_calling_settings_title);
121             preference.setTitle(title);
122             summaryText = getResourceIdForWfcMode(mSubId);
123         }
124         preference.setSummary(summaryText);
125         preference.setEnabled(mCallState == TelephonyManager.CALL_STATE_IDLE);
126     }
127 
getResourceIdForWfcMode(int subId)128     private CharSequence getResourceIdForWfcMode(int subId) {
129         int resId = com.android.internal.R.string.wifi_calling_off_summary;
130         if (queryImsState(subId).isEnabledByUser()) {
131             boolean useWfcHomeModeForRoaming = false;
132             if (mCarrierConfigManager != null) {
133                 final PersistableBundle carrierConfig =
134                         mCarrierConfigManager.getConfigForSubId(subId);
135                 if (carrierConfig != null) {
136                     useWfcHomeModeForRoaming = carrierConfig.getBoolean(
137                             CarrierConfigManager
138                                     .KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL);
139                 }
140             }
141             final boolean isRoaming = getTelephonyManager(mContext, subId)
142                     .isNetworkRoaming();
143             final int wfcMode = (isRoaming && !useWfcHomeModeForRoaming)
144                     ? mImsMmTelManager.getVoWiFiRoamingModeSetting() :
145                     mImsMmTelManager.getVoWiFiModeSetting();
146             switch (wfcMode) {
147                 case ImsMmTelManager.WIFI_MODE_WIFI_ONLY:
148                     resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
149                     break;
150                 case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED:
151                     resId = com.android.internal.R.string
152                             .wfc_mode_cellular_preferred_summary;
153                     break;
154                 case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED:
155                     resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
156                     break;
157                 default:
158                     break;
159             }
160         }
161         return SubscriptionManager.getResourcesForSubId(mContext, subId).getText(resId);
162     }
163 
init(int subId)164     public WifiCallingPreferenceController init(int subId) {
165         mSubId = subId;
166         mImsMmTelManager = getImsMmTelManager(mSubId);
167         mSimCallManager = mContext.getSystemService(TelecomManager.class)
168                 .getSimCallManagerForSubscription(mSubId);
169 
170         return this;
171     }
172 
173     @VisibleForTesting
queryImsState(int subId)174     WifiCallingQueryImsState queryImsState(int subId) {
175         return new WifiCallingQueryImsState(mContext, subId);
176     }
177 
getImsMmTelManager(int subId)178     protected ImsMmTelManager getImsMmTelManager(int subId) {
179         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
180             return null;
181         }
182         return ImsMmTelManager.createForSubscriptionId(subId);
183     }
184 
185     @VisibleForTesting
getTelephonyManager(Context context, int subId)186     TelephonyManager getTelephonyManager(Context context, int subId) {
187         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
188         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
189             return telephonyMgr;
190         }
191         final TelephonyManager subscriptionTelephonyMgr =
192                 telephonyMgr.createForSubscriptionId(subId);
193         return (subscriptionTelephonyMgr == null) ? telephonyMgr : subscriptionTelephonyMgr;
194     }
195 
196 
197     private class PhoneCallStateListener extends PhoneStateListener {
198 
PhoneCallStateListener()199         PhoneCallStateListener() {
200             super(Looper.getMainLooper());
201         }
202 
203         private TelephonyManager mTelephonyManager;
204 
205         @Override
onCallStateChanged(int state, String incomingNumber)206         public void onCallStateChanged(int state, String incomingNumber) {
207             mCallState = state;
208             updateState(mPreference);
209         }
210 
register(Context context, int subId)211         public void register(Context context, int subId) {
212             mTelephonyManager = getTelephonyManager(context, subId);
213             mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
214         }
215 
unregister()216         public void unregister() {
217             mCallState = null;
218             mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
219         }
220     }
221 
isWifiCallingEnabled(Context context, int subId)222     private boolean isWifiCallingEnabled(Context context, int subId) {
223         final PhoneAccountHandle simCallManager =
224                 context.getSystemService(TelecomManager.class)
225                        .getSimCallManagerForSubscription(subId);
226         final int phoneId = SubscriptionManager.getSlotIndex(subId);
227 
228         boolean isWifiCallingEnabled;
229         if (simCallManager != null) {
230             final Intent intent = MobileNetworkUtils.buildPhoneAccountConfigureIntent(
231                     context, simCallManager);
232 
233             isWifiCallingEnabled = intent != null;
234         } else {
235             isWifiCallingEnabled = queryImsState(subId).isReadyToWifiCalling();
236         }
237 
238         return isWifiCallingEnabled;
239     }
240 }
241