Improvement provisioning in AOSP
Improvement Ims provisioning in AOSP to store and handle provisioning data.
Bug: http://b/202199221
Test: atest
Change-Id: Ifd7030d3c04a036acb82a4eced19b0584ae5afc8
Merged-In: Ifd7030d3c04a036acb82a4eced19b0584ae5afc8
diff --git a/src/com/android/phone/ImsProvisioningController.java b/src/com/android/phone/ImsProvisioningController.java
new file mode 100644
index 0000000..b42f57f
--- /dev/null
+++ b/src/com/android/phone/ImsProvisioningController.java
@@ -0,0 +1,1427 @@
+/*
+ * 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.phone;
+
+import static android.telephony.ims.ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
+import static android.telephony.ims.ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
+import static android.telephony.ims.ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
+import static android.telephony.ims.ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
+import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_DISABLED;
+import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_ENABLED;
+import static android.telephony.ims.feature.ImsFeature.FEATURE_MMTEL;
+import static android.telephony.ims.feature.ImsFeature.FEATURE_RCS;
+import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER;
+import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS;
+import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT;
+import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO;
+import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
+import static android.telephony.ims.feature.RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_MAX;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyRegistryManager;
+import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.aidl.IFeatureProvisioningCallback;
+import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities;
+import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
+import android.telephony.ims.stub.ImsConfigImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.SparseArray;
+
+import com.android.ims.FeatureConnector;
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsException;
+import com.android.ims.ImsManager;
+import com.android.ims.RcsFeatureManager;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.HandlerExecutor;
+import com.android.telephony.Rlog;
+
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+
+/**
+ * Provides APIs for MMTEL and RCS provisioning status. This class handles provisioning status and
+ * notifies the status changing for each capability
+ * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
+ * {{@link RcsImsCapabilities.RcsImsCapabilityFlag} for RCS services}
+ */
+public class ImsProvisioningController {
+ private static final String TAG = "ImsProvisioningController";
+ private static final int INVALID_VALUE = -1;
+
+ private static final int EVENT_SUB_CHANGED = 1;
+ private static final int EVENT_PROVISIONING_CAPABILITY_CHANGED = 2;
+
+ // Provisioning Keys that are handled via AOSP cache and not sent to the ImsService
+ private static final int[] LOCAL_IMS_CONFIG_KEYS = {
+ KEY_VOLTE_PROVISIONING_STATUS,
+ KEY_VT_PROVISIONING_STATUS,
+ KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE,
+ KEY_EAB_PROVISIONING_STATUS
+ };
+ private static final int[] LOCAL_RADIO_TECHS = {
+ REGISTRATION_TECH_LTE,
+ REGISTRATION_TECH_IWLAN,
+ REGISTRATION_TECH_CROSS_SIM,
+ REGISTRATION_TECH_NR
+ };
+
+ private static final int MMTEL_CAPABILITY_MIN = MmTelCapabilities.CAPABILITY_TYPE_NONE;
+ private static final int MMTEL_CAPABILITY_MAX = MmTelCapabilities.CAPABILITY_TYPE_MAX;
+
+ private static final int RCS_CAPABILITY_MIN = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
+ private static final int RCS_CAPABILITY_MAX = RcsImsCapabilities.CAPABILITY_TYPE_MAX;
+
+ private static final int[] LOCAL_MMTEL_CAPABILITY = {
+ CAPABILITY_TYPE_VOICE,
+ CAPABILITY_TYPE_VIDEO,
+ CAPABILITY_TYPE_UT,
+ CAPABILITY_TYPE_SMS,
+ CAPABILITY_TYPE_CALL_COMPOSER
+ };
+
+ /**
+ * Create a FeatureConnector for this class to use to connect to an ImsManager.
+ */
+ @VisibleForTesting
+ public interface MmTelFeatureConnector {
+ /**
+ * Create a FeatureConnector for this class to use to connect to an ImsManager.
+ * @param listener will receive ImsManager instance.
+ * @param executor that the Listener callbacks will be called on.
+ * @return A FeatureConnector
+ */
+ FeatureConnector<ImsManager> create(Context context, int slotId,
+ String logPrefix, FeatureConnector.Listener<ImsManager> listener,
+ Executor executor);
+ }
+
+ /**
+ * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
+ */
+ @VisibleForTesting
+ public interface RcsFeatureConnector {
+ /**
+ * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
+ * @param listener will receive RcsFeatureManager instance.
+ * @param executor that the Listener callbacks will be called on.
+ * @return A FeatureConnector
+ */
+ FeatureConnector<RcsFeatureManager> create(Context context, int slotId,
+ FeatureConnector.Listener<RcsFeatureManager> listener,
+ Executor executor, String logPrefix);
+ }
+
+ private static ImsProvisioningController sInstance;
+
+ private final PhoneGlobals mApp;
+ private final Handler mHandler;
+ private final CarrierConfigManager mCarrierConfigManager;
+ private final SubscriptionManager mSubscriptionManager;
+ private final TelephonyRegistryManager mTelephonyRegistryManager;
+ private final MmTelFeatureConnector mMmTelFeatureConnector;
+ private final RcsFeatureConnector mRcsFeatureConnector;
+
+ // maps a slotId to a list of MmTelFeatureListeners
+ private final SparseArray<MmTelFeatureListener> mMmTelFeatureListenersSlotMap =
+ new SparseArray<>();
+ // maps a slotId to a list of RcsFeatureListeners
+ private final SparseArray<RcsFeatureListener> mRcsFeatureListenersSlotMap =
+ new SparseArray<>();
+ // map a slotId to a list of ProvisioningCallbackManager
+ private final SparseArray<ProvisioningCallbackManager> mProvisioningCallbackManagersSlotMap =
+ new SparseArray<>();
+ private final ImsProvisioningLoader mImsProvisioningLoader;
+
+ private int mNumSlot;
+
+ /**
+ * This class contains the provisioning status to notify changes.
+ * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
+ * {{@link RcsImsCapabilities.RcsImsCapabilityFlag} for RCS services}
+ * {{@link ImsRegistrationImplBase.ImsRegistrationTech} for Registration tech}
+ */
+ private static final class FeatureProvisioningData {
+ public final int mCapability;
+ public final int mTech;
+ public final boolean mProvisioned;
+ public final boolean mIsMmTel;
+
+ FeatureProvisioningData(int capability, int tech, boolean provisioned, boolean isMmTel) {
+ mCapability = capability;
+ mTech = tech;
+ mProvisioned = provisioned;
+ mIsMmTel = isMmTel;
+ }
+ }
+
+ private final class MessageHandler extends Handler {
+ private static final String LOG_PREFIX = "Handler";
+ MessageHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_SUB_CHANGED:
+ onSubscriptionsChanged();
+ break;
+ case EVENT_PROVISIONING_CAPABILITY_CHANGED:
+ try {
+ mProvisioningCallbackManagersSlotMap.get(msg.arg1)
+ .notifyProvisioningCapabilityChanged(
+ (FeatureProvisioningData) msg.obj);
+ } catch (NullPointerException e) {
+ logw(LOG_PREFIX, msg.arg1,
+ "can not find callback manager message" + msg.what);
+ }
+ break;
+ default:
+ log("unknown message " + msg);
+ break;
+ }
+ }
+ }
+
+ private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener =
+ new SubscriptionManager.OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ if (!mHandler.hasMessages(EVENT_SUB_CHANGED)) {
+ mHandler.sendEmptyMessage(EVENT_SUB_CHANGED);
+ }
+ }
+ };
+
+ private final class ProvisioningCallbackManager {
+ private static final String LOG_PREFIX = "ProvisioningCallbackManager";
+ private RemoteCallbackList<IFeatureProvisioningCallback> mIFeatureProvisioningCallbackList;
+ private int mSubId;
+ private int mSlotId;
+
+ ProvisioningCallbackManager(int slotId) {
+ mIFeatureProvisioningCallbackList =
+ new RemoteCallbackList<IFeatureProvisioningCallback>();
+ mSlotId = slotId;
+ mSubId = getSubId(slotId);
+ log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager create");
+ }
+
+ public void clear() {
+ log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager clear ");
+
+ mIFeatureProvisioningCallbackList.kill();
+
+ // All registered callbacks are unregistered, and the list is disabled
+ // need to create again
+ mIFeatureProvisioningCallbackList =
+ new RemoteCallbackList<IFeatureProvisioningCallback>();
+ }
+
+ public void registerCallback(IFeatureProvisioningCallback localCallback) {
+ if (!mIFeatureProvisioningCallbackList.register(localCallback, (Object) mSubId)) {
+ log(LOG_PREFIX, mSlotId, "registration callback fail");
+ }
+ }
+
+ public void unregisterCallback(IFeatureProvisioningCallback localCallback) {
+ mIFeatureProvisioningCallbackList.unregister(localCallback);
+ }
+
+ public void setSubId(int subId) {
+ if (mSubId == subId) {
+ log(LOG_PREFIX, mSlotId, "subId is not changed ");
+ return;
+ }
+
+ mSubId = subId;
+ mSlotId = getSlotId(subId);
+
+ // subId changed means the registered callbacks are not available.
+ clear();
+ }
+
+ public boolean hasCallblacks() {
+ int size = mIFeatureProvisioningCallbackList.beginBroadcast();
+ mIFeatureProvisioningCallbackList.finishBroadcast();
+
+ return (size > 0);
+ }
+
+ public void notifyProvisioningCapabilityChanged(FeatureProvisioningData data) {
+ int size = mIFeatureProvisioningCallbackList.beginBroadcast();
+ for (int index = 0; index < size; index++) {
+ try {
+ IFeatureProvisioningCallback imsFeatureProvisioningCallback =
+ mIFeatureProvisioningCallbackList.getBroadcastItem(index);
+
+ // MMTEL
+ if (data.mIsMmTel
+ && Arrays.stream(LOCAL_MMTEL_CAPABILITY)
+ .anyMatch(value -> value == data.mCapability)) {
+ imsFeatureProvisioningCallback.onFeatureProvisioningChanged(
+ data.mCapability, data.mTech, data.mProvisioned);
+ logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
+ + "onFeatureProvisioningChanged"
+ + " capability " + data.mCapability
+ + " tech " + data.mTech
+ + " isProvisioned " + data.mProvisioned);
+ } else if (data.mCapability == CAPABILITY_TYPE_PRESENCE_UCE) {
+ imsFeatureProvisioningCallback.onRcsFeatureProvisioningChanged(
+ data.mCapability, data.mTech, data.mProvisioned);
+ logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
+ + "onRcsFeatureProvisioningChanged"
+ + " capability " + data.mCapability
+ + " tech " + data.mTech
+ + " isProvisioned " + data.mProvisioned);
+ } else {
+ loge(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
+ + "unknown capability "
+ + data.mCapability);
+ }
+ } catch (RemoteException e) {
+ loge(LOG_PREFIX, mSlotId,
+ "notifyProvisioningChanged: callback #" + index + " failed");
+ }
+ }
+ mIFeatureProvisioningCallbackList.finishBroadcast();
+ }
+ }
+
+ private final class MmTelFeatureListener implements FeatureConnector.Listener<ImsManager> {
+ private static final String LOG_PREFIX = "MmTelFeatureListener";
+ private FeatureConnector<ImsManager> mConnector;
+ private ImsManager mImsManager;
+ private boolean mReady = false;
+ // stores whether the initial provisioning key value should be notified to ImsService
+ private boolean mRequiredNotify = false;
+ private int mSubId;
+ private int mSlotId;
+
+ MmTelFeatureListener(int slotId) {
+ log(LOG_PREFIX, slotId, "created");
+
+ mSlotId = slotId;
+ mSubId = getSubId(slotId);
+ mConnector = mMmTelFeatureConnector.create(
+ mApp, slotId, TAG, this, new HandlerExecutor(mHandler));
+ mConnector.connect();
+ }
+
+ public void setSubId(int subId) {
+ if (mRequiredNotify && mReady) {
+ mRequiredNotify = false;
+ setInitialProvisioningKeys(subId);
+ }
+ if (mSubId == subId) {
+ log(LOG_PREFIX, mSlotId, "subId is not changed");
+ return;
+ }
+
+ mSubId = subId;
+ mSlotId = getSlotId(subId);
+ }
+
+ public void destroy() {
+ log("destroy");
+ mConnector.disconnect();
+ mConnector = null;
+ mReady = false;
+ mImsManager = null;
+ }
+
+ public @Nullable ImsManager getImsManager() {
+ return mImsManager;
+ }
+
+ @Override
+ public void connectionReady(ImsManager manager, int subId) {
+ log(LOG_PREFIX, mSlotId, "connection ready");
+ mReady = true;
+ mImsManager = manager;
+
+ onMmTelAvailable();
+ }
+
+ @Override
+ public void connectionUnavailable(int reason) {
+ log(LOG_PREFIX, mSlotId, "connection unavailable " + reason);
+
+ mReady = false;
+ mImsManager = null;
+
+ // keep the callback for other reason
+ if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
+ onMmTelUnavailable();
+ }
+ }
+
+ public int setProvisioningValue(int key, int value) {
+ int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
+
+ if (!mReady) {
+ loge(LOG_PREFIX, mSlotId, "service is Unavailable");
+ return retVal;
+ }
+ try {
+ // getConfigInterface() will return not null or throw the ImsException
+ // need not null checking
+ ImsConfig imsConfig = getImsConfig(mImsManager);
+ retVal = imsConfig.setConfig(key, value);
+ log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
+ } catch (ImsException e) {
+ logw(LOG_PREFIX, mSlotId,
+ "setConfig operation failed for key =" + key
+ + ", value =" + value + ". Exception:" + e.getMessage());
+ }
+ return retVal;
+ }
+
+ public int getProvisioningValue(int key) {
+ if (!mReady) {
+ loge(LOG_PREFIX, mSlotId, "service is Unavailable");
+ return INVALID_VALUE;
+ }
+
+ int retValue = INVALID_VALUE;
+ try {
+ // getConfigInterface() will return not null or throw the ImsException
+ // need not null checking
+ ImsConfig imsConfig = getImsConfig(mImsManager);
+ retValue = imsConfig.getConfigInt(key);
+ } catch (ImsException e) {
+ logw(LOG_PREFIX, mSlotId,
+ "getConfig operation failed for key =" + key
+ + ", value =" + retValue + ". Exception:" + e.getMessage());
+ }
+ return retValue;
+ }
+
+ public void onMmTelAvailable() {
+ log(LOG_PREFIX, mSlotId, "onMmTelAvailable");
+
+ if (isValidSubId(mSubId)) {
+ mRequiredNotify = false;
+
+ // notify provisioning key value to ImsService
+ setInitialProvisioningKeys(mSubId);
+ } else {
+ // wait until subId is valid
+ mRequiredNotify = true;
+ }
+ }
+
+ public void onMmTelUnavailable() {
+ log(LOG_PREFIX, mSlotId, "onMmTelUnavailable");
+
+ try {
+ // delete all callbacks reference from ProvisioningManager
+ mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
+ } catch (NullPointerException e) {
+ logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
+ }
+ }
+
+ private void setInitialProvisioningKeys(int subId) {
+ boolean required;
+ int value = ImsProvisioningLoader.STATUS_NOT_SET;
+
+ // updating KEY_VOLTE_PROVISIONING_STATUS
+ required = isProvisioningRequired(subId, CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE,
+ /*isMmTel*/true);
+ log(LOG_PREFIX, mSlotId,
+ "setInitialProvisioningKeys provisioning required(voice, lte) " + required);
+ if (required) {
+ value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
+ CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE);
+ if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
+ value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
+ ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
+ setProvisioningValue(KEY_VOLTE_PROVISIONING_STATUS, value);
+ }
+ }
+
+ // updating KEY_VT_PROVISIONING_STATUS
+ required = isProvisioningRequired(subId, CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE,
+ /*isMmTel*/true);
+ log(LOG_PREFIX, mSlotId,
+ "setInitialProvisioningKeys provisioning required(video, lte) " + required);
+ if (required) {
+ value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
+ CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE);
+ if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
+ value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
+ ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
+ setProvisioningValue(KEY_VT_PROVISIONING_STATUS, value);
+ }
+ }
+
+ // updating KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
+ required = isProvisioningRequired(subId, CAPABILITY_TYPE_VOICE,
+ REGISTRATION_TECH_IWLAN, /*isMmTel*/true);
+ log(LOG_PREFIX, mSlotId,
+ "setInitialProvisioningKeys provisioning required(voice, iwlan) " + required);
+ if (required) {
+ value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
+ CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN);
+ if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
+ value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
+ ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
+ setProvisioningValue(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, value);
+ }
+ }
+ }
+ }
+
+ private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> {
+ private static final String LOG_PREFIX = "RcsFeatureListener";
+ private FeatureConnector<RcsFeatureManager> mConnector;
+ private RcsFeatureManager mRcsFeatureManager;
+ private boolean mReady = false;
+ // stores whether the initial provisioning key value should be notified to ImsService
+ private boolean mRequiredNotify = false;
+ private int mSubId;
+ private int mSlotId;
+
+ RcsFeatureListener(int slotId) {
+ log(LOG_PREFIX, slotId, "created");
+
+ mSlotId = slotId;
+ mSubId = getSubId(slotId);
+ mConnector = mRcsFeatureConnector.create(
+ mApp, slotId, this, new HandlerExecutor(mHandler), TAG);
+ mConnector.connect();
+ }
+
+ public void setSubId(int subId) {
+ if (mRequiredNotify && mReady) {
+ mRequiredNotify = false;
+ setInitialProvisioningKeys(subId);
+ }
+ if (mSubId == subId) {
+ log(LOG_PREFIX, mSlotId, "subId is not changed");
+ return;
+ }
+
+ mSubId = subId;
+ mSlotId = getSlotId(subId);
+ }
+
+ public void destroy() {
+ log(LOG_PREFIX, mSlotId, "destroy");
+ mConnector.disconnect();
+ mConnector = null;
+ mReady = false;
+ mRcsFeatureManager = null;
+ }
+
+ @Override
+ public void connectionReady(RcsFeatureManager manager, int subId) {
+ log(LOG_PREFIX, mSlotId, "connection ready");
+ mReady = true;
+ mRcsFeatureManager = manager;
+
+ onRcsAvailable();
+ }
+
+ @Override
+ public void connectionUnavailable(int reason) {
+ log(LOG_PREFIX, mSlotId, "connection unavailable");
+ mReady = false;
+ mRcsFeatureManager = null;
+
+ // keep the callback for other reason
+ if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
+ onRcsUnavailable();
+ }
+ }
+
+ public int setProvisioningValue(int key, int value) {
+ int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
+
+ if (!mReady) {
+ loge(LOG_PREFIX, mSlotId, "service is Unavailable");
+ return retVal;
+ }
+
+ try {
+ // getConfigInterface() will return not null or throw the ImsException
+ // need not null checking
+ ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
+ retVal = imsConfig.setConfig(key, value);
+ log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
+ } catch (ImsException e) {
+ logw(LOG_PREFIX, mSlotId,
+ "setConfig operation failed for key =" + key
+ + ", value =" + value + ". Exception:" + e.getMessage());
+ }
+ return retVal;
+ }
+
+ public int getProvisioningValue(int key) {
+ if (!mReady) {
+ loge(LOG_PREFIX, mSlotId, "service is Unavailable");
+ return INVALID_VALUE;
+ }
+
+ int retValue = INVALID_VALUE;
+ try {
+ // getConfigInterface() will return not null or throw the ImsException
+ // need not null checking
+ ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
+ retValue = imsConfig.getConfigInt(key);
+ } catch (ImsException e) {
+ logw(LOG_PREFIX, mSlotId,
+ "getConfig operation failed for key =" + key
+ + ", value =" + retValue + ". Exception:" + e.getMessage());
+ }
+ return retValue;
+ }
+
+ public void onRcsAvailable() {
+ log(LOG_PREFIX, mSlotId, "onRcsAvailable");
+
+ if (isValidSubId(mSubId)) {
+ mRequiredNotify = false;
+
+ // notify provisioning key value to ImsService
+ setInitialProvisioningKeys(mSubId);
+ } else {
+ // wait until subId is valid
+ mRequiredNotify = true;
+ }
+ }
+
+ public void onRcsUnavailable() {
+ log(LOG_PREFIX, mSlotId, "onRcsUnavailable");
+
+ try {
+ // delete all callbacks reference from ProvisioningManager
+ mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
+ } catch (NullPointerException e) {
+ logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
+ }
+ }
+
+ private void setInitialProvisioningKeys(int subId) {
+ boolean required;
+ int value = ImsProvisioningLoader.STATUS_NOT_SET;
+
+ // KEY_EAB_PROVISIONING_STATUS
+ int capability = CAPABILITY_TYPE_PRESENCE_UCE;
+ // Assume that all radio techs have the same provisioning value
+ int tech = REGISTRATION_TECH_LTE;
+
+ required = isProvisioningRequired(subId, capability, tech, /*isMmTel*/false);
+ if (required) {
+ value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
+ capability, tech);
+ if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
+ value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
+ ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
+ setProvisioningValue(KEY_EAB_PROVISIONING_STATUS, value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Do NOT use this directly, instead use {@link #getInstance()}.
+ */
+ @VisibleForTesting
+ public ImsProvisioningController(PhoneGlobals app, int numSlot, Looper looper,
+ MmTelFeatureConnector mmTelFeatureConnector, RcsFeatureConnector rcsFeatureConnector,
+ ImsProvisioningLoader imsProvisioningLoader) {
+ log("ImsProvisioningController");
+ mApp = app;
+ mNumSlot = numSlot;
+ mHandler = new MessageHandler(looper);
+ mMmTelFeatureConnector = mmTelFeatureConnector;
+ mRcsFeatureConnector = rcsFeatureConnector;
+ mCarrierConfigManager = mApp.getSystemService(CarrierConfigManager.class);
+ mSubscriptionManager = mApp.getSystemService(SubscriptionManager.class);
+ mTelephonyRegistryManager = mApp.getSystemService(TelephonyRegistryManager.class);
+ mTelephonyRegistryManager.addOnSubscriptionsChangedListener(
+ mSubChangedListener, mSubChangedListener.getHandlerExecutor());
+ mImsProvisioningLoader = imsProvisioningLoader;
+
+ initialize(numSlot);
+ }
+
+ private void initialize(int numSlot) {
+ for (int i = 0; i < numSlot; i++) {
+ MmTelFeatureListener m = new MmTelFeatureListener(i);
+ mMmTelFeatureListenersSlotMap.put(i, m);
+
+ RcsFeatureListener r = new RcsFeatureListener(i);
+ mRcsFeatureListenersSlotMap.put(i, r);
+
+ ProvisioningCallbackManager p = new ProvisioningCallbackManager(i);
+ mProvisioningCallbackManagersSlotMap.put(i, p);
+ }
+ }
+
+ /**
+ * destroy the instance
+ */
+ @VisibleForTesting
+ public void destroy() {
+ log("destroy");
+
+ mHandler.getLooper().quit();
+
+ mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener);
+
+ for (int i = 0; i < mMmTelFeatureListenersSlotMap.size(); i++) {
+ mMmTelFeatureListenersSlotMap.get(i).destroy();
+ }
+ mMmTelFeatureListenersSlotMap.clear();
+
+ for (int i = 0; i < mRcsFeatureListenersSlotMap.size(); i++) {
+ mRcsFeatureListenersSlotMap.get(i).destroy();
+ }
+ mRcsFeatureListenersSlotMap.clear();
+
+ for (int i = 0; i < mProvisioningCallbackManagersSlotMap.size(); i++) {
+ mProvisioningCallbackManagersSlotMap.get(i).clear();
+ }
+ }
+
+ /**
+ * create an instance
+ */
+ @VisibleForTesting
+ public static ImsProvisioningController make(PhoneGlobals app, int numSlot) {
+ synchronized (ImsProvisioningController.class) {
+ if (sInstance == null) {
+ Rlog.i(TAG, "ImsProvisioningController created");
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ sInstance = new ImsProvisioningController(app, numSlot, handlerThread.getLooper(),
+ ImsManager::getConnector, RcsFeatureManager::getConnector,
+ new ImsProvisioningLoader(app));
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * Gets a ImsProvisioningController instance
+ */
+ @VisibleForTesting
+ public static ImsProvisioningController getInstance() {
+ synchronized (ImsProvisioningController.class) {
+ return sInstance;
+ }
+ }
+
+ /**
+ * Register IFeatureProvisioningCallback from ProvisioningManager
+ */
+
+ @VisibleForTesting
+ public void addFeatureProvisioningChangedCallback(int subId,
+ IFeatureProvisioningCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("provisioning callback can't be null");
+ }
+ int slotId = getSlotId(subId);
+ if (slotId < 0 || slotId >= mNumSlot) {
+ throw new IllegalArgumentException("subscription id is not available");
+ }
+
+ try {
+ mProvisioningCallbackManagersSlotMap.get(slotId).registerCallback(callback);
+ log("Feature Provisioning Callback registered.");
+ } catch (NullPointerException e) {
+ logw("can not access callback manager to add callback");
+ }
+ }
+
+ /**
+ * Remove IFeatureProvisioningCallback
+ */
+ @VisibleForTesting
+ public void removeFeatureProvisioningChangedCallback(int subId,
+ IFeatureProvisioningCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("provisioning callback can't be null");
+ }
+
+ int slotId = getSlotId(subId);
+ if (slotId < 0 || slotId >= mNumSlot) {
+ throw new IllegalArgumentException("subscription id is not available");
+ }
+
+ try {
+ mProvisioningCallbackManagersSlotMap.get(slotId).unregisterCallback(callback);
+ log("Feature Provisioning Callback removed.");
+ } catch (NullPointerException e) {
+ logw("can not access callback manager to remove callback");
+ }
+ }
+
+ /**
+ * return the boolean whether MmTel capability is required provisiong or not
+ */
+ @VisibleForTesting
+ public boolean isImsProvisioningRequiredForCapability(int subId, int capability, int tech) {
+ // check subId
+ int slotId = getSlotId(subId);
+ if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
+ loge("Fail to retrieve slotId from subId");
+ throw new IllegalArgumentException("subscribe id is invalid");
+ }
+
+ // check valid capability
+ if (!(MMTEL_CAPABILITY_MIN < capability && capability < MMTEL_CAPABILITY_MAX)) {
+ throw new IllegalArgumentException("MmTel capability '" + capability + "' is invalid");
+ }
+
+ // check valid radio tech
+ if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
+ log("Ims not matched radio tech " + tech);
+ throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
+ }
+
+ boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/true);
+
+ log("isImsProvisioningRequiredForCapability capability " + capability
+ + " tech " + tech + " return value " + retVal);
+
+ return retVal;
+ }
+
+ /**
+ * return the boolean whether RCS capability is required provisiong or not
+ */
+ @VisibleForTesting
+ public boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech) {
+ // check slotId and Phone object
+ int slotId = getSlotId(subId);
+ if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
+ loge("Fail to retrieve slotId from subId");
+ throw new IllegalArgumentException("subscribe id is invalid");
+ }
+
+ // check valid capability
+ if (!(RCS_CAPABILITY_MIN < capability && capability < RCS_CAPABILITY_MAX)) {
+ throw new IllegalArgumentException("Rcs capability '" + capability + "' is invalid");
+ }
+
+ // check valid radio tech
+ if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
+ log("Rcs not matched radio tech " + tech);
+ throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
+ }
+
+ boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/false);
+
+ log("isRcsProvisioningRequiredForCapability capability " + capability
+ + " tech " + tech + " return value " + retVal);
+
+ return retVal;
+ }
+
+ /**
+ * return the provisioning status for MmTel capability in specific radio tech
+ */
+ @VisibleForTesting
+ public boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech) {
+ boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
+ if (!mmTelProvisioned) { // provisioning not required
+ log("getImsProvisioningStatusForCapability : not required "
+ + " capability " + capability + " tech " + tech);
+ return true;
+ }
+
+ // read value from ImsProvisioningLoader
+ int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
+ capability, tech);
+ if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
+ // not set means initial value
+ // read data from vendor ImsService and store that in ImsProvisioningLoader
+ result = getValueFromImsService(subId, capability, tech);
+ mmTelProvisioned = getBoolValue(result);
+ if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
+ setAndNotifyMmTelProvisioningValue(subId, capability, tech, mmTelProvisioned);
+ }
+ } else {
+ mmTelProvisioned = getBoolValue(result);
+ }
+
+ log("getImsProvisioningStatusForCapability : "
+ + " capability " + capability
+ + " tech " + tech
+ + " result " + mmTelProvisioned);
+ return mmTelProvisioned;
+ }
+
+ /**
+ * set MmTel provisioning status in specific tech
+ */
+ @VisibleForTesting
+ public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
+ boolean isProvisioned) {
+ boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
+ if (!mmTelProvisioned) { // provisioning not required
+ log("setImsProvisioningStatusForCapability : not required "
+ + " capability " + capability + " tech " + tech);
+ return;
+ }
+
+ // write value to ImsProvisioningLoader
+ boolean isChanged = setAndNotifyMmTelProvisioningValue(subId, capability, tech,
+ isProvisioned);
+ if (!isChanged) {
+ log("status not changed mmtel capability " + capability + " tech " + tech);
+ return;
+ }
+
+ int slotId = getSlotId(subId);
+ // find matched key from capability and tech
+ int value = getIntValue(isProvisioned);
+ int key = getKeyFromCapability(capability, tech);
+ if (key != INVALID_VALUE) {
+ log("setImsProvisioningStatusForCapability : matched key " + key);
+ try {
+ // set key and value to vendor ImsService for MmTel
+ mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
+
+ // notify provisioning status changed to ImsManager
+ updateImsServiceConfig(subId);
+ } catch (NullPointerException e) {
+ loge("can not access MmTelFeatureListener with capability " + capability);
+ }
+ }
+ }
+
+ /**
+ * return the provisioning status for RCS capability in specific radio tech
+ */
+ @VisibleForTesting
+ public boolean getRcsProvisioningStatusForCapability(int subId, int capability, int tech) {
+ boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
+ if (!rcsProvisioned) { // provisioning not required
+ log("getRcsProvisioningStatusForCapability : not required"
+ + " capability " + capability + " tech " + tech);
+ return true;
+ }
+
+ // read data from ImsProvisioningLoader
+ int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
+ capability, tech);
+ if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
+ // not set means initial value
+ // read data from vendor ImsService and store that in ImsProvisioningLoader
+ result = getRcsValueFromImsService(subId, capability);
+ rcsProvisioned = getBoolValue(result);
+ if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
+ setAndNotifyRcsProvisioningValueForAllTech(subId, capability, rcsProvisioned);
+ }
+ } else {
+ rcsProvisioned = getBoolValue(result);
+ }
+
+ log("getRcsProvisioningStatusForCapability : "
+ + " capability " + capability
+ + " tech " + tech
+ + " result " + rcsProvisioned);
+ return rcsProvisioned;
+ }
+
+ /**
+ * set RCS provisioning status in specific tech
+ */
+ @VisibleForTesting
+ public void setRcsProvisioningStatusForCapability(int subId, int capability, int tech,
+ boolean isProvisioned) {
+ boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
+ if (!rcsProvisioned) { // provisioning not required
+ log("set rcs provisioning status but not required");
+ return;
+ }
+
+ // write status using ImsProvisioningLoader
+ boolean isChanged = setAndNotifyRcsProvisioningValue(subId, capability, tech,
+ isProvisioned);
+ if (!isChanged) {
+ log("status not changed rcs capability " + capability + " tech " + tech);
+ return;
+ }
+
+ int slotId = getSlotId(subId);
+ int key = ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
+ int value = getIntValue(isProvisioned);
+ try {
+ // set key and value to vendor ImsService for Rcs
+ mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
+ } catch (NullPointerException e) {
+ loge("can not access RcsFeatureListener with capability " + capability);
+ }
+ }
+
+ /**
+ * set RCS provisioning status in specific key and value
+ * @param key integer key, defined as one of
+ * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
+ * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
+ * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
+ * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
+ * @param value in Integer format.
+ * @return the result of setting the configuration value, defined as one of
+ * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
+ * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
+ */
+ @VisibleForTesting
+ public int setProvisioningValue(int subId, int key, int value) {
+ log("setProvisioningValue");
+
+ int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
+ // check key value
+ if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
+ log("not matched key " + key);
+ return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+ }
+
+ // check subId
+ int slotId = getSlotId(subId);
+ if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
+ loge("Fail to retrieve slotId from subId");
+ return ImsConfigImplBase.CONFIG_RESULT_FAILED;
+ }
+
+ try {
+ if (key == KEY_EAB_PROVISIONING_STATUS) {
+ // set key and value to vendor ImsService for Rcs
+ retVal = mRcsFeatureListenersSlotMap.get(slotId)
+ .setProvisioningValue(key, value);
+ } else {
+ // set key and value to vendor ImsService for MmTel
+ retVal = mMmTelFeatureListenersSlotMap.get(slotId)
+ .setProvisioningValue(key, value);
+ }
+ } catch (NullPointerException e) {
+ loge("can not access FeatureListener to set provisioning value");
+ return ImsConfigImplBase.CONFIG_RESULT_FAILED;
+ }
+
+ // update and notify provisioning status changed capability and tech from key
+ updateCapabilityTechFromKey(subId, key, value);
+
+ if (key != KEY_EAB_PROVISIONING_STATUS) {
+ // notify provisioning status changed to ImsManager
+ updateImsServiceConfig(subId);
+ }
+
+ return retVal;
+ }
+
+ /**
+ * get RCS provisioning status in specific key and value
+ * @param key integer key, defined as one of
+ * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
+ * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
+ * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
+ * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
+ * @return the result of setting the configuration value, defined as one of
+ * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
+ * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
+ * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN}
+ */
+ @VisibleForTesting
+ public int getProvisioningValue(int subId, int key) {
+ log("getProvisioningValue");
+
+ // check key value
+ if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
+ log("not matched key " + key);
+ return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+ }
+
+ // check subId
+ int slotId = getSlotId(subId);
+ if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
+ loge("Fail to retrieve slotId from subId");
+ return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+ }
+
+ // check data from ImsProvisioningLoader
+ int capability = getCapabilityFromKey(key);
+ int tech = getTechFromKey(key);
+ int result;
+ if (capability != INVALID_VALUE && tech != INVALID_VALUE) {
+ if (key == KEY_EAB_PROVISIONING_STATUS) {
+ result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
+ capability, tech);
+ } else {
+ result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
+ capability, tech);
+ }
+ if (result != ImsProvisioningLoader.STATUS_NOT_SET) {
+ return result;
+ }
+ }
+
+ // get data from ImsService, update it in ImsProvisioningLoader
+ if (key == KEY_EAB_PROVISIONING_STATUS) {
+ result = getRcsValueFromImsService(subId, capability);
+ if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
+ logw("getProvisioningValue : fail to get data from ImsService capability"
+ + capability);
+ return result;
+ }
+ setAndNotifyRcsProvisioningValueForAllTech(subId, capability, getBoolValue(result));
+ return result;
+ } else {
+ result = getValueFromImsService(subId, capability, tech);
+ if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
+ logw("getProvisioningValue : fail to get data from ImsService capability"
+ + capability);
+ return result;
+ }
+ setAndNotifyMmTelProvisioningValue(subId, capability, tech, getBoolValue(result));
+ return result;
+ }
+ }
+
+ /**
+ * get the handler
+ */
+ @VisibleForTesting
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ private boolean isProvisioningRequired(int subId, int capability, int tech, boolean isMmTel) {
+ String[] dataArray;
+ if (isMmTel) {
+ dataArray = getMmTelStringArrayFromCarrierConfig(subId);
+ } else {
+ dataArray = getRcsStringArrayFromCarrierConfig(subId);
+ }
+ if (dataArray == null) {
+ logw("isProvisioningRequired : retrieve data from carrier config failed");
+
+ // KEY_MMTEL/RCS_REQUIRES_PROVISIONING_STRING_ARRAY is not exist in CarrierConfig that
+ // means provisioning is not required
+ return false;
+ }
+
+ // create String with capability and tech
+ String comp = capability + "," + tech;
+
+ // compare with carrier config
+ for (String data : dataArray) {
+ // existing same String {capability,tech} means provisioning required
+ if (data.replaceAll("\\s", "").equals(comp)) {
+ return true;
+ }
+ }
+
+ log("isProvisioningRequired : not matched capability " + capability + " tech " + tech);
+ return false;
+ }
+
+ @VisibleForTesting
+ protected String[] getMmTelStringArrayFromCarrierConfig(int subId) {
+ PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigByComponentForSubId(
+ CarrierConfigManager.Ims.KEY_PREFIX, subId);
+ return imsCarrierConfigs.getStringArray(
+ CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_STRING_ARRAY);
+ }
+
+ @VisibleForTesting
+ protected String[] getRcsStringArrayFromCarrierConfig(int subId) {
+ PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigByComponentForSubId(
+ CarrierConfigManager.Ims.KEY_PREFIX, subId);
+ return imsCarrierConfigs.getStringArray(
+ CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_STRING_ARRAY);
+ }
+
+ private int getValueFromImsService(int subId, int capability, int tech) {
+ int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+
+ // operation is based on capability
+ switch (capability) {
+ case CAPABILITY_TYPE_VOICE:
+ int item = (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)
+ ? ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
+ : ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
+ // read data from vendor ImsService
+ config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
+ .getProvisioningValue(item);
+ break;
+ case CAPABILITY_TYPE_VIDEO:
+ // read data from vendor ImsService
+ config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
+ .getProvisioningValue(ProvisioningManager.KEY_VT_PROVISIONING_STATUS);
+ break;
+ default:
+ log("Capability " + capability + " has been provisioning");
+ break;
+ }
+
+ return config;
+ }
+
+ private int getRcsValueFromImsService(int subId, int capability) {
+ int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+
+ if (capability == CAPABILITY_TYPE_PRESENCE_UCE) {
+ try {
+ config = mRcsFeatureListenersSlotMap.get(getSlotId(subId))
+ .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS);
+ } catch (NullPointerException e) {
+ logw("can not access RcsFeatureListener");
+ }
+ } else {
+ log("Capability " + capability + " has been provisioning");
+ }
+
+ return config;
+ }
+
+ private void onSubscriptionsChanged() {
+ for (int index = 0; index < mMmTelFeatureListenersSlotMap.size(); index++) {
+ MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(index);
+ m.setSubId(getSubId(index));
+ }
+ for (int index = 0; index < mRcsFeatureListenersSlotMap.size(); index++) {
+ RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(index);
+ r.setSubId(getSubId(index));
+ }
+ for (int index = 0; index < mProvisioningCallbackManagersSlotMap.size(); index++) {
+ ProvisioningCallbackManager m = mProvisioningCallbackManagersSlotMap.get(index);
+ m.setSubId(getSubId(index));
+ }
+ }
+
+ private void updateCapabilityTechFromKey(int subId, int key, int value) {
+ boolean isProvisioned = getBoolValue(value);
+ int capability = getCapabilityFromKey(key);
+ int tech = getTechFromKey(key);
+
+ if (capability == INVALID_VALUE || tech == INVALID_VALUE) {
+ logw("updateCapabilityTechFromKey : unknown key " + key);
+ return;
+ }
+
+ if (key == KEY_VOLTE_PROVISIONING_STATUS
+ || key == KEY_VT_PROVISIONING_STATUS
+ || key == KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE) {
+ setAndNotifyMmTelProvisioningValue(subId, capability, tech, isProvisioned);
+ }
+ if (key == KEY_EAB_PROVISIONING_STATUS) {
+ setAndNotifyRcsProvisioningValueForAllTech(subId, capability, isProvisioned);
+ }
+ }
+
+ private int getCapabilityFromKey(int key) {
+ int capability;
+ switch (key) {
+ case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
+ // intentional fallthrough
+ case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
+ capability = CAPABILITY_TYPE_VOICE;
+ break;
+ case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
+ capability = CAPABILITY_TYPE_VIDEO;
+ break;
+ case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
+ // default CAPABILITY_TYPE_PRESENCE_UCE used for KEY_EAB_PROVISIONING_STATUS
+ capability = CAPABILITY_TYPE_PRESENCE_UCE;
+ break;
+ default:
+ capability = INVALID_VALUE;
+ break;
+ }
+ return capability;
+ }
+
+ private int getTechFromKey(int key) {
+ int tech;
+ switch (key) {
+ case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
+ tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
+ break;
+ case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
+ // intentional fallthrough
+ case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
+ // intentional fallthrough
+ case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
+ tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+ break;
+ default:
+ tech = INVALID_VALUE;
+ break;
+ }
+ return tech;
+ }
+
+ private int getKeyFromCapability(int capability, int tech) {
+ int key = INVALID_VALUE;
+ if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_IWLAN) {
+ key = ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
+ } else if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_LTE) {
+ key = ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
+ } else if (capability == CAPABILITY_TYPE_VIDEO && tech == REGISTRATION_TECH_LTE) {
+ key = ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
+ }
+
+ return key;
+ }
+
+ protected int getSubId(int slotId) {
+ final int[] subIds = mSubscriptionManager.getSubscriptionIds(slotId);
+ int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ if (subIds != null && subIds.length >= 1) {
+ subId = subIds[0];
+ }
+
+ return subId;
+ }
+
+ protected int getSlotId(int subId) {
+ return mSubscriptionManager.getPhoneId(subId);
+ }
+
+ protected ImsConfig getImsConfig(ImsManager imsManager) throws ImsException {
+ return imsManager.getConfigInterface();
+ }
+
+ protected ImsConfig getImsConfig(IImsConfig iImsConfig) {
+ return new ImsConfig(iImsConfig);
+ }
+
+ private int getIntValue(boolean isProvisioned) {
+ return isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
+ : ProvisioningManager.PROVISIONING_VALUE_DISABLED;
+ }
+
+ private boolean getBoolValue(int value) {
+ return value == ProvisioningManager.PROVISIONING_VALUE_ENABLED ? true : false;
+ }
+
+ private boolean setAndNotifyMmTelProvisioningValue(int subId, int capability, int tech,
+ boolean isProvisioned) {
+ boolean changed = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_MMTEL,
+ capability, tech, isProvisioned);
+ // notify MmTel capability changed
+ if (changed) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
+ getSlotId(subId), 0, (Object) new FeatureProvisioningData(
+ capability, tech, isProvisioned, /*isMmTel*/true)));
+ }
+
+ return changed;
+ }
+
+ private boolean setAndNotifyRcsProvisioningValue(int subId, int capability, int tech,
+ boolean isProvisioned) {
+ boolean isChanged = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_RCS,
+ capability, tech, isProvisioned);
+
+ if (isChanged) {
+ int slotId = getSlotId(subId);
+
+ // notify RCS capability changed
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
+ slotId, 0, (Object) new FeatureProvisioningData(
+ capability, tech, isProvisioned, /*isMmtel*/false)));
+ }
+
+ return isChanged;
+ }
+
+ private boolean setAndNotifyRcsProvisioningValueForAllTech(int subId, int capability,
+ boolean isProvisioned) {
+ boolean isChanged = false;
+
+ for (int tech : LOCAL_RADIO_TECHS) {
+ isChanged |= setAndNotifyRcsProvisioningValue(subId, capability, tech, isProvisioned);
+ }
+
+ return isChanged;
+ }
+
+ private void updateImsServiceConfig(int subId) {
+ try {
+ ImsManager imsManager = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
+ .getImsManager();
+ imsManager.updateImsServiceConfig();
+ log("updateImsServiceConfig");
+ } catch (NullPointerException e) {
+ loge("updateImsServiceConfig : ImsService not ready");
+ }
+ }
+
+ protected boolean isValidSubId(int subId) {
+ int slotId = getSlotId(subId);
+ if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private void log(String s) {
+ Rlog.d(TAG, s);
+ }
+
+ private void log(String prefix, int slotId, String s) {
+ Rlog.d(TAG, prefix + "[" + slotId + "] " + s);
+ }
+
+ private void logi(String prefix, int slotId, String s) {
+ Rlog.i(TAG, prefix + "[" + slotId + "] " + s);
+ }
+
+ private void logw(String s) {
+ Rlog.w(TAG, s);
+ }
+
+ private void logw(String prefix, int slotId, String s) {
+ Rlog.w(TAG, prefix + "[" + slotId + "] " + s);
+ }
+
+ private void loge(String s) {
+ Rlog.e(TAG, s);
+ }
+
+ private void loge(String prefix, int slotId, String s) {
+ Rlog.e(TAG, prefix + "[" + slotId + "] " + s);
+ }
+}
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index e7cb28c..a4f405b 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -73,7 +73,6 @@
import com.android.internal.telephony.ims.ImsResolver;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
-import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccPort;
import com.android.internal.telephony.uicc.UiccProfile;
import com.android.internal.util.IndentingPrintWriter;
@@ -161,6 +160,7 @@
public PhoneInterfaceManager phoneMgr;
public ImsRcsController imsRcsController;
public ImsStateCallbackController mImsStateCallbackController;
+ public ImsProvisioningController mImsProvisioningController;
CarrierConfigLoader configLoader;
private Phone phoneInEcm;
@@ -470,6 +470,8 @@
PhoneFactory.getPhones().length);
mTelephonyRcsService.initialize();
imsRcsController.setRcsService(mTelephonyRcsService);
+ mImsProvisioningController =
+ ImsProvisioningController.make(this, PhoneFactory.getPhones().length);
}
configLoader = CarrierConfigLoader.init(this);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 3b1cfbd..9963040 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -122,6 +122,7 @@
import android.telephony.ims.RcsClientConfiguration;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.aidl.IFeatureProvisioningCallback;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsConfigCallback;
@@ -4522,6 +4523,7 @@
@Override
public void registerImsProvisioningChangedCallback(int subId, IImsConfigCallback callback) {
enforceReadPrivilegedPermission("registerImsProvisioningChangedCallback");
+
final long identity = Binder.clearCallingIdentity();
try {
if (!isImsAvailableOnDevice()) {
@@ -4542,6 +4544,7 @@
@Override
public void unregisterImsProvisioningChangedCallback(int subId, IImsConfigCallback callback) {
enforceReadPrivilegedPermission("unregisterImsProvisioningChangedCallback");
+
final long identity = Binder.clearCallingIdentity();
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
@@ -4559,6 +4562,39 @@
}
}
+ @Override
+ public void registerFeatureProvisioningChangedCallback(int subId,
+ IFeatureProvisioningCallback callback) {
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "registerFeatureProvisioningChangedCallback");
+
+ final long identity = Binder.clearCallingIdentity();
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+
+ ImsProvisioningController.getInstance()
+ .addFeatureProvisioningChangedCallback(subId, callback);
+
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ @Override
+ public void unregisterFeatureProvisioningChangedCallback(int subId,
+ IFeatureProvisioningCallback callback) {
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "unregisterFeatureProvisioningChangedCallback");
+
+ final long identity = Binder.clearCallingIdentity();
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+
+ ImsProvisioningController.getInstance()
+ .removeFeatureProvisioningChangedCallback(subId, callback);
+
+ Binder.restoreCallingIdentity(identity);
+ }
private void checkModifyPhoneStatePermission(int subId, String message) {
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
@@ -4585,60 +4621,30 @@
}
@Override
- public void setRcsProvisioningStatusForCapability(int subId, int capability,
+ public void setRcsProvisioningStatusForCapability(int subId, int capability, int tech,
boolean isProvisioned) {
checkModifyPhoneStatePermission(subId, "setRcsProvisioningStatusForCapability");
final long identity = Binder.clearCallingIdentity();
try {
- // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
- if (!isImsProvisioningRequired(subId, capability, false)) {
- return;
- }
-
- // this capability requires provisioning, route to the correct API.
- ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
- switch (capability) {
- case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE:
- case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
- ims.setEabProvisioned(isProvisioned);
- break;
- default: {
- throw new IllegalArgumentException("Tried to set provisioning for "
- + "rcs capability '" + capability + "', which does not require "
- + "provisioning.");
- }
- }
+ ImsProvisioningController.getInstance()
+ .setRcsProvisioningStatusForCapability(subId, capability, tech, isProvisioned);
+ return;
} finally {
Binder.restoreCallingIdentity(identity);
}
-
}
@Override
- public boolean getRcsProvisioningStatusForCapability(int subId, int capability) {
- enforceReadPrivilegedPermission("getRcsProvisioningStatusForCapability");
+ public boolean getRcsProvisioningStatusForCapability(int subId, int capability, int tech) {
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getRcsProvisioningStatusForCapability");
+
final long identity = Binder.clearCallingIdentity();
try {
- // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
- if (!isImsProvisioningRequired(subId, capability, false)) {
- return true;
- }
-
- ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
- switch (capability) {
- case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE:
- case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
- return ims.isEabProvisionedOnDevice();
-
- default: {
- throw new IllegalArgumentException("Tried to get rcs provisioning for "
- + "capability '" + capability + "', which does not require "
- + "provisioning.");
- }
- }
-
+ return ImsProvisioningController.getInstance()
+ .getRcsProvisioningStatusForCapability(subId, capability, tech);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4647,66 +4653,12 @@
@Override
public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
boolean isProvisioned) {
- if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_NR
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
- throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
- }
checkModifyPhoneStatePermission(subId, "setImsProvisioningStatusForCapability");
+
final long identity = Binder.clearCallingIdentity();
try {
- // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
- if (!isImsProvisioningRequired(subId, capability, true)) {
- return;
- }
- if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_NR
- || tech == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
- loge("setImsProvisioningStatusForCapability: called for technology that does "
- + "not support provisioning - " + tech);
- return;
- }
-
- // this capability requires provisioning, route to the correct API.
- ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
- switch (capability) {
- case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE: {
- if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
- ims.setVolteProvisioned(isProvisioned);
- } else if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
- ims.setWfcProvisioned(isProvisioned);
- }
- break;
- }
- case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO: {
- // There is currently no difference in VT provisioning type.
- ims.setVtProvisioned(isProvisioned);
- break;
- }
- case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT: {
- // There is no "deprecated" UT provisioning mechanism through ImsConfig, so
- // change the capability of the feature instead if needed.
- if (isMmTelCapabilityProvisionedInCache(subId, capability, tech)
- == isProvisioned) {
- // No change in provisioning.
- return;
- }
- cacheMmTelCapabilityProvisioning(subId, capability, tech, isProvisioned);
- try {
- ims.changeMmTelCapability(isProvisioned, capability, tech);
- } catch (com.android.ims.ImsException e) {
- loge("setImsProvisioningStatusForCapability: couldn't change UT capability"
- + ", Exception" + e.getMessage());
- }
- break;
- }
- default: {
- throw new IllegalArgumentException("Tried to set provisioning for "
- + "MmTel capability '" + capability + "', which does not require "
- + "provisioning. ");
- }
- }
-
+ ImsProvisioningController.getInstance()
+ .setImsProvisioningStatusForCapability(subId, capability, tech, isProvisioned);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4714,54 +4666,13 @@
@Override
public boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech) {
- if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_NR
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
- throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
- }
- enforceReadPrivilegedPermission("getProvisioningStatusForCapability");
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getProvisioningStatusForCapability");
+
final long identity = Binder.clearCallingIdentity();
try {
- // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
- if (!isImsProvisioningRequired(subId, capability, true)) {
- return true;
- }
-
- if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_NR
- || tech == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
- loge("getImsProvisioningStatusForCapability: called for technology that does "
- + "not support provisioning - " + tech);
- return true;
- }
-
- ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
- switch (capability) {
- case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE: {
- if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
- return ims.isVolteProvisionedOnDevice();
- } else if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
- return ims.isWfcProvisionedOnDevice();
- }
- // This should never happen, since we are checking tech above to make sure it
- // is either LTE or IWLAN.
- throw new IllegalArgumentException("Invalid radio technology for voice "
- + "capability.");
- }
- case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO: {
- // There is currently no difference in VT provisioning type.
- return ims.isVtProvisionedOnDevice();
- }
- case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT: {
- // There is no "deprecated" UT provisioning mechanism, so get from shared prefs.
- return isMmTelCapabilityProvisionedInCache(subId, capability, tech);
- }
- default: {
- throw new IllegalArgumentException(
- "Tried to get provisioning for MmTel capability '" + capability
- + "', which does not require provisioning.");
- }
- }
+ return ImsProvisioningController.getInstance()
+ .getImsProvisioningStatusForCapability(subId, capability, tech);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -4769,61 +4680,31 @@
}
@Override
- public boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech) {
- if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
- throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
+ public boolean isProvisioningRequiredForCapability(int subId, int capability, int tech) {
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isProvisioningRequiredForCapability");
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return ImsProvisioningController.getInstance()
+ .isImsProvisioningRequiredForCapability(subId, capability, tech);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- enforceReadPrivilegedPermission("isMmTelCapabilityProvisionedInCache");
- int provisionedBits = getMmTelCapabilityProvisioningBitfield(subId, tech);
- return (provisionedBits & capability) > 0;
}
@Override
- public void cacheMmTelCapabilityProvisioning(int subId, int capability, int tech,
- boolean isProvisioned) {
- if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
- && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
- throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
- }
- TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
- "setProvisioningStatusForCapability");
- int provisionedBits = getMmTelCapabilityProvisioningBitfield(subId, tech);
- // If the current provisioning status for capability already matches isProvisioned,
- // do nothing.
- if (((provisionedBits & capability) > 0) == isProvisioned) {
- return;
- }
- if (isProvisioned) {
- setMmTelCapabilityProvisioningBitfield(subId, tech, (provisionedBits | capability));
- } else {
- setMmTelCapabilityProvisioningBitfield(subId, tech, (provisionedBits & ~capability));
- }
- }
+ public boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech) {
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isProvisioningRequiredForCapability");
- /**
- * @return the bitfield containing the MmTel provisioning for the provided subscription and
- * technology. The bitfield should mirror the bitfield defined by
- * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
- */
- private int getMmTelCapabilityProvisioningBitfield(int subId, int tech) {
- String key = getMmTelProvisioningKey(subId, tech);
- // Default is no capabilities are provisioned.
- return mTelephonySharedPreferences.getInt(key, 0 /*default*/);
- }
-
- /**
- * Sets the MmTel capability provisioning bitfield (defined by
- * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}) for the subscription and
- * technology specified.
- *
- * Note: This is a synchronous command and should not be called on UI thread.
- */
- private void setMmTelCapabilityProvisioningBitfield(int subId, int tech, int newField) {
- final SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
- String key = getMmTelProvisioningKey(subId, tech);
- editor.putInt(key, newField);
- editor.commit();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return ImsProvisioningController.getInstance()
+ .isRcsProvisioningRequiredForCapability(subId, capability, tech);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
private static String getMmTelProvisioningKey(int subId, int tech) {
@@ -4896,7 +4777,9 @@
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription id '" + subId + "'");
}
- enforceReadPrivilegedPermission("getImsProvisioningInt");
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getImsProvisioningInt");
+
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -4906,6 +4789,12 @@
+ subId + "' for key:" + key);
return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
}
+
+ int retVal = ImsProvisioningController.getInstance().getProvisioningValue(subId, key);
+ if (retVal != ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
+ return retVal;
+ }
+
return ImsManager.getInstance(mApp, slotId).getConfigInt(key);
} catch (com.android.ims.ImsException e) {
Log.w(LOG_TAG, "getImsProvisioningInt: ImsService is not available for subscription '"
@@ -4921,7 +4810,9 @@
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription id '" + subId + "'");
}
- enforceReadPrivilegedPermission("getImsProvisioningString");
+ TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getImsProvisioningString");
+
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -4948,6 +4839,7 @@
}
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
"setImsProvisioningInt");
+
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -4957,6 +4849,13 @@
+ subId + "' for key:" + key);
return ImsConfigImplBase.CONFIG_RESULT_FAILED;
}
+
+ int retVal = ImsProvisioningController.getInstance()
+ .setProvisioningValue(subId, key, value);
+ if (retVal != ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
+ return retVal;
+ }
+
return ImsManager.getInstance(mApp, slotId).setConfig(key, value);
} catch (com.android.ims.ImsException | RemoteException e) {
Log.w(LOG_TAG, "setImsProvisioningInt: ImsService unavailable for sub '" + subId