RCS Provisioning APIs for Single Registration
Bug: 154864150
Test: atest FrameworksTelephonyTests:com.telephony.ims.RcsConfigTest
Test: atest TeleServiceTests:RcsProvisioningMonitorTest
Test: atest TelephonyProviderTests:TelephonyDatabaseHelperTest
Test: atest CtsTelephonyTestCases:android.telephony.ims.cts.ImsServiceTest
Change-Id: I60026b26758ffe2aa233f1c110e23c24579bd1b4
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 03d5afe..3ad702a 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -360,6 +360,7 @@
defaultImsRcsPackage, PhoneFactory.getPhones().length,
new ImsFeatureBinderRepository());
mImsResolver.initialize();
+ RcsProvisioningMonitor.make(this);
}
// Start TelephonyDebugService After the default phone is created.
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 2f37870..296e96b 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -108,12 +108,14 @@
import android.telephony.gba.UaSecurityProtocolIdentifier;
import android.telephony.ims.ImsException;
import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.RcsClientConfiguration;
import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsConfigCallback;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.feature.RcsFeature;
@@ -9085,15 +9087,19 @@
isCompressed) {
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
mApp, subId, "notifyRcsAutoConfigurationReceived");
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+ if (!isImsAvailableOnDevice()) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS not available on device.");
+ }
+
+ final long identity = Binder.clearCallingIdentity();
try {
- IImsConfig configBinder = getImsConfig(getSlotIndex(subId), ImsFeature.FEATURE_RCS);
- if (configBinder == null) {
- Rlog.e(LOG_TAG, "null result for getImsConfig");
- } else {
- configBinder.notifyRcsAutoConfigurationReceived(config, isCompressed);
- }
- } catch (RemoteException e) {
- Rlog.e(LOG_TAG, "fail to getImsConfig " + e.getMessage());
+ RcsProvisioningMonitor.getInstance().updateConfig(subId, config, isCompressed);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
@@ -9531,4 +9537,184 @@
}
return instance;
}
+
+ /**
+ * indicate whether the device and the carrier can support
+ * RCS VoLTE single registration.
+ */
+ @Override
+ public boolean isRcsVolteSingleRegistrationCapable(int subId) {
+ enforceReadPrivilegedPermission("isRcsVolteSingleRegistrationCapable");
+
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ RcsProvisioningMonitor rpm = RcsProvisioningMonitor.getInstance();
+ if (rpm != null) {
+ return rpm.isRcsVolteSingleRegistrationEnabled(subId);
+ }
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Register RCS provisioning callback.
+ */
+ @Override
+ public void registerRcsProvisioningChangedCallback(int subId,
+ IRcsConfigCallback callback) {
+ enforceReadPrivilegedPermission("registerRcsProvisioningChangedCallback");
+
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+ if (!isImsAvailableOnDevice()) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS not available on device.");
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
+ .addRcsProvisioningCallbackForSubscription(callback, subId);
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Unregister RCS provisioning callback.
+ */
+ @Override
+ public void unregisterRcsProvisioningChangedCallback(int subId,
+ IRcsConfigCallback callback) {
+ enforceReadPrivilegedPermission("unregisterRcsProvisioningChangedCallback");
+
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+ if (!isImsAvailableOnDevice()) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS not available on device.");
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
+ .removeRcsProvisioningCallbackForSubscription(callback, subId);
+ } catch (ImsException e) {
+ Log.i(LOG_TAG, "unregisterRcsProvisioningChangedCallback: " + subId
+ + "is inactive, ignoring unregister.");
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * trigger RCS reconfiguration.
+ */
+ public void triggerRcsReconfiguration(int subId) {
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ mApp, subId, "triggerRcsReconfiguration");
+
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+ if (!isImsAvailableOnDevice()) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS not available on device.");
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ RcsProvisioningMonitor.getInstance().requestReconfig(subId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Provide the client configuration parameters of the RCS application.
+ */
+ public void setRcsClientConfiguration(int subId, RcsClientConfiguration rcc) {
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ mApp, subId, "setRcsClientConfiguration");
+
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
+ }
+ if (!isImsAvailableOnDevice()) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS not available on device.");
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+
+ try {
+ IImsConfig configBinder = getImsConfig(getSlotIndex(subId), ImsFeature.FEATURE_RCS);
+ if (configBinder == null) {
+ Rlog.e(LOG_TAG, "null result for setRcsClientConfiguration");
+ } else {
+ configBinder.setRcsClientConfiguration(rcc);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(LOG_TAG, "fail to setRcsClientConfiguration " + e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Overrides the config of RCS VoLTE single registration enabled for the device.
+ */
+ @Override
+ public void setDeviceSingleRegistrationEnabledOverride(String enabledStr) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "setDeviceSingleRegistrationEnabledOverride");
+ enforceModifyPermission();
+
+ Boolean enabled = "NULL".equalsIgnoreCase(enabledStr) ? null
+ : Boolean.parseBoolean(enabledStr);
+ RcsProvisioningMonitor.getInstance().overrideDeviceSingleRegistrationEnabled(enabled);
+ }
+
+ /**
+ * Gets the config of RCS VoLTE single registration enabled for the device.
+ */
+ @Override
+ public boolean getDeviceSingleRegistrationEnabled() {
+ enforceReadPrivilegedPermission("getDeviceSingleRegistrationEnabled");
+ return RcsProvisioningMonitor.getInstance().getDeviceSingleRegistrationEnabled();
+ }
+
+ /**
+ * Overrides the config of RCS VoLTE single registration enabled for the carrier/subscription.
+ */
+ @Override
+ public boolean setCarrierSingleRegistrationEnabledOverride(int subId, String enabledStr) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "setCarrierSingleRegistrationEnabledOverride");
+ enforceModifyPermission();
+
+ Boolean enabled = "NULL".equalsIgnoreCase(enabledStr) ? null
+ : Boolean.parseBoolean(enabledStr);
+ return RcsProvisioningMonitor.getInstance().overrideCarrierSingleRegistrationEnabled(
+ subId, enabled);
+ }
+
+ /**
+ * Gets the config of RCS VoLTE single registration enabled for the carrier/subscription.
+ */
+ @Override
+ public boolean getCarrierSingleRegistrationEnabled(int subId) {
+ enforceReadPrivilegedPermission("getCarrierSingleRegistrationEnabled");
+ return RcsProvisioningMonitor.getInstance().getCarrierSingleRegistrationEnabled(subId);
+ }
}
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
new file mode 100644
index 0000000..8e4d35e
--- /dev/null
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2020 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 android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyRegistryManager;
+import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.RcsConfig;
+import android.telephony.ims.aidl.IImsConfig;
+import android.telephony.ims.feature.ImsFeature;
+import android.text.TextUtils;
+
+import com.android.ims.ImsManager;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
+import com.android.telephony.Rlog;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Class to monitor RCS Provisioning Status
+ */
+public class RcsProvisioningMonitor {
+ private static final String TAG = "RcsProvisioningMonitor";
+ private static final boolean DBG = Build.IS_ENG;
+
+ private static final int EVENT_SUB_CHANGED = 1;
+ private static final int EVENT_DMA_CHANGED = 2;
+ private static final int EVENT_CC_CHANGED = 3;
+ private static final int EVENT_CONFIG_RECEIVED = 4;
+ private static final int EVENT_RECONFIG_REQUEST = 5;
+ private static final int EVENT_DEVICE_CONFIG_OVERRIDE = 6;
+ private static final int EVENT_CARRIER_CONFIG_OVERRIDE = 7;
+
+ private final PhoneGlobals mPhone;
+ private final Handler mHandler;
+ //cache the rcs config per sub id
+ private final Map<Integer, byte[]> mConfigs = Collections.synchronizedMap(new HashMap<>());
+ //cache the single registration config per sub id
+ private final ConcurrentHashMap<Integer, Integer> mSingleRegistrations =
+ new ConcurrentHashMap<>();
+ private Boolean mDeviceSingleRegistrationEnabledOverride;
+ private final HashMap<Integer, Boolean> mCarrierSingleRegistrationEnabledOverride =
+ new HashMap<>();
+ private String mDmaPackageName;
+
+ private final CarrierConfigManager mCarrierConfigManager;
+ private final DmaChangedListener mDmaChangedListener;
+ private final SubscriptionManager mSubscriptionManager;
+ private final TelephonyRegistryManager mTelephonyRegistryManager;
+
+ private static RcsProvisioningMonitor sInstance;
+
+ 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 BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(
+ intent.getAction())) {
+ int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ logv("Carrier-config changed for sub : " + subId);
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && !mHandler.hasMessages(EVENT_CC_CHANGED)) {
+ mHandler.sendEmptyMessage(EVENT_CC_CHANGED);
+ }
+ }
+ }
+ };
+
+ private final class DmaChangedListener implements OnRoleHoldersChangedListener {
+ private RoleManager mRoleManager;
+
+ @Override
+ public void onRoleHoldersChanged(String role, UserHandle user) {
+ if (RoleManager.ROLE_SMS.equals(role)) {
+ logv("default messaging application changed.");
+ String packageName = getDmaPackageName();
+ mHandler.sendEmptyMessage(EVENT_DMA_CHANGED);
+ }
+ }
+
+ public void register() {
+ mRoleManager = mPhone.getSystemService(RoleManager.class);
+ if (mRoleManager != null) {
+ try {
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(
+ mPhone.getMainExecutor(), this, UserHandle.SYSTEM);
+ } catch (RuntimeException e) {
+ loge("Could not register dma change listener due to " + e);
+ }
+ }
+ }
+
+ public void unregister() {
+ if (mRoleManager != null) {
+ try {
+ mRoleManager.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.SYSTEM);
+ } catch (RuntimeException e) {
+ loge("Could not unregister dma change listener due to " + e);
+ }
+ }
+ }
+ }
+
+ private final class MyHandler extends Handler {
+ MyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_SUB_CHANGED:
+ onSubChanged();
+ break;
+ case EVENT_DMA_CHANGED:
+ onDefaultMessagingApplicationChanged();
+ break;
+ case EVENT_CC_CHANGED:
+ onCarrierConfigChange();
+ break;
+ case EVENT_CONFIG_RECEIVED:
+ onConfigReceived(msg.arg1, (byte[]) msg.obj, msg.arg2 == 1);
+ break;
+ case EVENT_RECONFIG_REQUEST:
+ onReconfigRequest(msg.arg1);
+ break;
+ case EVENT_DEVICE_CONFIG_OVERRIDE:
+ Boolean deviceEnabled = (Boolean) msg.obj;
+ if (!booleanEquals(deviceEnabled, mDeviceSingleRegistrationEnabledOverride)) {
+ mDeviceSingleRegistrationEnabledOverride = deviceEnabled;
+ onCarrierConfigChange();
+ }
+ break;
+ case EVENT_CARRIER_CONFIG_OVERRIDE:
+ Boolean carrierEnabledOverride = (Boolean) msg.obj;
+ Boolean carrierEnabled = mCarrierSingleRegistrationEnabledOverride.put(
+ msg.arg1, carrierEnabledOverride);
+ if (!booleanEquals(carrierEnabledOverride, carrierEnabled)) {
+ onCarrierConfigChange();
+ }
+ break;
+ default:
+ loge("Unhandled event " + msg.what);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public RcsProvisioningMonitor(PhoneGlobals app, Looper looper) {
+ mPhone = app;
+ mHandler = new MyHandler(looper);
+ mCarrierConfigManager = mPhone.getSystemService(CarrierConfigManager.class);
+ mSubscriptionManager = mPhone.getSystemService(SubscriptionManager.class);
+ mTelephonyRegistryManager = mPhone.getSystemService(TelephonyRegistryManager.class);
+ mDmaPackageName = getDmaPackageName();
+ logv("DMA is " + mDmaPackageName);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ mPhone.registerReceiver(mReceiver, filter);
+ mTelephonyRegistryManager.addOnSubscriptionsChangedListener(
+ mSubChangedListener, mSubChangedListener.getHandlerExecutor());
+ mDmaChangedListener = new DmaChangedListener();
+ mDmaChangedListener.register();
+ //initialize configs for all active sub
+ onSubChanged();
+ }
+
+ /**
+ * create an instance
+ */
+ public static RcsProvisioningMonitor make(PhoneGlobals app) {
+ if (sInstance == null) {
+ logd("RcsProvisioningMonitor created.");
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ sInstance = new RcsProvisioningMonitor(app, handlerThread.getLooper());
+ }
+ return sInstance;
+ }
+
+ /**
+ * get the instance
+ */
+ public static RcsProvisioningMonitor getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * destroy the instance
+ */
+ @VisibleForTesting
+ public void destroy() {
+ logd("destroy it.");
+ mDmaChangedListener.unregister();
+ mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener);
+ mPhone.unregisterReceiver(mReceiver);
+ mHandler.getLooper().quit();
+ }
+
+ /**
+ * get the handler
+ */
+ @VisibleForTesting
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ /**
+ * Gets the config for a subscription
+ */
+ @VisibleForTesting
+ public byte[] getConfig(int subId) {
+ return mConfigs.get(subId);
+ }
+
+ /**
+ * Returns whether Rcs Volte single registration is enabled for the sub.
+ */
+ public boolean isRcsVolteSingleRegistrationEnabled(int subId) {
+ if (mSingleRegistrations.containsKey(subId)) {
+ return mSingleRegistrations.get(subId) == ProvisioningManager.STATUS_CAPABLE;
+ }
+ return false;
+ }
+
+ /**
+ * Called when the new rcs config is received
+ */
+ public void updateConfig(int subId, byte[] config, boolean isCompressed) {
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_CONFIG_RECEIVED, subId, isCompressed ? 1 : 0, config));
+ }
+
+ /**
+ * Called when the application needs rcs re-config
+ */
+ public void requestReconfig(int subId) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_RECONFIG_REQUEST, subId, 0));
+ }
+
+ /**
+ * override the device config whether single registration is enabled
+ */
+ public void overrideDeviceSingleRegistrationEnabled(Boolean enabled) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_DEVICE_CONFIG_OVERRIDE, enabled));
+ }
+
+ /**
+ * Overrides the carrier config whether single registration is enabled
+ */
+ public boolean overrideCarrierSingleRegistrationEnabled(int subId, Boolean enabled) {
+ if (!mSingleRegistrations.containsKey(subId)) {
+ return false;
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_CARRIER_CONFIG_OVERRIDE, subId, 0, enabled));
+ return true;
+ }
+
+ /**
+ * Returns the device config whether single registration is enabled
+ */
+ public boolean getDeviceSingleRegistrationEnabled() {
+ for (int val : mSingleRegistrations.values()) {
+ return (val & ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) == 0;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the carrier config whether single registration is enabled
+ */
+ public boolean getCarrierSingleRegistrationEnabled(int subId) {
+ if (mSingleRegistrations.containsKey(subId)) {
+ return (mSingleRegistrations.get(subId)
+ & ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE) == 0;
+ }
+ return false;
+ }
+
+ private void onDefaultMessagingApplicationChanged() {
+ final String packageName = getDmaPackageName();
+ if (!TextUtils.equals(mDmaPackageName, packageName)) {
+ //clear old callbacks
+ ImsManager.getInstance(mPhone, mPhone.getPhone().getPhoneId())
+ .clearRcsProvisioningCallbacks();
+ mDmaPackageName = packageName;
+ logv("new default messaging application " + mDmaPackageName);
+ mConfigs.forEach((k, v) -> {
+ if (isAcsUsed(k)) {
+ logv("acs used, trigger to re-configure.");
+ notifyRcsAutoConfigurationRemoved(k);
+ triggerRcsReconfiguration(k);
+ } else {
+ logv("acs not used, notify.");
+ notifyRcsAutoConfigurationReceived(k, v, false);
+ }
+ });
+ }
+ }
+
+ private void notifyRcsAutoConfigurationReceived(int subId, byte[] config,
+ boolean isCompressed) {
+ IImsConfig imsConfig = getIImsConfig(subId, ImsFeature.FEATURE_RCS);
+ if (imsConfig != null) {
+ try {
+ imsConfig.notifyRcsAutoConfigurationReceived(config, isCompressed);
+ } catch (RemoteException e) {
+ loge("fail to notify rcs configuration received!");
+ }
+ } else {
+ logd("getIImsConfig returns null.");
+ }
+ }
+
+ private void notifyRcsAutoConfigurationRemoved(int subId) {
+ IImsConfig imsConfig = getIImsConfig(subId, ImsFeature.FEATURE_RCS);
+ if (imsConfig != null) {
+ try {
+ imsConfig.notifyRcsAutoConfigurationRemoved();
+ } catch (RemoteException e) {
+ loge("fail to notify rcs configuration removed!");
+ }
+ } else {
+ logd("getIImsConfig returns null.");
+ }
+ }
+
+ private void triggerRcsReconfiguration(int subId) {
+ IImsConfig imsConfig = getIImsConfig(subId, ImsFeature.FEATURE_RCS);
+ if (imsConfig != null) {
+ try {
+ imsConfig.triggerRcsReconfiguration();
+ } catch (RemoteException e) {
+ loge("fail to trigger rcs reconfiguration!");
+ }
+ } else {
+ logd("getIImsConfig returns null.");
+ }
+ }
+
+ private boolean isAcsUsed(int subId) {
+ PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId);
+ if (b == null) {
+ return false;
+ }
+ return b.getBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL);
+ }
+
+ private boolean isSingleRegistrationRequiredByCarrier(int subId) {
+ Boolean enabledByOverride = mCarrierSingleRegistrationEnabledOverride.get(subId);
+ if (enabledByOverride != null) {
+ return enabledByOverride;
+ }
+
+ PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId);
+ if (b == null) {
+ return false;
+ }
+ return b.getBoolean(CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL);
+ }
+
+ private int getSingleRegistrationCapableValue(int subId) {
+ boolean isSingleRegistrationEnabledOnDevice =
+ mDeviceSingleRegistrationEnabledOverride != null
+ ? mDeviceSingleRegistrationEnabledOverride
+ : mPhone.getResources().getBoolean(R.bool.config_rcsVolteSingleRegistrationEnabled);
+
+ int value = (isSingleRegistrationEnabledOnDevice ? 0
+ : ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) | (
+ isSingleRegistrationRequiredByCarrier(subId) ? 0
+ : ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE);
+ logv("SingleRegistrationCapableValue : " + value);
+ return value;
+ }
+
+ private void onCarrierConfigChange() {
+ logv("onCarrierConfigChange");
+ mConfigs.forEach((subId, config) -> {
+ int value = getSingleRegistrationCapableValue(subId);
+ if (value != mSingleRegistrations.get(subId)) {
+ mSingleRegistrations.put(subId, value);
+ notifyDmaForSub(subId);
+ }
+ });
+ }
+
+ private void onSubChanged() {
+ final int[] activeSubs = mSubscriptionManager.getActiveSubscriptionIdList();
+ final HashSet<Integer> subsToBeDeactivated = new HashSet<>(mConfigs.keySet());
+
+ for (int i : activeSubs) {
+ subsToBeDeactivated.remove(i);
+ if (!mConfigs.containsKey(i)) {
+ byte[] data = RcsConfig.loadRcsConfigForSub(mPhone, i, false);
+ logv("new config is created for sub : " + i);
+ mConfigs.put(i, data);
+ notifyRcsAutoConfigurationReceived(i, data, false);
+ mSingleRegistrations.put(i, getSingleRegistrationCapableValue(i));
+ notifyDmaForSub(i);
+ }
+ }
+
+ subsToBeDeactivated.forEach(i -> {
+ mConfigs.remove(i);
+ notifyRcsAutoConfigurationRemoved(i);
+ });
+ }
+
+ private void onConfigReceived(int subId, byte[] config, boolean isCompressed) {
+ logv("onConfigReceived, subId:" + subId + ", config:"
+ + config + ", isCompressed:" + isCompressed);
+ mConfigs.put(subId, isCompressed ? RcsConfig.decompressGzip(config) : config);
+ RcsConfig.updateConfigForSub(mPhone, subId, config, isCompressed);
+ notifyRcsAutoConfigurationReceived(subId, config, isCompressed);
+ }
+
+ private void onReconfigRequest(int subId) {
+ logv("onReconfigRequest, subId:" + subId);
+ mConfigs.remove(subId);
+ RcsConfig.updateConfigForSub(mPhone, subId, null, true);
+ notifyRcsAutoConfigurationRemoved(subId);
+ triggerRcsReconfiguration(subId);
+ }
+
+ private void notifyDmaForSub(int subId) {
+ final Intent intent = new Intent(
+ ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE);
+ intent.setPackage(mDmaPackageName);
+ intent.putExtra(ProvisioningManager.EXTRA_SUBSCRIPTION_ID, subId);
+ intent.putExtra(ProvisioningManager.EXTRA_STATUS, mSingleRegistrations.get(subId));
+ logv("notify " + intent);
+ mPhone.sendBroadcast(intent);
+ }
+
+ private IImsConfig getIImsConfig(int subId, int feature) {
+ return mPhone.getImsResolver().getImsConfig(
+ SubscriptionManager.getSlotIndex(subId), feature);
+ }
+
+ private String getDmaPackageName() {
+ try {
+ return CollectionUtils.firstOrNull(mPhone.getSystemService(RoleManager.class)
+ .getRoleHolders(RoleManager.ROLE_SMS));
+ } catch (RuntimeException e) {
+ loge("Could not get dma name due to " + e);
+ return null;
+ }
+ }
+
+ private static boolean booleanEquals(Boolean val1, Boolean val2) {
+ return (val1 == null && val2 == null)
+ || (Boolean.TRUE.equals(val1) && Boolean.TRUE.equals(val2))
+ || (Boolean.FALSE.equals(val1) && Boolean.FALSE.equals(val2));
+ }
+
+ private static void logv(String msg) {
+ if (DBG) {
+ Rlog.d(TAG, msg);
+ }
+ }
+
+ private static void logd(String msg) {
+ Rlog.d(TAG, msg);
+ }
+
+ private static void loge(String msg) {
+ Rlog.e(TAG, msg);
+ }
+}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 8d67092..ed719b6 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -87,6 +87,12 @@
private static final String GBA_SET_RELEASE_TIME = "set-release";
private static final String GBA_GET_RELEASE_TIME = "get-release";
+ private static final String SINGLE_REGISTATION_CONFIG = "src";
+ private static final String SRC_SET_DEVICE_ENABLED = "set-device-enabled";
+ private static final String SRC_GET_DEVICE_ENABLED = "get-device-enabled";
+ private static final String SRC_SET_CARRIER_ENABLED = "set-carrier-enabled";
+ private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled";
+
// Take advantage of existing methods that already contain permissions checks when possible.
private final ITelephony mInterface;
@@ -169,6 +175,8 @@
return handleEndBlockSuppressionCommand();
case GBA_SUBCOMMAND:
return handleGbaCommand();
+ case SINGLE_REGISTATION_CONFIG:
+ return handleSingleRegistrationConfigCommand();
default: {
return handleDefaultCommands(cmd);
}
@@ -193,12 +201,15 @@
pw.println(" Carrier Config Commands.");
pw.println(" gba");
pw.println(" GBA Commands.");
+ pw.println(" src");
+ pw.println(" RCS VoLTE Single Registration Config Commands.");
onHelpIms();
onHelpEmergencyNumber();
onHelpEndBlockSupperssion();
onHelpDataTestMode();
onHelpCc();
onHelpGba();
+ onHelpSrc();
}
private void onHelpIms() {
@@ -330,6 +341,27 @@
pw.println(" is specified, it will choose the default voice SIM slot.");
}
+ private void onHelpSrc() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("RCS VoLTE Single Registration Config Commands:");
+ pw.println(" src set-device-enabled true|false|null");
+ pw.println(" Sets the device config for RCS VoLTE single registration to the value.");
+ pw.println(" The value could be true, false, or null(undefined).");
+ pw.println(" src get-device-enabled");
+ pw.println(" Gets the device config for RCS VoLTE single registration.");
+ pw.println(" src set-carrier-enabled [-s SLOT_ID] true|false|null");
+ pw.println(" Sets the carrier config for RCS VoLTE single registration to the value.");
+ pw.println(" The value could be true, false, or null(undefined).");
+ pw.println(" Options are:");
+ pw.println(" -s: The SIM slot ID to set the config value for. If no option");
+ pw.println(" is specified, it will choose the default voice SIM slot.");
+ pw.println(" src get-carrier-enabled [-s SLOT_ID]");
+ pw.println(" Gets the carrier config for RCS VoLTE single registration.");
+ pw.println(" Options are:");
+ pw.println(" -s: The SIM slot ID to read the config value for. If no option");
+ pw.println(" is specified, it will choose the default voice SIM slot.");
+ }
+
private int handleImsCommand() {
String arg = getNextArg();
if (arg == null) {
@@ -1418,4 +1450,112 @@
getOutPrintWriter().println(result);
return 0;
}
+
+ private int handleSingleRegistrationConfigCommand() {
+ String arg = getNextArg();
+ if (arg == null) {
+ onHelpSrc();
+ return 0;
+ }
+
+ switch (arg) {
+ case SRC_SET_DEVICE_ENABLED: {
+ return handleSrcSetDeviceEnabledCommand();
+ }
+ case SRC_GET_DEVICE_ENABLED: {
+ return handleSrcGetDeviceEnabledCommand();
+ }
+ case SRC_SET_CARRIER_ENABLED: {
+ return handleSrcSetCarrierEnabledCommand();
+ }
+ case SRC_GET_CARRIER_ENABLED: {
+ return handleSrcGetCarrierEnabledCommand();
+ }
+ }
+
+ return -1;
+ }
+
+ private int handleSrcSetDeviceEnabledCommand() {
+ String enabledStr = getNextArg();
+ if (enabledStr == null) {
+ return -1;
+ }
+
+ try {
+ mInterface.setDeviceSingleRegistrationEnabledOverride(enabledStr);
+ if (VDBG) {
+ Log.v(LOG_TAG, "src set-device-enabled " + enabledStr + ", done");
+ }
+ getOutPrintWriter().println("Done");
+ } catch (NumberFormatException | RemoteException e) {
+ Log.w(LOG_TAG, "src set-device-enabled " + enabledStr + ", error" + e.getMessage());
+ getErrPrintWriter().println("Exception: " + e.getMessage());
+ return -1;
+ }
+ return 0;
+ }
+
+ private int handleSrcGetDeviceEnabledCommand() {
+ boolean result = false;
+ try {
+ result = mInterface.getDeviceSingleRegistrationEnabled();
+ } catch (RemoteException e) {
+ return -1;
+ }
+ if (VDBG) {
+ Log.v(LOG_TAG, "src get-device-enabled, returned: " + result);
+ }
+ getOutPrintWriter().println(result);
+ return 0;
+ }
+
+ private int handleSrcSetCarrierEnabledCommand() {
+ //the release time value could be -1
+ int subId = getRemainingArgsCount() > 1 ? getSubId("src set-carrier-enabled")
+ : SubscriptionManager.getDefaultSubscriptionId();
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return -1;
+ }
+
+ String enabledStr = getNextArg();
+ if (enabledStr == null) {
+ return -1;
+ }
+
+ try {
+ boolean result =
+ mInterface.setCarrierSingleRegistrationEnabledOverride(subId, enabledStr);
+ if (VDBG) {
+ Log.v(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
+ + enabledStr + ", result=" + result);
+ }
+ getOutPrintWriter().println(result);
+ } catch (NumberFormatException | RemoteException e) {
+ Log.w(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
+ + enabledStr + ", error" + e.getMessage());
+ getErrPrintWriter().println("Exception: " + e.getMessage());
+ return -1;
+ }
+ return 0;
+ }
+
+ private int handleSrcGetCarrierEnabledCommand() {
+ int subId = getSubId("src get-carrier-enabled");
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return -1;
+ }
+
+ boolean result = false;
+ try {
+ result = mInterface.getCarrierSingleRegistrationEnabled(subId);
+ } catch (RemoteException e) {
+ return -1;
+ }
+ if (VDBG) {
+ Log.v(LOG_TAG, "src get-carrier-enabled -s " + subId + ", returned: " + result);
+ }
+ getOutPrintWriter().println(result);
+ return 0;
+ }
}