1 /*
2  * Copyright (C) 2021 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.imsserviceentitlement.utils;
18 
19 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
20 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR;
21 
22 import android.content.Context;
23 import android.os.AsyncTask;
24 import android.os.PersistableBundle;
25 import android.telephony.CarrierConfigManager;
26 import android.telephony.ims.ImsMmTelManager;
27 import android.telephony.ims.ProvisioningManager;
28 import android.util.Log;
29 import android.util.SparseArray;
30 
31 import androidx.annotation.GuardedBy;
32 import androidx.annotation.Nullable;
33 
34 import com.google.common.annotations.VisibleForTesting;
35 
36 /** A helper class for IMS relevant APIs with subscription id. */
37 public class ImsUtils {
38     private static final String TAG = "IMSSE-ImsUtils";
39 
40     @Nullable private final PersistableBundle mCarrierConfigs;
41     private final ImsMmTelManager mImsMmTelManager;
42     private final ProvisioningManager mProvisioningManager;
43 
44     /**
45      * Turns Volte provisioning status ON/OFF.
46      * Value is in Integer format. ON (1), OFF(0).
47      * Key is from {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}.
48      */
49     private static final int KEY_VOLTE_PROVISIONING_STATUS = 10;
50 
51     /**
52      * Turns SMS over IP ON/OFF on the device.
53      * Value is in Integer format. ON (1), OFF(0).
54      * Key is from {@link ProvisioningManager#KEY_SMS_OVER_IP_ENABLED}.
55      */
56     private static final int KEY_SMS_OVER_IP_ENABLED = 14;
57 
58     /**
59      * Enable voice over wifi on device.
60      * Value is in Integer format. Enabled (1), or Disabled (0).
61      * Key is from {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}.
62      */
63     private static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28;
64 
65     // Cache subscription id associated {@link ImsUtils} objects for reusing.
66     @GuardedBy("ImsUtils.class")
67     private static SparseArray<ImsUtils> sInstances = new SparseArray<ImsUtils>();
68 
ImsUtils(Context context, int subId)69     private ImsUtils(Context context, int subId) {
70         this(
71                 context.getSystemService(CarrierConfigManager.class).getConfigForSubId(subId),
72                 getImsMmTelManager(subId),
73                 getProvisioningManager(subId));
74     }
75 
76     @VisibleForTesting
ImsUtils( PersistableBundle carrierConfigs, ImsMmTelManager imsMmTelManager, ProvisioningManager provisioningManager)77     ImsUtils(
78             PersistableBundle carrierConfigs,
79             ImsMmTelManager imsMmTelManager,
80             ProvisioningManager provisioningManager) {
81         mCarrierConfigs = carrierConfigs;
82         mImsMmTelManager = imsMmTelManager;
83         mProvisioningManager = provisioningManager;
84     }
85 
86     /** Returns {@link ImsUtils} instance. */
getInstance(Context context, int subId)87     public static synchronized ImsUtils getInstance(Context context, int subId) {
88         ImsUtils instance = sInstances.get(subId);
89         if (instance != null) {
90             return instance;
91         }
92 
93         instance = new ImsUtils(context, subId);
94         sInstances.put(subId, instance);
95         return instance;
96     }
97 
98     /** Changes persistent WFC enabled setting. */
setWfcSetting(boolean enabled)99     private void setWfcSetting(boolean enabled) {
100         try {
101             mImsMmTelManager.setVoWiFiSettingEnabled(enabled);
102         } catch (RuntimeException e) {
103             // ignore this exception, possible exception should be NullPointerException or
104             // RemoteException.
105         }
106     }
107 
108     /** Sets whether VoWiFi is provisioned. */
setVowifiProvisioned(boolean value)109     public void setVowifiProvisioned(boolean value) {
110         try {
111             mProvisioningManager.setProvisioningIntValue(
112                     KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, value
113                             ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
114                             : ProvisioningManager.PROVISIONING_VALUE_DISABLED);
115         } catch (RuntimeException e) {
116             // ignore this exception, possible exception should be NullPointerException or
117             // RemoteException.
118         }
119     }
120 
121     /** Sets whether Volte is provisioned. */
setVolteProvisioned(boolean value)122     public void setVolteProvisioned(boolean value) {
123         try {
124             mProvisioningManager.setProvisioningIntValue(
125                     KEY_VOLTE_PROVISIONING_STATUS, value
126                             ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
127                             : ProvisioningManager.PROVISIONING_VALUE_DISABLED);
128         } catch (RuntimeException e) {
129             // ignore this exception, possible exception should be NullPointerException or
130             // RemoteException.
131         }
132     }
133 
134     /** Sets whether Vonr is provisioned. */
setVonrProvisioned(boolean value)135     public void setVonrProvisioned(boolean value) {
136         setProvisioningIntValue(CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_NR, value);
137     }
138 
139     /** Sets whether SMSoIP is provisioned. */
setSmsoipProvisioned(boolean value)140     public void setSmsoipProvisioned(boolean value) {
141         try {
142             mProvisioningManager.setProvisioningIntValue(
143                     KEY_SMS_OVER_IP_ENABLED, value
144                             ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
145                             : ProvisioningManager.PROVISIONING_VALUE_DISABLED);
146         } catch (RuntimeException e) {
147             // ignore this exception, possible exception should be NullPointerException or
148             // RemoteException.
149         }
150     }
151 
setProvisioningIntValue(int capability, int tech, boolean provisioned)152     private void setProvisioningIntValue(int capability, int tech, boolean provisioned) {
153         try {
154             mProvisioningManager.setProvisioningStatusForCapability(capability, tech, provisioned);
155         } catch (RuntimeException e) {
156             // ignore this exception, possible exception should be NullPointerException or
157             // RemoteException.
158         }
159     }
160 
161     /** Disables WFC and reset WFC mode to carrier default value */
162     @VisibleForTesting
disableAndResetVoWiFiImsSettings()163     void disableAndResetVoWiFiImsSettings() {
164         try {
165             disableWfc();
166 
167             // Reset WFC mode to carrier default value
168             if (mCarrierConfigs != null) {
169                 mImsMmTelManager.setVoWiFiModeSetting(
170                         mCarrierConfigs.getInt(
171                                 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
172                 mImsMmTelManager.setVoWiFiRoamingModeSetting(
173                         mCarrierConfigs.getInt(
174                                 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT));
175             }
176         } catch (RuntimeException e) {
177             // ignore this exception, possible exception should be NullPointerException or
178             // RemoteException.
179         }
180     }
181 
182     /**
183      * Returns {@link ImsMmTelManager} with specific subscription id.
184      * Returns {@code null} if provided subscription id invalid.
185      */
186     @Nullable
getImsMmTelManager(int subId)187     private static ImsMmTelManager getImsMmTelManager(int subId) {
188         try {
189             return ImsMmTelManager.createForSubscriptionId(subId);
190         } catch (IllegalArgumentException e) {
191             Log.e(TAG, "Can't get ImsMmTelManager, IllegalArgumentException: subId = " + subId);
192         }
193 
194         return null;
195     }
196 
197     /**
198      * Returns {@link ProvisioningManager} with specific subscription id.
199      * Returns {@code null} if provided subscription id invalid.
200      */
201     @Nullable
getProvisioningManager(int subId)202     private static ProvisioningManager getProvisioningManager(int subId) {
203         try {
204             return ProvisioningManager.createForSubscriptionId(subId);
205         } catch (IllegalArgumentException e) {
206             Log.e(TAG, "Can't get ProvisioningManager, IllegalArgumentException: subId = " + subId);
207         }
208         return null;
209     }
210 
211     /** Returns whether WFC is enabled by user for current subId */
isWfcEnabledByUser()212     public boolean isWfcEnabledByUser() {
213         try {
214             return mImsMmTelManager.isVoWiFiSettingEnabled();
215         } catch (RuntimeException e) {
216             // ignore this exception, possible exception should be NullPointerException or
217             // RemoteException.
218         }
219         return false;
220     }
221 
222     /** Calls {@link #disableAndResetVoWiFiImsSettings()} in background thread. */
turnOffWfc(Runnable action)223     public void turnOffWfc(Runnable action) {
224         new AsyncTask<Void, Void, Void>() {
225             @Override
226             protected Void doInBackground(Void... params) {
227                 disableAndResetVoWiFiImsSettings();
228                 return null; // To satisfy compiler
229             }
230 
231             @Override
232             protected void onPostExecute(Void result) {
233                 action.run();
234             }
235         }.execute();
236     }
237 
238     /** Disables WFC */
disableWfc()239     public void disableWfc() {
240         setWfcSetting(false);
241     }
242 }
243