/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.imsserviceentitlement.utils; import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR; import android.content.Context; import android.os.AsyncTask; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.ProvisioningManager; import android.util.Log; import android.util.SparseArray; import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; import com.google.common.annotations.VisibleForTesting; /** A helper class for IMS relevant APIs with subscription id. */ public class ImsUtils { private static final String TAG = "IMSSE-ImsUtils"; @Nullable private final PersistableBundle mCarrierConfigs; private final ImsMmTelManager mImsMmTelManager; private final ProvisioningManager mProvisioningManager; /** * Turns Volte provisioning status ON/OFF. * Value is in Integer format. ON (1), OFF(0). * Key is from {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}. */ private static final int KEY_VOLTE_PROVISIONING_STATUS = 10; /** * Turns SMS over IP ON/OFF on the device. * Value is in Integer format. ON (1), OFF(0). * Key is from {@link ProvisioningManager#KEY_SMS_OVER_IP_ENABLED}. */ private static final int KEY_SMS_OVER_IP_ENABLED = 14; /** * Enable voice over wifi on device. * Value is in Integer format. Enabled (1), or Disabled (0). * Key is from {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}. */ private static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; // Cache subscription id associated {@link ImsUtils} objects for reusing. @GuardedBy("ImsUtils.class") private static SparseArray sInstances = new SparseArray(); private ImsUtils(Context context, int subId) { this( context.getSystemService(CarrierConfigManager.class).getConfigForSubId(subId), getImsMmTelManager(subId), getProvisioningManager(subId)); } @VisibleForTesting ImsUtils( PersistableBundle carrierConfigs, ImsMmTelManager imsMmTelManager, ProvisioningManager provisioningManager) { mCarrierConfigs = carrierConfigs; mImsMmTelManager = imsMmTelManager; mProvisioningManager = provisioningManager; } /** Returns {@link ImsUtils} instance. */ public static synchronized ImsUtils getInstance(Context context, int subId) { ImsUtils instance = sInstances.get(subId); if (instance != null) { return instance; } instance = new ImsUtils(context, subId); sInstances.put(subId, instance); return instance; } /** Changes persistent WFC enabled setting. */ private void setWfcSetting(boolean enabled) { try { mImsMmTelManager.setVoWiFiSettingEnabled(enabled); } catch (RuntimeException e) { // ignore this exception, possible exception should be NullPointerException or // RemoteException. } } /** Sets whether VoWiFi is provisioned. */ public void setVowifiProvisioned(boolean value) { try { mProvisioningManager.setProvisioningIntValue( KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, value ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : ProvisioningManager.PROVISIONING_VALUE_DISABLED); } catch (RuntimeException e) { // ignore this exception, possible exception should be NullPointerException or // RemoteException. } } /** Sets whether Volte is provisioned. */ public void setVolteProvisioned(boolean value) { try { mProvisioningManager.setProvisioningIntValue( KEY_VOLTE_PROVISIONING_STATUS, value ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : ProvisioningManager.PROVISIONING_VALUE_DISABLED); } catch (RuntimeException e) { // ignore this exception, possible exception should be NullPointerException or // RemoteException. } } /** Sets whether Vonr is provisioned. */ public void setVonrProvisioned(boolean value) { setProvisioningIntValue(CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_NR, value); } /** Sets whether SMSoIP is provisioned. */ public void setSmsoipProvisioned(boolean value) { try { mProvisioningManager.setProvisioningIntValue( KEY_SMS_OVER_IP_ENABLED, value ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : ProvisioningManager.PROVISIONING_VALUE_DISABLED); } catch (RuntimeException e) { // ignore this exception, possible exception should be NullPointerException or // RemoteException. } } private void setProvisioningIntValue(int capability, int tech, boolean provisioned) { try { mProvisioningManager.setProvisioningStatusForCapability(capability, tech, provisioned); } catch (RuntimeException e) { // ignore this exception, possible exception should be NullPointerException or // RemoteException. } } /** Disables WFC and reset WFC mode to carrier default value */ @VisibleForTesting void disableAndResetVoWiFiImsSettings() { try { disableWfc(); // Reset WFC mode to carrier default value if (mCarrierConfigs != null) { mImsMmTelManager.setVoWiFiModeSetting( mCarrierConfigs.getInt( CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT)); mImsMmTelManager.setVoWiFiRoamingModeSetting( mCarrierConfigs.getInt( CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT)); } } catch (RuntimeException e) { // ignore this exception, possible exception should be NullPointerException or // RemoteException. } } /** * Returns {@link ImsMmTelManager} with specific subscription id. * Returns {@code null} if provided subscription id invalid. */ @Nullable private static ImsMmTelManager getImsMmTelManager(int subId) { try { return ImsMmTelManager.createForSubscriptionId(subId); } catch (IllegalArgumentException e) { Log.e(TAG, "Can't get ImsMmTelManager, IllegalArgumentException: subId = " + subId); } return null; } /** * Returns {@link ProvisioningManager} with specific subscription id. * Returns {@code null} if provided subscription id invalid. */ @Nullable private static ProvisioningManager getProvisioningManager(int subId) { try { return ProvisioningManager.createForSubscriptionId(subId); } catch (IllegalArgumentException e) { Log.e(TAG, "Can't get ProvisioningManager, IllegalArgumentException: subId = " + subId); } return null; } /** Returns whether WFC is enabled by user for current subId */ public boolean isWfcEnabledByUser() { try { return mImsMmTelManager.isVoWiFiSettingEnabled(); } catch (RuntimeException e) { // ignore this exception, possible exception should be NullPointerException or // RemoteException. } return false; } /** Calls {@link #disableAndResetVoWiFiImsSettings()} in background thread. */ public void turnOffWfc(Runnable action) { new AsyncTask() { @Override protected Void doInBackground(Void... params) { disableAndResetVoWiFiImsSettings(); return null; // To satisfy compiler } @Override protected void onPostExecute(Void result) { action.run(); } }.execute(); } /** Disables WFC */ public void disableWfc() { setWfcSetting(false); } }