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