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