Merge "Update system APIs based on feedback."
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index a1d73ff..94cf1b2 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -117,4 +117,9 @@
<!-- Whether using the new SubscriptionManagerService or the old SubscriptionController -->
<bool name="config_using_subscription_manager_service">false</bool>
<java-symbol type="bool" name="config_using_subscription_manager_service" />
+
+ <!-- Whether asynchronously update the subscription database or not. Async mode increases
+ the performance, but sync mode reduces the chance of database/cache out-of-sync. -->
+ <bool name="config_subscription_database_async_update">true</bool>
+ <java-symbol type="bool" name="config_subscription_database_async_update" />
</resources>
diff --git a/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java b/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
index 0eff5f2..b5e5b25 100644
--- a/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
+++ b/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
@@ -97,7 +97,7 @@
public static ReadOperation[] READ_OPERATIONS =
new ReadOperation[] {
(parcel, provider) -> {
- parcel.setDataPosition(provider.consumeInt());
+ parcel.setDataPosition(provider.consumeInt(0, Integer.MAX_VALUE));
},
(parcel, provider) -> {
parcel.setDataCapacity(provider.consumeInt());
@@ -155,6 +155,7 @@
byte[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new byte[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -166,6 +167,7 @@
char[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new char[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -177,6 +179,7 @@
int[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new int[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -188,6 +191,7 @@
double[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new double[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -199,6 +203,7 @@
float[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new float[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -210,6 +215,7 @@
boolean[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new boolean[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -221,6 +227,7 @@
long[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new long[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -232,6 +239,7 @@
IBinder[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new IBinder[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -274,6 +282,7 @@
SingleDataParcelable[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new SingleDataParcelable[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -293,6 +302,7 @@
EmptyParcelable[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new EmptyParcelable[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -312,6 +322,7 @@
GenericDataParcelable[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new GenericDataParcelable[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -334,6 +345,7 @@
SomeParcelable[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new SomeParcelable[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
@@ -390,6 +402,7 @@
TestInterface[] array;
if (provider.consumeBoolean()) {
int pos = parcel.dataPosition();
+ if (pos < 0) return;
array = new TestInterface[Math.min(MAX_LEN, parcel.readInt())];
parcel.setDataPosition(pos);
} else {
diff --git a/services/tests/PackageManagerServiceTests/TEST_MAPPING b/services/tests/PackageManagerServiceTests/TEST_MAPPING
index af0008c..63f26b6 100644
--- a/services/tests/PackageManagerServiceTests/TEST_MAPPING
+++ b/services/tests/PackageManagerServiceTests/TEST_MAPPING
@@ -9,6 +9,38 @@
"name": "PackageManagerServiceHostTests"
}
],
+ "kernel-presubmit": [
+ {
+ "name": "PackageManagerServiceHostTests",
+ "options": [
+ {
+ // TODO(b/197552347) (crashes postsubmit)
+ "exclude-filter": "com.android.server.pm.test.OverlayActorVisibilityTest#testVisibilityByOverlayable"
+ },
+ {
+ // TODO(b/204133664)
+ "exclude-filter": "com.android.server.pm.test.SdCardEjectionTests"
+ },
+ {
+ // TODO(b/272575212)
+ "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptDataBinaryXml"
+ },
+ {
+ "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptDataTextXml"
+ },
+ {
+ "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptHeaderBinaryXml"
+ },
+ {
+ "exclude-filter": "com.android.server.pm.test.SettingsTest#testWriteCorruptHeaderTextXml"
+ },
+ {
+ // TODO(b/272714903)
+ "exclude-filter": "com.android.server.pm.test.OverlayPathsUninstallSystemUpdatesTest#verify"
+ }
+ ]
+ }
+ ],
"imports": [
{
"path": "frameworks/base/services/tests/PackageManagerServiceTests/unit"
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 80de823..3f83d4e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -736,8 +736,8 @@
verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class),
onFinishedCaptor.capture(), any(Handler.class), isNull(),
optionsCaptor.capture());
- assertTrue(optionsCaptor.getValue()
- .getBoolean(BroadcastOptions.KEY_ALARM_BROADCAST, false));
+ final BroadcastOptions options = new BroadcastOptions(optionsCaptor.getValue());
+ assertTrue(options.isAlarmBroadcast());
}
@Test
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 1ba997f..fdf69430 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -743,11 +743,23 @@
/**
* Given a list of permissions, check to see if the caller has at least one of them granted. If
- * not, check to see if the caller has carrier privileges. If the caller does not have any of
+ * not, check to see if the caller has carrier privileges. If the caller does not have any of
* these permissions, throw a SecurityException.
*/
public static void enforceAnyPermissionGrantedOrCarrierPrivileges(Context context, int subId,
int uid, String message, String... permissions) {
+ enforceAnyPermissionGrantedOrCarrierPrivileges(
+ context, subId, uid, false, message, permissions);
+ }
+
+ /**
+ * Given a list of permissions, check to see if the caller has at least one of them granted. If
+ * not, check to see if the caller has carrier privileges on the specified subscription (or any
+ * subscription if {@code allowCarrierPrivilegeOnAnySub} is {@code true}. If the caller does not
+ * have any of these permissions, throw a {@link SecurityException}.
+ */
+ public static void enforceAnyPermissionGrantedOrCarrierPrivileges(Context context, int subId,
+ int uid, boolean allowCarrierPrivilegeOnAnySub, String message, String... permissions) {
if (permissions.length == 0) return;
boolean isGranted = false;
for (String perm : permissions) {
@@ -758,7 +770,12 @@
}
if (isGranted) return;
- if (checkCarrierPrivilegeForSubId(context, subId)) return;
+
+ if (allowCarrierPrivilegeOnAnySub) {
+ if (checkCarrierPrivilegeForAnySubId(context, Binder.getCallingUid())) return;
+ } else {
+ if (checkCarrierPrivilegeForSubId(context, subId)) return;
+ }
StringBuilder b = new StringBuilder(message);
b.append(": Neither user ");
@@ -769,7 +786,8 @@
b.append(" or ");
b.append(permissions[i]);
}
- b.append(" or carrier privileges");
+ b.append(" or carrier privileges. subId=" + subId + ", allowCarrierPrivilegeOnAnySub="
+ + allowCarrierPrivilegeOnAnySub);
throw new SecurityException(b.toString());
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 35226c1..59b822ebe 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -58,6 +58,7 @@
import android.provider.Telephony.SimInfo;
import android.telephony.euicc.EuiccManager;
import android.telephony.ims.ImsMmTelManager;
+import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.util.Pair;
@@ -347,7 +348,7 @@
/**
* A content {@link Uri} used to receive updates on advanced calling user setting
- * @see ImsMmTelManager#isAdvancedCallingSettingEnabled().
+ *
* <p>
* Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
* subscription advanced calling enabled
@@ -358,6 +359,9 @@
* delivery of updates to the {@link Uri}.
* To be notified of changes to a specific subId, append subId to the URI
* {@link Uri#withAppendedPath(Uri, String)}.
+ *
+ * @see ImsMmTelManager#isAdvancedCallingSettingEnabled()
+ *
* @hide
*/
@NonNull
@@ -731,6 +735,15 @@
/** Indicates that data roaming is disabled for a subscription */
public static final int DATA_ROAMING_DISABLE = SimInfo.DATA_ROAMING_DISABLE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"DATA_ROAMING_"},
+ value = {
+ DATA_ROAMING_ENABLE,
+ DATA_ROAMING_DISABLE
+ })
+ public @interface DataRoamingMode {}
+
/**
* TelephonyProvider column name for subscription carrier id.
* @see TelephonyManager#getSimCarrierId()
@@ -1133,7 +1146,7 @@
*
* An opportunistic subscription will default to data-centric.
*
- * {@see SubscriptionInfo#isOpportunistic}
+ * @see SubscriptionInfo#isOpportunistic
*/
public static final int USAGE_SETTING_DEFAULT = 0;
@@ -1917,7 +1930,7 @@
*
* <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
*
- * @see {@link TelephonyManager#getCardIdForDefaultEuicc()} for more information on the card ID.
+ * @see TelephonyManager#getCardIdForDefaultEuicc() for more information on the card ID.
*
* @hide
*/
@@ -1947,7 +1960,7 @@
*
* @param cardId the card ID of the eUICC.
*
- * @see {@link TelephonyManager#getCardIdForDefaultEuicc()} for more information on the card ID.
+ * @see TelephonyManager#getCardIdForDefaultEuicc() for more information on the card ID.
*
* @hide
*/
@@ -2071,10 +2084,15 @@
}
/**
- * Remove SubscriptionInfo record from the SubscriptionInfo database
+ * Remove subscription info record from the subscription database.
+ *
* @param uniqueId This is the unique identifier for the subscription within the specific
- * subscription type.
- * @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
+ * subscription type.
+ * @param subscriptionType the type of subscription to be removed.
+ *
+ * @throws NullPointerException if {@code uniqueId} is {@code null}.
+ * @throws SecurityException if callers do not hold the required permission.
+ *
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@@ -2109,7 +2127,7 @@
/**
* Set SIM icon tint color for subscription ID
* @param tint the RGB value of icon tint color of the SIM
- * @param subId the unique Subscritpion ID in database
+ * @param subId the unique subscription ID in database
* @return the number of records updated
* @hide
*/
@@ -2117,7 +2135,7 @@
public int setIconTint(@ColorInt int tint, int subId) {
if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
return setSubscriptionPropertyHelper(subId, "setIconTint",
- (iSub)-> iSub.setIconTint(tint, subId)
+ (iSub)-> iSub.setIconTint(subId, tint)
);
}
@@ -2425,20 +2443,6 @@
return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
}
- /** @hide */
- public void clearSubscriptionInfo() {
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- iSub.clearSubInfo();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return;
- }
-
/**
* Check if the supplied subscription ID is valid.
*
@@ -2582,48 +2586,27 @@
}
/**
- * Returns a constant indicating the state of sim for the slot index.
+ * Set a field in the subscription database. Note not all fields are supported.
*
- * @param slotIndex
+ * @param subscriptionId Subscription Id of Subscription.
+ * @param columnName Column name in the database. Note not all fields are supported.
+ * @param value Value to store in the database.
*
- * {@See TelephonyManager#SIM_STATE_UNKNOWN}
- * {@See TelephonyManager#SIM_STATE_ABSENT}
- * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED}
- * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED}
- * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED}
- * {@See TelephonyManager#SIM_STATE_READY}
- * {@See TelephonyManager#SIM_STATE_NOT_READY}
- * {@See TelephonyManager#SIM_STATE_PERM_DISABLED}
- * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR}
+ * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not
+ * exposed.
+ * @throws SecurityException if callers do not hold the required permission.
*
- * {@hide}
- */
- public static int getSimStateForSlotIndex(int slotIndex) {
- int simState = TelephonyManager.SIM_STATE_UNKNOWN;
-
- try {
- ISub iSub = TelephonyManager.getSubscriptionService();
- if (iSub != null) {
- simState = iSub.getSimStateForSlotIndex(slotIndex);
- }
- } catch (RemoteException ex) {
- }
-
- return simState;
- }
-
- /**
- * Store properties associated with SubscriptionInfo in database
- * @param subId Subscription Id of Subscription
- * @param propKey Column name in database associated with SubscriptionInfo
- * @param propValue Value to store in DB for particular subId & column name
+ * @see android.provider.Telephony.SimInfo for all the columns.
+ *
* @hide
*/
- public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public static void setSubscriptionProperty(int subscriptionId, @NonNull String columnName,
+ @NonNull String value) {
try {
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
- iSub.setSubscriptionProperty(subId, propKey, propValue);
+ iSub.setSubscriptionProperty(subscriptionId, columnName, value);
}
} catch (RemoteException ex) {
// ignore it
@@ -2652,118 +2635,149 @@
}
/**
- * Return list of contacts uri corresponding to query result.
- * @param subId Subscription Id of Subscription
- * @param propKey Column name in SubscriptionInfo database
- * @return list of contacts uri to be returned
+ * Get specific field in string format from the subscription info database.
+ *
+ * @param context The calling context.
+ * @param subscriptionId Subscription id of the subscription.
+ * @param columnName Column name in subscription database.
+ *
+ * @return Value in string format associated with {@code subscriptionId} and {@code columnName}
+ * from the database.
+ *
+ * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not
+ * exposed.
+ *
+ * @see android.provider.Telephony.SimInfo for all the columns.
+ *
* @hide
*/
- private static List<Uri> getContactsFromSubscriptionProperty(int subId, String propKey,
- Context context) {
- String result = getSubscriptionProperty(subId, propKey, context);
- if (result != null) {
- try {
- byte[] b = Base64.decode(result, Base64.DEFAULT);
- ByteArrayInputStream bis = new ByteArrayInputStream(b);
- ObjectInputStream ois = new ObjectInputStream(bis);
- List<String> contacts = ArrayList.class.cast(ois.readObject());
- List<Uri> uris = new ArrayList<>();
- for (String contact : contacts) {
- uris.add(Uri.parse(contact));
- }
- return uris;
- } catch (IOException e) {
- logd("getContactsFromSubscriptionProperty IO exception");
- } catch (ClassNotFoundException e) {
- logd("getContactsFromSubscriptionProperty ClassNotFound exception");
- }
- }
- return new ArrayList<>();
- }
-
- /**
- * Store properties associated with SubscriptionInfo in database
- * @param subId Subscription Id of Subscription
- * @param propKey Column name in SubscriptionInfo database
- * @return Value associated with subId and propKey column in database
- * @hide
- */
- private static String getSubscriptionProperty(int subId, String propKey,
- Context context) {
+ @NonNull
+ @RequiresPermission(anyOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ "carrier privileges",
+ })
+ private static String getStringSubscriptionProperty(@NonNull Context context,
+ int subscriptionId, @NonNull String columnName) {
String resultValue = null;
try {
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
- resultValue = iSub.getSubscriptionProperty(subId, propKey,
+ resultValue = iSub.getSubscriptionProperty(subscriptionId, columnName,
context.getOpPackageName(), context.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
}
- return resultValue;
+ return TextUtils.emptyIfNull(resultValue);
}
/**
- * Returns boolean value corresponding to query result.
- * @param subId Subscription Id of Subscription
- * @param propKey Column name in SubscriptionInfo database
- * @param defValue Default boolean value to be returned
- * @return boolean result value to be returned
+ * Get specific field in {@code boolean} format from the subscription info database.
+ *
+ * @param subscriptionId Subscription id of the subscription.
+ * @param columnName Column name in subscription database.
+ * @param defaultValue Default value in case not found or error.
+ * @param context The calling context.
+ *
+ * @return Value in {@code boolean} format associated with {@code subscriptionId} and
+ * {@code columnName} from the database, or {@code defaultValue} if not found or error.
+ *
+ * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not
+ * exposed.
+ *
+ * @see android.provider.Telephony.SimInfo for all the columns.
+ *
* @hide
*/
- public static boolean getBooleanSubscriptionProperty(int subId, String propKey,
- boolean defValue, Context context) {
- String result = getSubscriptionProperty(subId, propKey, context);
- if (result != null) {
+ @RequiresPermission(anyOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ "carrier privileges",
+ })
+ public static boolean getBooleanSubscriptionProperty(int subscriptionId,
+ @NonNull String columnName, boolean defaultValue, @NonNull Context context) {
+ String result = getStringSubscriptionProperty(context, subscriptionId, columnName);
+ if (!result.isEmpty()) {
try {
return Integer.parseInt(result) == 1;
} catch (NumberFormatException err) {
logd("getBooleanSubscriptionProperty NumberFormat exception");
}
}
- return defValue;
+ return defaultValue;
}
/**
- * Returns integer value corresponding to query result.
- * @param subId Subscription Id of Subscription
- * @param propKey Column name in SubscriptionInfo database
- * @param defValue Default integer value to be returned
- * @return integer result value to be returned
+ * Get specific field in {@code integer} format from the subscription info database.
+ *
+ * @param subscriptionId Subscription id of the subscription.
+ * @param columnName Column name in subscription database.
+ * @param defaultValue Default value in case not found or error.
+ * @param context The calling context.
+ *
+ * @return Value in {@code integer} format associated with {@code subscriptionId} and
+ * {@code columnName} from the database, or {@code defaultValue} if not found or error.
+ *
+ * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not
+ * exposed.
+ *
+ * @see android.provider.Telephony.SimInfo for all the columns.
+ *
* @hide
*/
- public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue,
- Context context) {
- String result = getSubscriptionProperty(subId, propKey, context);
- if (result != null) {
+ @RequiresPermission(anyOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ "carrier privileges",
+ })
+ public static int getIntegerSubscriptionProperty(int subscriptionId, @NonNull String columnName,
+ int defaultValue, @NonNull Context context) {
+ String result = getStringSubscriptionProperty(context, subscriptionId, columnName);
+ if (!result.isEmpty()) {
try {
return Integer.parseInt(result);
} catch (NumberFormatException err) {
logd("getIntegerSubscriptionProperty NumberFormat exception");
}
}
- return defValue;
+ return defaultValue;
}
/**
- * Returns long value corresponding to query result.
- * @param subId Subscription Id of Subscription
- * @param propKey Column name in SubscriptionInfo database
- * @param defValue Default long value to be returned
- * @return long result value to be returned
+ * Get specific field in {@code long} format from the subscription info database.
+ *
+ * @param subscriptionId Subscription id of the subscription.
+ * @param columnName Column name in subscription database.
+ * @param defaultValue Default value in case not found or error.
+ * @param context The calling context.
+ *
+ * @return Value in {@code long} format associated with {@code subscriptionId} and
+ * {@code columnName} from the database, or {@code defaultValue} if not found or error.
+ *
+ * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not
+ * exposed.
+ *
+ * @see android.provider.Telephony.SimInfo for all the columns.
+ *
* @hide
*/
- public static long getLongSubscriptionProperty(int subId, String propKey, long defValue,
- Context context) {
- String result = getSubscriptionProperty(subId, propKey, context);
- if (result != null) {
+ @RequiresPermission(anyOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ "carrier privileges",
+ })
+ public static long getLongSubscriptionProperty(int subscriptionId, @NonNull String columnName,
+ long defaultValue, @NonNull Context context) {
+ String result = getStringSubscriptionProperty(context, subscriptionId, columnName);
+ if (!result.isEmpty()) {
try {
return Long.parseLong(result);
} catch (NumberFormatException err) {
logd("getLongSubscriptionProperty NumberFormat exception");
}
}
- return defValue;
+ return defaultValue;
}
/**
@@ -3001,7 +3015,6 @@
* considered unmetered.
* @param networkTypes the network types this override applies to. If no
* network types are specified, override values will be ignored.
- * {@see TelephonyManager#getAllNetworkTypes()}
* @param expirationDurationMillis the duration after which the requested override
* will be automatically cleared, or {@code 0} to leave in the
* requested state until explicitly cleared, or the next reboot,
@@ -3062,17 +3075,14 @@
* </ul>
*
* @param subId the subscriber this override applies to.
- * @param overrideCongested set if the subscription should be considered
- * congested.
- * @param networkTypes the network types this override applies to. If no
- * network types are specified, override values will be ignored.
- * {@see TelephonyManager#getAllNetworkTypes()}
+ * @param overrideCongested set if the subscription should be considered congested.
+ * @param networkTypes the network types this override applies to. If no network types are
+ * specified, override values will be ignored.
* @param expirationDurationMillis the duration after which the requested override
- * will be automatically cleared, or {@code 0} to leave in the
- * requested state until explicitly cleared, or the next reboot,
- * whichever happens first.
- * @throws SecurityException if the caller doesn't meet the requirements
- * outlined above.
+ * will be automatically cleared, or {@code 0} to leave in the requested state until explicitly
+ * cleared, or the next reboot, whichever happens first.
+ *
+ * @throws SecurityException if the caller doesn't meet the requirements outlined above.
*/
public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
@NonNull @Annotation.NetworkType int[] networkTypes,
@@ -3088,10 +3098,11 @@
*
* Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} returns
* true). To check for permissions for non-embedded subscription as well,
- * {@see android.telephony.TelephonyManager#hasCarrierPrivileges}.
*
* @param info The subscription to check.
* @return whether the app is authorized to manage this subscription per its metadata.
+ *
+ * @see android.telephony.TelephonyManager#hasCarrierPrivileges
*/
public boolean canManageSubscription(SubscriptionInfo info) {
return canManageSubscription(info, mContext.getPackageName());
@@ -3104,11 +3115,13 @@
*
* Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} returns
* true). To check for permissions for non-embedded subscription as well,
- * {@see android.telephony.TelephonyManager#hasCarrierPrivileges}.
*
* @param info The subscription to check.
* @param packageName Package name of the app to check.
+ *
* @return whether the app is authorized to manage this subscription per its access rules.
+ *
+ * @see android.telephony.TelephonyManager#hasCarrierPrivileges
* @hide
*/
@SystemApi
@@ -3421,21 +3434,20 @@
/**
* Remove a list of subscriptions from their subscription group.
- * See {@link #createSubscriptionGroup(List)} for more details.
*
* Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
- * permission or had carrier privilege permission on the subscriptions:
- * {@link TelephonyManager#hasCarrierPrivileges()} or
- * {@link #canManageSubscription(SubscriptionInfo)}
- *
- * @throws SecurityException if the caller doesn't meet the requirements
- * outlined above.
- * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong
- * the specified group.
- * @throws IllegalStateException if Telephony service is in bad state.
+ * permission or has carrier privilege permission on all of the subscriptions provided in
+ * {@code subIdList}.
*
* @param subIdList list of subId that need removing from their groups.
+ * @param groupUuid The UUID of the subscription group.
*
+ * @throws SecurityException if the caller doesn't meet the requirements outlined above.
+ * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong the
+ * specified group.
+ * @throws IllegalStateException if Telephony service is in bad state.
+ *
+ * @see #createSubscriptionGroup(List)
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@@ -3443,7 +3455,7 @@
@NonNull ParcelUuid groupUuid) {
Preconditions.checkNotNull(subIdList, "subIdList can't be null.");
Preconditions.checkNotNull(groupUuid, "groupUuid can't be null.");
- String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ String callingPackage = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (VDBG) {
logd("[removeSubscriptionsFromGroup]");
}
@@ -3453,7 +3465,7 @@
try {
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
- iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug);
+ iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, callingPackage);
} else {
if (!isSystemProcess()) {
throw new IllegalStateException("telephony service is null.");
@@ -3491,7 +3503,6 @@
* @param groupUuid of which list of subInfo will be returned.
* @return list of subscriptionInfo that belong to the same group, including the given
* subscription itself. It will return an empty list if no subscription belongs to the group.
- *
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@@ -3531,7 +3542,8 @@
* want to see their own hidden subscriptions.
*
* @param info the subscriptionInfo to check against.
- * @return true if this subscription should be visible to the API caller.
+ *
+ * @return {@code true} if this subscription should be visible to the API caller.
*
* @hide
*/
@@ -3604,9 +3616,9 @@
* <p>
* Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
*
+ * @param subscriptionId Subscription to be enabled or disabled. It could be a eSIM or pSIM
+ * subscription.
* @param enable whether user is turning it on or off.
- * @param subscriptionId Subscription to be enabled or disabled.
- * It could be a eSIM or pSIM subscription.
*
* @return whether the operation is successful.
*
@@ -3639,8 +3651,6 @@
* available from SubscriptionInfo.areUiccApplicationsEnabled() will be updated
* immediately.)
*
- * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
- *
* @param subscriptionId which subscription to operate on.
* @param enabled whether uicc applications are enabled or disabled.
* @hide
@@ -3673,8 +3683,6 @@
* It provides whether a physical SIM card can be disabled without taking it out, which is done
* via {@link #setSubscriptionEnabled(int, boolean)} API.
*
- * Requires Permission: READ_PRIVILEGED_PHONE_STATE.
- *
* @return whether can disable subscriptions on physical SIMs.
*
* @hide
@@ -3702,10 +3710,11 @@
}
/**
- * DO NOT USE.
- * This API is designed for features that are not finished at this point. Do not call this API.
+ * Check if the subscription is currently active in any slot.
+ *
+ * @param subscriptionId The subscription id.
+ *
* @hide
- * TODO b/135547512: further clean up
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -3723,11 +3732,14 @@
}
/**
- * Set the device to device status sharing user preference for a subscription ID. The setting
+ * Set the device to device status sharing user preference for a subscription id. The setting
* app uses this method to indicate with whom they wish to share device to device status
* information.
- * @param sharing the status sharing preference
- * @param subscriptionId the unique Subscription ID in database
+ *
+ * @param subscriptionId The subscription id.
+ * @param sharing The status sharing preference.
+ *
+ * @throws SecurityException if the caller doesn't have permissions required.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setDeviceToDeviceStatusSharingPreference(int subscriptionId,
@@ -3744,6 +3756,8 @@
* Returns the user-chosen device to device status sharing preference
* @param subscriptionId Subscription id of subscription
* @return The device to device status sharing preference
+ *
+ * @throws SecurityException if the caller doesn't have permissions required.
*/
public @DeviceToDeviceStatusSharingPreference int getDeviceToDeviceStatusSharingPreference(
int subscriptionId) {
@@ -3755,11 +3769,14 @@
}
/**
- * Set the list of contacts that allow device to device status sharing for a subscription ID.
+ * Set the list of contacts that allow device to device status sharing for a subscription id.
* The setting app uses this method to indicate with whom they wish to share device to device
* status information.
- * @param contacts The list of contacts that allow device to device status sharing
- * @param subscriptionId The unique Subscription ID in database
+ *
+ * @param subscriptionId The subscription id.
+ * @param contacts The list of contacts that allow device to device status sharing.
+ *
+ * @throws SecurityException if the caller doesn't have permissions required.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setDeviceToDeviceStatusSharingContacts(int subscriptionId,
@@ -3775,17 +3792,33 @@
}
/**
- * Returns the list of contacts that allow device to device status sharing.
- * @param subscriptionId Subscription id of subscription
- * @return The list of contacts that allow device to device status sharing
+ * Get the list of contacts that allow device to device status sharing.
+ *
+ * @param subscriptionId Subscription id.
+ *
+ * @return The list of contacts that allow device to device status sharing.
*/
- public @NonNull List<Uri> getDeviceToDeviceStatusSharingContacts(
- int subscriptionId) {
- if (VDBG) {
- logd("[getDeviceToDeviceStatusSharingContacts] + subId: " + subscriptionId);
+ public @NonNull List<Uri> getDeviceToDeviceStatusSharingContacts(int subscriptionId) {
+ String result = getStringSubscriptionProperty(mContext, subscriptionId,
+ D2D_STATUS_SHARING_SELECTED_CONTACTS);
+ if (result != null) {
+ try {
+ byte[] b = Base64.decode(result, Base64.DEFAULT);
+ ByteArrayInputStream bis = new ByteArrayInputStream(b);
+ ObjectInputStream ois = new ObjectInputStream(bis);
+ List<String> contacts = ArrayList.class.cast(ois.readObject());
+ List<Uri> uris = new ArrayList<>();
+ for (String contact : contacts) {
+ uris.add(Uri.parse(contact));
+ }
+ return uris;
+ } catch (IOException e) {
+ logd("getDeviceToDeviceStatusSharingContacts IO exception");
+ } catch (ClassNotFoundException e) {
+ logd("getDeviceToDeviceStatusSharingContacts ClassNotFound exception");
+ }
}
- return getContactsFromSubscriptionProperty(subscriptionId,
- D2D_STATUS_SHARING_SELECTED_CONTACTS, mContext);
+ return new ArrayList<>();
}
/**
@@ -3840,12 +3873,12 @@
/**
* Get active data subscription id. Active data subscription refers to the subscription
* currently chosen to provide cellular internet connection to the user. This may be
- * different from getDefaultDataSubscriptionId(). Eg. Opportunistics data
+ * different from {@link #getDefaultDataSubscriptionId()}.
*
- * See {@link PhoneStateListener#onActiveDataSubscriptionIdChanged(int)} for the details.
+ * @return Active data subscription id if any is chosen, or {@link #INVALID_SUBSCRIPTION_ID} if
+ * not.
*
- * @return Active data subscription id if any is chosen, or
- * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not.
+ * @see TelephonyCallback.ActiveDataSubscriptionIdListener
*/
public static int getActiveDataSubscriptionId() {
if (isSubscriptionManagerServiceEnabled()) {
@@ -4038,12 +4071,15 @@
* security-related or other sensitive scenarios.
*
* @param subscriptionId the subscription ID, or {@link #DEFAULT_SUBSCRIPTION_ID}
- * for the default one.
+ * for the default one.
* @param source the source of the phone number, one of the PHONE_NUMBER_SOURCE_* constants.
+ *
* @return the phone number, or an empty string if not available.
+ *
* @throws IllegalArgumentException if {@code source} is invalid.
* @throws IllegalStateException if the telephony process is not currently available.
* @throws SecurityException if the caller doesn't have permissions required.
+ *
* @see #PHONE_NUMBER_SOURCE_UICC
* @see #PHONE_NUMBER_SOURCE_CARRIER
* @see #PHONE_NUMBER_SOURCE_IMS
@@ -4096,8 +4132,10 @@
* @param subscriptionId the subscription ID, or {@link #DEFAULT_SUBSCRIPTION_ID}
* for the default one.
* @return the phone number, or an empty string if not available.
+ *
* @throws IllegalStateException if the telephony process is not currently available.
* @throws SecurityException if the caller doesn't have permissions required.
+ *
* @see #getPhoneNumber(int, int)
*/
@RequiresPermission(anyOf = {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7a19d36..9d418e1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3504,7 +3504,7 @@
"state as absent");
return SIM_STATE_ABSENT;
}
- return SubscriptionManager.getSimStateForSlotIndex(slotIndex);
+ return getSimStateForSlotIndex(slotIndex);
}
/**
@@ -3651,9 +3651,7 @@
@Deprecated
public @SimState int getSimApplicationState(int physicalSlotIndex) {
int activePort = getFirstActivePortIndex(physicalSlotIndex);
- int simState =
- SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex,
- activePort));
+ int simState = getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, activePort));
return getSimApplicationStateFromSimState(simState);
}
@@ -3679,9 +3677,7 @@
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public @SimState int getSimApplicationState(int physicalSlotIndex, int portIndex) {
- int simState =
- SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex,
- portIndex));
+ int simState = getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex, portIndex));
return getSimApplicationStateFromSimState(simState);
}
@@ -3750,7 +3746,7 @@
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public @SimState int getSimState(int slotIndex) {
- int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex);
+ int simState = getSimStateForSlotIndex(slotIndex);
if (simState == SIM_STATE_LOADED) {
simState = SIM_STATE_READY;
}
@@ -17006,4 +17002,30 @@
}
return false;
}
+
+ /**
+ * Returns a constant indicating the state of sim for the slot index.
+ *
+ * @param slotIndex Logical SIM slot index.
+ *
+ * @see TelephonyManager.SimState
+ *
+ * @hide
+ */
+ @SimState
+ public static int getSimStateForSlotIndex(int slotIndex) {
+ try {
+ ITelephony telephony = ITelephony.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
+ if (telephony != null) {
+ return telephony.getSimStateForSlotIndex(slotIndex);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in getSimStateForSlotIndex: " + e);
+ }
+ return TelephonyManager.SIM_STATE_UNKNOWN;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 5173405..c5f6902 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -135,11 +135,11 @@
/**
* Set SIM icon tint color by simInfo index
- * @param tint the icon tint color of the SIM
* @param subId the unique SubscriptionInfo index in database
+ * @param tint the icon tint color of the SIM
* @return the number of records updated
*/
- int setIconTint(int tint, int subId);
+ int setIconTint(int subId, int tint);
/**
* Set display name by simInfo index with name source
@@ -242,8 +242,6 @@
int getDefaultSubId();
- int clearSubInfo();
-
int getPhoneId(int subId);
/**
@@ -274,11 +272,6 @@
boolean isSubscriptionEnabled(int subId);
int getEnabledSubscriptionId(int slotIndex);
- /**
- * Get the SIM state for the slot index
- * @return SIM state as the ordinal of IccCardConstants.State
- */
- int getSimStateForSlotIndex(int slotIndex);
boolean isActiveSubId(int subId, String callingPackage, String callingFeatureId);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index da1ffcd..ecafe70 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2564,4 +2564,11 @@
* @hide
*/
boolean isRemovableEsimDefaultEuicc(String callingPackage);
+
+ /**
+ * Get the SIM state for the logical SIM slot index.
+ *
+ * @param slotIndex Logical SIM slot index.
+ */
+ int getSimStateForSlotIndex(int slotIndex);
}