Merge "[RCS]Implement File Upload"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a6c1ec5..6bdf55c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -94,6 +94,11 @@
<protected-broadcast android:name= "android.telephony.action.NETWORK_COUNTRY_CHANGED" />
<protected-broadcast android:name= "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED" />
<protected-broadcast android:name= "android.telephony.action.MULTI_SIM_CONFIG_CHANGED" />
+ <protected-broadcast android:name= "android.telephony.action.CARRIER_SIGNAL_RESET" />
+ <protected-broadcast android:name= "android.telephony.action.CARRIER_SIGNAL_PCO_VALUE" />
+ <protected-broadcast android:name= "android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE" />
+ <protected-broadcast android:name= "android.telephony.action.CARRIER_SIGNAL_REDIRECTED" />
+ <protected-broadcast android:name= "android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" />
<!-- For Vendor Debugging in Telephony -->
<protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
@@ -575,16 +580,6 @@
</intent-filter>
</receiver>
- <activity android:name="com.android.services.telephony.sip.SipPhoneAccountSettingsActivity"
- android:theme="@android:style/Theme.NoDisplay"
- android:exported="true"
- android:excludeFromRecents="true">
- <intent-filter>
- <action android:name="android.telecom.action.CONFIGURE_PHONE_ACCOUNT" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
<activity android:label="Sip Settings"
android:name="com.android.services.telephony.sip.SipSettings"
android:theme="@style/DialerSettingsLight"
diff --git a/res/values/config.xml b/res/values/config.xml
index 08a84f8..9f8cc81 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -313,4 +313,8 @@
<!-- Whether or not to show notifications for when bluetooth connection is bad during a call -->
<bool name="enable_bluetooth_call_quality_notification">false</bool>
+
+ <!-- The package names which can request thermal mitigation. -->
+ <string-array name="thermal_mitigation_allowlisted_packages" translatable="false">
+ </string-array>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4df6a52..46eaaaf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -644,6 +644,13 @@
<string name="limited_sim_function_with_phone_num_notification_message"><xliff:g id="carrier_name">%1$s</xliff:g> calls and data services may be blocked while using <xliff:g id="phone_number">%2$s</xliff:g>.</string>
<!-- Notification message for limited sim function during dual sim [CHAR LIMIT=80]-->
<string name="limited_sim_function_notification_message"><xliff:g id="carrier_name">%1$s</xliff:g> calls and data services may be blocked while using another SIM.</string>
+ <!-- Notification title for SIP accounts removed -->
+ <string name="sip_accounts_removed_notification_title">Deprecated SIP accounts found and removed</string>
+ <!-- Notification message for SIP accoutns removed -->
+ <string name="sip_accounts_removed_notification_message">
+ SIP calling is no longer supported by Android platform.\nYour existing SIP accounts <xliff:g id="removed_sip_accounts">%s</xliff:g> have been removed.\nPlease confirm your default calling account setting.
+ </string>
+ <string name="sip_accounts_removed_notification_action">Go to settings</string>
<!-- Mobile network settings screen, data usage setting check box name -->
<string name="data_usage_title">App data usage</string>
<!-- Summary about how much data has been used in a date range [CHAR LIMIT=100] -->
@@ -2180,4 +2187,7 @@
<!-- name of the notification that pops up during
a phone call when there is bad call quality -->
<string name="call_quality_notification_name">Call Quality Notification</string>
+ <!-- Telephony notification channel name for a channel containing SIP accounts removed
+ notificatios -->
+ <string name="notification_channel_sip_account">Deprecated SIP accounts</string>
</resources>
diff --git a/res/xml/phone_account_settings.xml b/res/xml/phone_account_settings.xml
index a243a65..8722761 100644
--- a/res/xml/phone_account_settings.xml
+++ b/res/xml/phone_account_settings.xml
@@ -55,34 +55,4 @@
</PreferenceCategory>
- <PreferenceCategory
- android:key="phone_accounts_sip_settings_category_key"
- android:title="@string/sip_settings"
- android:persistent="false">
-
- <PreferenceScreen
- android:title="@string/sip_accounts"
- android:persistent="false">
-
- <intent android:action="android.intent.action.MAIN"
- android:targetPackage="com.android.phone"
- android:targetClass="com.android.services.telephony.sip.SipSettings" />
-
- </PreferenceScreen>
-
- <ListPreference
- android:key="use_sip_calling_options_key"
- android:title="@string/sip_call_options_title"
- android:persistent="true"
- android:entries="@array/sip_call_options_entries"
- android:entryValues="@array/sip_call_options_values"/>
-
- <SwitchPreference
- android:key="sip_receive_calls_key"
- android:title="@string/sip_receive_calls"
- android:summary="@string/sip_receive_calls_summary"
- android:persistent="true"/>
-
- </PreferenceCategory>
-
</PreferenceScreen>
diff --git a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
index 1cf7f4b..2845dac 100644
--- a/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
+++ b/sip/src/com/android/services/telephony/sip/SipAccountRegistry.java
@@ -16,8 +16,12 @@
package com.android.services.telephony.sip;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.Context;
-import android.net.sip.SipException;
+import android.content.Intent;
import android.net.sip.SipManager;
import android.net.sip.SipProfile;
import android.telecom.PhoneAccount;
@@ -25,9 +29,13 @@
import android.telecom.TelecomManager;
import android.util.Log;
+import com.android.phone.R;
+
+import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Collectors;
/**
* Manages the {@link PhoneAccount} entries for SIP calling.
@@ -45,41 +53,6 @@
}
/**
- * Starts the SIP service associated with the SIP profile.
- *
- * @param sipManager The SIP manager.
- * @param context The context.
- * @param isReceivingCalls {@code True} if the sip service is being started to make and
- * receive calls. {@code False} if the sip service is being started only for
- * outgoing calls.
- * @return {@code True} if the service started successfully.
- */
- boolean startSipService(SipManager sipManager, Context context, boolean isReceivingCalls) {
- if (VERBOSE) log("startSipService, profile: " + mProfile);
- try {
- // Stop the Sip service for the profile if it is already running. This is important
- // if we are changing the state of the "receive calls" option.
- sipManager.close(mProfile.getUriString());
-
- // Start the sip service for the profile.
- if (isReceivingCalls) {
- sipManager.open(
- mProfile,
- SipUtil.createIncomingCallPendingIntent(context,
- mProfile.getProfileName()),
- null);
- } else {
- sipManager.open(mProfile);
- }
- return true;
- } catch (SipException e) {
- log("startSipService, profile: " + mProfile.getProfileName() +
- ", exception: " + e);
- }
- return false;
- }
-
- /**
* Stops the SIP service associated with the SIP profile. The {@code SipAccountRegistry} is
* informed when the service has been stopped via an intent which triggers
* {@link SipAccountRegistry#removeSipProfile(String)}.
@@ -102,9 +75,16 @@
private static final String PREFIX = "[SipAccountRegistry] ";
private static final boolean VERBOSE = false; /* STOP SHIP if true */
private static final SipAccountRegistry INSTANCE = new SipAccountRegistry();
+ private static final String NOTIFICATION_TAG = SipAccountRegistry.class.getSimpleName();
+ private static final int SIP_ACCOUNTS_REMOVED_NOTIFICATION_ID = 1;
+
+ private static final String CHANNEL_ID_SIP_ACCOUNTS_REMOVED = "sipAccountsRemoved";
private final List<AccountEntry> mAccounts = new CopyOnWriteArrayList<>();
+ private NotificationChannel mNotificationChannel;
+ private NotificationManager mNm;
+
private SipAccountRegistry() {}
public static SipAccountRegistry getInstance() {
@@ -115,8 +95,20 @@
* Sets up the Account registry and performs any upgrade operations before it is used.
*/
public void setup(Context context) {
+ setupNotificationChannel(context);
verifyAndPurgeInvalidPhoneAccounts(context);
- startSipProfilesAsync(context, (String) null, false);
+ startSipProfilesAsync(context);
+ }
+
+ private void setupNotificationChannel(Context context) {
+ mNotificationChannel = new NotificationChannel(
+ CHANNEL_ID_SIP_ACCOUNTS_REMOVED,
+ context.getText(R.string.notification_channel_sip_account),
+ NotificationManager.IMPORTANCE_HIGH);
+ mNm = context.getSystemService(NotificationManager.class);
+ if (mNm != null) {
+ mNm.createNotificationChannel(mNotificationChannel);
+ }
}
/**
@@ -149,8 +141,8 @@
* @param sipProfileName The name of the {@link SipProfile} to start, or {@code null} for all.
* @param enableProfile Sip account should be enabled
*/
- void startSipService(Context context, String sipProfileName, boolean enableProfile) {
- startSipProfilesAsync(context, sipProfileName, enableProfile);
+ void startSipService(Context context, String sipProfileName, boolean enabledProfile) {
+ startSipProfilesAsync(context);
}
/**
@@ -193,33 +185,20 @@
}
/**
- * Causes the SIP service to be restarted for all {@link SipProfile}s. For example, if the user
- * toggles the "receive calls" option for SIP, this method handles restarting the SIP services
- * in the new mode.
- *
- * @param context The context.
- */
- public void restartSipService(Context context) {
- startSipProfiles(context, null, false);
- }
-
- /**
* Performs an asynchronous call to
* {@link SipAccountRegistry#startSipProfiles(android.content.Context, String)}, starting the
* specified SIP profile and registering its {@link android.telecom.PhoneAccount}.
*
* @param context The context.
- * @param sipProfileName Name of the SIP profile.
- * @param enableProfile Sip account should be enabled.
*/
private void startSipProfilesAsync(
- final Context context, final String sipProfileName, final boolean enableProfile) {
+ final Context context) {
if (VERBOSE) log("startSipProfiles, start auto registration");
new Thread(new Runnable() {
@Override
public void run() {
- startSipProfiles(context, sipProfileName, enableProfile);
+ startSipProfiles(context);
}}
).start();
}
@@ -230,48 +209,54 @@
* register the associated SIP account.
*
* @param context The context.
- * @param sipProfileName A specific SIP profile Name to start, or {@code null} to start all.
- * @param enableProfile Sip account should be enabled.
*/
- private void startSipProfiles(Context context, String sipProfileName, boolean enableProfile) {
- final SipPreferences sipPreferences = new SipPreferences(context);
- boolean isReceivingCalls = sipPreferences.isReceivingCallsEnabled();
- TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
- SipManager sipManager = SipManager.newInstance(context);
+ private void startSipProfiles(Context context) {
SipProfileDb profileDb = new SipProfileDb(context);
List<SipProfile> sipProfileList = profileDb.retrieveSipProfileList();
- for (SipProfile profile : sipProfileList) {
- // Register a PhoneAccount for the profile and optionally enable the primary
- // profile.
- if (sipProfileName == null || sipProfileName.equals(profile.getProfileName())) {
- PhoneAccount phoneAccount = SipUtil.createPhoneAccount(context, profile);
- telecomManager.registerPhoneAccount(phoneAccount);
- if (enableProfile) {
- telecomManager.enablePhoneAccount(phoneAccount.getAccountHandle(), true);
+ // If there're SIP profiles existing in DB, display a notification and delete all these
+ // profiles.
+ if (!sipProfileList.isEmpty()) {
+ for (SipProfile profile : sipProfileList) {
+ stopSipService(context, profile.getProfileName());
+ removeSipProfile(profile.getProfileName());
+ try {
+ profileDb.deleteProfile(profile);
+ } catch (IOException e) {
+ // Ignore
}
- startSipServiceForProfile(profile, sipManager, context, isReceivingCalls);
}
+ sendSipAccountsRemovedNotification(context, sipProfileList);
}
}
- /**
- * Starts the SIP service for a sip profile and saves a new {@code AccountEntry} in the
- * registry.
- *
- * @param profile The {@link SipProfile} to start.
- * @param sipManager The SIP manager.
- * @param context The context.
- * @param isReceivingCalls {@code True} if the profile should be started such that it can
- * receive incoming calls.
- */
- private void startSipServiceForProfile(SipProfile profile, SipManager sipManager,
- Context context, boolean isReceivingCalls) {
- removeSipProfile(profile.getUriString());
+ private void sendSipAccountsRemovedNotification(Context context, List<SipProfile> profiles) {
+ String sipAccounts = profiles.stream().map(p -> p.getProfileName())
+ .collect(Collectors.joining(","));
- AccountEntry entry = new AccountEntry(profile);
- if (entry.startSipService(sipManager, context, isReceivingCalls)) {
- mAccounts.add(entry);
+ Intent intent = new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS);
+ intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
+
+ Notification.Action action = new Notification.Action.Builder(R.drawable.ic_sim_card,
+ context.getString(R.string.sip_accounts_removed_notification_action),
+ pendingIntent).build();
+ Notification.Builder builder = new Notification.Builder(context)
+ .setSmallIcon(R.drawable.ic_sim_card)
+ .setChannelId(CHANNEL_ID_SIP_ACCOUNTS_REMOVED)
+ .setContentTitle(context.getText(R.string.sip_accounts_removed_notification_title))
+ .setStyle(new Notification.BigTextStyle()
+ .bigText(context.getString(
+ R.string.sip_accounts_removed_notification_message,
+ sipAccounts)))
+ .setAutoCancel(true)
+ .addAction(action);
+ Notification notification = builder.build();
+ if (mNm != null) {
+ mNm.notify(NOTIFICATION_TAG, SIP_ACCOUNTS_REMOVED_NOTIFICATION_ID,
+ notification);
+ } else {
+ log("NotificationManager is null when send the notification of removed SIP accounts");
}
}
diff --git a/sip/src/com/android/services/telephony/sip/SipPhoneAccountSettingsActivity.java b/sip/src/com/android/services/telephony/sip/SipPhoneAccountSettingsActivity.java
deleted file mode 100644
index a6f6381..0000000
--- a/sip/src/com/android/services/telephony/sip/SipPhoneAccountSettingsActivity.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2014 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.services.telephony.sip;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.sip.SipProfile;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.util.Log;
-
-/**
- * This activity receives the standard telecom intent to open settings for a PhoneAccount. It
- * translates the incoming phone account to a SIP profile and opens the corresponding
- * PreferenceActivity for said profile.
- */
-public final class SipPhoneAccountSettingsActivity extends Activity {
- private static final String TAG = "SipSettingsActivity";
-
- /** ${inheritDoc} */
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Intent intent = getIntent();
- Log.i(TAG, "" + intent);
- if (intent != null) {
- PhoneAccountHandle accountHandle = (PhoneAccountHandle)
- intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
- Log.i(TAG, "" + accountHandle);
-
- if (accountHandle != null) {
- SipProfileDb profileDb = new SipProfileDb(this);
- String profileName = SipUtil.getSipProfileNameFromPhoneAccount(accountHandle);
- SipProfile profile = profileDb.retrieveSipProfileFromName(profileName);
- if (profile != null) {
- Intent settingsIntent = new Intent(this, SipEditor.class);
- settingsIntent.putExtra(SipSettings.KEY_SIP_PROFILE, (Parcelable) profile);
- startActivity(settingsIntent);
- }
- }
- }
-
- finish();
- }
-}
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 69c2b8a..9a1e275 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -333,6 +333,7 @@
/** The singleton instance. */
private static PhoneInterfaceManager sInstance;
+ private static List<String> sThermalMitigationAllowlistedPackages = new ArrayList<>();
private PhoneGlobals mApp;
private CallManager mCM;
@@ -9404,11 +9405,43 @@
return TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
}
+ private static List<String> getThermalMitigationAllowlist(Context context) {
+ if (sThermalMitigationAllowlistedPackages.isEmpty()) {
+ for (String pckg : context.getResources()
+ .getStringArray(R.array.thermal_mitigation_allowlisted_packages)) {
+ sThermalMitigationAllowlistedPackages.add(pckg);
+ }
+ }
+
+ return sThermalMitigationAllowlistedPackages;
+ }
+
+ /**
+ * Used by shell commands to add an authorized package name for thermal mitigation.
+ * @param packageName name of package to be allowlisted
+ * @param context
+ */
+ static void addPackageToThermalMitigationAllowlist(String packageName, Context context) {
+ sThermalMitigationAllowlistedPackages = getThermalMitigationAllowlist(context);
+ sThermalMitigationAllowlistedPackages.add(packageName);
+ }
+
+ /**
+ * Used by shell commands to remove an authorized package name for thermal mitigation.
+ * @param packageName name of package to remove from allowlist
+ * @param context
+ */
+ static void removePackageFromThermalMitigationAllowlist(String packageName, Context context) {
+ sThermalMitigationAllowlistedPackages = getThermalMitigationAllowlist(context);
+ sThermalMitigationAllowlistedPackages.remove(packageName);
+ }
+
/**
* Thermal mitigation request to control functionalities at modem.
*
* @param subId the id of the subscription.
* @param thermalMitigationRequest holds all necessary information to be passed down to modem.
+ * @param callingPackage the package name of the calling package.
*
* @return thermalMitigationResult enum as defined in android.telephony.Annotation.
*/
@@ -9416,9 +9449,17 @@
@ThermalMitigationResult
public int sendThermalMitigationRequest(
int subId,
- ThermalMitigationRequest thermalMitigationRequest) throws IllegalArgumentException {
+ ThermalMitigationRequest thermalMitigationRequest,
+ String callingPackage) throws IllegalArgumentException {
enforceModifyPermission();
+ mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
+ if (!getThermalMitigationAllowlist(getDefaultPhone().getContext())
+ .contains(callingPackage)) {
+ throw new SecurityException("Calling package must be configured in the device config. "
+ + "calling package: " + callingPackage);
+ }
+
WorkSource workSource = getWorkSource(Binder.getCallingUid());
final long identity = Binder.clearCallingIdentity();
@@ -9843,6 +9884,30 @@
}
/**
+ * Overrides the ims feature validation result
+ */
+ @Override
+ public boolean setImsFeatureValidationOverride(int subId, String enabledStr) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "setImsFeatureValidationOverride");
+
+ Boolean enabled = "NULL".equalsIgnoreCase(enabledStr) ? null
+ : Boolean.parseBoolean(enabledStr);
+ return RcsProvisioningMonitor.getInstance().overrideImsFeatureValidation(
+ subId, enabled);
+ }
+
+ /**
+ * Gets the ims feature validation override value
+ */
+ @Override
+ public boolean getImsFeatureValidationOverride(int subId) {
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+ "getImsFeatureValidationOverride");
+ return RcsProvisioningMonitor.getInstance().getImsFeatureValidationOverride(subId);
+ }
+
+ /**
* Get the mobile provisioning url that is used to launch a browser to allow users to manage
* their mobile plan.
*/
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index bcf1491..6fdde78 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -73,6 +73,7 @@
private static final int EVENT_DEVICE_CONFIG_OVERRIDE = 6;
private static final int EVENT_CARRIER_CONFIG_OVERRIDE = 7;
private static final int EVENT_RESET = 8;
+ private static final int EVENT_FEATURE_ENABLED_OVERRIDE = 9;
private final PhoneGlobals mPhone;
private final Handler mHandler;
@@ -82,6 +83,8 @@
private Boolean mDeviceSingleRegistrationEnabledOverride;
private final HashMap<Integer, Boolean> mCarrierSingleRegistrationEnabledOverride =
new HashMap<>();
+ private final ConcurrentHashMap<Integer, Boolean> mImsFeatureValidationOverride =
+ new ConcurrentHashMap<>();
private String mDmaPackageName;
private final SparseArray<RcsFeatureListener> mRcsFeatureListeners = new SparseArray<>();
private volatile boolean mTestModeEnabled;
@@ -626,6 +629,18 @@
}
/**
+ * override the rcs feature validation result for a subscription
+ */
+ public boolean overrideImsFeatureValidation(int subId, Boolean enabled) {
+ if (enabled == null) {
+ mImsFeatureValidationOverride.remove(subId);
+ } else {
+ mImsFeatureValidationOverride.put(subId, enabled);
+ }
+ return true;
+ }
+
+ /**
* Returns the device config whether single registration is enabled
*/
public boolean getDeviceSingleRegistrationEnabled() {
@@ -647,6 +662,13 @@
return false;
}
+ /**
+ * Returns the rcs feature validation override value, null if it is not set.
+ */
+ public Boolean getImsFeatureValidationOverride(int subId) {
+ return mImsFeatureValidationOverride.get(subId);
+ }
+
private void onDefaultMessagingApplicationChanged() {
final String packageName = getDmaPackageName();
if (!TextUtils.equals(mDmaPackageName, packageName)) {
diff --git a/src/com/android/phone/ServiceStateProvider.java b/src/com/android/phone/ServiceStateProvider.java
index a7d27d5..32562fa 100644
--- a/src/com/android/phone/ServiceStateProvider.java
+++ b/src/com/android/phone/ServiceStateProvider.java
@@ -18,6 +18,9 @@
import static android.provider.Telephony.ServiceStateTable;
import static android.provider.Telephony.ServiceStateTable.CONTENT_URI;
+import static android.provider.Telephony.ServiceStateTable.DATA_NETWORK_TYPE;
+import static android.provider.Telephony.ServiceStateTable.DATA_REG_STATE;
+import static android.provider.Telephony.ServiceStateTable.DUPLEX_MODE;
import static android.provider.Telephony.ServiceStateTable.IS_MANUAL_NETWORK_SELECTION;
import static android.provider.Telephony.ServiceStateTable.VOICE_REG_STATE;
import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
@@ -61,18 +64,6 @@
public static final String SERVICE_STATE = "service_state";
/**
- * An integer value indicating the current data service state.
- * <p>
- * Valid values: {@link ServiceState#STATE_IN_SERVICE},
- * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
- * {@link ServiceState#STATE_POWER_OFF}.
- * <p>
- * This is the same as {@link ServiceState#getDataRegState()}.
- * @hide
- */
- public static final String DATA_REG_STATE = "data_reg_state";
-
- /**
* An integer value indicating the current voice roaming type.
* <p>
* This is the same as {@link ServiceState#getVoiceRoamingType()}.
@@ -257,6 +248,8 @@
IS_USING_CARRIER_AGGREGATION,
OPERATOR_ALPHA_LONG_RAW,
OPERATOR_ALPHA_SHORT_RAW,
+ DATA_NETWORK_TYPE,
+ DUPLEX_MODE,
};
@Override
@@ -392,6 +385,8 @@
final int is_using_carrier_aggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
final String operator_alpha_long_raw = ss.getOperatorAlphaLongRaw();
final String operator_alpha_short_raw = ss.getOperatorAlphaShortRaw();
+ final int data_network_type = ss.getDataNetworkType();
+ final int duplex_mode = ss.getDuplexMode();
return buildSingleRowResult(projection, sColumns, new Object[] {
voice_reg_state,
@@ -418,6 +413,8 @@
is_using_carrier_aggregation,
operator_alpha_long_raw,
operator_alpha_short_raw,
+ data_network_type,
+ duplex_mode,
});
}
}
@@ -480,6 +477,10 @@
context.getContentResolver().notifyChange(
getUriForSubscriptionIdAndField(subId, DATA_ROAMING_TYPE), null, false);
}
+ if (firstUpdate || dataNetworkTypeChanged(oldSS, newSS)) {
+ context.getContentResolver().notifyChange(
+ getUriForSubscriptionIdAndField(subId, DATA_NETWORK_TYPE), null, false);
+ }
}
private static boolean voiceRegStateChanged(ServiceState oldSS, ServiceState newSS) {
@@ -498,6 +499,10 @@
return oldSS.getDataRoamingType() != newSS.getDataRoamingType();
}
+ private static boolean dataNetworkTypeChanged(ServiceState oldSS, ServiceState newSS) {
+ return oldSS.getDataNetworkType() != newSS.getDataNetworkType();
+ }
+
/**
* Notify interested apps that the ServiceState has changed.
*
@@ -517,7 +522,8 @@
// If oldSS is null and newSS is not (e.g. first update of service state) this will also
// notify
if (oldSS == null || voiceRegStateChanged(oldSS, newSS) || dataRegStateChanged(oldSS, newSS)
- || voiceRoamingTypeChanged(oldSS, newSS) || dataRoamingTypeChanged(oldSS, newSS)) {
+ || voiceRoamingTypeChanged(oldSS, newSS) || dataRoamingTypeChanged(oldSS, newSS)
+ || dataNetworkTypeChanged(oldSS, newSS)) {
context.getContentResolver().notifyChange(getUriForSubscriptionId(subId), null, false);
}
}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 87dc868..36d539a 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -113,6 +113,8 @@
private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled";
private static final String SRC_SET_TEST_ENABLED = "set-test-enabled";
private static final String SRC_GET_TEST_ENABLED = "get-test-enabled";
+ private static final String SRC_SET_FEATURE_ENABLED = "set-feature-validation";
+ private static final String SRC_GET_FEATURE_ENABLED = "get-feature-validation";
private static final String D2D_SUBCOMMAND = "d2d";
private static final String D2D_SEND = "send";
@@ -128,6 +130,10 @@
// Check if a package has carrier privileges on any SIM, regardless of subId/phoneId.
private static final String HAS_CARRIER_PRIVILEGES_COMMAND = "has-carrier-privileges";
+ private static final String THERMAL_MITIGATION_COMMAND = "thermal-mitigation";
+ private static final String ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "allow-package";
+ private static final String DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "disallow-package";
+
// Take advantage of existing methods that already contain permissions checks when possible.
private final ITelephony mInterface;
@@ -264,6 +270,8 @@
return handleUnattendedReboot();
case HAS_CARRIER_PRIVILEGES_COMMAND:
return handleHasCarrierPrivilegesCommand();
+ case THERMAL_MITIGATION_COMMAND:
+ return handleThermalMitigationCommand();
default: {
return handleDefaultCommands(cmd);
}
@@ -410,6 +418,16 @@
pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
}
+ private void onHelpThermalMitigation() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Thermal mitigation commands");
+ pw.println(" thermal-mitigation allow-package PACKAGE_NAME");
+ pw.println(" Set the package as one of authorized packages for thermal mitigation.");
+ pw.println(" thermal-mitigation disallow-package PACKAGE_NAME");
+ pw.println(" Remove the package from one of the authorized packages for thermal "
+ + "mitigation.");
+ }
+
private void onHelpDataTestMode() {
PrintWriter pw = getOutPrintWriter();
pw.println("Mobile Data Test Mode Commands:");
@@ -516,6 +534,17 @@
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.");
+ pw.println(" src set-feature-validation [-s SLOT_ID] true|false|null");
+ pw.println(" Sets ims feature validation result.");
+ 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-feature-validation [-s SLOT_ID]");
+ pw.println(" Gets ims feature validation override value.");
+ 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() {
@@ -696,6 +725,36 @@
return -1;
}
+ private int handleThermalMitigationCommand() {
+ String arg = getNextArg();
+ String packageName = getNextArg();
+ if (arg == null || packageName == null) {
+ onHelpThermalMitigation();
+ return 0;
+ }
+
+ if (!checkShellUid()) {
+ return -1;
+ }
+
+ switch (arg) {
+ case ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: {
+ PhoneInterfaceManager.addPackageToThermalMitigationAllowlist(packageName, mContext);
+ return 0;
+ }
+ case DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: {
+ PhoneInterfaceManager.removePackageFromThermalMitigationAllowlist(packageName,
+ mContext);
+ return 0;
+ }
+ default:
+ onHelpThermalMitigation();
+ }
+
+ return -1;
+
+ }
+
private int handleD2dCommand() {
String arg = getNextArg();
if (arg == null) {
@@ -1719,6 +1778,12 @@
case SRC_GET_CARRIER_ENABLED: {
return handleSrcGetCarrierEnabledCommand();
}
+ case SRC_SET_FEATURE_ENABLED: {
+ return handleSrcSetFeatureValidationCommand();
+ }
+ case SRC_GET_FEATURE_ENABLED: {
+ return handleSrcGetFeatureValidationCommand();
+ }
}
return -1;
@@ -2042,6 +2107,55 @@
return 0;
}
+ private int handleSrcSetFeatureValidationCommand() {
+ //the release time value could be -1
+ int subId = getRemainingArgsCount() > 1 ? getSubId("src set-feature-validation")
+ : SubscriptionManager.getDefaultSubscriptionId();
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return -1;
+ }
+
+ String enabledStr = getNextArg();
+ if (enabledStr == null) {
+ return -1;
+ }
+
+ try {
+ boolean result =
+ mInterface.setImsFeatureValidationOverride(subId, enabledStr);
+ if (VDBG) {
+ Log.v(LOG_TAG, "src set-feature-validation -s " + subId + " "
+ + enabledStr + ", result=" + result);
+ }
+ getOutPrintWriter().println(result);
+ } catch (NumberFormatException | RemoteException e) {
+ Log.w(LOG_TAG, "src set-feature-validation -s " + subId + " "
+ + enabledStr + ", error" + e.getMessage());
+ getErrPrintWriter().println("Exception: " + e.getMessage());
+ return -1;
+ }
+ return 0;
+ }
+
+ private int handleSrcGetFeatureValidationCommand() {
+ int subId = getSubId("src get-feature-validation");
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return -1;
+ }
+
+ Boolean result = false;
+ try {
+ result = mInterface.getImsFeatureValidationOverride(subId);
+ } catch (RemoteException e) {
+ return -1;
+ }
+ if (VDBG) {
+ Log.v(LOG_TAG, "src get-feature-validation -s " + subId + ", returned: " + result);
+ }
+ getOutPrintWriter().println(result);
+ return 0;
+ }
+
private int handleHasCarrierPrivilegesCommand() {
String packageName = getNextArgRequired();
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index 3811a77..224a1f9 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -6,14 +6,11 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Icon;
-import android.net.sip.SipManager;
import android.os.Bundle;
import android.os.UserManager;
-import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
-import android.preference.SwitchPreference;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -28,9 +25,6 @@
import com.android.phone.PhoneUtils;
import com.android.phone.R;
import com.android.phone.SubscriptionInfoHelper;
-import com.android.services.telephony.sip.SipAccountRegistry;
-import com.android.services.telephony.sip.SipPreferences;
-import com.android.services.telephony.sip.SipUtil;
import java.util.ArrayList;
import java.util.Collections;
@@ -48,11 +42,6 @@
private static final String ALL_CALLING_ACCOUNTS_KEY = "phone_accounts_all_calling_accounts";
- private static final String SIP_SETTINGS_CATEGORY_PREF_KEY =
- "phone_accounts_sip_settings_category_key";
- private static final String USE_SIP_PREF_KEY = "use_sip_calling_options_key";
- private static final String SIP_RECEIVE_CALLS_PREF_KEY = "sip_receive_calls_key";
-
private static final String MAKE_AND_RECEIVE_CALLS_CATEGORY_KEY =
"make_and_receive_calls_settings_category_key";
private static final String DEFAULT_OUTGOING_ACCOUNT_KEY = "default_outgoing_account";
@@ -84,10 +73,6 @@
private PreferenceCategory mMakeAndReceiveCallsCategory;
private boolean mMakeAndReceiveCallsCategoryPresent;
- private ListPreference mUseSipCalling;
- private SwitchPreference mSipReceiveCallsPreference;
- private SipPreferences mSipPreferences;
-
private final SubscriptionManager.OnSubscriptionsChangedListener
mOnSubscriptionsChangeListener =
new SubscriptionManager.OnSubscriptionsChangedListener() {
@@ -154,39 +139,6 @@
updateAccounts();
updateMakeCallsOptions();
- if (isPrimaryUser() && SipUtil.isVoipSupported(getActivity())) {
- mSipPreferences = new SipPreferences(getActivity());
-
- mUseSipCalling = (ListPreference)
- getPreferenceScreen().findPreference(USE_SIP_PREF_KEY);
- mUseSipCalling.setEntries(!SipManager.isSipWifiOnly(getActivity())
- ? R.array.sip_call_options_wifi_only_entries
- : R.array.sip_call_options_entries);
- mUseSipCalling.setOnPreferenceChangeListener(this);
-
- int optionsValueIndex =
- mUseSipCalling.findIndexOfValue(mSipPreferences.getSipCallOption());
- if (optionsValueIndex == -1) {
- // If the option is invalid (eg. deprecated value), default to SIP_ADDRESS_ONLY.
- mSipPreferences.setSipCallOption(
- getResources().getString(R.string.sip_address_only));
- optionsValueIndex =
- mUseSipCalling.findIndexOfValue(mSipPreferences.getSipCallOption());
- }
- mUseSipCalling.setValueIndex(optionsValueIndex);
- mUseSipCalling.setSummary(mUseSipCalling.getEntry());
-
- mSipReceiveCallsPreference = (SwitchPreference)
- getPreferenceScreen().findPreference(SIP_RECEIVE_CALLS_PREF_KEY);
- mSipReceiveCallsPreference.setEnabled(SipUtil.isPhoneIdle(getActivity()));
- mSipReceiveCallsPreference.setChecked(
- mSipPreferences.isReceivingCallsEnabled());
- mSipReceiveCallsPreference.setOnPreferenceChangeListener(this);
- } else {
- getPreferenceScreen().removePreference(
- getPreferenceScreen().findPreference(SIP_SETTINGS_CATEGORY_PREF_KEY));
- }
-
SubscriptionManager.from(getActivity()).addOnSubscriptionsChangedListener(
mOnSubscriptionsChangeListener);
}
@@ -207,21 +159,6 @@
*/
@Override
public boolean onPreferenceChange(Preference pref, Object objValue) {
- if (pref == mUseSipCalling) {
- String option = objValue.toString();
- mSipPreferences.setSipCallOption(option);
- mUseSipCalling.setValueIndex(mUseSipCalling.findIndexOfValue(option));
- mUseSipCalling.setSummary(mUseSipCalling.getEntry());
- return true;
- } else if (pref == mSipReceiveCallsPreference) {
- final boolean isEnabled = !mSipReceiveCallsPreference.isChecked();
- new Thread(new Runnable() {
- public void run() {
- handleSipReceiveCallsOption(isEnabled);
- }
- }).start();
- return true;
- }
return false;
}
@@ -256,22 +193,6 @@
@Override
public void onAccountChanged(AccountSelectionPreference pref) {}
- private synchronized void handleSipReceiveCallsOption(boolean isEnabled) {
- Context context = getActivity();
- if (context == null) {
- // Return if the fragment is detached from parent activity before executed by thread.
- return;
- }
-
- mSipPreferences.setReceivingCallsEnabled(isEnabled);
-
- SipUtil.useSipToReceiveIncomingCalls(context, isEnabled);
-
- // Restart all Sip services to ensure we reflect whether we are receiving calls.
- SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance();
- sipAccountRegistry.restartSipService(context);
- }
-
/**
* Queries the telcomm manager to update the default outgoing account selection preference
* with the list of outgoing accounts and the current default outgoing account.
@@ -409,32 +330,24 @@
mAccountList.removeAll();
List<PhoneAccountHandle> allNonSimAccounts =
getCallingAccounts(false /* includeSims */, true /* includeDisabled */);
- // Check to see if we should show the entire section at all.
- if (shouldShowConnectionServiceList(allNonSimAccounts)) {
- List<PhoneAccountHandle> enabledAccounts =
- getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
- // Initialize the account list with the set of enabled & SIM accounts.
- initAccountList(enabledAccounts);
- // Only show the 'Make Calls With..." option if there are multiple accounts.
- if (enabledAccounts.size() > 1) {
- mMakeAndReceiveCallsCategory.addPreference(mDefaultOutgoingAccount);
- mMakeAndReceiveCallsCategoryPresent = true;
- mDefaultOutgoingAccount.setListener(this);
- updateDefaultOutgoingAccountsModel();
- } else {
- mMakeAndReceiveCallsCategory.removePreference(mDefaultOutgoingAccount);
- }
+ List<PhoneAccountHandle> enabledAccounts =
+ getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
+ // Initialize the account list with the set of enabled & SIM accounts.
+ initAccountList(enabledAccounts);
- // If there are no third party (nonSim) accounts,
- // then don't show enable/disable dialog.
- if (!allNonSimAccounts.isEmpty()) {
- mAccountList.addPreference(mAllCallingAccounts);
- } else {
- mAccountList.removePreference(mAllCallingAccounts);
- }
+ // Always show the 'Make Calls With..." option
+ mMakeAndReceiveCallsCategory.addPreference(mDefaultOutgoingAccount);
+ mMakeAndReceiveCallsCategoryPresent = true;
+ mDefaultOutgoingAccount.setListener(this);
+ updateDefaultOutgoingAccountsModel();
+
+ // If there are no third party (nonSim) accounts,
+ // then don't show enable/disable dialog.
+ if (!allNonSimAccounts.isEmpty()) {
+ mAccountList.addPreference(mAllCallingAccounts);
} else {
- getPreferenceScreen().removePreference(mAccountList);
+ mAccountList.removePreference(mAllCallingAccounts);
}
}
}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 3706d3b..d745aab 100755
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -1596,6 +1596,7 @@
Connection.AUDIO_CODEC_NONE);
if (newCodecType != oldCodecType) {
newExtras.putInt(Connection.EXTRA_AUDIO_CODEC, newCodecType);
+ Log.i(this, "put audio codec:" + newCodecType);
changed = true;
}
if (isImsConnection()) {
@@ -1603,6 +1604,7 @@
float oldBitrate = newExtras.getFloat(Connection.EXTRA_AUDIO_CODEC_BITRATE_KBPS, 0.0f);
if (Math.abs(newBitrate - oldBitrate) > THRESHOLD) {
newExtras.putFloat(Connection.EXTRA_AUDIO_CODEC_BITRATE_KBPS, newBitrate);
+ Log.i(this, "put audio bitrate:" + newBitrate);
changed = true;
}
@@ -1611,6 +1613,7 @@
0.0f);
if (Math.abs(newBandwidth - oldBandwidth) > THRESHOLD) {
newExtras.putFloat(Connection.EXTRA_AUDIO_CODEC_BANDWIDTH_KHZ, newBandwidth);
+ Log.i(this, "put audio bandwidth:" + newBandwidth);
changed = true;
}
} else {
@@ -1621,6 +1624,12 @@
}
if (changed) {
+ Log.i(this, "Audio attribute, Codec:"
+ + newExtras.getInt(Connection.EXTRA_AUDIO_CODEC, Connection.AUDIO_CODEC_NONE)
+ + ", Bitrate:"
+ + newExtras.getFloat(Connection.EXTRA_AUDIO_CODEC_BITRATE_KBPS, 0.0f)
+ + ", Bandwidth:"
+ + newExtras.getFloat(Connection.EXTRA_AUDIO_CODEC_BANDWIDTH_KHZ, 0.0f));
putTelephonyExtras(newExtras);
}
}
diff --git a/src/com/android/services/telephony/rcs/SipTransportController.java b/src/com/android/services/telephony/rcs/SipTransportController.java
index a948cdb..cecc8a2 100644
--- a/src/com/android/services/telephony/rcs/SipTransportController.java
+++ b/src/com/android/services/telephony/rcs/SipTransportController.java
@@ -19,8 +19,10 @@
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.content.Context;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.telephony.CarrierConfigManager;
import android.telephony.ims.DelegateRequest;
import android.telephony.ims.FeatureTagState;
import android.telephony.ims.ImsException;
@@ -44,12 +46,14 @@
import com.android.ims.RcsFeatureManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.phone.RcsProvisioningMonitor;
import com.google.common.base.Objects;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
@@ -247,6 +251,10 @@
private RcsFeatureManager mRcsManager;
// Cached package name of the app that is considered the default SMS app.
private String mCachedSmsRolePackageName = "";
+ // Callback to monitor rcs provisioning change
+ private CarrierConfigManager mCarrierConfigManager;
+ // Cached allowed feature tags from carrier config
+ ArraySet<String> mFeatureTagsAllowed = new ArraySet<>();
/**
* Create an instance of SipTransportController.
@@ -261,6 +269,7 @@
mRoleManagerAdapter = new RoleManagerAdapterImpl(context);
mTimerAdapter = new TimerAdapterImpl();
mExecutorService = Executors.newSingleThreadScheduledExecutor();
+ mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
}
/**
@@ -277,6 +286,7 @@
mTimerAdapter = timerAdapter;
mDelegateControllerFactory = delegateFactory;
mExecutorService = executor;
+ mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
logi("created");
}
@@ -813,21 +823,14 @@
}
ArraySet<String> previouslyGrantedTags = new ArraySet<>(alreadyRequestedTags);
- // deny tags already used by other delegates
- Set<FeatureTagState> deniedTags = new ArraySet<>();
- for (String s : requestedFeatureTags) {
- if (previouslyGrantedTags.contains(s)) {
- deniedTags.add(new FeatureTagState(s,
- SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE));
- }
- }
- Set<String> nonDeniedTags = requestedFeatureTags.stream()
- .filter(r -> !previouslyGrantedTags.contains(r))
- .collect(Collectors.toSet());
+ ArraySet<String> candidateFeatureTags = new ArraySet<>(requestedFeatureTags);
+ Set<FeatureTagState> deniedTags =
+ updateSupportedTags(candidateFeatureTags, previouslyGrantedTags);
+
// Add newly granted tags to the already requested tags list.
- previouslyGrantedTags.addAll(nonDeniedTags);
+ previouslyGrantedTags.addAll(candidateFeatureTags);
CompletableFuture<Boolean> pendingChange = controller.changeSupportedFeatureTags(
- nonDeniedTags, deniedTags);
+ candidateFeatureTags, deniedTags);
logi("changeSupportedFeatureTags pendingChange=" + pendingChange);
// do not worry about executor used here, this stage used to interpret result + add log.
return pendingChange.thenApply((completedSuccessfully) -> {
@@ -838,6 +841,51 @@
}
/**
+ * Update candidate feature tags according to feature tags allowed by carrier config,
+ * and previously granted by other SipDelegates.
+ *
+ * @param candidateFeatureTags The candidate feature tags to be updated. It will be
+ * updated as needed per the carrier config and previously granted feature tags.
+ * @param previouslyGrantedTags The feature tags already granted by other SipDelegates.
+ * @return The set of denied feature tags.
+ */
+ private Set<FeatureTagState> updateSupportedTags(Set<String> candidateFeatureTags,
+ Set<String> previouslyGrantedTags) {
+ Boolean overrideRes = RcsProvisioningMonitor.getInstance()
+ .getImsFeatureValidationOverride(mSubId);
+ // deny tags already used by other delegates
+ Set<FeatureTagState> deniedTags = new ArraySet<>();
+
+ // match config if feature validation is not overridden
+ if (overrideRes == null) {
+ Iterator<String> it = candidateFeatureTags.iterator();
+ while (it.hasNext()) {
+ String tag = it.next();
+ if (previouslyGrantedTags.contains(tag)) {
+ logi(tag + " has already been granted previously.");
+ it.remove();
+ deniedTags.add(new FeatureTagState(tag,
+ SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE));
+ } else if (!mFeatureTagsAllowed.contains(tag.trim().toLowerCase())) {
+ logi(tag + " is not allowed per config.");
+ it.remove();
+ deniedTags.add(new FeatureTagState(tag,
+ SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
+ }
+ }
+ } else if (Boolean.FALSE.equals(overrideRes)) {
+ logi("all features are denied for test purpose.");
+ for (String s : candidateFeatureTags) {
+ deniedTags.add(new FeatureTagState(s,
+ SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
+ }
+ candidateFeatureTags.clear();
+ }
+
+ return deniedTags;
+ }
+
+ /**
* Run a Callable on the ExecutorService Thread and wait for the result.
* If an ImsException is thrown, catch it and rethrow it to caller.
*/
@@ -918,6 +966,8 @@
scheduleDestroyDelegates(
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
}
+
+ onCarrierConfigChangedInternal();
}
/**
@@ -925,6 +975,15 @@
*/
private void onCarrierConfigChangedInternal() {
logi("Carrier Config changed for subId: " + mSubId);
+ mFeatureTagsAllowed.clear();
+ PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
+ String[] tagConfigs = carrierConfig.getStringArray(
+ CarrierConfigManager.Ims.KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY);
+ if (tagConfigs != null && tagConfigs.length > 0) {
+ for (String tag : tagConfigs) {
+ mFeatureTagsAllowed.add(tag.trim().toLowerCase());
+ }
+ }
}
/**
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index 28c4390..54333bb 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -537,6 +537,50 @@
@Test
@SmallTest
+ public void testOverrideDeviceSingleRegistrationEnabled() throws Exception {
+ createMonitor(1);
+
+ when(mPackageManager.hasSystemFeature(
+ eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
+ mBundle.putBoolean(
+ CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
+ broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.overrideDeviceSingleRegistrationEnabled(false);
+ processAllMessages();
+ assertFalse(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.overrideDeviceSingleRegistrationEnabled(null);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ when(mPackageManager.hasSystemFeature(
+ eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(false);
+ //use carrier config change to refresh the value as system feature is static
+ mBundle.putBoolean(
+ CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
+ broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+ processAllMessages();
+
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.overrideDeviceSingleRegistrationEnabled(true);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.overrideDeviceSingleRegistrationEnabled(null);
+ processAllMessages();
+ assertFalse(mRcsProvisioningMonitor.getDeviceSingleRegistrationEnabled());
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ }
+
+ @Test
+ @SmallTest
public void testTestModeEnabledAndDisabled() throws Exception {
when(mCursor.getBlob(anyInt())).thenReturn(null);
createMonitor(1);
@@ -574,6 +618,65 @@
(byte[]) mProvider.getContentValues().get(SimInfo.COLUMN_RCS_CONFIG)));
}
+ @Test
+ @SmallTest
+ public void testOverrideCarrierSingleRegistrationEnabled() throws Exception {
+ createMonitor(1);
+
+ when(mPackageManager.hasSystemFeature(
+ eq(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION))).thenReturn(true);
+ mBundle.putBoolean(
+ CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, true);
+ broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor
+ .overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, false);
+ processAllMessages();
+ assertFalse(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor
+ .overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, null);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mBundle.putBoolean(
+ CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
+ broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+ processAllMessages();
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor
+ .overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, true);
+ processAllMessages();
+ assertTrue(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ assertTrue(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor
+ .overrideCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE, null);
+ processAllMessages();
+ assertFalse(mRcsProvisioningMonitor.getCarrierSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ assertFalse(mRcsProvisioningMonitor.isRcsVolteSingleRegistrationEnabled(FAKE_SUB_ID_BASE));
+ }
+
+ @Test
+ @SmallTest
+ public void testOverrideImsFeatureValidation() throws Exception {
+ createMonitor(1);
+
+ mRcsProvisioningMonitor.overrideImsFeatureValidation(FAKE_SUB_ID_BASE, false);
+ assertFalse(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.overrideImsFeatureValidation(FAKE_SUB_ID_BASE, true);
+ assertTrue(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
+
+ mRcsProvisioningMonitor.overrideImsFeatureValidation(FAKE_SUB_ID_BASE, null);
+ assertNull(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
+ }
+
private void createMonitor(int subCount) throws Exception {
if (Looper.myLooper() == null) {
Looper.prepare();
diff --git a/tests/src/com/android/phone/ServiceStateProviderTest.java b/tests/src/com/android/phone/ServiceStateProviderTest.java
index 32e5f26..d85976a 100644
--- a/tests/src/com/android/phone/ServiceStateProviderTest.java
+++ b/tests/src/com/android/phone/ServiceStateProviderTest.java
@@ -18,6 +18,7 @@
import static android.provider.Telephony.ServiceStateTable;
import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
+import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -31,8 +32,11 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
@@ -60,7 +64,7 @@
private final String[] mTestProjection =
{
ServiceStateTable.VOICE_REG_STATE,
- ServiceStateProvider.DATA_REG_STATE,
+ ServiceStateTable.DATA_REG_STATE,
ServiceStateProvider.VOICE_OPERATOR_ALPHA_LONG,
ServiceStateProvider.VOICE_OPERATOR_ALPHA_SHORT,
ServiceStateTable.VOICE_OPERATOR_NUMERIC,
@@ -81,15 +85,24 @@
ServiceStateProvider.IS_USING_CARRIER_AGGREGATION,
ServiceStateProvider.OPERATOR_ALPHA_LONG_RAW,
ServiceStateProvider.OPERATOR_ALPHA_SHORT_RAW,
+ ServiceStateTable.DATA_NETWORK_TYPE,
+ ServiceStateTable.DUPLEX_MODE,
};
+ // Exception used internally to verify if the Resolver#notifyChange has been called.
+ private class TestNotifierException extends RuntimeException {
+ TestNotifierException() {
+ super();
+ }
+ }
+
@Before
public void setUp() throws Exception {
mContext = mock(Context.class);
mContentResolver = new MockContentResolver() {
@Override
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
- throw new RuntimeException("notifyChange!");
+ throw new TestNotifierException();
}
};
doReturn(mContentResolver).when(mContext).getContentResolver();
@@ -99,6 +112,15 @@
mTestServiceStateForSubId1 = new ServiceState();
mTestServiceStateForSubId1.setStateOff();
+ // Add NRI to trigger SS with non-default values (e.g. duplex mode)
+ NetworkRegistrationInfo nriWwan = new NetworkRegistrationInfo.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .build();
+ mTestServiceStateForSubId1.addNetworkRegistrationInfo(nriWwan);
+ mTestServiceStateForSubId1.setChannelNumber(65536); // EutranBand.BAND_65, DUPLEX_MODE_FDD
+
// Mock out the actual phone state
ServiceStateProvider provider = new ServiceStateProvider() {
@Override
@@ -183,6 +205,8 @@
final int isUsingCarrierAggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
final String operatorAlphaLongRaw = ss.getOperatorAlphaLongRaw();
final String operatorAlphaShortRaw = ss.getOperatorAlphaShortRaw();
+ final int dataNetworkType = ss.getDataNetworkType();
+ final int duplexMode = ss.getDuplexMode();
assertEquals(voiceRegState, cursor.getInt(0));
assertEquals(dataRegState, cursor.getInt(1));
@@ -206,6 +230,8 @@
assertEquals(isUsingCarrierAggregation, cursor.getInt(19));
assertEquals(operatorAlphaLongRaw, cursor.getString(20));
assertEquals(operatorAlphaShortRaw, cursor.getString(21));
+ assertEquals(dataNetworkType, cursor.getInt(22));
+ assertEquals(duplexMode, cursor.getInt(23));
}
/**
@@ -226,21 +252,12 @@
newSS.setCdmaSystemAndNetworkId(0, 0);
// Test that notifyChange is not called for these fields
- boolean notifyChangeWasCalled = false;
- try {
- ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
- } catch (RuntimeException e) {
- final String message = e.getMessage();
- if (message != null && message.equals("notifyChange!")) {
- notifyChangeWasCalled = true;
- }
- }
- assertFalse(notifyChangeWasCalled);
+ assertFalse(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
}
@Test
@SmallTest
- public void testNotifyChanged() {
+ public void testNotifyChanged_noStateUpdated() {
int subId = 0;
ServiceState oldSS = new ServiceState();
@@ -251,57 +268,106 @@
copyOfOldSS.setStateOutOfService();
copyOfOldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+ // Test that notifyChange is not called with no change in notifyChangeForSubIdAndField
+ assertFalse(notifyChangeCalledForSubId(oldSS, copyOfOldSS, subId));
+
+ // Test that notifyChange is not called with no change in notifyChangeForSubId
+ assertFalse(notifyChangeCalledForSubIdAndField(oldSS, copyOfOldSS, subId));
+ }
+
+ @Test
+ @SmallTest
+ public void testNotifyChanged_voiceRegStateUpdated() {
+ int subId = 0;
+
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+ oldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+
ServiceState newSS = new ServiceState();
newSS.setStateOutOfService();
newSS.setVoiceRegState(ServiceState.STATE_POWER_OFF);
- // Test that notifyChange is not called with no change in notifyChangeForSubIdAndField
- boolean notifyChangeWasCalled = false;
- try {
- ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, copyOfOldSS, subId);
- } catch (RuntimeException e) {
- final String message = e.getMessage();
- if (message != null && message.equals("notifyChange!")) {
- notifyChangeWasCalled = true;
- }
- }
- assertFalse(notifyChangeWasCalled);
-
- // Test that notifyChange is not called with no change in notifyChangeForSubId
- notifyChangeWasCalled = false;
- try {
- ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, copyOfOldSS, subId);
- } catch (RuntimeException e) {
- final String message = e.getMessage();
- if (message != null && message.equals("notifyChange!")) {
- notifyChangeWasCalled = true;
- }
- }
- assertFalse(notifyChangeWasCalled);
-
// Test that notifyChange is called by notifyChangeForSubIdAndField when the voice_reg_state
// changes
- notifyChangeWasCalled = false;
- try {
- ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
- } catch (RuntimeException e) {
- final String message = e.getMessage();
- if (message != null && message.equals("notifyChange!")) {
- notifyChangeWasCalled = true;
- }
- }
- assertTrue(notifyChangeWasCalled);
+ assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId));
// Test that notifyChange is called by notifyChangeForSubId when the voice_reg_state changes
- notifyChangeWasCalled = false;
+ assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
+ }
+
+ @Test
+ @SmallTest
+ public void testNotifyChanged_dataNetworkTypeUpdated() {
+ int subId = 0;
+
+ // While we don't have a method to directly set dataNetworkType, we emulate a ServiceState
+ // change that will trigger the change of dataNetworkType, according to the logic in
+ // ServiceState#getDataNetworkType
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+
+ NetworkRegistrationInfo nriWwan = new NetworkRegistrationInfo.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setRegistrationState(REGISTRATION_STATE_HOME)
+ .build();
+ newSS.addNetworkRegistrationInfo(nriWwan);
+
+ // Test that notifyChange is called by notifyChangeForSubId when the
+ // data_network_type changes
+ assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId));
+
+ // Test that notifyChange is called by notifyChangeForSubIdAndField when the
+ // data_network_type changes
+ assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
+ }
+
+ @Test
+ @SmallTest
+ public void testNotifyChanged_dataRegStateUpdated() {
+ int subId = 0;
+
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+ oldSS.setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+ newSS.setDataRegState(ServiceState.STATE_POWER_OFF);
+
+ // Test that notifyChange is called by notifyChangeForSubId
+ // when the data_reg_state changes
+ assertTrue(notifyChangeCalledForSubId(oldSS, newSS, subId));
+
+ // Test that notifyChange is called by notifyChangeForSubIdAndField
+ // when the data_reg_state changes
+ assertTrue(notifyChangeCalledForSubIdAndField(oldSS, newSS, subId));
+ }
+
+ // Check if notifyChange was called by notifyChangeForSubId
+ private boolean notifyChangeCalledForSubId(ServiceState oldSS,
+ ServiceState newSS, int subId) {
try {
ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, newSS, subId);
- } catch (RuntimeException e) {
- final String message = e.getMessage();
- if (message != null && message.equals("notifyChange!")) {
- notifyChangeWasCalled = true;
- }
+ } catch (TestNotifierException e) {
+ return true;
}
- assertTrue(notifyChangeWasCalled);
+ return false;
+ }
+
+ // Check if notifyChange was called by notifyChangeForSubIdAndField
+ private boolean notifyChangeCalledForSubIdAndField(ServiceState oldSS,
+ ServiceState newSS, int subId) {
+ try {
+ ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
+ } catch (TestNotifierException e) {
+ return true;
+ }
+ return false;
}
}
diff --git a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
index fa27775..d364fe4 100644
--- a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
@@ -35,7 +35,9 @@
import android.app.role.RoleManager;
import android.os.IBinder;
+import android.os.PersistableBundle;
import android.os.UserHandle;
+import android.telephony.CarrierConfigManager;
import android.telephony.ims.DelegateRequest;
import android.telephony.ims.FeatureTagState;
import android.telephony.ims.ImsException;
@@ -54,6 +56,7 @@
import com.android.TelephonyTestBase;
import com.android.TestExecutorService;
import com.android.ims.RcsFeatureManager;
+import com.android.phone.RcsProvisioningMonitor;
import org.junit.After;
import org.junit.Before;
@@ -129,6 +132,9 @@
return c;
}).when(mMockDelegateControllerFactory).create(anyInt(), any(), anyString(), any(), any(),
any(), any(), any());
+ setFeatureAllowedConfig(TEST_SUB_ID, new String[]{ImsSignallingUtils.MMTEL_TAG,
+ ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG, ImsSignallingUtils.GROUP_CHAT_TAG,
+ ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG});
}
@After
@@ -138,6 +144,7 @@
if (!isShutdown) {
mExecutorService.shutdownNow();
}
+ RcsProvisioningMonitor.getInstance().overrideImsFeatureValidation(TEST_SUB_ID, null);
}
@SmallTest
@@ -607,6 +614,9 @@
@Test
public void testTimingSubIdChangedAndCreateNewSubId() throws Exception {
SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
+ setFeatureAllowedConfig(TEST_SUB_ID + 1, new String[]{ImsSignallingUtils.MMTEL_TAG,
+ ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG, ImsSignallingUtils.GROUP_CHAT_TAG,
+ ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG});
ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
@@ -643,6 +653,67 @@
verifyDelegateChanged(c2, pendingC2Change, secondDelegate, Collections.emptySet(), 0);
}
+ @SmallTest
+ @Test
+ public void testFeatureTagsDeniedByConfig() throws Exception {
+ setFeatureAllowedConfig(TEST_SUB_ID, new String[]{ImsSignallingUtils.GROUP_CHAT_TAG,
+ ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG});
+ SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
+
+ ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
+ ArraySet<String> allowedTags = new ArraySet<>(requestTags);
+ ArraySet<String> deniedTags = new ArraySet<>();
+ DelegateRequest delegateRequest = new DelegateRequest(requestTags);
+ SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
+ delegateRequest);
+ CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
+ delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+ allowedTags.remove(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
+ deniedTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
+
+ assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
+ verifyDelegateChanged(sc, pendingScChange, allowedTags, getDeniedTagsForReason(
+ deniedTags, SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
+ }
+
+ @SmallTest
+ @Test
+ public void testFeatureTagsDeniedByOverride() throws Exception {
+ RcsProvisioningMonitor.getInstance().overrideImsFeatureValidation(TEST_SUB_ID, false);
+ SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
+
+ ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
+ ArraySet<String> deniedTags = new ArraySet<>(requestTags);
+ DelegateRequest delegateRequest = new DelegateRequest(requestTags);
+ SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
+ delegateRequest);
+ CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
+ delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+
+ assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
+ verifyDelegateChanged(sc, pendingScChange, Collections.emptySet(), getDeniedTagsForReason(
+ deniedTags, SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
+ }
+
+ @SmallTest
+ @Test
+ public void testFeatureTagsDeniedByConfigAllowedByOverride() throws Exception {
+ setFeatureAllowedConfig(TEST_SUB_ID, new String[]{});
+ RcsProvisioningMonitor.getInstance().overrideImsFeatureValidation(TEST_SUB_ID, true);
+ SipTransportController controller = setupLiveTransportController(THROTTLE_MS, 0);
+
+ ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
+ ArraySet<String> allowedTags = new ArraySet<>(requestTags);
+ DelegateRequest delegateRequest = new DelegateRequest(requestTags);
+ SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
+ delegateRequest);
+ CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
+ delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+
+ assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
+ verifyDelegateChanged(sc, pendingScChange, allowedTags, Collections.emptySet(), 0);
+ }
+
@SafeVarargs
private final Pair<Set<String>, Set<FeatureTagState>> getAllowedAndDeniedTagsForConfig(
DelegateRequest r, int denyReason, Set<String>... previousRequestedTagSets) {
@@ -910,4 +981,10 @@
}
return true;
}
+
+ private void setFeatureAllowedConfig(int subId, String[] tags) {
+ PersistableBundle bundle = mContext.getCarrierConfig(subId);
+ bundle.putStringArray(
+ CarrierConfigManager.Ims.KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY, tags);
+ }
}