diff options
Diffstat (limited to 'telephony')
162 files changed, 15944 insertions, 1696 deletions
diff --git a/telephony/OWNERS b/telephony/OWNERS index 025869dd2999..3158ad8fc58e 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -11,12 +11,6 @@ chinmayd@google.com amruthr@google.com sasindran@google.com -# Temporarily reduced the owner during refactoring -per-file SubscriptionManager.java=set noparent -per-file SubscriptionManager.java=jackyu@google.com,amruthr@google.com -per-file SubscriptionInfo.java=set noparent -per-file SubscriptionInfo.java=jackyu@google.com,amruthr@google.com - # Requiring TL ownership for new carrier config keys. per-file CarrierConfigManager.java=set noparent per-file CarrierConfigManager.java=amruthr@google.com,tgunn@google.com,rgreenwalt@google.com,satk@google.com diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index 423022599de6..a9cdf7e5bc08 100644 --- a/telephony/common/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java @@ -190,12 +190,11 @@ public final class SmsApplication { } /** - * Returns the userId of the Context object, if called from a system app, + * Returns the userId of the current process, if called from a system app, * otherwise it returns the caller's userId - * @param context The context object passed in by the caller. - * @return + * @return userId of the caller. */ - private static int getIncomingUserId(Context context) { + private static int getIncomingUserId() { int contextUserId = UserHandle.myUserId(); final int callingUid = Binder.getCallingUid(); if (DEBUG_MULTIUSER) { @@ -211,6 +210,15 @@ public final class SmsApplication { } /** + * Returns the userHandle of the current process, if called from a system app, + * otherwise it returns the caller's userHandle + * @return userHandle of the caller. + */ + private static UserHandle getIncomingUserHandle() { + return UserHandle.of(getIncomingUserId()); + } + + /** * Returns the list of available SMS apps defined as apps that are registered for both the * SMS_RECEIVED_ACTION (SMS) and WAP_PUSH_RECEIVED_ACTION (MMS) broadcasts (and their broadcast * receivers are enabled) @@ -231,7 +239,7 @@ public final class SmsApplication { */ @UnsupportedAppUsage public static Collection<SmsApplicationData> getApplicationCollection(Context context) { - return getApplicationCollectionAsUser(context, getIncomingUserId(context)); + return getApplicationCollectionAsUser(context, getIncomingUserId()); } /** @@ -590,7 +598,7 @@ public final class SmsApplication { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static void setDefaultApplication(String packageName, Context context) { - setDefaultApplicationAsUser(packageName, context, getIncomingUserId(context)); + setDefaultApplicationAsUser(packageName, context, getIncomingUserId()); } /** @@ -952,24 +960,28 @@ public final class SmsApplication { */ @UnsupportedAppUsage public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) { - return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId(context)); + return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle()); } /** * Gets the default SMS application on a given user * @param context context from the calling app * @param updateIfNeeded update the default app if there is no valid default app configured. - * @param userId target user ID. + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. * @return component name of the app and class to deliver SMS messages to */ - @VisibleForTesting public static ComponentName getDefaultSmsApplicationAsUser(Context context, - boolean updateIfNeeded, int userId) { + boolean updateIfNeeded, @Nullable UserHandle userHandle) { + if (userHandle == null) { + userHandle = getIncomingUserHandle(); + } + final long token = Binder.clearCallingIdentity(); try { ComponentName component = null; SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded, - userId); + userHandle.getIdentifier()); if (smsApplicationData != null) { component = new ComponentName(smsApplicationData.mPackageName, smsApplicationData.mSmsReceiverClass); @@ -988,12 +1000,28 @@ public final class SmsApplication { */ @UnsupportedAppUsage public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) { - int userId = getIncomingUserId(context); + return getDefaultMmsApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle()); + } + + /** + * Gets the default MMS application on a given user + * @param context context from the calling app + * @param updateIfNeeded update the default app if there is no valid default app configured. + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. + * @return component name of the app and class to deliver MMS messages to. + */ + public static ComponentName getDefaultMmsApplicationAsUser(Context context, + boolean updateIfNeeded, @Nullable UserHandle userHandle) { + if (userHandle == null) { + userHandle = getIncomingUserHandle(); + } + final long token = Binder.clearCallingIdentity(); try { ComponentName component = null; SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded, - userId); + userHandle.getIdentifier()); if (smsApplicationData != null) { component = new ComponentName(smsApplicationData.mPackageName, smsApplicationData.mMmsReceiverClass); @@ -1013,12 +1041,29 @@ public final class SmsApplication { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static ComponentName getDefaultRespondViaMessageApplication(Context context, boolean updateIfNeeded) { - int userId = getIncomingUserId(context); + return getDefaultRespondViaMessageApplicationAsUser(context, updateIfNeeded, + getIncomingUserHandle()); + } + + /** + * Gets the default Respond Via Message application on a given user + * @param context context from the calling app + * @param updateIfNeeded update the default app if there is no valid default app configured + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. + * @return component name of the app and class to direct Respond Via Message intent to + */ + public static ComponentName getDefaultRespondViaMessageApplicationAsUser(Context context, + boolean updateIfNeeded, @Nullable UserHandle userHandle) { + if (userHandle == null) { + userHandle = getIncomingUserHandle(); + } + final long token = Binder.clearCallingIdentity(); try { ComponentName component = null; SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded, - userId); + userHandle.getIdentifier()); if (smsApplicationData != null) { component = new ComponentName(smsApplicationData.mPackageName, smsApplicationData.mRespondViaMessageClass); @@ -1039,7 +1084,8 @@ public final class SmsApplication { */ public static ComponentName getDefaultSendToApplication(Context context, boolean updateIfNeeded) { - int userId = getIncomingUserId(context); + int userId = getIncomingUserId(); + final long token = Binder.clearCallingIdentity(); try { ComponentName component = null; @@ -1064,12 +1110,30 @@ public final class SmsApplication { */ public static ComponentName getDefaultExternalTelephonyProviderChangedApplication( Context context, boolean updateIfNeeded) { - int userId = getIncomingUserId(context); + return getDefaultExternalTelephonyProviderChangedApplicationAsUser(context, updateIfNeeded, + getIncomingUserHandle()); + } + + /** + * Gets the default application that handles external changes to the SmsProvider and + * MmsProvider on a given user. + * @param context context from the calling app + * @param updateIfNeeded update the default app if there is no valid default app configured + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. + * @return component name of the app and class to deliver change intents to. + */ + public static ComponentName getDefaultExternalTelephonyProviderChangedApplicationAsUser( + Context context, boolean updateIfNeeded, @Nullable UserHandle userHandle) { + if (userHandle == null) { + userHandle = getIncomingUserHandle(); + } + final long token = Binder.clearCallingIdentity(); try { ComponentName component = null; SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded, - userId); + userHandle.getIdentifier()); if (smsApplicationData != null && smsApplicationData.mProviderChangedReceiverClass != null) { component = new ComponentName(smsApplicationData.mPackageName, @@ -1089,12 +1153,28 @@ public final class SmsApplication { */ public static ComponentName getDefaultSimFullApplication( Context context, boolean updateIfNeeded) { - int userId = getIncomingUserId(context); + return getDefaultSimFullApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle()); + } + + /** + * Gets the default application that handles sim full event on a given user. + * @param context context from the calling app + * @param updateIfNeeded update the default app if there is no valid default app configured + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. + * @return component name of the app and class to deliver change intents to + */ + public static ComponentName getDefaultSimFullApplicationAsUser(Context context, + boolean updateIfNeeded, @Nullable UserHandle userHandle) { + if (userHandle == null) { + userHandle = getIncomingUserHandle(); + } + final long token = Binder.clearCallingIdentity(); try { ComponentName component = null; SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded, - userId); + userHandle.getIdentifier()); if (smsApplicationData != null && smsApplicationData.mSimFullReceiverClass != null) { component = new ComponentName(smsApplicationData.mPackageName, @@ -1107,13 +1187,35 @@ public final class SmsApplication { } /** - * Returns whether need to write the SMS message to SMS database for this package. + * Returns whether it is required to write the SMS message to SMS database for this package. + * + * @param packageName the name of the package to be checked + * @param context context from the calling app + * @return true if it is required to write SMS message to SMS database for this package. + * * <p> * Caller must pass in the correct user context if calling from a singleton service. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static boolean shouldWriteMessageForPackage(String packageName, Context context) { - return !isDefaultSmsApplication(context, packageName); + return !shouldWriteMessageForPackageAsUser(packageName, context, getIncomingUserHandle()); + } + + /** + * Returns whether it is required to write the SMS message to SMS database for this package. + * + * @param packageName the name of the package to be checked + * @param context context from the calling app + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. + * @return true if it is required to write SMS message to SMS database for this package. + * + * <p> + * Caller must pass in the correct user context if calling from a singleton service. + */ + public static boolean shouldWriteMessageForPackageAsUser(String packageName, Context context, + @Nullable UserHandle userHandle) { + return !isDefaultSmsApplicationAsUser(context, packageName, userHandle); } /** @@ -1125,28 +1227,48 @@ public final class SmsApplication { */ @UnsupportedAppUsage public static boolean isDefaultSmsApplication(Context context, String packageName) { + return isDefaultSmsApplicationAsUser(context, packageName, getIncomingUserHandle()); + } + + /** + * Check if a package is default sms app (or equivalent, like bluetooth) on a given user. + * + * @param context context from the calling app + * @param packageName the name of the package to be checked + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. + * @return true if the package is default sms app or bluetooth + */ + public static boolean isDefaultSmsApplicationAsUser(Context context, String packageName, + @Nullable UserHandle userHandle) { if (packageName == null) { return false; } - final String defaultSmsPackage = getDefaultSmsApplicationPackageName(context); - final String bluetoothPackageName = context.getResources() + + if (userHandle == null) { + userHandle = getIncomingUserHandle(); + } + + ComponentName component = getDefaultSmsApplicationAsUser(context, false, + userHandle); + if (component == null) { + return false; + } + + String defaultSmsPackage = component.getPackageName(); + if (defaultSmsPackage == null) { + return false; + } + + String bluetoothPackageName = context.getResources() .getString(com.android.internal.R.string.config_systemBluetoothStack); - if ((defaultSmsPackage != null && defaultSmsPackage.equals(packageName)) - || bluetoothPackageName.equals(packageName)) { + if (defaultSmsPackage.equals(packageName) || bluetoothPackageName.equals(packageName)) { return true; } return false; } - private static String getDefaultSmsApplicationPackageName(Context context) { - final ComponentName component = getDefaultSmsApplication(context, false); - if (component != null) { - return component.getPackageName(); - } - return null; - } - /** * Check if a package is default mms app (or equivalent, like bluetooth) * @@ -1156,25 +1278,45 @@ public final class SmsApplication { */ @UnsupportedAppUsage public static boolean isDefaultMmsApplication(Context context, String packageName) { + return isDefaultMmsApplicationAsUser(context, packageName, getIncomingUserHandle()); + } + + /** + * Check if a package is default mms app (or equivalent, like bluetooth) on a given user. + * + * @param context context from the calling app + * @param packageName the name of the package to be checked + * @param userHandle target user handle + * if {@code null} is passed in then calling package uid is used to find out target user handle. + * @return true if the package is default mms app or bluetooth + */ + public static boolean isDefaultMmsApplicationAsUser(Context context, String packageName, + @Nullable UserHandle userHandle) { if (packageName == null) { return false; } - String defaultMmsPackage = getDefaultMmsApplicationPackageName(context); + + if (userHandle == null) { + userHandle = getIncomingUserHandle(); + } + + ComponentName component = getDefaultMmsApplicationAsUser(context, false, + userHandle); + if (component == null) { + return false; + } + + String defaultMmsPackage = component.getPackageName(); + if (defaultMmsPackage == null) { + return false; + } + String bluetoothPackageName = context.getResources() .getString(com.android.internal.R.string.config_systemBluetoothStack); - if ((defaultMmsPackage != null && defaultMmsPackage.equals(packageName)) - || bluetoothPackageName.equals(packageName)) { + if (defaultMmsPackage.equals(packageName)|| bluetoothPackageName.equals(packageName)) { return true; } return false; } - - private static String getDefaultMmsApplicationPackageName(Context context) { - ComponentName component = getDefaultMmsApplication(context, false); - if (component != null) { - return component.getPackageName(); - } - return null; - } -} +}
\ No newline at end of file diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index f90eabc7175e..29a952a5d6d1 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -108,6 +109,21 @@ public final class TelephonyPermissions { } } + /** + * Check whether the caller (or self, if not processing an IPC) has internet permission. + * @param context app context + * @param message detail message + * @return true if permission is granted, else false + */ + public static boolean checkInternetPermissionNoThrow(Context context, String message) { + try { + context.enforcePermission(Manifest.permission.INTERNET, + Binder.getCallingPid(), Binder.getCallingUid(), message); + return true; + } catch (SecurityException se) { + return false; + } + } /** * Check whether the caller (or self, if not processing an IPC) has non dangerous @@ -315,8 +331,8 @@ public final class TelephonyPermissions { * Same as {@link #checkCallingOrSelfReadSubscriberIdentifiers(Context, int, String, String, * String)} except this allows an additional parameter reportFailure. Caller may not want to * report a failure when this is an internal/intermediate check, for example, - * SubscriptionController calls this with an INVALID_SUBID to check if caller has the required - * permissions to bypass carrier privilege checks. + * SubscriptionManagerService calls this with an INVALID_SUBID to check if caller has the + * required permissions to bypass carrier privilege checks. * @param reportFailure Indicates if failure should be reported. */ public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId, @@ -826,6 +842,37 @@ public final class TelephonyPermissions { /** * Check if calling user is associated with the given subscription. + * Subscription-user association check is skipped if destination address is an emergency number. + * + * @param context Context + * @param subId subscription ID + * @param callerUserHandle caller user handle + * @param destAddr destination address of the message + * @return true if destAddr is an emergency number + * and return false if user is not associated with the subscription. + */ + public static boolean checkSubscriptionAssociatedWithUser(@NonNull Context context, int subId, + @NonNull UserHandle callerUserHandle, @NonNull String destAddr) { + // Skip subscription-user association check for emergency numbers + TelephonyManager tm = context.getSystemService(TelephonyManager.class); + final long token = Binder.clearCallingIdentity(); + try { + if (tm != null && tm.isEmergencyNumber(destAddr)) { + Log.d(LOG_TAG, "checkSubscriptionAssociatedWithUser:" + + " destAddr is emergency number"); + return true; + } + } catch(Exception e) { + Log.e(LOG_TAG, "Cannot verify if destAddr is an emergency number: " + e); + } finally { + Binder.restoreCallingIdentity(token); + } + + return checkSubscriptionAssociatedWithUser(context, subId, callerUserHandle); + } + + /** + * Check if calling user is associated with the given subscription. * @param context Context * @param subId subscription ID * @param callerUserHandle caller user handle @@ -844,7 +891,7 @@ public final class TelephonyPermissions { if ((subManager != null) && (!subManager.isSubscriptionAssociatedWithUser(subId, callerUserHandle))) { // If subId is not associated with calling user, return false. - Log.e(LOG_TAG,"User[User ID:" + callerUserHandle.getIdentifier() + Log.e(LOG_TAG, "User[User ID:" + callerUserHandle.getIdentifier() + "] is not associated with Subscription ID:" + subId); return false; @@ -854,4 +901,27 @@ public final class TelephonyPermissions { } return true; } + + /** + * Ensure the caller (or self, if not processing an IPC) has + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or + * {@link android.Manifest.permission#READ_PHONE_NUMBERS}. + * + * @throws SecurityException if the caller does not have the required permission/privileges + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PHONE_NUMBERS, + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE + }) + public static boolean checkCallingOrSelfReadPrivilegedPhoneStatePermissionOrReadPhoneNumber( + Context context, int subId, String callingPackage, @Nullable String callingFeatureId, + String message) { + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + return false; + } + return (context.checkCallingOrSelfPermission( + Manifest.permission.READ_PRIVILEGED_PHONE_STATE) == PERMISSION_GRANTED + || checkCallingOrSelfReadPhoneNumber(context, subId, callingPackage, + callingFeatureId, message)); + } } diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java index 5179babbd31d..9a8c9655375d 100644 --- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java @@ -19,6 +19,8 @@ import static android.telephony.Annotation.DataState; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.role.RoleManager; import android.content.Context; import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; @@ -26,8 +28,16 @@ import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; import android.os.PersistableBundle; +import android.os.RemoteException; import android.os.SystemProperties; +import android.os.UserHandle; +import android.os.UserManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; +import android.util.Log; + +import com.android.internal.telephony.ITelephony; import java.io.PrintWriter; import java.util.Collections; @@ -41,6 +51,8 @@ import java.util.function.Supplier; * This class provides various util functions */ public final class TelephonyUtils { + private static final String LOG_TAG = "TelephonyUtils"; + public static boolean IS_USER = "user".equals(android.os.Build.TYPE); public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1; @@ -206,8 +218,105 @@ public final class TelephonyUtils { return "DATA_ON_NON_DEFAULT_DURING_VOICE_CALL"; case TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED: return "MMS_ALWAYS_ALLOWED"; + case TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH: + return "AUTO_DATA_SWITCH"; default: return "UNKNOWN(" + mobileDataPolicy + ")"; } } -} + + /** + * Utility method to get user handle associated with this subscription. + * + * This method should be used internally as it returns null instead of throwing + * IllegalArgumentException or IllegalStateException. + * + * @param context Context object + * @param subId the subId of the subscription. + * @return userHandle associated with this subscription + * or {@code null} if: + * 1. subscription is not associated with any user + * 2. subId is invalid. + * 3. subscription service is not available. + * + * @throws SecurityException if the caller doesn't have permissions required. + */ + @Nullable + public static UserHandle getSubscriptionUserHandle(Context context, int subId) { + UserHandle userHandle = null; + SubscriptionManager subManager = context.getSystemService(SubscriptionManager.class); + if ((subManager != null) && (SubscriptionManager.isValidSubscriptionId(subId))) { + userHandle = subManager.getSubscriptionUserHandle(subId); + } + return userHandle; + } + + /** + * Show switch to managed profile dialog if subscription is associated with managed profile. + * + * @param context Context object + * @param subId subscription id + * @param callingUid uid for the calling app + * @param callingPackage package name of the calling app + */ + public static void showSwitchToManagedProfileDialogIfAppropriate(Context context, + int subId, int callingUid, String callingPackage) { + final long token = Binder.clearCallingIdentity(); + try { + UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid); + // We only want to show this dialog, while user actually trying to send the message from + // a messaging app, in other cases this dialog don't make sense. + if (!TelephonyUtils.isUidForeground(context, callingUid) + || !TelephonyUtils.isPackageSMSRoleHolderForUser(context, callingPackage, + callingUserHandle)) { + return; + } + + SubscriptionManager subscriptionManager = context.getSystemService( + SubscriptionManager.class); + UserHandle associatedUserHandle = subscriptionManager.getSubscriptionUserHandle(subId); + UserManager um = context.getSystemService(UserManager.class); + + if (associatedUserHandle != null && um.isManagedProfile( + associatedUserHandle.getIdentifier())) { + + ITelephony iTelephony = ITelephony.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getTelephonyServiceRegisterer() + .get()); + if (iTelephony != null) { + try { + iTelephony.showSwitchToManagedProfileDialog(); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Failed to launch switch to managed profile dialog."); + } + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private static boolean isUidForeground(Context context, int uid) { + ActivityManager am = context.getSystemService(ActivityManager.class); + boolean result = am != null && am.getUidImportance(uid) + == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + return result; + } + + private static boolean isPackageSMSRoleHolderForUser(Context context, String callingPackage, + UserHandle user) { + RoleManager roleManager = context.getSystemService(RoleManager.class); + final List<String> smsRoleHolder = roleManager.getRoleHoldersAsUser( + RoleManager.ROLE_SMS, user); + + // ROLE_SMS is an exclusive role per user, so there would just be one entry in the + // retuned list if not empty + if (!smsRoleHolder.isEmpty() && callingPackage.equals(smsRoleHolder.get(0))) { + return true; + } + return false; + + } +}
\ No newline at end of file diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java index 7eccd1a4482f..f7c8237bdda4 100644 --- a/telephony/java/android/service/euicc/EuiccProfileInfo.java +++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java @@ -24,6 +24,7 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.service.carrier.CarrierIdentifier; +import android.telephony.SubscriptionInfo; import android.telephony.UiccAccessRule; import android.text.TextUtils; @@ -451,6 +452,8 @@ public final class EuiccProfileInfo implements Parcelable { + mPolicyRules + ", accessRules=" + Arrays.toString(mAccessRules) + + ", iccid=" + + SubscriptionInfo.getPrintableId(mIccid) + ")"; } } diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java index e19117bc805f..b59e855825b9 100644 --- a/telephony/java/android/service/euicc/EuiccService.java +++ b/telephony/java/android/service/euicc/EuiccService.java @@ -17,10 +17,12 @@ package android.service.euicc; import static android.telephony.euicc.EuiccCardManager.ResetOption; +import android.Manifest; import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.app.PendingIntent; @@ -132,13 +134,25 @@ public abstract class EuiccService extends Service { * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS * The difference is this one is used by system to bring up the LUI. */ + @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */ + @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; + /** @see android.telephony.euicc.EuiccManager#ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS */ + @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) + public static final String ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS = + "android.service.euicc.action.TRANSFER_EMBEDDED_SUBSCRIPTIONS"; + + /** @see android.telephony.euicc.EuiccManager#ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION */ + @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) + public static final String ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION = + "android.service.euicc.action.CONVERT_TO_EMBEDDED_SUBSCRIPTION"; + /** * @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED. This is * a protected intent that can only be sent by the system, and requires the @@ -490,6 +504,28 @@ public abstract class EuiccService extends Service { int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim); /** + * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. + * + * @param slotId ID of the SIM slot to use for the operation. + * @param portIndex Index of the port from the slot. portIndex is used if the eUICC must + * be activated to perform the operation. + * @param subscription A subscription whose metadata needs to be populated. + * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the + * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} + * should be returned to allow the user to consent to this operation first. + * @return The result of the operation. + * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata + */ + @NonNull + public GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( + int slotId, int portIndex, @NonNull DownloadableSubscription subscription, + boolean forceDeactivateSim) { + // stub implementation, LPA needs to implement this + throw new UnsupportedOperationException( + "LPA must override onGetDownloadableSubscriptionMetadata"); + } + + /** * Return metadata for subscriptions which are available for download for this device. * * @param slotId ID of the SIM slot to use for the operation. @@ -833,16 +869,31 @@ public abstract class EuiccService extends Service { } @Override - public void getDownloadableSubscriptionMetadata(int slotId, + public void getDownloadableSubscriptionMetadata(int slotId, int portIndex, DownloadableSubscription subscription, - boolean forceDeactivateSim, + boolean switchAfterDownload, boolean forceDeactivateSim, IGetDownloadableSubscriptionMetadataCallback callback) { mExecutor.execute(new Runnable() { @Override public void run() { - GetDownloadableSubscriptionMetadataResult result = - EuiccService.this.onGetDownloadableSubscriptionMetadata( + GetDownloadableSubscriptionMetadataResult result; + if (switchAfterDownload) { + try { + result = EuiccService.this.onGetDownloadableSubscriptionMetadata( + slotId, portIndex, subscription, forceDeactivateSim); + } catch (UnsupportedOperationException | AbstractMethodError e) { + Log.w(TAG, "The new onGetDownloadableSubscriptionMetadata(int, int, " + + "DownloadableSubscription, boolean) is not implemented." + + " Fall back to the old one.", e); + result = EuiccService.this.onGetDownloadableSubscriptionMetadata( slotId, subscription, forceDeactivateSim); + } + } else { + // When switchAfterDownload is false, this operation is port agnostic. + // Call API without portIndex. + result = EuiccService.this.onGetDownloadableSubscriptionMetadata( + slotId, subscription, forceDeactivateSim); + } try { callback.onComplete(result); } catch (RemoteException e) { diff --git a/telephony/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl index 6b0397d67015..f8d5ae9ca86d 100644 --- a/telephony/java/android/service/euicc/IEuiccService.aidl +++ b/telephony/java/android/service/euicc/IEuiccService.aidl @@ -38,8 +38,10 @@ oneway interface IEuiccService { void downloadSubscription(int slotId, int portIndex, in DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, in Bundle resolvedBundle, in IDownloadSubscriptionCallback callback); - void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription, - boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback); + void getDownloadableSubscriptionMetadata( + int slotId, int portIndex, in DownloadableSubscription subscription, + boolean switchAfterDownload, boolean forceDeactivateSim, + in IGetDownloadableSubscriptionMetadataCallback callback); void getEid(int slotId, in IGetEidCallback callback); void getOtaStatus(int slotId, in IGetOtaStatusCallback callback); void startOtaIfNecessary(int slotId, in IOtaStatusChangedCallback statusChangedCallback); diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index 86b98f1cbe79..2435243f0044 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -5,6 +5,7 @@ import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.telecom.Connection; import android.telephony.data.ApnSetting; +import android.telephony.ims.ImsCallProfile; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -494,7 +495,7 @@ public class Annotation { PreciseCallState.PRECISE_CALL_STATE_HOLDING, PreciseCallState.PRECISE_CALL_STATE_DIALING, PreciseCallState.PRECISE_CALL_STATE_ALERTING, - PreciseCallState. PRECISE_CALL_STATE_INCOMING, + PreciseCallState.PRECISE_CALL_STATE_INCOMING, PreciseCallState.PRECISE_CALL_STATE_WAITING, PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED, PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING}) @@ -727,6 +728,36 @@ public class Annotation { }) public @interface ValidationStatus {} + /** + * IMS call Service types + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "SERVICE_TYPE_" }, value = { + ImsCallProfile.SERVICE_TYPE_NONE, + ImsCallProfile.SERVICE_TYPE_NORMAL, + ImsCallProfile.SERVICE_TYPE_EMERGENCY, + }) + public @interface ImsCallServiceType {} + + /** + * IMS call types + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "CALL_TYPE_" }, value = { + ImsCallProfile.CALL_TYPE_NONE, + ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, + ImsCallProfile.CALL_TYPE_VOICE, + ImsCallProfile.CALL_TYPE_VIDEO_N_VOICE, + ImsCallProfile.CALL_TYPE_VT, + ImsCallProfile.CALL_TYPE_VT_TX, + ImsCallProfile.CALL_TYPE_VT_RX, + ImsCallProfile.CALL_TYPE_VT_NODIR, + ImsCallProfile.CALL_TYPE_VS, + ImsCallProfile.CALL_TYPE_VS_TX, + ImsCallProfile.CALL_TYPE_VS_RX, + }) + public @interface ImsCallType {} + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = { diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java index 061b71b25275..db38f8873a02 100644 --- a/telephony/java/android/telephony/AnomalyReporter.java +++ b/telephony/java/android/telephony/AnomalyReporter.java @@ -105,13 +105,22 @@ public final class AnomalyReporter { * @param carrierId the carrier of the id associated with this event. */ public static void reportAnomaly(@NonNull UUID eventId, String description, int carrierId) { + Rlog.i(TAG, "reportAnomaly: Received anomaly event report with eventId= " + eventId + + " and description= " + description); if (sContext == null) { Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId); return; } - // Don't report if the server-side flag isn't loaded, as it implies other anomaly report - // related config hasn't loaded. + //always write atoms to statsd + TelephonyStatsLog.write( + TELEPHONY_ANOMALY_DETECTED, + carrierId, + eventId.getLeastSignificantBits(), + eventId.getMostSignificantBits()); + + // Don't report via Intent if the server-side flag isn't loaded, as it implies other anomaly + // report related config hasn't loaded. try { boolean isAnomalyReportEnabledFromServer = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_TELEPHONY, KEY_IS_TELEPHONY_ANOMALY_REPORT_ENABLED, @@ -122,12 +131,6 @@ public final class AnomalyReporter { return; } - TelephonyStatsLog.write( - TELEPHONY_ANOMALY_DETECTED, - carrierId, - eventId.getLeastSignificantBits(), - eventId.getMostSignificantBits()); - // If this event has already occurred, skip sending intents for it; regardless log its // invocation here. Integer count = sEvents.containsKey(eventId) ? sEvents.get(eventId) + 1 : 1; diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java index b7bef39aa275..1dc64a9200fc 100644 --- a/telephony/java/android/telephony/CallAttributes.java +++ b/telephony/java/android/telephony/CallAttributes.java @@ -29,8 +29,10 @@ import java.util.Objects; * Contains information about a call's attributes as passed up from the HAL. If there are multiple * ongoing calls, the CallAttributes will pertain to the call in the foreground. * @hide + * @deprecated use {@link CallState} for call information for each call. */ @SystemApi +@Deprecated public final class CallAttributes implements Parcelable { private PreciseCallState mPreciseCallState; @NetworkType diff --git a/telephony/java/android/telephony/CallState.aidl b/telephony/java/android/telephony/CallState.aidl new file mode 100644 index 000000000000..dd5af8e65921 --- /dev/null +++ b/telephony/java/android/telephony/CallState.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 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 android.telephony; + +parcelable CallState; + diff --git a/telephony/java/android/telephony/CallState.java b/telephony/java/android/telephony/CallState.java new file mode 100644 index 000000000000..836cb53488ef --- /dev/null +++ b/telephony/java/android/telephony/CallState.java @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.Annotation.ImsCallServiceType; +import android.telephony.Annotation.ImsCallType; +import android.telephony.Annotation.NetworkType; +import android.telephony.Annotation.PreciseCallStates; +import android.telephony.ims.ImsCallProfile; +import android.telephony.ims.ImsCallSession; + +import java.util.Objects; + +/** + * Contains information about various states for a call. + * @hide + */ +@SystemApi +public final class CallState implements Parcelable { + + /** + * Call classifications are just used for backward compatibility of deprecated API {@link + * TelephonyCallback#CallAttributesListener#onCallAttributesChanged}, Since these will be + * removed when the deprecated API is removed, they should not be opened. + */ + /** + * Call classification is not valid. It should not be opened. + * @hide + */ + public static final int CALL_CLASSIFICATION_UNKNOWN = -1; + + /** + * Call classification indicating foreground call + * @hide + */ + public static final int CALL_CLASSIFICATION_RINGING = 0; + + /** + * Call classification indicating background call + * @hide + */ + public static final int CALL_CLASSIFICATION_FOREGROUND = 1; + + /** + * Call classification indicating ringing call + * @hide + */ + public static final int CALL_CLASSIFICATION_BACKGROUND = 2; + + /** + * Call classification Max value. + * @hide + */ + public static final int CALL_CLASSIFICATION_MAX = CALL_CLASSIFICATION_BACKGROUND + 1; + + @PreciseCallStates + private final int mPreciseCallState; + + @NetworkType + private final int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints + private final CallQuality mCallQuality; + + private final int mCallClassification; + /** + * IMS call session ID. {@link ImsCallSession#getCallId()} + */ + @Nullable + private String mImsCallId; + + /** + * IMS call service type of this call + */ + @ImsCallServiceType + private int mImsCallServiceType; + + /** + * IMS call type of this call. + */ + @ImsCallType + private int mImsCallType; + + /** + * Constructor of CallAttributes + * + * @param callState call state defined in {@link PreciseCallState} + * @param networkType network type for this call attributes + * @param callQuality call quality for this call attributes, only CallState in + * {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call + * quality. + * @param callClassification call classification + * @param imsCallId IMS call session ID for this call attributes + * @param imsCallServiceType IMS call service type for this call attributes + * @param imsCallType IMS call type for this call attributes + */ + private CallState(@PreciseCallStates int callState, @NetworkType int networkType, + @NonNull CallQuality callQuality, int callClassification, @Nullable String imsCallId, + @ImsCallServiceType int imsCallServiceType, @ImsCallType int imsCallType) { + this.mPreciseCallState = callState; + this.mNetworkType = networkType; + this.mCallQuality = callQuality; + this.mCallClassification = callClassification; + this.mImsCallId = imsCallId; + this.mImsCallServiceType = imsCallServiceType; + this.mImsCallType = imsCallType; + } + + @NonNull + @Override + public String toString() { + return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType + + " mCallQuality=" + mCallQuality + " mCallClassification" + mCallClassification + + " mImsCallId=" + mImsCallId + " mImsCallServiceType=" + mImsCallServiceType + + " mImsCallType=" + mImsCallType; + } + + private CallState(Parcel in) { + this.mPreciseCallState = in.readInt(); + this.mNetworkType = in.readInt(); + this.mCallQuality = in.readParcelable( + CallQuality.class.getClassLoader(), CallQuality.class); + this.mCallClassification = in.readInt(); + this.mImsCallId = in.readString(); + this.mImsCallServiceType = in.readInt(); + this.mImsCallType = in.readInt(); + } + + // getters + /** + * Returns the precise call state of the call. + */ + @PreciseCallStates + public int getCallState() { + return mPreciseCallState; + } + + /** + * Returns the {@link TelephonyManager#NetworkType} of the call. + * + * @see TelephonyManager#NETWORK_TYPE_UNKNOWN + * @see TelephonyManager#NETWORK_TYPE_GPRS + * @see TelephonyManager#NETWORK_TYPE_EDGE + * @see TelephonyManager#NETWORK_TYPE_UMTS + * @see TelephonyManager#NETWORK_TYPE_CDMA + * @see TelephonyManager#NETWORK_TYPE_EVDO_0 + * @see TelephonyManager#NETWORK_TYPE_EVDO_A + * @see TelephonyManager#NETWORK_TYPE_1xRTT + * @see TelephonyManager#NETWORK_TYPE_HSDPA + * @see TelephonyManager#NETWORK_TYPE_HSUPA + * @see TelephonyManager#NETWORK_TYPE_HSPA + * @see TelephonyManager#NETWORK_TYPE_IDEN + * @see TelephonyManager#NETWORK_TYPE_EVDO_B + * @see TelephonyManager#NETWORK_TYPE_LTE + * @see TelephonyManager#NETWORK_TYPE_EHRPD + * @see TelephonyManager#NETWORK_TYPE_HSPAP + * @see TelephonyManager#NETWORK_TYPE_GSM + * @see TelephonyManager#NETWORK_TYPE_TD_SCDMA + * @see TelephonyManager#NETWORK_TYPE_IWLAN + * @see TelephonyManager#NETWORK_TYPE_LTE_CA + * @see TelephonyManager#NETWORK_TYPE_NR + */ + @NetworkType + public int getNetworkType() { + return mNetworkType; + } + + /** + * Returns the {#link CallQuality} of the call. + * @return call quality for this call attributes, only CallState in {@link + * PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call quality. It will be + * null for the call which is not in {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE}. + */ + @Nullable + public CallQuality getCallQuality() { + return mCallQuality; + } + + /** + * Returns the call classification. + * @hide + */ + public int getCallClassification() { + return mCallClassification; + } + + /** + * Returns the IMS call session ID. + */ + @Nullable + public String getImsCallSessionId() { + return mImsCallId; + } + + /** + * Returns the IMS call service type. + */ + @ImsCallServiceType + public int getImsCallServiceType() { + return mImsCallServiceType; + } + + /** + * Returns the IMS call type. + */ + @ImsCallType + public int getImsCallType() { + return mImsCallType; + } + + @Override + public int hashCode() { + return Objects.hash(mPreciseCallState, mNetworkType, mCallQuality, mCallClassification, + mImsCallId, mImsCallServiceType, mImsCallType); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null || !(o instanceof CallState) || hashCode() != o.hashCode()) { + return false; + } + + if (this == o) { + return true; + } + + CallState s = (CallState) o; + + return (mPreciseCallState == s.mPreciseCallState + && mNetworkType == s.mNetworkType + && Objects.equals(mCallQuality, s.mCallQuality) + && mCallClassification == s.mCallClassification + && Objects.equals(mImsCallId, s.mImsCallId) + && mImsCallType == s.mImsCallType + && mImsCallServiceType == s.mImsCallServiceType); + } + + /** + * {@link Parcelable#describeContents} + */ + public int describeContents() { + return 0; + } + + /** + * {@link Parcelable#writeToParcel} + */ + public void writeToParcel(@Nullable Parcel dest, int flags) { + dest.writeInt(mPreciseCallState); + dest.writeInt(mNetworkType); + dest.writeParcelable(mCallQuality, flags); + dest.writeInt(mCallClassification); + dest.writeString(mImsCallId); + dest.writeInt(mImsCallServiceType); + dest.writeInt(mImsCallType); + } + + public static final @NonNull Creator<CallState> CREATOR = new Creator() { + public CallState createFromParcel(Parcel in) { + return new CallState(in); + } + + public CallState[] newArray(int size) { + return new CallState[size]; + } + }; + + /** + * Builder of {@link CallState} + * + * <p>The example below shows how you might create a new {@code CallState}. A precise call state + * {@link PreciseCallStates} is mandatory to build a CallState. + * + * <pre><code> + * + * CallState = new CallState.Builder({@link PreciseCallStates}) + * .setNetworkType({@link TelephonyManager#NETWORK_TYPE_LTE}) + * .setCallQuality({@link CallQuality}) + * .setImsCallSessionId({@link String}) + * .setImsCallServiceType({@link ImsCallProfile#SERVICE_TYPE_NORMAL}) + * .setImsCallType({@link ImsCallProfile#CALL_TYPE_VOICE}) + * .build(); + * </code></pre> + */ + public static final class Builder { + private @PreciseCallStates int mPreciseCallState; + private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + private CallQuality mCallQuality = null; + private int mCallClassification = CALL_CLASSIFICATION_UNKNOWN; + private String mImsCallId; + private @ImsCallServiceType int mImsCallServiceType = ImsCallProfile.SERVICE_TYPE_NONE; + private @ImsCallType int mImsCallType = ImsCallProfile.CALL_TYPE_NONE; + + + /** + * Default constructor for the Builder. + */ + public Builder(@PreciseCallStates int preciseCallState) { + mPreciseCallState = preciseCallState; + } + + /** + * Set network type of this call. + * + * @param networkType the transport type. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setNetworkType(@NetworkType int networkType) { + this.mNetworkType = networkType; + return this; + } + + /** + * Set the call quality {@link CallQuality} of this call. + * + * @param callQuality call quality of active call. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setCallQuality(@Nullable CallQuality callQuality) { + this.mCallQuality = callQuality; + return this; + } + + /** + * Set call classification for this call. + * + * @param classification call classification type defined in this class. + * @return The same instance of the builder. + * @hide + */ + @NonNull + public CallState.Builder setCallClassification(int classification) { + this.mCallClassification = classification; + return this; + } + + /** + * Set IMS call session ID of this call. + * + * @param imsCallId IMS call session ID. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setImsCallSessionId(@Nullable String imsCallId) { + this.mImsCallId = imsCallId; + return this; + } + + /** + * Set IMS call service type of this call. + * + * @param serviceType IMS call service type defined in {@link ImsCallProfile}. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setImsCallServiceType(@ImsCallServiceType int serviceType) { + this.mImsCallServiceType = serviceType; + return this; + } + + /** + * Set IMS call type of this call. + * + * @param callType IMS call type defined in {@link ImsCallProfile}. + * @return The same instance of the builder. + */ + @NonNull + public CallState.Builder setImsCallType(@ImsCallType int callType) { + this.mImsCallType = callType; + return this; + } + + /** + * Build the {@link CallState} + * + * @return the {@link CallState} object + */ + @NonNull + public CallState build() { + return new CallState( + mPreciseCallState, + mNetworkType, + mCallQuality, + mCallClassification, + mImsCallId, + mImsCallServiceType, + mImsCallType); + } + } +} diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 34a901c69f77..7193de789743 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -34,6 +34,7 @@ import android.content.pm.PackageManager; import android.net.NetworkCapabilities; import android.net.ipsec.ike.SaProposal; import android.os.Build; +import android.os.Handler; import android.os.PersistableBundle; import android.os.RemoteException; import android.service.carrier.CarrierService; @@ -45,9 +46,11 @@ import android.telephony.gba.UaSecurityProtocolIdentifier; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ImsSsData; +import android.telephony.ims.MediaQualityStatus; import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.feature.RcsFeature; +import android.telephony.ims.stub.ImsRegistrationImplBase; import com.android.internal.telephony.ICarrierConfigLoader; import com.android.telephony.Rlog; @@ -56,6 +59,7 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; /** * Provides access to telephony configuration values that are carrier-specific. @@ -63,7 +67,7 @@ import java.util.concurrent.TimeUnit; @SystemService(Context.CARRIER_CONFIG_SERVICE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public class CarrierConfigManager { - private final static String TAG = "CarrierConfigManager"; + private static final String TAG = "CarrierConfigManager"; /** * Extra included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate the slot index that the @@ -106,25 +110,25 @@ public class CarrierConfigManager { * Only send USSD over IMS while CS is out of service, otherwise send USSD over CS. * {@link #KEY_CARRIER_USSD_METHOD_INT} */ - public static final int USSD_OVER_CS_PREFERRED = 0; + public static final int USSD_OVER_CS_PREFERRED = 0; /** * Send USSD over IMS or CS while IMS is out of service or silent redial over CS if needed. * {@link #KEY_CARRIER_USSD_METHOD_INT} */ - public static final int USSD_OVER_IMS_PREFERRED = 1; + public static final int USSD_OVER_IMS_PREFERRED = 1; /** * Only send USSD over CS. * {@link #KEY_CARRIER_USSD_METHOD_INT} */ - public static final int USSD_OVER_CS_ONLY = 2; + public static final int USSD_OVER_CS_ONLY = 2; /** * Only send USSD over IMS and disallow silent redial over CS. * {@link #KEY_CARRIER_USSD_METHOD_INT} */ - public static final int USSD_OVER_IMS_ONLY = 3; + public static final int USSD_OVER_IMS_ONLY = 3; /** * Indicates CARRIER_NR_AVAILABILITY_NSA determine that the carrier enable the non-standalone @@ -159,8 +163,8 @@ public class CarrierConfigManager { * @see TelephonyManager#getSimCarrierId() * @see TelephonyManager#getSimSpecificCarrierId() */ - public static final String - ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED"; + public static final String ACTION_CARRIER_CONFIG_CHANGED = + "android.telephony.action.CARRIER_CONFIG_CHANGED"; // Below are the keys used in carrier config bundles. To add a new variable, define the key and // give it a default value in sDefaults. If you need to ship a per-network override in the @@ -181,8 +185,8 @@ public class CarrierConfigManager { * @deprecated Use {@link Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL} instead. */ @Deprecated - public static final String - KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; + public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = + "carrier_volte_provisioned_bool"; /** * Boolean indicating the Supplementary Services(SS) is disable when airplane mode on in the @@ -215,29 +219,29 @@ public class CarrierConfigManager { public static final String KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL = "call_forwarding_when_unreachable_supported_bool"; - /** - * Boolean indicating if carrier supports call forwarding option "When unanswered". - * - * {@code true}: Call forwarding option "When unanswered" is supported. - * {@code false}: Call forwarding option "When unanswered" is not supported. Option will be - * removed in the UI. - * - * By default this value is true. - * @hide - */ + /** + * Boolean indicating if carrier supports call forwarding option "When unanswered". + * + * {@code true}: Call forwarding option "When unanswered" is supported. + * {@code false}: Call forwarding option "When unanswered" is not supported. Option will be + * removed in the UI. + * + * By default this value is true. + * @hide + */ public static final String KEY_CALL_FORWARDING_WHEN_UNANSWERED_SUPPORTED_BOOL = "call_forwarding_when_unanswered_supported_bool"; - /** - * Boolean indicating if carrier supports call forwarding option "When busy". - * - * {@code true}: Call forwarding option "When busy" is supported. - * {@code false}: Call forwarding option "When busy" is not supported. Option will be - * removed in the UI. - * - * By default this value is true. - * @hide - */ + /** + * Boolean indicating if carrier supports call forwarding option "When busy". + * + * {@code true}: Call forwarding option "When busy" is supported. + * {@code false}: Call forwarding option "When busy" is not supported. Option will be + * removed in the UI. + * + * By default this value is true. + * @hide + */ public static final String KEY_CALL_FORWARDING_WHEN_BUSY_SUPPORTED_BOOL = "call_forwarding_when_busy_supported_bool"; @@ -259,12 +263,12 @@ public class CarrierConfigManager { public static final String KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL = "additional_settings_call_waiting_visibility_bool"; - /** - * Boolean indicating if the "Call barring" item is visible in the Call Settings menu. - * If true, the "Call Barring" menu will be visible. If false, the menu will be gone. - * - * Disabled by default. - */ + /** + * Boolean indicating if the "Call barring" item is visible in the Call Settings menu. + * If true, the "Call Barring" menu will be visible. If false, the menu will be gone. + * + * Disabled by default. + */ public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool"; @@ -321,8 +325,8 @@ public class CarrierConfigManager { * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and * effectively disable the "Sim network lock" feature. */ - public static final String - KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool"; + public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = + "ignore_sim_network_locked_events_bool"; /** * When checking if a given number is the voicemail number, if this flag is true @@ -340,16 +344,15 @@ public class CarrierConfigManager { * consequence: there will be no way to make an Emergency Call if your SIM is network-locked and * you don't know the PIN.) */ - public static final String - KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; + public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = + "sim_network_unlock_allow_dismiss_bool"; /** * Flag indicating whether or not sending emergency SMS messages over IMS * is supported when in LTE/limited LTE (Emergency only) service mode.. - * */ - public static final String - KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool"; + public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = + "support_emergency_sms_over_ims_bool"; /** Flag indicating if the phone is a world phone */ public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool"; @@ -359,8 +362,8 @@ public class CarrierConfigManager { * If true, entitlement checks will be executed if device has been configured for it, * If false, entitlement checks will be skipped. */ - public static final String - KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; + public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = + "require_entitlement_checks_bool"; /** * Flag indicating if the carrier supports tethering of mobile data. @@ -392,8 +395,8 @@ public class CarrierConfigManager { * consistent with the regular Dialer, this value should agree with the corresponding values * from config.xml under apps/Contacts. */ - public static final String - KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool"; + public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = + "enable_dialer_key_vibration_bool"; /** Flag indicating if dtmf tone type is enabled */ public static final String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool"; @@ -416,11 +419,12 @@ public class CarrierConfigManager { * @hide */ public static final String KEY_PLAY_CALL_RECORDING_TONE_BOOL = "play_call_recording_tone_bool"; + /** * Determines if the carrier requires converting the destination number before sending out an * SMS. Certain networks and numbering plans require different formats. */ - public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL= + public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; /** @@ -428,7 +432,8 @@ public class CarrierConfigManager { * platforms, even the ones with hard SEND/END keys, but for maximum flexibility it's controlled * by a flag here (which can be overridden on a per-product basis.) */ - public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool"; + public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = + "show_onscreen_dial_button_bool"; /** Determines if device implements a noise suppression device for in call audio. */ public static final String @@ -440,8 +445,8 @@ public class CarrierConfigManager { * accidental redialing from the call log UI. This is a good idea, so the default here is * false.) */ - public static final String - KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool"; + public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = + "allow_emergency_numbers_in_call_log_bool"; /** * A string array containing numbers that shouldn't be included in the call log. @@ -467,10 +472,9 @@ public class CarrierConfigManager { * Flag indicating whether to show single operator row in the choose network setting. * * The device configuration value {@code config_enableNewAutoSelectNetworkUI} ultimately - * controls whether this carrier configuration option is used. Where - * {@code config_enableNewAutoSelectNetworkUI} is false, the value of the - * {@link #KEY_SHOW_SINGLE_OPERATOR_ROW_IN_CHOOSE_NETWORK_SETTING_BOOL} carrier configuration - * option is ignored. + * controls whether this carrier configuration option is used. + * Where {@code config_enableNewAutoSelectNetworkUI} is false, the value of this + * carrier configuration is ignored. * * If {@code true}, default value, merge the duplicate networks which with the same plmn, keep * the one that with the higher signal strength level. @@ -494,19 +498,22 @@ public class CarrierConfigManager { /** * Control whether users receive a simplified network settings UI and improved network * selection. + * + * @deprecated Never implemented. Has no behavior impact when override. DO NOT USE. */ - public static final String - KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool"; + @Deprecated + public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = + "simplified_network_settings_bool"; /** Control whether users can reach the SIM lock settings. */ - public static final String - KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool"; + public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool"; /** Control whether users can edit APNs in Settings. */ public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool"; /** Control whether users can choose a network operator. */ - public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool"; + public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = + "operator_selection_expand_bool"; /** * Used in the Preferred Network Types menu to determine if the 2G option is displayed. @@ -530,11 +537,11 @@ public class CarrierConfigManager { /** * CDMA activation goes through OTASP. - * <p> - * TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum - * (NONE, HFA, OTASP). */ - public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; + // TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum + // (NONE, HFA, OTASP). + public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = + "use_otasp_for_provisioning_bool"; /** Display carrier settings menu if true */ public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; @@ -559,41 +566,41 @@ public class CarrierConfigManager { * available the user cannot use voicemail. This flag allows the user to edit the voicemail * number in such cases, and is false by default. */ - public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL= "editable_voicemail_number_bool"; + public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = + "editable_voicemail_number_bool"; /** * Determine whether the voicemail notification is persistent in the notification bar. If true, * the voicemail notifications cannot be dismissed from the notification bar. */ - public static final String - KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool"; + public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = + "voicemail_notification_persistent_bool"; /** For IMS video over LTE calls, determines whether video pause signalling is supported. */ - public static final String - KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool"; + public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = + "support_pause_ims_video_calls_bool"; /** * Disables dialing "*228" (OTASP provisioning) on CDMA carriers where it is not supported or is * potentially harmful by locking the SIM to 3G. */ - public static final String - KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; + public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = + "disable_cdma_activation_code_bool"; /** * List of network type constants which support only a single data connection at a time. * Some carriers do not support multiple PDP on UMTS. * @see TelephonyManager NETWORK_TYPE_* + * @see #KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY */ - public static final String - KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array"; + public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = + "only_single_dc_allowed_int_array"; /** - * List of network capabilities which, if requested, will exempt the request from single PDN - * connection checks. + * Only apply if {@link #KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY} specifies the network types that + * support a single data connection at a time. This key defines a list of network capabilities + * which, if requested, will exempt the request from single data connection checks. * @see NetworkCapabilities NET_CAPABILITY_* - * @see #KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY - * - * @hide */ public static final String KEY_CAPABILITIES_EXEMPT_FROM_SINGLE_DC_CHECK_INT_ARRAY = "capabilities_exempt_from_single_dc_check_int_array"; @@ -602,15 +609,15 @@ public class CarrierConfigManager { * Override the platform's notion of a network operator being considered roaming. * Value is string array of MCCMNCs to be considered roaming for 3GPP RATs. */ - public static final String - KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array"; + public static final String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = + "gsm_roaming_networks_string_array"; /** * Override the platform's notion of a network operator being considered not roaming. * Value is string array of MCCMNCs to be considered not roaming for 3GPP RATs. */ - public static final String - KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array"; + public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = + "gsm_nonroaming_networks_string_array"; /** * The package name containing the ImsService that will be bound to the telephony framework to @@ -620,6 +627,7 @@ public class CarrierConfigManager { * {@link #KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING} instead to configure these values * separately. If any of those values are not empty, they will override this value. */ + @Deprecated public static final String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string"; @@ -666,7 +674,7 @@ public class CarrierConfigManager { /** * Override the platform's notion of a network operator being considered non roaming. - * If true all networks are considered as home network a.k.a non-roaming. When false, + * If true all networks are considered as home network a.k.a. non-roaming. When false, * the 2 pairs of CMDA and GSM roaming/non-roaming arrays are consulted. * * @see #KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY @@ -701,8 +709,7 @@ public class CarrierConfigManager { * <li>3: {@link #USSD_OVER_IMS_ONLY} </li> * </ul> */ - public static final String KEY_CARRIER_USSD_METHOD_INT = - "carrier_ussd_method_int"; + public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int"; /** * Flag specifying whether to show an alert dialog for 5G disable when the user disables VoLTE. @@ -733,8 +740,7 @@ public class CarrierConfigManager { * downgrading the call in the process. * @hide */ - public static final String KEY_ALLOW_MERGING_RTT_CALLS_BOOL = - "allow_merging_rtt_calls_bool"; + public static final String KEY_ALLOW_MERGING_RTT_CALLS_BOOL = "allow_merging_rtt_calls_bool"; /** * Flag specifying whether the carrier wants to notify the user when a VT call has been handed @@ -795,7 +801,7 @@ public class CarrierConfigManager { /** * When {@code true}, changes to the mobile data enabled switch will not cause the VT - * registration state to change. That is, turning on or off mobile data will not cause VT to be + * registration state to change. That is, turning on or off mobile data will not cause VT to be * enabled or disabled. * When {@code false}, disabling mobile data will cause VT to be de-registered. */ @@ -818,7 +824,8 @@ public class CarrierConfigManager { * carrier provisioning. If false: hard disabled. If true: then depends on carrier * provisioning, availability etc. */ - public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool"; + public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = + "carrier_wfc_ims_available_bool"; /** * Flag specifying whether Cross SIM over IMS should be available for carrier. @@ -858,8 +865,8 @@ public class CarrierConfigManager { "international_roaming_dial_string_replace_string_array"; /** - * Flag specifying whether WFC over IMS supports the "wifi only" option. If false, the wifi - * calling settings will not include an option for "wifi only". If true, the wifi calling + * Flag specifying whether WFC over IMS supports the "wifi only" option. If false, the wifi + * calling settings will not include an option for "wifi only". If true, the wifi calling * settings will include an option for "wifi only" * <p> * By default, it is assumed that WFC supports "wifi only". @@ -902,7 +909,7 @@ public class CarrierConfigManager { /** * Flag indicating whether failed calls due to no service should prompt the user to enable - * WIFI calling. When {@code true}, if the user attempts to establish a call when there is no + * WIFI calling. When {@code true}, if the user attempts to establish a call when there is no * service available, they are connected to WIFI, and WIFI calling is disabled, a different * call failure message will be used to encourage the user to enable WIFI calling. * @hide @@ -928,8 +935,8 @@ public class CarrierConfigManager { * {@link Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE} */ @Deprecated - public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL - = "carrier_volte_provisioning_required_bool"; + public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = + "carrier_volte_provisioning_required_bool"; /** * Flag indicating whether or not the IMS MmTel UT capability requires carrier provisioning @@ -972,22 +979,22 @@ public class CarrierConfigManager { * As of now, Verizon is the only carrier enforcing this dependency in their * WFC awareness and activation requirements. */ - public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL - = "carrier_volte_override_wfc_provisioning_bool"; + public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = + "carrier_volte_override_wfc_provisioning_bool"; /** * Override the device's configuration for the cellular data service to use for this SIM card. * @hide */ - public static final String KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING - = "carrier_data_service_wwan_package_override_string"; + public static final String KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING = + "carrier_data_service_wwan_package_override_string"; /** * Override the device's configuration for the IWLAN data service to use for this SIM card. * @hide */ - public static final String KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING - = "carrier_data_service_wlan_package_override_string"; + public static final String KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING = + "carrier_data_service_wlan_package_override_string"; /** * Override the device's configuration for the cellular data service class to use @@ -1006,8 +1013,8 @@ public class CarrierConfigManager { "carrier_data_service_wlan_class_override_string"; /** Flag specifying whether VoLTE TTY is supported. */ - public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL - = "carrier_volte_tty_supported_bool"; + public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = + "carrier_volte_tty_supported_bool"; /** Flag specifying whether VoWIFI TTY is supported. * @hide @@ -1019,37 +1026,37 @@ public class CarrierConfigManager { * Flag specifying whether IMS service can be turned off. If false then the service will not be * turned-off completely, but individual features can be disabled. */ - public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL - = "carrier_allow_turnoff_ims_bool"; + public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = + "carrier_allow_turnoff_ims_bool"; /** * Flag specifying whether Generic Bootstrapping Architecture capable SIM is required for IMS. */ - public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL - = "carrier_ims_gba_required_bool"; + public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL = + "carrier_ims_gba_required_bool"; /** - * Flag specifying whether IMS instant lettering is available for the carrier. {@code True} if + * Flag specifying whether IMS instant lettering is available for the carrier. {@code True} if * instant lettering is available for the carrier, {@code false} otherwise. */ public static final String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL = "carrier_instant_lettering_available_bool"; - /* + /** * Flag specifying whether IMS should be the first phone attempted for E911 even if the * phone is not in service. */ - public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL - = "carrier_use_ims_first_for_emergency_bool"; + public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = + "carrier_use_ims_first_for_emergency_bool"; /** * When {@code true}, the determination of whether to place a call as an emergency call will be * based on the known {@link android.telephony.emergency.EmergencyNumber}s for the SIM on which - * the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers + * the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789, * it will not be treated as an emergency call in this case. * When {@code false}, the determination is based on the emergency numbers from all device SIMs, - * regardless of which SIM the call is being placed on. If Sim A has the emergency numbers + * regardless of which SIM the call is being placed on. If Sim A has the emergency numbers * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789, * the call will be dialed as an emergency number, but with an unspecified routing. * @hide @@ -1060,7 +1067,7 @@ public class CarrierConfigManager { /** * When IMS instant lettering is available for a carrier (see * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters - * which may not be contained in messages. Should be specified as a regular expression suitable + * which may not be contained in messages. Should be specified as a regular expression suitable * for use with {@link String#matches(String)}. */ public static final String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = @@ -1069,8 +1076,8 @@ public class CarrierConfigManager { /** * When IMS instant lettering is available for a carrier (see * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines a list of characters which - * must be escaped with a backslash '\' character. Should be specified as a string containing - * the characters to be escaped. For example to escape quote and backslash the string would be + * must be escaped with a backslash '\' character. Should be specified as a string containing + * the characters to be escaped. For example to escape quote and backslash the string would be * a quote and a backslash. */ public static final String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = @@ -1079,10 +1086,10 @@ public class CarrierConfigManager { /** * When IMS instant lettering is available for a carrier (see * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the character encoding - * which will be used when determining the length of messages. Used in the InCall UI to limit - * the number of characters the user may type. If empty-string, the instant lettering - * message size limit will be enforced on a 1:1 basis. That is, each character will count - * towards the messages size limit as a single bye. If a character encoding is specified, the + * which will be used when determining the length of messages. Used in the InCall UI to limit + * the number of characters the user may type. If empty-string, the instant lettering + * message size limit will be enforced on a 1:1 basis. That is, each character will count + * towards the messages size limit as a single byte. If a character encoding is specified, the * message size limit will be based on the number of bytes in the message per the specified * encoding. */ @@ -1091,7 +1098,7 @@ public class CarrierConfigManager { /** * When IMS instant lettering is available for a carrier (see - * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), the length limit for messages. Used + * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), the length limit for messages. Used * in the InCall UI to ensure the user cannot enter more characters than allowed by the carrier. * See also {@link #KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING} for more information on how * the length of the message is calculated. @@ -1112,7 +1119,8 @@ public class CarrierConfigManager { * manager can control and route outgoing and incoming phone calls, even if they're placed * using another connection service (PSTN, for example). */ - public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string"; + public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = + "default_sim_call_manager_string"; /** * The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in @@ -1148,21 +1156,65 @@ public class CarrierConfigManager { "carrier_data_call_apn_retry_after_disconnect_long"; /** - * Data call setup permanent failure causes by the carrier + * Data call setup permanent failure causes by the carrier. + * + * @deprecated This API key was added in mistake and is not used anymore by the telephony data + * frameworks. */ @Deprecated public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings"; /** - * Default APN types that are metered by the carrier - * @hide + * A string array indicating the default APN types that are metered by the carrier. + * + * The string in the array is the name of the APN type. For example, "default" for + * {@link ApnSetting#TYPE_DEFAULT}, "mms" for {@link ApnSetting#TYPE_MMS}, etc. + * + * The default value is {@code {"default", "mms", "dun", "supl"}}. + * + * @see ApnSetting#TYPE_DEFAULT + * @see ApnSetting#TYPE_MMS + * @see ApnSetting#TYPE_SUPL + * @see ApnSetting#TYPE_DUN + * @see ApnSetting#TYPE_HIPRI + * @see ApnSetting#TYPE_FOTA + * @see ApnSetting#TYPE_IMS + * @see ApnSetting#TYPE_CBS + * @see ApnSetting#TYPE_IA + * @see ApnSetting#TYPE_EMERGENCY + * @see ApnSetting#TYPE_MCX + * @see ApnSetting#TYPE_XCAP + * @see ApnSetting#TYPE_BIP + * @see ApnSetting#TYPE_VSIM + * @see ApnSetting#TYPE_ENTERPRISE */ public static final String KEY_CARRIER_METERED_APN_TYPES_STRINGS = "carrier_metered_apn_types_strings"; + /** - * Default APN types that are roaming-metered by the carrier - * @hide + * A string array indicating the default APN types that are roaming-metered by the carrier. + * + * The string in the array is the name of the APN type. For example, "default" for + * {@link ApnSetting#TYPE_DEFAULT}, "mms" for {@link ApnSetting#TYPE_MMS}, etc. + * + * The default value is {@code {"default", "mms", "dun", "supl"}}. + * + * @see ApnSetting#TYPE_DEFAULT + * @see ApnSetting#TYPE_MMS + * @see ApnSetting#TYPE_SUPL + * @see ApnSetting#TYPE_DUN + * @see ApnSetting#TYPE_HIPRI + * @see ApnSetting#TYPE_FOTA + * @see ApnSetting#TYPE_IMS + * @see ApnSetting#TYPE_CBS + * @see ApnSetting#TYPE_IA + * @see ApnSetting#TYPE_EMERGENCY + * @see ApnSetting#TYPE_MCX + * @see ApnSetting#TYPE_XCAP + * @see ApnSetting#TYPE_BIP + * @see ApnSetting#TYPE_VSIM + * @see ApnSetting#TYPE_ENTERPRISE */ public static final String KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS = "carrier_metered_roaming_apn_types_strings"; @@ -1171,8 +1223,7 @@ public class CarrierConfigManager { * CDMA carrier ERI (Enhanced Roaming Indicator) file name * @hide */ - public static final String KEY_CARRIER_ERI_FILE_NAME_STRING = - "carrier_eri_file_name_string"; + public static final String KEY_CARRIER_ERI_FILE_NAME_STRING = "carrier_eri_file_name_string"; /* The following 3 fields are related to carrier visual voicemail. */ @@ -1196,13 +1247,12 @@ public class CarrierConfigManager { * Whether cellular data is required to access visual voicemail. */ public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = - "vvm_cellular_data_required_bool"; + "vvm_cellular_data_required_bool"; /** * The default OMTP visual voicemail client prefix to use. Defaulted to "//VVM" */ - public static final String KEY_VVM_CLIENT_PREFIX_STRING = - "vvm_client_prefix_string"; + public static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string"; /** * Whether to use SSL to connect to the visual voicemail IMAP server. Defaulted to false. @@ -1227,8 +1277,7 @@ public class CarrierConfigManager { * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to * function without the data cost. */ - public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = - "vvm_legacy_mode_enabled_bool"; + public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool"; /** * Whether to prefetch audio data on new voicemail arrival, defaulted to true. @@ -1242,7 +1291,8 @@ public class CarrierConfigManager { * @deprecated use {@link #KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY}. */ @Deprecated - public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string"; + public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = + "carrier_vvm_package_name_string"; /** * A list of the carrier's visual voicemail app package names to ensure that dialer visual @@ -1261,7 +1311,7 @@ public class CarrierConfigManager { * Status screen. The default value is true. */ public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = - "show_signal_strength_in_sim_status_bool"; + "show_signal_strength_in_sim_status_bool"; /** * Flag specifying if we should interpret all signal strength as one bar higher @@ -1340,9 +1390,8 @@ public class CarrierConfigManager { public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool"; - /** - * Determines whether adhoc conference calls are supported by a carrier. When {@code true}, + * Determines whether adhoc conference calls are supported by a carrier. When {@code true}, * adhoc conference calling is supported, {@code false otherwise}. */ public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = @@ -1350,14 +1399,14 @@ public class CarrierConfigManager { /** * Determines whether conference participants can be added to existing call to form an adhoc - * conference call (in contrast to merging calls to form a conference). When {@code true}, + * conference call (in contrast to merging calls to form a conference). When {@code true}, * adding conference participants to existing call is supported, {@code false otherwise}. */ public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool"; /** - * Determines whether conference calls are supported by a carrier. When {@code true}, + * Determines whether conference calls are supported by a carrier. When {@code true}, * conference calling is supported, {@code false otherwise}. */ public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool"; @@ -1365,7 +1414,7 @@ public class CarrierConfigManager { /** * Determines whether a maximum size limit for IMS conference calls is enforced on the device. * When {@code true}, IMS conference calls will be limited to at most - * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants. When {@code false}, no attempt is + * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants. When {@code false}, no attempt is * made to limit the number of participants in a conference (the carrier will raise an error * when an attempt is made to merge too many participants into a conference). * <p> @@ -1379,14 +1428,14 @@ public class CarrierConfigManager { /** * Determines the maximum number of participants the carrier supports for a conference call. - * This number is exclusive of the current device. A conference between 3 devices, for example, + * This number is exclusive of the current device. A conference between 3 devices, for example, * would have a size limit of 2 participants. * Enforced when {@link #KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL} is {@code true}. */ public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int"; /** - * Determines whether manage IMS conference calls is supported by a carrier. When {@code true}, + * Determines whether manage IMS conference calls is supported by a carrier. When {@code true}, * manage IMS conference call is supported, {@code false otherwise}. * @hide */ @@ -1409,7 +1458,7 @@ public class CarrierConfigManager { * and B and C are considered the conference peers. * <p> * When {@code true}, the conference peer will display the conference state if it receives - * conference event package data from the network. When {@code false}, the conference peer will + * conference event package data from the network. When {@code false}, the conference peer will * ignore conference event package data received from the network. * @hide */ @@ -1427,7 +1476,7 @@ public class CarrierConfigManager { /** * Indicates whether the carrier supports the negotiations of RFC8285 compliant RTP header - * extensions supported on a call during the Session Description Protocol (SDP). This option + * extensions supported on a call during the Session Description Protocol (SDP). This option * is only used when {@link #KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL} is * {@code true}. * <p> @@ -1457,7 +1506,7 @@ public class CarrierConfigManager { "display_hd_audio_property_bool"; /** - * Determines whether IMS conference calls are supported by a carrier. When {@code true}, + * Determines whether IMS conference calls are supported by a carrier. When {@code true}, * IMS conference calling is supported, {@code false} otherwise. * @hide */ @@ -1466,9 +1515,9 @@ public class CarrierConfigManager { /** * Determines whether the device will locally disconnect an IMS conference when the participant - * count drops to zero. When {@code true}, it is assumed the carrier does NOT disconnect a + * count drops to zero. When {@code true}, it is assumed the carrier does NOT disconnect a * conference when the participant count drops to zero and that the device must do this by - * disconnecting the conference locally. When {@code false}, it is assumed that the carrier + * disconnecting the conference locally. When {@code false}, it is assumed that the carrier * is responsible for disconnecting the conference when there are no longer any participants * present. * <p> @@ -1484,8 +1533,8 @@ public class CarrierConfigManager { "local_disconnect_empty_ims_conference_bool"; /** - * Determines whether video conference calls are supported by a carrier. When {@code true}, - * video calls can be merged into conference calls, {@code false} otherwiwse. + * Determines whether video conference calls are supported by a carrier. When {@code true}, + * video calls can be merged into conference calls, {@code false} otherwise. * <p> * Note: even if video conference calls are not supported, audio calls may be merged into a * conference if {@link #KEY_SUPPORT_CONFERENCE_CALL_BOOL} is {@code true}. @@ -1522,7 +1571,8 @@ public class CarrierConfigManager { /** * Determine whether preferred network type can be shown. */ - public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool"; + public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = + "hide_preferred_network_type_bool"; /** * String array for package names that need to be enabled for this carrier. @@ -1578,6 +1628,7 @@ public class CarrierConfigManager { * <li> 9: WiFi Calling</li> * <li> 10: VoWifi</li> * <li> 11: %s WiFi Calling</li> + * <li> 12: WiFi Call</li> * @hide */ public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int"; @@ -1750,26 +1801,24 @@ public class CarrierConfigManager { * Instead, each sim carrier should have a single country code, apply per carrier based iso * code as an override. The overridden value can be read from * {@link TelephonyManager#getSimCountryIso()} and {@link SubscriptionInfo#getCountryIso()} - * - * @hide */ public static final String KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING = "sim_country_iso_override_string"; - /** - * The Component Name of a carrier-provided CallScreeningService implementation. Telecom will - * bind to {@link android.telecom.CallScreeningService} for ALL incoming calls and provide - * the carrier - * CallScreeningService with the opportunity to allow or block calls. - * <p> - * The String includes the package name/the class name. - * Example: - * <item>com.android.carrier/com.android.carrier.callscreeningserviceimpl</item> - * <p> - * Using {@link ComponentName#flattenToString()} to convert a ComponentName object to String. - * Using {@link ComponentName#unflattenFromString(String)} to convert a String object to a - * ComponentName. - */ + /** + * The Component Name of a carrier-provided CallScreeningService implementation. Telecom will + * bind to {@link android.telecom.CallScreeningService} for ALL incoming calls and provide + * the carrier + * CallScreeningService with the opportunity to allow or block calls. + * <p> + * The String includes the package name/the class name. + * Example: + * <item>com.android.carrier/com.android.carrier.callscreeningserviceimpl</item> + * <p> + * Using {@link ComponentName#flattenToString()} to convert a ComponentName object to String. + * Using {@link ComponentName#unflattenFromString(String)} to convert a String object to a + * ComponentName. + */ public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app"; /** @@ -1881,20 +1930,20 @@ public class CarrierConfigManager { "broadcast_emergency_call_state_changes_bool"; /** - * Indicates whether STK LAUNCH_BROWSER command is disabled. - * If {@code true}, then the browser will not be launched - * on UI for the LAUNCH_BROWSER STK command. - * @hide - */ + * Indicates whether STK LAUNCH_BROWSER command is disabled. + * If {@code true}, then the browser will not be launched + * on UI for the LAUNCH_BROWSER STK command. + * @hide + */ public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL = "stk_disable_launch_browser_bool"; /** - * Boolean indicating if the helper text for STK GET INKEY/INPUT commands with the digit only - * mode is displayed on the input screen. - * The helper text is dispayed regardless of the input mode, if {@code false}. - * @hide - */ + * Boolean indicating if the helper text for STK GET INKEY/INPUT commands with the digit only + * mode is displayed on the input screen. + * The helper text is displayed regardless of the input mode, if {@code false}. + * @hide + */ public static final String KEY_HIDE_DIGITS_HELPER_TEXT_ON_STK_INPUT_SCREEN_BOOL = "hide_digits_helper_text_on_stk_input_screen_bool"; @@ -1926,8 +1975,13 @@ public class CarrierConfigManager { /** * Boolean indicating if LTE+ icon should be shown if available. */ - public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = - "hide_lte_plus_data_icon_bool"; + public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool"; + + /** + * Boolean indicting if the 5G slice icon should be shown if available. + * @hide + */ + public static final String KEY_SHOW_5G_SLICE_ICON_BOOL = "show_5g_slice_icon_bool"; /** * The combined channel bandwidth threshold (non-inclusive) in KHz required to display the @@ -1957,13 +2011,24 @@ public class CarrierConfigManager { * cell bandwidth meets the required threshold for NR advanced. * * @see TelephonyDisplayInfo#OVERRIDE_NETWORK_TYPE_NR_ADVANCED - * - * @hide */ public static final String KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL = "include_lte_for_nr_advanced_threshold_bandwidth_bool"; /** + * Indicating whether to ratchet the aggregated cell bandwidths on receiving new values when + * the device is in RRC IDLE mode. + * The aggregated cell bandwidths are used for determining NR advanced state. + * + * If this is {@code true}, we will only update the aggregate cell bandwidths if the new + * aggregate is higher than the current aggregate and the anchor NR cell is the same. + * If this is {@code false}, we will always update the aggregate cell bandwidths when receiving + * new values. + */ + public static final String KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL = + "ratchet_nr_advanced_bandwidth_if_rrc_idle_bool"; + + /** * Boolean indicating if operator name should be shown in the status bar * @hide */ @@ -2043,16 +2108,22 @@ public class CarrierConfigManager { public static final String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio"; public static final String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID"; public static final String KEY_MMS_GROUP_MMS_ENABLED_BOOL = "enableGroupMms"; - public static final String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL = "enableMMSDeliveryReports"; + public static final String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL = + "enableMMSDeliveryReports"; public static final String KEY_MMS_MMS_ENABLED_BOOL = "enabledMMS"; public static final String KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL = "enableMMSReadReports"; public static final String KEY_MMS_MULTIPART_SMS_ENABLED_BOOL = "enableMultipartSMS"; public static final String KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL = "enabledNotifyWapMMSC"; - public static final String KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL = "sendMultipartSmsAsSeparateMessages"; - public static final String KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL = "config_cellBroadcastAppLinks"; - public static final String KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL = "enableSMSDeliveryReports"; - public static final String KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL = "supportHttpCharsetHeader"; - public static final String KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL = "supportMmsContentDisposition"; + public static final String KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL = + "sendMultipartSmsAsSeparateMessages"; + public static final String KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL = + "config_cellBroadcastAppLinks"; + public static final String KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL = + "enableSMSDeliveryReports"; + public static final String KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL = + "supportHttpCharsetHeader"; + public static final String KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL = + "supportMmsContentDisposition"; public static final String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars"; public static final String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars"; public static final String KEY_MMS_HTTP_SOCKET_TIMEOUT_INT = "httpSocketTimeout"; @@ -2061,7 +2132,8 @@ public class CarrierConfigManager { public static final String KEY_MMS_MAX_MESSAGE_SIZE_INT = "maxMessageSize"; public static final String KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT = "maxMessageTextSize"; public static final String KEY_MMS_RECIPIENT_LIMIT_INT = "recipientLimit"; - public static final String KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT = "smsToMmsTextLengthThreshold"; + public static final String KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT = + "smsToMmsTextLengthThreshold"; public static final String KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT = "smsToMmsTextThreshold"; public static final String KEY_MMS_SUBJECT_MAX_LENGTH_INT = "maxSubjectLength"; public static final String KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING = "emailGatewayNumber"; @@ -2090,7 +2162,7 @@ public class CarrierConfigManager { * The flatten {@link android.content.ComponentName componentName} of the activity that can * setup the device and activate with the network per carrier requirements. * - * e.g, com.google.android.carrierPackageName/.CarrierActivityName + * e.g., com.google.android.carrierPackageName/.CarrierActivityName * @hide */ @SystemApi @@ -2231,7 +2303,7 @@ public class CarrierConfigManager { /** * Determines whether the carrier supports making non-emergency phone calls while the phone is - * in emergency callback mode. Default value is {@code true}, meaning that non-emergency calls + * in emergency callback mode. Default value is {@code true}, meaning that non-emergency calls * are allowed in emergency callback mode. */ public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = @@ -2254,7 +2326,7 @@ public class CarrierConfigManager { /** * Flag indicating whether to allow carrier video calls to emergency numbers. - * When {@code true}, video calls to emergency numbers will be allowed. When {@code false}, + * When {@code true}, video calls to emergency numbers will be allowed. When {@code false}, * video calls to emergency numbers will be initiated as audio-only calls instead. */ public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = @@ -2282,7 +2354,7 @@ public class CarrierConfigManager { * When presence is supported, the device should use the * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate - * whether each contact supports video calling. The UI is made aware that presence is enabled + * whether each contact supports video calling. The UI is made aware that presence is enabled * via {@link android.telecom.PhoneAccount#CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE} * and can choose to hide or show the video calling icon based on whether a contact supports * video. @@ -2306,7 +2378,7 @@ public class CarrierConfigManager { * contacts emergency services. Platform considers values for below cases: * 1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly. * 2) VALUE > 604800(one week): will use the default value as duration instead. - * 3) VALUE < 0: block will be disabled forever until user re-eanble block manually, + * 3) VALUE < 0: block will be disabled forever until user re-enable block manually, * the suggested value to disable forever is -1. * See {@code android.provider.BlockedNumberContract#notifyEmergencyContact(Context)} * See {@code android.provider.BlockedNumberContract#isBlocked(Context, String)}. @@ -2336,7 +2408,7 @@ public class CarrierConfigManager { /** * For carriers which require an empty flash to be sent before sending the normal 3-way calling - * flash, the duration in milliseconds of the empty flash to send. When {@code 0}, no empty + * flash, the duration in milliseconds of the empty flash to send. When {@code 0}, no empty * flash is sent. */ public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int"; @@ -2376,8 +2448,7 @@ public class CarrierConfigManager { * Int indicating the max number length for FDN * @hide */ - public static final String KEY_FDN_NUMBER_LENGTH_LIMIT_INT = - "fdn_number_length_limit_int"; + public static final String KEY_FDN_NUMBER_LENGTH_LIMIT_INT = "fdn_number_length_limit_int"; /** * Report IMEI as device id even if it's a CDMA/LTE phone. @@ -2389,16 +2460,15 @@ public class CarrierConfigManager { /** * The families of Radio Access Technologies that will get clustered and ratcheted, * ie, we will report transitions up within the family, but not down until we change - * cells. This prevents flapping between base technologies and higher techs that are + * cells. This prevents flapping between base technologies and higher techs that are * granted on demand within the cell. * @hide */ - public static final String KEY_RATCHET_RAT_FAMILIES = - "ratchet_rat_families"; + public static final String KEY_RATCHET_RAT_FAMILIES = "ratchet_rat_families"; /** * Flag indicating whether some telephony logic will treat a call which was formerly a video - * call as if it is still a video call. When {@code true}: + * call as if it is still a video call. When {@code true}: * <p> * Logic which will automatically drop a video call which takes place over WIFI when a * voice call is answered (see {@link #KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL}. @@ -2410,7 +2480,7 @@ public class CarrierConfigManager { /** * When {@code true}, if the user is in an ongoing video call over WIFI and answers an incoming - * audio call, the video call will be disconnected before the audio call is answered. This is + * audio call, the video call will be disconnected before the audio call is answered. This is * in contrast to the usual expected behavior where a foreground video call would be put into * the background and held when an incoming audio call is answered. */ @@ -2420,8 +2490,8 @@ public class CarrierConfigManager { /** * Flag indicating whether the carrier supports merging wifi calls when VoWIFI is disabled. * This can happen in the case of a carrier which allows offloading video calls to WIFI - * separately of whether voice over wifi is enabled. In such a scenario when two video calls - * are downgraded to voice, they remain over wifi. However, if VoWIFI is disabled, these calls + * separately of whether voice over wifi is enabled. In such a scenario when two video calls + * are downgraded to voice, they remain over wifi. However, if VoWIFI is disabled, these calls * cannot be merged. */ public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = @@ -2431,9 +2501,9 @@ public class CarrierConfigManager { * Flag indicating whether the carrier supports the Hold command while in an IMS call. * <p> * The device configuration value {@code config_device_respects_hold_carrier_config} ultimately - * controls whether this carrier configuration option is used. Where - * {@code config_device_respects_hold_carrier_config} is false, the value of the - * {@link #KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} carrier configuration option is ignored. + * controls whether this carrier configuration option is used. + * Where {@code config_device_respects_hold_carrier_config} is false, the value of + * this carrier configuration is ignored. * @hide */ public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call"; @@ -2488,8 +2558,7 @@ public class CarrierConfigManager { * <p> * This is {@code true} by default. */ - public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL = - "allow_hold_video_call_bool"; + public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL = "allow_hold_video_call_bool"; /** * When true, indicates that the HD audio icon in the in-call screen should not be shown for @@ -2583,7 +2652,8 @@ public class CarrierConfigManager { * is returned. * @hide */ - public static final String KEY_FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array"; + public static final String KEY_FILTERED_CNAP_NAMES_STRING_ARRAY = + "filtered_cnap_names_string_array"; /** * The RCS configuration server URL. This URL is used to initiate RCS provisioning. @@ -2651,9 +2721,9 @@ public class CarrierConfigManager { "emergency_notification_delay_int"; /** - * When {@code true}, the carrier allows the user of the - * {@link TelephonyManager#sendUssdRequest(String, TelephonyManager.UssdResponseCallback, - * Handler)} API to perform USSD requests. {@code True} by default. + * When {@code true}, the carrier allows the user of the {@link + * TelephonyManager#sendUssdRequest(String, TelephonyManager.UssdResponseCallback, Handler)} + * API to perform USSD requests. {@code True} by default. * @hide */ public static final String KEY_ALLOW_USSD_REQUESTS_VIA_TELEPHONY_MANAGER_BOOL = @@ -2665,7 +2735,7 @@ public class CarrierConfigManager { * fails. */ public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = - "support_3gpp_call_forwarding_while_roaming_bool"; + "support_3gpp_call_forwarding_while_roaming_bool"; /** * Boolean indicating whether to display voicemail number as default call forwarding number in @@ -2731,8 +2801,7 @@ public class CarrierConfigManager { * This setting may be still overridden by explicit user choice. By default, * {@link #DATA_CYCLE_USE_PLATFORM_DEFAULT} will be used. */ - public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = - "monthly_data_cycle_day_int"; + public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int"; /** * When {@link #KEY_MONTHLY_DATA_CYCLE_DAY_INT}, {@link #KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG}, @@ -2778,7 +2847,7 @@ public class CarrierConfigManager { /** * Controls if the device should automatically warn the user that sim voice & data function - * might be limited due to dual sim scenario. When set to {@true} display the notification, + * might be limited due to dual sim scenario. When set to {@code true} display the notification, * {@code false} otherwise. * @hide */ @@ -2804,16 +2873,14 @@ public class CarrierConfigManager { * their cellular data limit. When set to {@code false} the carrier is * expected to have implemented their own notification mechanism. {@code true} by default. */ - public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = - "data_limit_notification_bool"; + public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool"; /** * Controls if the device should automatically notify the user when rapid * cellular data usage is observed. When set to {@code false} the carrier is - * expected to have implemented their own notification mechanism. {@code true} by default. + * expected to have implemented their own notification mechanism. {@code true} by default. */ - public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL = - "data_rapid_notification_bool"; + public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL = "data_rapid_notification_bool"; /** * Offset to be reduced from rsrp threshold while calculating signal strength level. @@ -2846,8 +2913,7 @@ public class CarrierConfigManager { * "nrarfcn2_start-nrarfcn2_end" ... } * @hide */ - public static final String KEY_BOOSTED_NRARFCNS_STRING_ARRAY = - "boosted_nrarfcns_string_array"; + public static final String KEY_BOOSTED_NRARFCNS_STRING_ARRAY = "boosted_nrarfcns_string_array"; /** * Determine whether to use only RSRP for the number of LTE signal bars. @@ -2947,6 +3013,39 @@ public class CarrierConfigManager { "5g_nr_sssinr_thresholds_int_array"; /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_SSRSRP} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT = + "ngran_ssrsrp_hysteresis_db_int"; + + /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_SSRSRQ} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_NGRAN_SSRSRQ_HYSTERESIS_DB_INT = + "ngran_ssrsrq_hysteresis_db_int"; + + /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_SSSINR} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_NGRAN_SSSINR_HYSTERESIS_DB_INT = + "ngran_sssinr_hysteresis_db_int"; + + /** * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP), * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference * ratio (SSSINR) for the number of 5G NR signal bars and signal criteria reporting enabling. @@ -3032,8 +3131,7 @@ public class CarrierConfigManager { * A match on this supersedes a match on {@link #KEY_NON_ROAMING_OPERATOR_STRING_ARRAY}. * @hide */ - public static final String KEY_ROAMING_OPERATOR_STRING_ARRAY = - "roaming_operator_string_array"; + public static final String KEY_ROAMING_OPERATOR_STRING_ARRAY = "roaming_operator_string_array"; /** * URL from which the proto containing the public key of the Carrier used for @@ -3102,7 +3200,7 @@ public class CarrierConfigManager { * Boolean flag indicating whether the carrier supports TTY. * <p> * Note that {@link #KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL} controls availability of TTY over - * VoLTE; if {@link #KEY_TTY_SUPPORTED_BOOL} is disabled, then + * VoLTE; if this carrier configuration is disabled, then * {@link #KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL} is also implicitly disabled. * <p> * {@link TelecomManager#isTtySupported()} should be used to determine if a device supports TTY, @@ -3226,11 +3324,11 @@ public class CarrierConfigManager { public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; - /** - * Determines whether we should show a notification when the phone established a data - * connection in roaming network, to warn users about possible roaming charges. - * @hide - */ + /** + * Determines whether we should show a notification when the phone established a data + * connection in roaming network, to warn users about possible roaming charges. + * @hide + */ public static final String KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL = "show_data_connected_roaming_notification"; @@ -3245,8 +3343,7 @@ public class CarrierConfigManager { * these boundaries is considered invalid. * @hide */ - public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY = - "lte_rsrp_thresholds_int_array"; + public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY = "lte_rsrp_thresholds_int_array"; /** * A list of 4 customized LTE Reference Signal Received Quality (RSRQ) thresholds. @@ -3263,8 +3360,7 @@ public class CarrierConfigManager { * This key is considered invalid if the format is violated. If the key is invalid or * not configured, a default value set will apply. */ - public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = - "lte_rsrq_thresholds_int_array"; + public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array"; /** * A list of 4 customized LTE Reference Signal Signal to Noise Ratio (RSSNR) thresholds. @@ -3283,6 +3379,37 @@ public class CarrierConfigManager { "lte_rssnr_thresholds_int_array"; /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_RSRP} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT = "eutran_rsrp_hysteresis_db_int"; + + /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_RSRQ} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_EUTRAN_RSRQ_HYSTERESIS_DB_INT = "eutran_rsrq_hysteresis_db_int"; + + /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_RSSNR} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_EUTRAN_RSSNR_HYSTERESIS_DB_INT = + "eutran_rssnr_hysteresis_db_int"; + + /** * Decides when clients try to bind to iwlan network service, which package name will * the binding intent go to. * @hide @@ -3329,28 +3456,64 @@ public class CarrierConfigManager { */ public static final String KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING = "carrier_qualified_networks_service_class_override_string"; + /** - * A list of 4 LTE RSCP thresholds above which a signal level is considered POOR, + * A list of 4 WCDMA RSCP thresholds above which a signal level is considered POOR, * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting. * * Note that the min and max thresholds are fixed at -120 and -24, as set in 3GPP TS 27.007 * section 8.69. * <p> - * See SignalStrength#MAX_WCDMA_RSCP and SignalStrength#MIN_WDCMA_RSCP. Any signal level outside - * these boundaries is considered invalid. + * See CellSignalStrengthWcdma#WCDMA_RSCP_MAX and CellSignalStrengthWcdma#WCDMA_RSCP_MIN. + * Any signal level outside these boundaries is considered invalid. * @hide */ public static final String KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY = "wcdma_rscp_thresholds_int_array"; /** + * A list of 4 WCDMA ECNO thresholds above which a signal level is considered POOR, + * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting. + * + * Note that the min and max thresholds are fixed at -24 and 1, as set in 3GPP TS 25.215 + * section 5.1.5. + * Any signal level outside these boundaries is considered invalid. + * <p> + * + * The default value is {@code {-24, -14, -6, 1}}. + * @hide + */ + public static final String KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY = + "wcdma_ecno_thresholds_int_array"; + + /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_RSCP} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_UTRAN_RSCP_HYSTERESIS_DB_INT = "utran_rscp_hysteresis_db_int"; + + /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_ECNO} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_UTRAN_ECNO_HYSTERESIS_DB_INT = "utran_ecno_hysteresis_db_int"; + + /** * The default measurement to use for signal strength reporting. If this is not specified, the * RSSI is used. * <p> * e.g.) To use RSCP by default, set the value to "rscp". The signal strength level will * then be determined by #KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY * <p> - * Currently this supports the value "rscp" and "rssi". + * Currently this supports the value "rscp","rssi" and "ecno". * @hide */ // FIXME: this key and related keys must not be exposed without a consistent philosophy for @@ -3369,7 +3532,7 @@ public class CarrierConfigManager { /** * Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom - * will bind to for outgoing calls. An empty string indicates that no carrier-defined + * will bind to for outgoing calls. An empty string indicates that no carrier-defined * {@link android.telecom.CallRedirectionService} is specified. */ public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = @@ -3669,7 +3832,7 @@ public class CarrierConfigManager { * This configuration allows the framework to use user data communication to detect Idle state, * and this is used on the 5G icon. * - * There is a new way for for RRC state detection at Android 12. If + * There is a new way for RRC state detection at Android 12. If * {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}( * {@link TelephonyManager#CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED}) returns true, * then framework can use PHYSICAL_CHANNEL_CONFIG for RRC state detection. Based on this @@ -3769,8 +3932,7 @@ public class CarrierConfigManager { * FQDN (Fully Qualified Domain Name) of the SM-DP+ (e.g., smdp.gsma.com) restricted to the * Alphanumeric mode character set defined in table 5 of ISO/IEC 18004 excluding '$'. */ - public static final String KEY_SMDP_SERVER_ADDRESS_STRING = - "smdp_server_address_string"; + public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string"; /** * This timer value is used in the eSIM Exponential Backoff download retry algorithm. @@ -3821,7 +3983,7 @@ public class CarrierConfigManager { public static final String KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL = "opportunistic_esim_download_via_wifi_only_bool"; -/** + /** * Controls RSRP threshold, in dBm, at which OpportunisticNetworkService will decide whether * the opportunistic network is good enough for internet data. * @@ -3915,6 +4077,7 @@ public class CarrierConfigManager { */ public static final String KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG = "opportunistic_network_ping_pong_time_long"; + /** * Controls back off time in milli seconds for switching back to * opportunistic subscription. This time will be added to @@ -4134,7 +4297,7 @@ public class CarrierConfigManager { * If opportunistic network is determined as out of service or below * {@link #KEY_EXIT_THRESHOLD_SS_RSRP_INT} or * {@link #KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE} within - * {@link #KEY_5G_PING_PONG_TIME_LONG} of switching to opportunistic network, + * the time specified by this carrier config of switching to opportunistic network, * it will be determined as ping pong situation by system app or 1st party app. * * @hide @@ -4190,29 +4353,30 @@ public class CarrierConfigManager { public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL = "enabled_4g_opportunistic_network_scan_bool"; - /** - * Only relevant when the device supports opportunistic networks but does not support - * simultaneuous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network - * goes out of service before switching the 5G capability back to primary stack. The idea of - * waiting a few seconds is to minimize the calling of the expensive capability switching - * operation in the case where CBRS goes back into service shortly after going out of it. - * - * @hide - */ - public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG = + /** + * Only relevant when the device supports opportunistic networks but does not support + * simultaneous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network + * goes out of service before switching the 5G capability back to primary stack. The idea of + * waiting a few seconds is to minimize the calling of the expensive capability switching + * operation in the case where CBRS goes back into service shortly after going out of it. + * + * @hide + */ + public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG = "time_to_switch_back_to_primary_if_opportunistic_oos_long"; - /** - * Only relevant when the device supports opportunistic networks but does not support - * simultaneuous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back - * to primary stack due to opportunistic network being OOS. The idea is to minimizing the - * 'ping-ponging' effect where device is constantly witching capability back and forth between - * primary and opportunistic stack. - * - * @hide - */ - public static final String KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG - = "opportunistic_time_to_scan_after_capability_switch_to_primary_long"; + /** + * Only relevant when the device supports opportunistic networks but does not support + * simultaneous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back + * to primary stack due to opportunistic network being OOS. The idea is to minimizing the + * 'ping-ponging' effect where device is constantly witching capability back and forth between + * primary and opportunistic stack. + * + * @hide + */ + public static final String + KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG = + "opportunistic_time_to_scan_after_capability_switch_to_primary_long"; /** * Indicates zero or more emergency number prefix(es), because some carrier requires @@ -4355,8 +4519,7 @@ public class CarrierConfigManager { * @hide */ @SystemApi - public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = - "gba_ua_security_protocol_int"; + public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = "gba_ua_security_protocol_int"; /** * An integer representing the cipher suite to be used when building the @@ -4366,8 +4529,7 @@ public class CarrierConfigManager { * @hide */ @SystemApi - public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = - "gba_ua_tls_cipher_suite_int"; + public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = "gba_ua_tls_cipher_suite_int"; /** * The data stall recovery timers array in milliseconds, each element is the delay before @@ -4577,7 +4739,6 @@ public class CarrierConfigManager { */ public static final int SUPL_EMERGENCY_MODE_TYPE_DP_ONLY = 2; - /** * Determine whether current lpp_mode used for E-911 needs to be kept persistently. * {@code false} - not keeping the lpp_mode means using default configuration of gps.conf @@ -4695,8 +4856,8 @@ public class CarrierConfigManager { * The default value for this configuration is {@link #SUPL_EMERGENCY_MODE_TYPE_CP_ONLY}. * @hide */ - public static final String KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT = KEY_PREFIX - + "es_supl_control_plane_support_int"; + public static final String KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT = + KEY_PREFIX + "es_supl_control_plane_support_int"; /** * A list of roaming PLMNs where SUPL ES mode does not support a control-plane mechanism to @@ -4731,13 +4892,14 @@ public class CarrierConfigManager { } } - /** - * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) network. - * The default values come from 3GPP2 C.R1001 table 8.1-1. - * Enhanced Roaming Indicator Number Assignments - * - * @hide - */ + /** + * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) + * network. + * The default values come from 3GPP2 C.R1001 table 8.1-1. + * Enhanced Roaming Indicator Number Assignments + * + * @hide + */ public static final String KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY = "cdma_enhanced_roaming_indicator_for_home_network_int_array"; @@ -4749,7 +4911,7 @@ public class CarrierConfigManager { /** * Indicates use 3GPP application to replace 3GPP2 application even if it's a CDMA/CDMA-LTE - * phone, becasue some carriers's CSIM application is present but not supported. + * phone, because some carriers' CSIM application is present but not supported. * @hide */ public static final String KEY_USE_USIM_BOOL = "use_usim_bool"; @@ -4812,8 +4974,7 @@ public class CarrierConfigManager { * {@see SubscriptionInfo#getUsageSetting} * */ - public static final String KEY_CELLULAR_USAGE_SETTING_INT = - "cellular_usage_setting_int"; + public static final String KEY_CELLULAR_USAGE_SETTING_INT = "cellular_usage_setting_int"; /** * Data switch validation minimal gap time, in milliseconds. @@ -4877,7 +5038,7 @@ public class CarrierConfigManager { * "Carrier Provisioning Info" or "Trigger Carrier Provisioning" button clicked. * * <p> - * e.g, com.google.android.carrierPackageName/.CarrierReceiverName + * e.g., com.google.android.carrierPackageName/.CarrierReceiverName * * @hide */ @@ -4917,9 +5078,9 @@ public class CarrierConfigManager { * Capability Exchange (UCE). See RCC.71, section 3 for more information. * <p> * If this key's value is set to false, the procedure for RCS contact capability exchange - * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and - * {@link Ims#KEY_ENABLE_PRESENCE_PUBLISH_BOOL} must also be set to false to ensure - * apps do not improperly think that capability exchange via SIP PUBLISH is enabled. + * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and this key must also be set + * to false to ensure apps do not improperly think that capability exchange via SIP PUBLISH + * is enabled. * <p> The default value for this key is {@code false}. */ public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = @@ -4975,7 +5136,6 @@ public class CarrierConfigManager { public static final String KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL = KEY_PREFIX + "enable_presence_capability_exchange_bool"; - /** * Flag indicating whether or not the carrier expects the RCS UCE service to periodically * refresh the RCS capabilities cache of the user's contacts as well as request the @@ -5109,7 +5269,7 @@ public class CarrierConfigManager { KEY_PREFIX + "sip_timer_j_millis_int"; /** Specifies the SIP Server default port. */ - public static final String KEY_SIP_SERVER_PORT_NUMBER_INT = + public static final String KEY_SIP_SERVER_PORT_NUMBER_INT = KEY_PREFIX + "sip_server_port_number_int"; /** @@ -5121,7 +5281,6 @@ public class CarrierConfigManager { /** @hide */ @IntDef({REQUEST_URI_FORMAT_TEL, REQUEST_URI_FORMAT_SIP}) - public @interface RequestUriFormatType {} /** @@ -5168,7 +5327,6 @@ public class CarrierConfigManager { PREFERRED_TRANSPORT_DYNAMIC_UDP_TCP, PREFERRED_TRANSPORT_TLS }) - public @interface PreferredTransportType {} /** Preferred Transport is always UDP. */ @@ -5249,7 +5407,6 @@ public class CarrierConfigManager { /** @hide */ @IntDef({IPSEC_AUTHENTICATION_ALGORITHM_HMAC_MD5, IPSEC_AUTHENTICATION_ALGORITHM_HMAC_SHA1}) - public @interface IpsecAuthenticationAlgorithmType {} /** IPSec Authentication algorithm is HMAC-MD5. see Annex H of TS 33.203 */ @@ -5274,7 +5431,6 @@ public class CarrierConfigManager { IPSEC_ENCRYPTION_ALGORITHM_DES_EDE3_CBC, IPSEC_ENCRYPTION_ALGORITHM_AES_CBC }) - public @interface IpsecEncryptionAlgorithmType {} /** IPSec Encryption algorithm is NULL. see Annex H of TS 33.203 */ @@ -5333,7 +5489,6 @@ public class CarrierConfigManager { GEOLOCATION_PIDF_FOR_NON_EMERGENCY_ON_CELLULAR, GEOLOCATION_PIDF_FOR_EMERGENCY_ON_CELLULAR }) - public @interface GeolocationPidfAllowedType {} /** @@ -5427,7 +5582,6 @@ public class CarrierConfigManager { NETWORK_TYPE_HOME, NETWORK_TYPE_ROAMING }) - public @interface NetworkType {} /** Indicates HOME Network. */ @@ -5444,7 +5598,6 @@ public class CarrierConfigManager { E911_RTCP_INACTIVITY_ON_CONNECTED, E911_RTP_INACTIVITY_ON_CONNECTED }) - public @interface MediaInactivityReason {} /** RTCP inactivity occurred when call is on HOLD. */ @@ -5490,7 +5643,7 @@ public class CarrierConfigManager { * <li>{@link #KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY}</li> * </ul> * <p> The values are defined in - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech} + * {@link ImsRegistrationImplBase.ImsRegistrationTech} * * changing mmtel_requires_provisioning_bundle requires changes to * carrier_volte_provisioning_required_bool and vice versa @@ -5504,10 +5657,10 @@ public class CarrierConfigManager { * is supported. * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE * <p>Possible values are, - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY = KEY_PREFIX + "capability_type_voice_int_array"; @@ -5517,10 +5670,10 @@ public class CarrierConfigManager { * is supported. * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO * <p>Possible values are, - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY = KEY_PREFIX + "capability_type_video_int_array"; @@ -5530,10 +5683,10 @@ public class CarrierConfigManager { * supplementary services. (IR.92) is supported. * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT * <p>Possible values are, - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_UT_INT_ARRAY = KEY_PREFIX + "capability_type_ut_int_array"; @@ -5542,10 +5695,10 @@ public class CarrierConfigManager { * List of different RAT technologies on which Provisioning for SMS (IR.92) is supported. * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS * <p>Possible values are, - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_SMS_INT_ARRAY = KEY_PREFIX + "capability_type_sms_int_array"; @@ -5555,10 +5708,10 @@ public class CarrierConfigManager { * (section 2.4 of RCC.20) is supported. * @see MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER * <p>Possible values are, - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY = KEY_PREFIX + "capability_type_call_composer_int_array"; @@ -5574,7 +5727,7 @@ public class CarrierConfigManager { * <li>{@link #KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY}</li> * </ul> * <p> The values are defined in - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech} + * {@link ImsRegistrationImplBase.ImsRegistrationTech} */ public static final String KEY_RCS_REQUIRES_PROVISIONING_BUNDLE = KEY_PREFIX + "rcs_requires_provisioning_bundle"; @@ -5585,10 +5738,10 @@ public class CarrierConfigManager { * If not set, this RcsFeature should not service capability requests. * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE * <p>Possible values are, - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY = KEY_PREFIX + "capability_type_options_uce_int_array"; @@ -5600,14 +5753,66 @@ public class CarrierConfigManager { * requests using presence. * @see RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE * <p>Possible values are, - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} - * {@link android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_LTE} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_IWLAN} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_CROSS_SIM} + * {@link ImsRegistrationImplBase.ImsRegistrationTech#REGISTRATION_TECH_NR} */ public static final String KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY = KEY_PREFIX + "capability_type_presence_uce_int_array"; + /** + * Specifies the policy for disabling NR SA mode. Default value is + *{@link #SA_DISABLE_POLICY_NONE}. + * The value set as below: + * <ul> + * <li>0: {@link #SA_DISABLE_POLICY_NONE }</li> + * <li>1: {@link #SA_DISABLE_POLICY_WFC_ESTABLISHED }</li> + * <li>2: {@link #SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED }</li> + * <li>3: {@link #SA_DISABLE_POLICY_VOWIFI_REGISTERED }</li> + * </ul> + * @hide + */ + public static final String KEY_NR_SA_DISABLE_POLICY_INT = + KEY_PREFIX + "sa_disable_policy_int"; + + /** @hide */ + @IntDef({ + NR_SA_DISABLE_POLICY_NONE, + NR_SA_DISABLE_POLICY_WFC_ESTABLISHED, + NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED, + NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED + }) + public @interface NrSaDisablePolicy {} + + /** + * Do not disables NR SA mode. + * @hide + */ + public static final int NR_SA_DISABLE_POLICY_NONE = 0; + + /** + * Disables NR SA mode when VoWiFi call is established in order to improve the delay or + * voice mute when the handover from ePDG to NR is not supported in UE or network. + * @hide + */ + public static final int NR_SA_DISABLE_POLICY_WFC_ESTABLISHED = 1; + + /** + * Disables NR SA mode when VoWiFi call is established when VoNR is disabled in order to + * improve the delay or voice mute when the handover from ePDG to NR is not supported + * in UE or network. + * @hide + */ + public static final int NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED = 2; + + /** + * Disables NR SA mode when IMS is registered over WiFi in order to improve the delay or + * voice mute when the handover from ePDG to NR is not supported in UE or network. + * @hide + */ + public static final int NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED = 3; + private Ims() {} private static PersistableBundle getDefaults() { @@ -5616,7 +5821,7 @@ public class CarrierConfigManager { defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false); defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false); defaults.putStringArray(KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY, - new String[] {}); + new String[0]); defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false); defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false); defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, false); @@ -5679,6 +5884,7 @@ public class CarrierConfigManager { defaults.putInt(KEY_REGISTRATION_RETRY_BASE_TIMER_MILLIS_INT, 30000); defaults.putInt(KEY_REGISTRATION_RETRY_MAX_TIMER_MILLIS_INT, 1800000); defaults.putInt(KEY_REGISTRATION_SUBSCRIBE_EXPIRY_TIMER_SEC_INT, 600000); + defaults.putInt(KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_NONE); defaults.putIntArray( KEY_IPSEC_AUTHENTICATION_ALGORITHMS_INT_ARRAY, @@ -5741,7 +5947,7 @@ public class CarrierConfigManager { * <p>If {@code false}: hard disabled. * If {@code true}: then depends on availability, etc. */ - public static final String KEY_CARRIER_VOLTE_ROAMING_AVAILABLE_BOOL = + public static final String KEY_CARRIER_VOLTE_ROAMING_AVAILABLE_BOOL = KEY_PREFIX + "carrier_volte_roaming_available_bool"; /** @@ -5752,7 +5958,7 @@ public class CarrierConfigManager { * will be sent in the dialed string in the SIP:INVITE. * If {@code false}, *67 and *82 will be removed. */ - public static final String KEY_INCLUDE_CALLER_ID_SERVICE_CODES_IN_SIP_INVITE_BOOL = + public static final String KEY_INCLUDE_CALLER_ID_SERVICE_CODES_IN_SIP_INVITE_BOOL = KEY_PREFIX + "include_caller_id_service_codes_in_sip_invite_bool"; /** @@ -5796,7 +6002,6 @@ public class CarrierConfigManager { SESSION_REFRESHER_TYPE_UAC, SESSION_REFRESHER_TYPE_UAS }) - public @interface SessionRefresherType {} /** @@ -5838,14 +6043,12 @@ public class CarrierConfigManager { public static final String KEY_SESSION_REFRESHER_TYPE_INT = KEY_PREFIX + "session_refresher_type_int"; - /** @hide */ @IntDef({ SESSION_PRIVACY_TYPE_HEADER, SESSION_PRIVACY_TYPE_NONE, SESSION_PRIVACY_TYPE_ID }) - public @interface SessionPrivacyType {} /** @@ -5883,7 +6086,7 @@ public class CarrierConfigManager { * If {@code true}, SIP 18x responses (other than SIP 183 response) * are sent reliably. */ - public static final String KEY_PRACK_SUPPORTED_FOR_18X_BOOL = + public static final String KEY_PRACK_SUPPORTED_FOR_18X_BOOL = KEY_PREFIX + "prack_supported_for_18x_bool"; /** @hide */ @@ -5891,7 +6094,6 @@ public class CarrierConfigManager { CONFERENCE_SUBSCRIBE_TYPE_IN_DIALOG, CONFERENCE_SUBSCRIBE_TYPE_OUT_OF_DIALOG }) - public @interface ConferenceSubscribeType {} /** @@ -5912,7 +6114,7 @@ public class CarrierConfigManager { /** * This is used to specify whether the SIP SUBSCRIBE to conference state events, - * is sent in or out of the SIP INVITE dialog between the UE and the + * is sent in or out of the SIP INVITE dialog between the UE and the * conference server. * * <p>Reference: IR.92 Section 2.3.3. @@ -5937,7 +6139,7 @@ public class CarrierConfigManager { * * <p>Reference: 3GPP TS 24.229 */ - public static final String KEY_VOICE_QOS_PRECONDITION_SUPPORTED_BOOL = + public static final String KEY_VOICE_QOS_PRECONDITION_SUPPORTED_BOOL = KEY_PREFIX + "voice_qos_precondition_supported_bool"; /** @@ -5945,7 +6147,7 @@ public class CarrierConfigManager { * * <p>If {@code true}: voice packets can be sent on default bearer. {@code false} otherwise. */ - public static final String KEY_VOICE_ON_DEFAULT_BEARER_SUPPORTED_BOOL = + public static final String KEY_VOICE_ON_DEFAULT_BEARER_SUPPORTED_BOOL = KEY_PREFIX + "voice_on_default_bearer_supported_bool"; /** @@ -5967,7 +6169,6 @@ public class CarrierConfigManager { PREALERTING_SRVCC_SUPPORT, MIDCALL_SRVCC_SUPPORT }) - public @interface SrvccType {} /** @@ -6065,7 +6266,6 @@ public class CarrierConfigManager { SESSION_REFRESH_METHOD_INVITE, SESSION_REFRESH_METHOD_UPDATE_PREFERRED }) - public @interface SessionRefreshMethod {} /** @@ -6100,7 +6300,7 @@ public class CarrierConfigManager { * determination of the originating party identity in OIP. * {@code false} otherwise. */ - public static final String KEY_OIP_SOURCE_FROM_HEADER_BOOL = + public static final String KEY_OIP_SOURCE_FROM_HEADER_BOOL = KEY_PREFIX + "oip_source_from_header_bool"; /** @@ -6188,7 +6388,7 @@ public class CarrierConfigManager { * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_EVS_PAYLOAD_TYPE_INT_ARRAY = + public static final String KEY_EVS_PAYLOAD_TYPE_INT_ARRAY = KEY_PREFIX + "evs_payload_type_int_array"; /** @@ -6197,7 +6397,7 @@ public class CarrierConfigManager { * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_AMRWB_PAYLOAD_TYPE_INT_ARRAY = + public static final String KEY_AMRWB_PAYLOAD_TYPE_INT_ARRAY = KEY_PREFIX + "amrwb_payload_type_int_array"; /** @@ -6206,7 +6406,7 @@ public class CarrierConfigManager { * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_AMRNB_PAYLOAD_TYPE_INT_ARRAY = + public static final String KEY_AMRNB_PAYLOAD_TYPE_INT_ARRAY = KEY_PREFIX + "amrnb_payload_type_int_array"; /** @@ -6215,7 +6415,7 @@ public class CarrierConfigManager { * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_DTMFWB_PAYLOAD_TYPE_INT_ARRAY = + public static final String KEY_DTMFWB_PAYLOAD_TYPE_INT_ARRAY = KEY_PREFIX + "dtmfwb_payload_type_int_array"; /** @@ -6224,15 +6424,56 @@ public class CarrierConfigManager { * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_DTMFNB_PAYLOAD_TYPE_INT_ARRAY = + public static final String KEY_DTMFNB_PAYLOAD_TYPE_INT_ARRAY = KEY_PREFIX + "dtmfnb_payload_type_int_array"; + /** + * This indicates the threshold for RTP packet loss rate in percentage. If measured packet + * loss rate crosses this, a callback with {@link MediaQualityStatus} will be invoked to + * listeners. + * See {@link android.telephony.TelephonyCallback.MediaQualityStatusChangedListener} + * + * <p/> + * Valid threshold range : 0 ~ 100 + * + * @hide + */ + public static final String KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT = + KEY_PREFIX + "rtp_packet_loss_rate_threshold_int"; + + /** + * This indicates the threshold for RTP jitter value in milliseconds (RFC3550). If measured + * jitter value crosses this, a callback with {@link MediaQualityStatus} will be invoked + * to listeners. + * See {@link android.telephony.TelephonyCallback.MediaQualityStatusChangedListener} + * + * <p/> + * Valid threshold range : 0 ~ 10000 + * + * @hide + */ + public static final String KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT = + KEY_PREFIX + "rtp_jitter_threshold_millis_int"; + + /** + * This indicates the threshold for RTP inactivity time in milliseconds. If measured + * inactivity timer crosses this, a callback with {@link MediaQualityStatus} will be invoked + * to listeners. + * See {@link android.telephony.TelephonyCallback.MediaQualityStatusChangedListener} + * + * <p/> + * Valid threshold range : 0 ~ 60000 + * + * @hide + */ + public static final String KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG = + KEY_PREFIX + "rtp_inactivity_time_threshold_millis_long"; + /** @hide */ @IntDef({ BANDWIDTH_EFFICIENT, OCTET_ALIGNED }) - public @interface AmrPayloadFormat {} /** AMR NB/WB Payload format is bandwidth-efficient. */ @@ -6253,7 +6494,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 4867 Section 8.1. */ - public static final String KEY_AMR_CODEC_ATTRIBUTE_PAYLOAD_FORMAT_INT = + public static final String KEY_AMR_CODEC_ATTRIBUTE_PAYLOAD_FORMAT_INT = KEY_PREFIX + "amr_codec_attribute_payload_format_int"; /** @@ -6268,7 +6509,7 @@ public class CarrierConfigManager { * <p>Possible values are subset of, * [0,1,2,3,4,5,6,7,8] - AMRWB with the modes representing nine speech codec modes * with bit rates of 6.6, 8.85, 12.65, 14.25, 15.85, 18.25, 19.85, 23.05, 23.85 kbps. - * [0,1,2,3,4,5,6,7] - AMRNB with the modes representing eight speech codec modes + * [0,1,2,3,4,5,6,7] - AMRNB with the modes representing eight speech codec modes * with bit rates of 4.75, 5.15, 5.90, 6.70, 7.40, 7.95, 10.2, 12.2 kbps. * * <p>If value is not specified, then it means device supports all @@ -6276,7 +6517,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 4867 Section 8.1, 3GPP 26.445 A.3.1 */ - public static final String KEY_AMR_CODEC_ATTRIBUTE_MODESET_INT_ARRAY = + public static final String KEY_AMR_CODEC_ATTRIBUTE_MODESET_INT_ARRAY = KEY_PREFIX + "amr_codec_attribute_modeset_int_array"; /** @@ -6326,7 +6567,6 @@ public class CarrierConfigManager { EVS_OPERATIONAL_MODE_PRIMARY, EVS_OPERATIONAL_MODE_AMRWB_IO }) - public @interface EvsOperationalMode {} /** Indicates the EVS primary mode. 3GPP 26.445 Section 3.1 */ @@ -6361,7 +6601,6 @@ public class CarrierConfigManager { EVS_ENCODED_BW_TYPE_WB_SWB, EVS_ENCODED_BW_TYPE_WB_SWB_FB }) - public @interface EvsEncodedBwType {} /** @@ -6437,7 +6676,7 @@ public class CarrierConfigManager { * * <p>Reference: 3GPP 26.441 Table 1. */ - public static final String KEY_EVS_CODEC_ATTRIBUTE_BANDWIDTH_INT = + public static final String KEY_EVS_CODEC_ATTRIBUTE_BANDWIDTH_INT = KEY_PREFIX + "evs_codec_attribute_bandwidth_int"; /** @hide */ @@ -6455,7 +6694,6 @@ public class CarrierConfigManager { EVS_PRIMARY_MODE_BITRATE_96_0_KBPS, EVS_PRIMARY_MODE_BITRATE_128_0_KBPS }) - public @interface EvsPrimaryModeBitRate {} /** EVS primary mode with bitrate 5.9 kbps */ @@ -6521,14 +6759,14 @@ public class CarrierConfigManager { * * <p>Reference: 3GPP 26.445 Section A.3.1 */ - public static final String KEY_EVS_CODEC_ATTRIBUTE_BITRATE_INT_ARRAY = + public static final String KEY_EVS_CODEC_ATTRIBUTE_BITRATE_INT_ARRAY = KEY_PREFIX + "evs_codec_attribute_bitrate_int_array"; /** * Specifies the Channel aware mode (ch-aw-recv) for the receive direction. * This is applicable for EVS codec. * - * <p>Permissible values are -1, 0, 2, 3, 5, and 7. + * <p> Permissible values are -1, 0, 2, 3, 5, and 7. * If this key is not specified, then the behavior is same as value 0 * (channel aware mode disabled). * <p> If this key is configured, then device is expected to send @@ -6536,7 +6774,7 @@ public class CarrierConfigManager { * * <p>Reference: 3GPP TS 26.445 section 4.4.5, 3GPP 26.445 Section A.3.1 */ - public static final String KEY_EVS_CODEC_ATTRIBUTE_CH_AW_RECV_INT = + public static final String KEY_EVS_CODEC_ATTRIBUTE_CH_AW_RECV_INT = KEY_PREFIX + "evs_codec_attribute_ch_aw_recv_int"; /** @@ -6557,7 +6795,7 @@ public class CarrierConfigManager { * * <p>Reference: 3GPP 26.445 Section A.3.1. */ - public static final String KEY_EVS_CODEC_ATTRIBUTE_HF_ONLY_INT = + public static final String KEY_EVS_CODEC_ATTRIBUTE_HF_ONLY_INT = KEY_PREFIX + "evs_codec_attribute_hf_only_int"; /** @@ -6573,7 +6811,7 @@ public class CarrierConfigManager { * will apply. * <p>Reference: 3GPP TS 26.445 Section A.3.1. */ - public static final String KEY_EVS_CODEC_ATTRIBUTE_DTX_BOOL = + public static final String KEY_EVS_CODEC_ATTRIBUTE_DTX_BOOL = KEY_PREFIX + "evs_codec_attribute_dtx_bool"; /** @@ -6598,7 +6836,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 3551 */ - public static final String KEY_EVS_CODEC_ATTRIBUTE_CHANNELS_INT = + public static final String KEY_EVS_CODEC_ATTRIBUTE_CHANNELS_INT = KEY_PREFIX + "evs_codec_attribute_channels_int"; /** @@ -6611,7 +6849,7 @@ public class CarrierConfigManager { * * <p>Reference: 3GPP 26.445 Section A.3.1, 3GPP 26.114 Table 6.2a */ - public static final String KEY_EVS_CODEC_ATTRIBUTE_CMR_INT = + public static final String KEY_EVS_CODEC_ATTRIBUTE_CMR_INT = KEY_PREFIX + "codec_attribute_cmr_int"; /** @@ -6625,7 +6863,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 4867 Section 8.1. */ - public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_PERIOD_INT = + public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_PERIOD_INT = KEY_PREFIX + "codec_attribute_mode_change_period_int"; /** @@ -6639,7 +6877,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 4867 Section 8.1. */ - public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_CAPABILITY_INT = + public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_CAPABILITY_INT = KEY_PREFIX + "codec_attribute_mode_change_capability_int"; /** @@ -6647,7 +6885,7 @@ public class CarrierConfigManager { * This attribute is applicable for EVS codec in AMR-WB IO mode * and AMR-WB. * - * <p>Possible values are 0, 1. If value is 1, then the sender should only + * <p>Possible values are 0, 1. If value is 1, then the sender should only * perform mode changes to the neighboring modes in the active codec mode set. * If value is 0, then mode changes between any two modes * in the active codec mode set is allowed. @@ -6656,7 +6894,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 4867 Section 8.1. */ - public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_NEIGHBOR_INT = + public static final String KEY_CODEC_ATTRIBUTE_MODE_CHANGE_NEIGHBOR_INT = KEY_PREFIX + "codec_attribute_mode_change_neighbor_int"; /** @@ -6713,6 +6951,9 @@ public class CarrierConfigManager { defaults.putInt(KEY_AUDIO_AS_BANDWIDTH_KBPS_INT, 41); defaults.putInt(KEY_AUDIO_RS_BANDWIDTH_BPS_INT, 600); defaults.putInt(KEY_AUDIO_RR_BANDWIDTH_BPS_INT, 2000); + defaults.putInt(KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT, 40); + defaults.putInt(KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT, 120); + defaults.putLong(KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG, 5000); defaults.putIntArray( KEY_AUDIO_INACTIVITY_CALL_END_REASONS_INT_ARRAY, @@ -6817,7 +7058,7 @@ public class CarrierConfigManager { * <p>If {@code true}: SMS over IMS support available. * {@code false}: otherwise. */ - public static final String KEY_SMS_OVER_IMS_SUPPORTED_BOOL = + public static final String KEY_SMS_OVER_IMS_SUPPORTED_BOOL = KEY_PREFIX + "sms_over_ims_supported_bool"; /** @@ -6827,7 +7068,7 @@ public class CarrierConfigManager { * <p>If {@code true}: allow SMS CSFB in case of SMS over PS failure. * {@code false} otherwise. */ - public static final String KEY_SMS_CSFB_RETRY_ON_FAILURE_BOOL = + public static final String KEY_SMS_CSFB_RETRY_ON_FAILURE_BOOL = KEY_PREFIX + "sms_csfb_retry_on_failure_bool"; /** @hide */ @@ -6835,7 +7076,6 @@ public class CarrierConfigManager { SMS_FORMAT_3GPP, SMS_FORMAT_3GPP2 }) - public @interface SmsFormat {} /** SMS format is 3GPP. */ @@ -6868,6 +7108,79 @@ public class CarrierConfigManager { public static final String KEY_SMS_OVER_IMS_SUPPORTED_RATS_INT_ARRAY = KEY_PREFIX + "sms_over_ims_supported_rats_int_array"; + /** + * Maximum Retry Count for Failure, If the Retry Count exceeds this value, + * it must display to User Interface as sending failed + */ + public static final String KEY_SMS_MAX_RETRY_COUNT_INT = + KEY_PREFIX + "sms_max_retry_count_int"; + + /** + * Maximum Retry Count for SMS over IMS on Failure, If the Retry Count exceeds this value, + * and if the retry count is less than {@link #KEY_SMS_MAX_RETRY_COUNT_INT} + * sending SMS should fallback to CS + */ + public static final String KEY_SMS_MAX_RETRY_OVER_IMS_COUNT_INT = + KEY_PREFIX + "sms_max_retry_over_ims_count_int"; + + /** + * Delay Timer Value in milliseconds + * Retry SMS over IMS after this Timer expires + */ + public static final String KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT = + KEY_PREFIX + "sms_over_ims_send_retry_delay_millis_int"; + + /** + * TR1 Timer Value in milliseconds, + * Waits for RP-Ack from network for MO SMS. + */ + public static final String KEY_SMS_TR1_TIMER_MILLIS_INT = + KEY_PREFIX + "sms_tr1_timer_millis_int"; + + /** + * TR2 Timer Value in milliseconds, + * Waits for RP-Ack from Transfer Layer for MT SMS. + */ + public static final String KEY_SMS_TR2_TIMER_MILLIS_INT = + KEY_PREFIX + "sms_tr2_timer_millis_int"; + + /** + * SMS RP-Cause Values for which SMS should be retried over IMS + * + * <p>Possible values are, + * {@link SmsManager#SMS_RP_CAUSE_UNALLOCATED_NUMBER} + * {@link SmsManager#SMS_RP_CAUSE_OPERATOR_DETERMINED_BARRING} + * {@link SmsManager#SMS_RP_CAUSE_CALL_BARRING} + * {@link SmsManager#SMS_RP_CAUSE_RESERVED} + * {@link SmsManager#SMS_RP_CAUSE_SHORT_MESSAGE_TRANSFER_REJECTED} + * {@link SmsManager#SMS_RP_CAUSE_DESTINATION_OUT_OF_ORDER} + * {@link SmsManager#SMS_RP_CAUSE_UNIDENTIFIED_SUBSCRIBER} + * {@link SmsManager#SMS_RP_CAUSE_FACILITY_REJECTED} + * {@link SmsManager#SMS_RP_CAUSE_UNKNOWN_SUBSCRIBER} + * {@link SmsManager#SMS_RP_CAUSE_NETWORK_OUT_OF_ORDER} + * {@link SmsManager#SMS_RP_CAUSE_TEMPORARY_FAILURE} + * {@link SmsManager#SMS_RP_CAUSE_CONGESTION} + * {@link SmsManager#SMS_RP_CAUSE_RESOURCES_UNAVAILABLE} + * {@link SmsManager#SMS_RP_CAUSE_FACILITY_NOT_SUBSCRIBED} + * {@link SmsManager#SMS_RP_CAUSE_FACILITY_NOT_IMPLEMENTED} + * {@link SmsManager#SMS_RP_CAUSE_INVALID_MESSAGE_REFERENCE_VALUE} + * {@link SmsManager#SMS_RP_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE} + * {@link SmsManager#SMS_RP_CAUSE_INVALID_MANDATORY_INFORMATION} + * {@link SmsManager#SMS_RP_CAUSE_MESSAGE_TYPE_NON_EXISTENT} + * {@link SmsManager#SMS_RP_CAUSE_MESSAGE_INCOMPATIBLE_WITH_PROTOCOL_STATE} + * {@link SmsManager#SMS_RP_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT} + * {@link SmsManager#SMS_RP_CAUSE_PROTOCOL_ERROR} + * {@link SmsManager#SMS_RP_CAUSE_INTERWORKING_UNSPECIFIED + */ + public static final String KEY_SMS_RP_CAUSE_VALUES_TO_RETRY_OVER_IMS_INT_ARRAY = + KEY_PREFIX + "sms_rp_cause_values_to_retry_over_ims_int_array"; + + /** + * SMS RP-Cause Values for which Sending SMS should fallback + */ + public static final String KEY_SMS_RP_CAUSE_VALUES_TO_FALLBACK_INT_ARRAY = + KEY_PREFIX + "sms_rp_cause_values_to_fallback_int_array"; + private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putBoolean(KEY_SMS_OVER_IMS_SUPPORTED_BOOL, true); @@ -6875,6 +7188,45 @@ public class CarrierConfigManager { defaults.putInt(KEY_SMS_OVER_IMS_FORMAT_INT, SMS_FORMAT_3GPP); + defaults.putInt(KEY_SMS_MAX_RETRY_COUNT_INT, 3); + defaults.putInt(KEY_SMS_MAX_RETRY_OVER_IMS_COUNT_INT, 3); + defaults.putInt(KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, + 2000); + defaults.putInt(KEY_SMS_TR1_TIMER_MILLIS_INT, 130000); + defaults.putInt(KEY_SMS_TR2_TIMER_MILLIS_INT, 15000); + + defaults.putIntArray( + KEY_SMS_RP_CAUSE_VALUES_TO_RETRY_OVER_IMS_INT_ARRAY, + new int[] { + SmsManager.SMS_RP_CAUSE_TEMPORARY_FAILURE + }); + defaults.putIntArray( + KEY_SMS_RP_CAUSE_VALUES_TO_FALLBACK_INT_ARRAY, + new int[] { + SmsManager.SMS_RP_CAUSE_UNALLOCATED_NUMBER, + SmsManager.SMS_RP_CAUSE_OPERATOR_DETERMINED_BARRING, + SmsManager.SMS_RP_CAUSE_CALL_BARRING, + SmsManager.SMS_RP_CAUSE_RESERVED, + SmsManager.SMS_RP_CAUSE_SHORT_MESSAGE_TRANSFER_REJECTED, + SmsManager.SMS_RP_CAUSE_DESTINATION_OUT_OF_ORDER, + SmsManager.SMS_RP_CAUSE_UNIDENTIFIED_SUBSCRIBER, + SmsManager.SMS_RP_CAUSE_FACILITY_REJECTED, + SmsManager.SMS_RP_CAUSE_UNKNOWN_SUBSCRIBER, + SmsManager.SMS_RP_CAUSE_NETWORK_OUT_OF_ORDER, + SmsManager.SMS_RP_CAUSE_CONGESTION, + SmsManager.SMS_RP_CAUSE_RESOURCES_UNAVAILABLE, + SmsManager.SMS_RP_CAUSE_FACILITY_NOT_SUBSCRIBED, + SmsManager.SMS_RP_CAUSE_FACILITY_NOT_IMPLEMENTED, + SmsManager.SMS_RP_CAUSE_INVALID_MESSAGE_REFERENCE_VALUE, + SmsManager.SMS_RP_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE, + SmsManager.SMS_RP_CAUSE_INVALID_MANDATORY_INFORMATION, + SmsManager.SMS_RP_CAUSE_MESSAGE_TYPE_NON_EXISTENT, + SmsManager.SMS_RP_CAUSE_MESSAGE_INCOMPATIBLE_WITH_PROTOCOL_STATE, + SmsManager.SMS_RP_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT, + SmsManager.SMS_RP_CAUSE_PROTOCOL_ERROR, + SmsManager.SMS_RP_CAUSE_INTERWORKING_UNSPECIFIED + }); + defaults.putIntArray( KEY_SMS_OVER_IMS_SUPPORTED_RATS_INT_ARRAY, new int[] { @@ -6902,7 +7254,7 @@ public class CarrierConfigManager { * <p>If {@code true}: text media can be sent on default bearer. * {@code false} otherwise. */ - public static final String KEY_TEXT_ON_DEFAULT_BEARER_SUPPORTED_BOOL = + public static final String KEY_TEXT_ON_DEFAULT_BEARER_SUPPORTED_BOOL = KEY_PREFIX + "text_on_default_bearer_supported_bool"; /** @@ -6912,7 +7264,7 @@ public class CarrierConfigManager { * {@code false} otherwise. * <p>Reference: 3GPP TS 24.229 */ - public static final String KEY_TEXT_QOS_PRECONDITION_SUPPORTED_BOOL = + public static final String KEY_TEXT_QOS_PRECONDITION_SUPPORTED_BOOL = KEY_PREFIX + "text_qos_precondition_supported_bool"; /** @@ -6962,14 +7314,14 @@ public class CarrierConfigManager { * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_T140_PAYLOAD_TYPE_INT = + public static final String KEY_T140_PAYLOAD_TYPE_INT = KEY_PREFIX + "t140_payload_type_int"; /** Integer representing payload type for RED/redundancy codec. * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_RED_PAYLOAD_TYPE_INT = + public static final String KEY_RED_PAYLOAD_TYPE_INT = KEY_PREFIX + "red_payload_type_int"; private static PersistableBundle getDefaults() { @@ -7018,7 +7370,7 @@ public class CarrierConfigManager { * <p>If {@code true}: Allow UE to retry emergency call on * IMS PDN if emergency PDN setup failed.{@code false} otherwise. */ - public static final String KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL = + public static final String KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL = KEY_PREFIX + "retry_emergency_on_ims_pdn_bool"; /** @@ -7028,7 +7380,7 @@ public class CarrierConfigManager { * <p>If {@code true}: Enter ECBM mode after E911 call is ended. * {@code false} otherwise. */ - public static final String KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL = + public static final String KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL = KEY_PREFIX + "emergency_callback_mode_supported_bool"; /** @@ -7040,7 +7392,7 @@ public class CarrierConfigManager { * * <p>Reference: 3GPP TS 24.229 */ - public static final String KEY_EMERGENCY_QOS_PRECONDITION_SUPPORTED_BOOL = + public static final String KEY_EMERGENCY_QOS_PRECONDITION_SUPPORTED_BOOL = KEY_PREFIX + "emergency_qos_precondition_supported_bool"; /** @@ -7071,6 +7423,387 @@ public class CarrierConfigManager { public static final String KEY_REFRESH_GEOLOCATION_TIMEOUT_MILLIS_INT = KEY_PREFIX + "refresh_geolocation_timeout_millis_int"; + /** + * List of 3GPP access network technologies where e911 over IMS is supported + * in the home network and domestic 3rd-party networks. The order in the list represents + * the preference. The domain selection service shall scan the network type in the order + * of the preference. + * + * <p>Possible values are, + * {@link AccessNetworkConstants.AccessNetworkType#NGRAN} + * {@link AccessNetworkConstants.AccessNetworkType#EUTRAN} + * + * The default value for this key is + * {{@link AccessNetworkConstants.AccessNetworkType#EUTRAN}, + * @hide + */ + public static final String + KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY = KEY_PREFIX + + "emergency_over_ims_supported_3gpp_network_types_int_array"; + + /** + * List of 3GPP access network technologies where e911 over IMS is supported + * in the roaming network and non-domestic 3rd-party networks. The order in the list + * represents the preference. The domain selection service shall scan the network type + * in the order of the preference. + * + * <p>Possible values are, + * {@link AccessNetworkConstants.AccessNetworkType#NGRAN} + * {@link AccessNetworkConstants.AccessNetworkType#EUTRAN} + * + * The default value for this key is + * {{@link AccessNetworkConstants.AccessNetworkType#EUTRAN}, + * @hide + */ + public static final String + KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY = KEY_PREFIX + + "emergency_over_ims_roaming_supported_3gpp_network_types_int_array"; + + /** + * List of CS access network technologies where circuit-switched emergency calls are + * supported in the home network and domestic 3rd-party networks. The order in the list + * represents the preference. The domain selection service shall scan the network type + * in the order of the preference. + * + * <p>Possible values are, + * {@link AccessNetworkConstants.AccessNetworkType#GERAN} + * {@link AccessNetworkConstants.AccessNetworkType#UTRAN} + * {@link AccessNetworkConstants.AccessNetworkType#CDMA2000} + * + * The default value for this key is + * {{@link AccessNetworkConstants.AccessNetworkType#UTRAN}, + * {@link AccessNetworkConstants.AccessNetworkType#GERAN}}. + * @hide + */ + public static final String KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY = + KEY_PREFIX + "emergency_over_cs_supported_access_network_types_int_array"; + + /** + * List of CS access network technologies where circuit-switched emergency calls are + * supported in the roaming network and non-domestic 3rd-party networks. The order + * in the list represents the preference. The domain selection service shall scan + * the network type in the order of the preference. + * + * <p>Possible values are, + * {@link AccessNetworkConstants.AccessNetworkType#GERAN} + * {@link AccessNetworkConstants.AccessNetworkType#UTRAN} + * {@link AccessNetworkConstants.AccessNetworkType#CDMA2000} + * + * The default value for this key is + * {{@link AccessNetworkConstants.AccessNetworkType#UTRAN}, + * {@link AccessNetworkConstants.AccessNetworkType#GERAN}}. + * @hide + */ + public static final String + KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY = KEY_PREFIX + + "emergency_over_cs_roaming_supported_access_network_types_int_array"; + + /** @hide */ + @IntDef({ + DOMAIN_CS, + DOMAIN_PS_3GPP, + DOMAIN_PS_NON_3GPP + }) + public @interface EmergencyDomain {} + + /** + * Circuit switched domain. + * @hide + */ + public static final int DOMAIN_CS = 1; + + /** + * Packet switched domain over 3GPP networks. + * @hide + */ + public static final int DOMAIN_PS_3GPP = 2; + + /** + * Packet switched domain over non-3GPP networks such as Wi-Fi. + * @hide + */ + public static final int DOMAIN_PS_NON_3GPP = 3; + + /** + * Specifies the emergency call domain preference for the home network. + * The domain selection service shall choose the domain in the order + * for attempting the emergency call + * + * <p>Possible values are, + * {@link #DOMAIN_CS} + * {@link #DOMAIN_PS_3GPP} + * {@link #DOMAIN_PS_NON_3GPP}. + * + * The default value for this key is + * {{@link #DOMAIN_PS_3GPP}, + * {@link #DOMAIN_CS}, + * {@link #DOMAIN_PS_NON_3GPP}}. + * @hide + */ + public static final String KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY = + KEY_PREFIX + "emergency_domain_preference_int_array"; + + /** + * Specifies the emergency call domain preference for the roaming network. + * The domain selection service shall choose the domain in the order + * for attempting the emergency call. + * + * <p>Possible values are, + * {@link #DOMAIN_CS} + * {@link #DOMAIN_PS_3GPP} + * {@link #DOMAIN_PS_NON_3GPP}. + * + * The default value for this key is + * {{@link #DOMAIN_PS_3GPP}, + * {@link #DOMAIN_CS}, + * {@link #DOMAIN_PS_NON_3GPP}}. + * @hide + */ + public static final String KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY = + KEY_PREFIX + "emergency_domain_preference_roaming_int_array"; + + /** + * Specifies if emergency call shall be attempted on IMS, if PS is attached even though IMS + * is not registered and normal calls fallback to the CS networks. + * + * The default value for this key is {@code false}. + * @hide + */ + public static final String KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL = + KEY_PREFIX + "prefer_ims_emergency_when_voice_calls_on_cs_bool"; + + /** @hide */ + @IntDef({ + VOWIFI_REQUIRES_NONE, + VOWIFI_REQUIRES_SETTING_ENABLED, + VOWIFI_REQUIRES_VALID_EID, + }) + public @interface VoWiFiRequires {} + + /** + * Default value. + * If {@link ImsWfc#KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL} is {@code true}, + * VoWi-Fi emergency call shall be attempted if Wi-Fi network is connected. + * Otherwise, it shall be attempted if IMS is registered over Wi-Fi. + * @hide + */ + public static final int VOWIFI_REQUIRES_NONE = 0; + + /** + * VoWi-Fi emergency call shall be attempted on IMS over Wi-Fi if Wi-Fi network is connected + * and Wi-Fi calling setting is enabled. This value is applicable if the value of + * {@link ImsWfc#KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL} is {@code true}. + * @hide + */ + public static final int VOWIFI_REQUIRES_SETTING_ENABLED = 1; + + /** + * VoWi-Fi emergency call shall be attempted on IMS over Wi-Fi if Wi-Fi network is connected + * and Wi-Fi calling is activated successfully. This value is applicable if the value of + * {@link ImsWfc#KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL} is {@code true}. + * @hide + */ + public static final int VOWIFI_REQUIRES_VALID_EID = 2; + + /** + * Specifies the condition when emergency call shall be attempted on IMS over Wi-Fi. + * + * The default value for this key is {@code #VOWIFI_REQUIRES_NONE}. + * @hide + */ + public static final String KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT = + KEY_PREFIX + "emergency_vowifi_requires_condition_int"; + + /** + * Specifies maximum number of emergency call retries over Wi-Fi. + * This is valid only when {@link #DOMAIN_PS_NON_3GPP} is included in + * {@link #KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY} or + * {@link #KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY}. + * + * The default value for this key is 1. + * @hide + */ + public static final String KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT = + KEY_PREFIX + "maximum_number_of_emergency_tries_over_vowifi_int"; + + /** + * Emergency scan timer to wait for scan results from radio before attempting the call + * over Wi-Fi. On timer expiry, if emergency call on Wi-Fi is allowed and possible, + * telephony shall cancel the scan and place the call on Wi-Fi. If emergency call on Wi-Fi + * is not possible, then domain seleciton continues to wait for the scan result from the + * radio. If an emergency scan result is received before the timer expires, the timer shall + * be stopped and no dialing over Wi-Fi will be tried. If this value is set to 0, then + * the timer is never started and domain selection waits for the scan result from the radio. + * + * The default value for the timer is 10 seconds. + * @hide + */ + public static final String KEY_EMERGENCY_SCAN_TIMER_SEC_INT = + KEY_PREFIX + "emergency_scan_timer_sec_int"; + + /** + * The timer to wait for the call completion on the cellular network before attempting the + * call over Wi-Fi. On timer expiry, if emergency call on Wi-Fi is allowed and possible, + * telephony shall cancel the scan on the cellular network and place the call on Wi-Fi. + * If dialing over cellular network is ongoing when timer expires, dialing over Wi-Fi + * will be requested only when the ongoing dialing fails. If emergency call on Wi-Fi is not + * possible, then domain selection continues to try dialing from the radio and the timer + * remains expired. Later when calling over Wi-Fi is possible and dialing over cellular + * networks fails, calling over Wi-Fi will be requested. The timer shall be restarted from + * initial state if calling over Wi-Fi fails. + * If this value is set to {@link #REDIAL_TIMER_DISABLED}, then the timer will never be + * started. + * + * The default value for the timer is {@link #REDIAL_TIMER_DISABLED}. + * @hide + */ + public static final String KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT = + KEY_PREFIX + "maximum_cellular_search_timer_sec_int"; + + /** @hide */ + @IntDef(prefix = "SCAN_TYPE_", + value = { + SCAN_TYPE_NO_PREFERENCE, + SCAN_TYPE_FULL_SERVICE, + SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE}) + public @interface EmergencyScanType {} + + /** + * No specific preference given to the modem. Modem can return an emergency + * capable network either with limited service or full service. + * @hide + */ + public static final int SCAN_TYPE_NO_PREFERENCE = 0; + + /** + * Modem will attempt to camp on a network with full service only. + * @hide + */ + public static final int SCAN_TYPE_FULL_SERVICE = 1; + + /** + * Telephony shall attempt full service scan first. + * If a full service network is not found, telephony shall attempt a limited service scan. + * @hide + */ + public static final int SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE = 2; + + /** + * Specifies the preferred emergency network scanning type. + * + * <p>Possible values are, + * {@link #SCAN_TYPE_NO_PREFERENCE} + * {@link #SCAN_TYPE_FULL_SERVICE} + * {@link #SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE} + * + * The default value for this key is {@link #SCAN_TYPE_NO_PREFERENCE}. + * @hide + */ + public static final String KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT = + KEY_PREFIX + "emergency_network_scan_type_int"; + + /** + * Specifies the time by which a call should be set up on the current network + * once the call is routed on the network. If the call cannot be set up by timer expiry, + * call shall be re-dialed on the next available network. + * If this value is set to 0, the timer shall be disabled. + * + * The default value for this key is 0. + * @hide + */ + public static final String KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT = + KEY_PREFIX + "emergency_call_setup_timer_on_current_network_sec_int"; + + /** + * Specifies if emergency call shall be attempted on IMS only when IMS is registered. + * This is applicable only for the case PS is in service. + * + * The default value for this key is {@code false}. + * @hide + */ + public static final String KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL = + KEY_PREFIX + "emergency_requires_ims_registration_bool"; + + /** + * Specifies if LTE is preferred when re-scanning networks after the failure of dialing + * over NR. If not, CS will be preferred. + * + * The default value for this key is {@code false}. + * @hide + */ + public static final String KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL = + KEY_PREFIX + "emergency_lte_preferred_after_nr_failed_bool"; + + /** + * Specifies the numbers to be dialed over CDMA network in case of dialing over CS network. + * + * The default value for this key is an empty string array. + * @hide + */ + public static final String KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY = + KEY_PREFIX + "emergency_cdma_preferred_numbers_string_array"; + + /** + * Specifies if emergency call shall be attempted on IMS over cellular network + * only when VoLTE is enabled. + * + * The default value for this key is {@code false}. + * @hide + */ + public static final String KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL = + KEY_PREFIX + "emergency_requires_volte_enabled_bool"; + + /** + * This values indicates that the cross SIM redialing timer and maximum celluar search + * timer shall be disabled. + * + * @see #KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT + * @see #KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT + * @see #KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT + * @hide + */ + public static final int REDIAL_TIMER_DISABLED = 0; + + /** + * A timer to guard the max attempting time on current SIM slot so that modem will not + * stuck in current SIM slot for long time. On timer expiry, if emergency call on the + * other SIM slot is preferable, telephony shall cancel the emergency call and place the + * call on the other SIM slot. If this value is set to {@link #REDIAL_TIMER_DISABLED}, then + * the timer will never be started and domain selection continues on the current SIM slot. + * This value should be greater than the value of {@link #KEY_EMERGENCY_SCAN_TIMER_SEC_INT}. + * + * The default value for the timer is 120 seconds. + * @hide + */ + public static final String KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT = + KEY_PREFIX + "cross_stack_redial_timer_sec_int"; + + /** + * If emergency calls are only allowed with normal-registered service and UE should get + * normal service in a short time with acquired band information, telephony + * expects dialing emergency call will be completed in a short time. + * If dialing is not completed with in a certain timeout, telephony shall place on + * another SIM slot. If this value is set to {@link #REDIAL_TIMER_DISABLED}, then the timer + * will never be started and domain selection continues on the current SIM slot. + * The timer shall be started for the first trial of each subscription and shall be ignored + * in the roaming networks and non-domestic networks. + * + * The default value for the timer is {@link #REDIAL_TIMER_DISABLED}. + * @hide + */ + public static final String KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT = + KEY_PREFIX + "quick_cross_stack_redial_timer_sec_int"; + + /** + * Indicates whether the quick cross stack redial timer will be triggered only when + * the device is registered to the network. + * + * The default value is {@code true}. + * @hide + */ + public static final String KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL = + KEY_PREFIX + "start_quick_cross_stack_redial_timer_when_registered_bool"; + private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putBoolean(KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL, false); @@ -7087,6 +7820,62 @@ public class CarrierConfigManager { defaults.putInt(KEY_EMERGENCY_REGISTRATION_TIMER_MILLIS_INT, 10000); defaults.putInt(KEY_REFRESH_GEOLOCATION_TIMEOUT_MILLIS_INT, 5000); + defaults.putIntArray( + KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY, + new int[] { + AccessNetworkType.EUTRAN, + }); + + defaults.putIntArray( + KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY, + new int[] { + AccessNetworkType.EUTRAN, + }); + + defaults.putIntArray( + KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY, + new int[] { + AccessNetworkType.UTRAN, + AccessNetworkType.GERAN, + }); + + defaults.putIntArray( + KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY, + new int[] { + AccessNetworkType.UTRAN, + AccessNetworkType.GERAN, + }); + + defaults.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, + new int[] { + DOMAIN_PS_3GPP, + DOMAIN_CS, + DOMAIN_PS_NON_3GPP + }); + defaults.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY, + new int[] { + DOMAIN_PS_3GPP, + DOMAIN_CS, + DOMAIN_PS_NON_3GPP + }); + + defaults.putBoolean(KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL, false); + defaults.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_NONE); + defaults.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, 1); + defaults.putInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT, 10); + defaults.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, REDIAL_TIMER_DISABLED); + defaults.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, SCAN_TYPE_NO_PREFERENCE); + defaults.putInt(KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT, 0); + defaults.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, false); + defaults.putBoolean(KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL, false); + defaults.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, false); + defaults.putStringArray(KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY, + new String[0]); + defaults.putInt(KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT, 120); + defaults.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, REDIAL_TIMER_DISABLED); + defaults.putBoolean(KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL, + true); + return defaults; } } @@ -7106,7 +7895,7 @@ public class CarrierConfigManager { * <p>If {@code true}: video media can be sent on default bearer. * {@code false} otherwise. */ - public static final String KEY_VIDEO_ON_DEFAULT_BEARER_SUPPORTED_BOOL = + public static final String KEY_VIDEO_ON_DEFAULT_BEARER_SUPPORTED_BOOL = KEY_PREFIX + "video_on_default_bearer_supported_bool"; /** @@ -7172,7 +7961,7 @@ public class CarrierConfigManager { * {@code false} otherwise. * <p>Reference: 3GPP TS 24.229 */ - public static final String KEY_VIDEO_QOS_PRECONDITION_SUPPORTED_BOOL = + public static final String KEY_VIDEO_QOS_PRECONDITION_SUPPORTED_BOOL = KEY_PREFIX + "video_qos_precondition_supported_bool"; /** @@ -7197,7 +7986,7 @@ public class CarrierConfigManager { * <p>Payload type is an integer in dynamic payload type range 96-127 * as per RFC RFC 3551 Section 6. */ - public static final String KEY_H264_PAYLOAD_TYPE_INT_ARRAY = + public static final String KEY_H264_PAYLOAD_TYPE_INT_ARRAY = KEY_PREFIX + "h264_payload_type_int_array"; /** @@ -7239,7 +8028,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 6184 Section 5.4 */ - public static final String KEY_VIDEO_CODEC_ATTRIBUTE_PACKETIZATION_MODE_INT = + public static final String KEY_VIDEO_CODEC_ATTRIBUTE_PACKETIZATION_MODE_INT = KEY_PREFIX + "video_codec_attribute_packetization_mode_int"; /** @@ -7253,7 +8042,7 @@ public class CarrierConfigManager { * <UL> * <p>Reference: RFC 4566 Section 6, 3GPP 26.114 Section 6.2.3.2 */ - public static final String KEY_VIDEO_CODEC_ATTRIBUTE_FRAME_RATE_INT = + public static final String KEY_VIDEO_CODEC_ATTRIBUTE_FRAME_RATE_INT = KEY_PREFIX + "video_codec_attribute_frame_rate_int"; /** @@ -7272,7 +8061,7 @@ public class CarrierConfigManager { * <p>Reference: RFC 4566 Section 6, 3GPP 26.114 Section 6.2.3.2 * */ - public static final String KEY_VIDEO_CODEC_ATTRIBUTE_RESOLUTION_INT_ARRAY = + public static final String KEY_VIDEO_CODEC_ATTRIBUTE_RESOLUTION_INT_ARRAY = KEY_PREFIX + "video_codec_attribute_resolution_int_array"; /** @@ -7285,7 +8074,7 @@ public class CarrierConfigManager { * * <p>Reference: RFC 6184 Section 8.1, ITU-T Recommendation H.264 */ - public static final String KEY_H264_VIDEO_CODEC_ATTRIBUTE_PROFILE_LEVEL_ID_STRING = + public static final String KEY_H264_VIDEO_CODEC_ATTRIBUTE_PROFILE_LEVEL_ID_STRING = KEY_PREFIX + "h264_video_codec_attribute_profile_level_id_string"; private static PersistableBundle getDefaults() { @@ -7353,7 +8142,7 @@ public class CarrierConfigManager { * List of MDNs for which Geo-location PIDF XML with country info * needs to included for normal calls involving short code. */ - public static final String KEY_PIDF_SHORT_CODE_STRING_ARRAY = + public static final String KEY_PIDF_SHORT_CODE_STRING_ARRAY = KEY_PREFIX + "pidf_short_code_string_array"; /** @@ -7363,15 +8152,14 @@ public class CarrierConfigManager { * <p>If {@code false}: E911 call uses IMS PDN for E911 call over VoWiFi. * If {@code true}: E911 call uses Emergency PDN for E911 call over VoWiFi. */ - public static final String KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL = + public static final String KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL = KEY_PREFIX + "emergency_call_over_emergency_pdn_bool"; - private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, false); - defaults.putStringArray(KEY_PIDF_SHORT_CODE_STRING_ARRAY, new String[] {}); + defaults.putStringArray(KEY_PIDF_SHORT_CODE_STRING_ARRAY, new String[0]); return defaults; } @@ -7418,7 +8206,7 @@ public class CarrierConfigManager { * If XCAP over UT fails, return error. * if {@code true}, Use CSFB if XCAP over UT fails. */ - public static final String KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL = + public static final String KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL = KEY_PREFIX + "use_csfb_on_xcap_over_ut_failure_bool"; /** @@ -7430,7 +8218,7 @@ public class CarrierConfigManager { * * Reference: IR.92 Section 5.5.1 */ - public static final String KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL = + public static final String KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL = KEY_PREFIX + "ut_supported_when_ps_data_off_bool"; /** @@ -7440,7 +8228,7 @@ public class CarrierConfigManager { * <p>If {@code true}: Support Available.{@code false}: Otherwise. * Reference: 3GPP 24.390. */ - public static final String KEY_NETWORK_INITIATED_USSD_OVER_IMS_SUPPORTED_BOOL = + public static final String KEY_NETWORK_INITIATED_USSD_OVER_IMS_SUPPORTED_BOOL = KEY_PREFIX + "network_initiated_ussd_over_ims_supported_bool"; /** @@ -7524,7 +8312,6 @@ public class CarrierConfigManager { SUPPLEMENTARY_SERVICE_CB_ACR, SUPPLEMENTARY_SERVICE_CB_BIL }) - public @interface SsType {} /** Communication Waiting (CW) support as per 3GPP 24.615. */ @@ -7755,6 +8542,99 @@ public class CarrierConfigManager { public static final String KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY = KEY_PREFIX + "xcap_over_ut_supported_rats_int_array"; + /** @hide */ + @IntDef({ + CALL_WAITING_SYNC_NONE, + CALL_WAITING_SYNC_USER_CHANGE, + CALL_WAITING_SYNC_FIRST_POWER_UP, + CALL_WAITING_SYNC_FIRST_CHANGE, + CALL_WAITING_SYNC_IMS_ONLY + }) + public @interface CwSyncType {} + + /** + * Do not synchronize the user's call waiting setting with the network. Call waiting is + * always enabled on the carrier network and the user setting for call waiting is applied + * on the terminal side. If the user disables call waiting, the call will be rejected on + * the terminal. + */ + public static final int CALL_WAITING_SYNC_NONE = 0; + + /** + * The change of user’s setting is always passed to the carrier network + * and then synchronized to the terminal based call waiting solution over IMS. + * If changing the service over the carrier network is not successful, + * the setting over IMS shall not be changed. + */ + public static final int CALL_WAITING_SYNC_USER_CHANGE = 1; + + /** + * Activate call waiting on the carrier network when the device boots or a subscription + * using this carrier is loaded. Call waiting is always considered enabled on the carrier + * network and the user setting for call waiting is applied on the terminal side only. If + * the user disables call waiting, the call will be rejected on the terminal. + * The mismatch between CS calls and IMS calls can happen when the network based call + * waiting service is in disabled state in the legacy 3G/2G networks while it's enabled + * in the terminal side. + */ + public static final int CALL_WAITING_SYNC_FIRST_POWER_UP = 2; + + /** + * Activate call waiting on the carrier network when the user enables call waiting the + * first time. Call waiting is then always considered enabled on the carrier network. If + * the user disables call waiting, the setting will only be applied to the terminal based + * call waiting service and the call will be rejected on the terminal. + * The mismatch between CS calls and IMS calls can happen when the network based call + * waiting service is in disabled state in the legacy 3G/2G networks while it's enabled + * in the terminal side. However, if the user retrieves the setting again when the device + * is in the legacy 3G/2G networks, the correct state will be shown to the user. + */ + public static final int CALL_WAITING_SYNC_FIRST_CHANGE = 3; + + /** + * Do not synchronize the call waiting service state between the carrier network and + * the terminal based IMS call waiting service. If the user changes the call waiting setting + * when IMS is registered, the change will only be applied to the terminal based call + * waiting service. If IMS is not registered when call waiting is changed, synchronize this + * setting with the carrier network. + */ + public static final int CALL_WAITING_SYNC_IMS_ONLY = 4; + + /** @hide */ + public static final int CALL_WAITING_SYNC_MAX = CALL_WAITING_SYNC_IMS_ONLY; + + /** + * Flag indicating the way to synchronize the setting between CS and IMS. + * + * <p>Possible values are, + * {@link #CALL_WAITING_SYNC_NONE}, + * {@link #CALL_WAITING_SYNC_USER_CHANGE}, + * {@link #CALL_WAITING_SYNC_FIRST_POWER_UP}, + * {@link #CALL_WAITING_SYNC_FIRST_CHANGE}, + * {@link #CALL_WAITING_SYNC_IMS_ONLY}. + * + * This configuration is valid only when + * {@link #KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY} includes + * {@link #SUPPLEMENTARY_SERVICE_CW}. + * + * <p>If key is invalid or not configured, the default value + * {@link #CALL_WAITING_SYNC_FIRST_CHANGE} will apply. + */ + public static final String KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT = + KEY_PREFIX + "terminal_based_call_waiting_sync_type_int"; + + /** + * Flag indicating whether the user setting for terminal-based call waiting + * is enabled by default or not. + * This configuration is valid only when + * {@link #KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY} includes + * {@link #SUPPLEMENTARY_SERVICE_CW}. + * + * The default value for this key is {@code true}. + */ + public static final String KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL = + KEY_PREFIX + "terminal_based_call_waiting_default_enabled_bool"; + private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putBoolean(KEY_UT_REQUIRES_IMS_REGISTRATION_BOOL, false); @@ -7794,17 +8674,19 @@ public class CarrierConfigManager { SUPPLEMENTARY_SERVICE_CB_ACR, SUPPLEMENTARY_SERVICE_CB_BIL }); - defaults.putIntArray( - KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, - new int[] {}); + defaults.putIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, new int[0]); defaults.putIntArray( KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY, new int[] { AccessNetworkType.EUTRAN, - AccessNetworkType.IWLAN + AccessNetworkType.IWLAN, + AccessNetworkType.NGRAN }); defaults.putString(KEY_UT_AS_SERVER_FQDN_STRING, ""); + defaults.putBoolean(KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL, true); + defaults.putInt(KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT, + CALL_WAITING_SYNC_FIRST_CHANGE); return defaults; } @@ -7986,7 +8868,6 @@ public class CarrierConfigManager { public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array"; - /** * List of supported key sizes for AES Counter (CTR) encryption mode of IKE session. * Possible values - @@ -8121,7 +9002,7 @@ public class CarrierConfigManager { public static final int EPDG_ADDRESS_PCO = 2; /** Use cellular location to chose epdg server */ public static final int EPDG_ADDRESS_CELLULAR_LOC = 3; - /* Use Visited Country FQDN rule*/ + /** Use Visited Country FQDN rule*/ public static final int EPDG_ADDRESS_VISITED_COUNTRY = 4; /** @hide */ @@ -8295,7 +9176,7 @@ public class CarrierConfigManager { EPDG_PLMN_RPLMN, EPDG_PLMN_HPLMN, EPDG_PLMN_EHPLMN_ALL}); - defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[] {}); + defaults.putStringArray(KEY_MCC_MNCS_STRING_ARRAY, new String[0]); defaults.putInt(KEY_IKE_LOCAL_ID_TYPE_INT, ID_TYPE_RFC822_ADDR); defaults.putInt(KEY_IKE_REMOTE_ID_TYPE_INT, ID_TYPE_FQDN); defaults.putBoolean(KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL, false); @@ -8318,8 +9199,17 @@ public class CarrierConfigManager { * level outside these boundaries is considered invalid. * @hide */ - public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY = - "gsm_rssi_thresholds_int_array"; + public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY = "gsm_rssi_thresholds_int_array"; + + /** + * An interval in dB for {@link SignalThresholdInfo#SIGNAL_MEASUREMENT_TYPE_RSSI} measurement + * type defining the required magnitude change between reports. + * + * <p>The default value is 2 and the minimum allowed value is 0. If no value or negative value + * is set, the default value 2 is used. + * @hide + */ + public static final String KEY_GERAN_RSSI_HYSTERESIS_DB_INT = "geran_rssi_hysteresis_db_int"; /** * Determines whether Wireless Priority Service call is supported over IMS. @@ -8327,8 +9217,7 @@ public class CarrierConfigManager { * See Wireless Priority Service from https://www.fcc.gov/general/wireless-priority-service-wps * @hide */ - public static final String KEY_SUPPORT_WPS_OVER_IMS_BOOL = - "support_wps_over_ims_bool"; + public static final String KEY_SUPPORT_WPS_OVER_IMS_BOOL = "support_wps_over_ims_bool"; /** * The two digital number pattern of MMI code which is defined by carrier. @@ -8377,8 +9266,7 @@ public class CarrierConfigManager { * When true, forwarded number is shown. * When false, forwarded number is not shown. */ - public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = - "show_forwarded_number_bool"; + public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool"; /** * The list of originating address of missed incoming call SMS. If the SMS has originator @@ -8390,7 +9278,6 @@ public class CarrierConfigManager { public static final String KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY = "missed_incoming_call_sms_originator_string_array"; - /** * String array of Apn Type configurations. * The entries should be of form "APN_TYPE_NAME:priority". @@ -8538,8 +9425,7 @@ public class CarrierConfigManager { * * @hide */ - public static final String KEY_DEFAULT_RTT_MODE_INT = - "default_rtt_mode_int"; + public static final String KEY_DEFAULT_RTT_MODE_INT = "default_rtt_mode_int"; /** * Indicates whether RTT is supported while roaming. @@ -8565,10 +9451,9 @@ public class CarrierConfigManager { * seamlessly after an unattended reboot. * * The device configuration value {@code config_allow_pin_storage_for_unattended_reboot} - * ultimately controls whether this carrier configuration option is used. Where - * {@code config_allow_pin_storage_for_unattended_reboot} is false, the value of the - * {@link #KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL} carrier configuration option is - * ignored. + * ultimately controls whether this carrier configuration option is used. Where + * {@code config_allow_pin_storage_for_unattended_reboot} is false, the value of this + * carrier configuration is ignored. * * @hide */ @@ -8670,7 +9555,6 @@ public class CarrierConfigManager { * * Enabled by default. * - * @hide */ public static final String KEY_VONR_ON_BY_DEFAULT_BOOL = "vonr_on_by_default_bool"; @@ -8683,6 +9567,134 @@ public class CarrierConfigManager { "unthrottle_data_retry_when_tac_changes_bool"; /** + * A list of premium capabilities the carrier supports. Applications can prompt users to + * purchase these premium capabilities from their carrier for a performance boost. + * Valid values are any of {@link TelephonyManager.PremiumCapability}. + * + * This is empty by default, indicating that no premium capabilities are supported. + * + * @see TelephonyManager#isPremiumCapabilityAvailableForPurchase(int) + * @see TelephonyManager#purchasePremiumCapability(int, Executor, Consumer) + */ + public static final String KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY = + "supported_premium_capabilities_int_array"; + + /** + * The amount of time in milliseconds the notification for a performance boost via + * premium capabilities will be visible to the user after + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} + * requests user action to purchase the boost from the carrier. Once the timeout expires, + * the performance boost notification will be automatically dismissed and the request will fail + * with {@link TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT}. + * + * The default value is 30 minutes. + */ + public static final String KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG = + "premium_capability_notification_display_timeout_millis_long"; + + /** + * The amount of time in milliseconds that the notification for a performance boost via + * premium capabilities should be blocked when + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} + * returns a failure due to user action or timeout. + * The maximum number of performance boost notifications to show the user are defined in + * {@link #KEY_PREMIUM_CAPABILITY_MAXIMUM_DAILY_NOTIFICATION_COUNT_INT} and + * {@link #KEY_PREMIUM_CAPABILITY_MAXIMUM_MONTHLY_NOTIFICATION_COUNT_INT}. + * + * The default value is 30 minutes. + * + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT + */ + public static final String + KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG = + "premium_capability_notification_backoff_hysteresis_time_millis_long"; + + /** + * The maximum number of times in a day that we display the notification for a performance boost + * via premium capabilities when + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} + * returns a failure due to user action or timeout. + * + * The default value is 2 times. + * + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT + */ + public static final String KEY_PREMIUM_CAPABILITY_MAXIMUM_DAILY_NOTIFICATION_COUNT_INT = + "premium_capability_maximum_daily_notification_count_int"; + + /** + * The maximum number of times in a month that we display the notification for a performance + * boost via premium capabilities when + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} + * returns a failure due to user action or timeout. + * + * The default value is 10 times. + * + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT + */ + public static final String KEY_PREMIUM_CAPABILITY_MAXIMUM_MONTHLY_NOTIFICATION_COUNT_INT = + "premium_capability_maximum_monthly_notification_count_int"; + + /** + * The amount of time in milliseconds that the purchase request should be throttled when + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} + * returns a failure due to the carrier. + * + * The default value is 30 minutes. + * + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR + * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED + */ + public static final String + KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG = + "premium_capability_purchase_condition_backoff_hysteresis_time_millis_long"; + + /** + * The amount of time in milliseconds within which the network must set up a slicing + * configuration for the premium capability after + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} + * returns {@link TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS}. + * During the setup time, calls to + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} will return + * {@link TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP}. + * If the network fails to set up a slicing configuration for the premium capability within the + * setup time, subsequent purchase requests will be allowed to go through again. + * + * The default value is 5 minutes. + */ + public static final String KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG = + "premium_capability_network_setup_time_millis_long"; + + /** + * The URL to redirect to when the user clicks on the notification for a performance boost via + * premium capabilities after applications call + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)}. + * If the URL is empty or invalid, the purchase request will return + * {@link TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED}. + * + * This is empty by default. + */ + public static final String KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING = + "premium_capability_purchase_url_string"; + + /** + * Whether to allow premium capabilities to be purchased when the device is connected to LTE. + * If this is {@code true}, applications can call + * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} + * when connected to {@link TelephonyManager#NETWORK_TYPE_LTE} to purchase and use + * premium capabilities. + * If this is {@code false}, applications can only purchase and use premium capabilities when + * connected to {@link TelephonyManager#NETWORK_TYPE_NR}. + * + * This is {@code false} by default. + */ + public static final String KEY_PREMIUM_CAPABILITY_SUPPORTED_ON_LTE_BOOL = + "premium_capability_supported_on_lte_bool"; + + /** * IWLAN handover rules that determine whether handover is allowed or disallowed between * cellular and IWLAN. * @@ -8705,7 +9717,7 @@ public class CarrierConfigManager { * or EIMS--> * <item value="source=EUTRAN, target=IWLAN, type=disallowed, capabilities=IMS|EIMS"/> * <!-- Handover is always allowed in any condition. --> - * <item value="source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, + * <item value="source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN|UNKNOWN, * target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"/> * </string-array> * @@ -8719,7 +9731,7 @@ public class CarrierConfigManager { "iwlan_handover_policy_string_array"; /** The default value for every variable. */ - private final static PersistableBundle sDefaults; + private static final PersistableBundle sDefaults; static { sDefaults = new PersistableBundle(); @@ -8829,17 +9841,17 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true); sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, true); sDefaults.putBoolean(KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL, false); - sDefaults.putIntArray(KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, new int[]{}); + sDefaults.putIntArray(KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, new int[0]); sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0); sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, ""); sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, ""); sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0); sDefaults.putString(KEY_VVM_TYPE_STRING, ""); sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false); - sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING,"//VVM"); - sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL,false); + sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING, "//VVM"); + sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL, false); sDefaults.putStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY, null); - sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL,false); + sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL, false); sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOL, true); sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, ""); sDefaults.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY, null); @@ -8996,7 +10008,6 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null); sDefaults.putBoolean(KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL, false); - // Default carrier app configurations sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY, new String[]{ @@ -9010,9 +10021,10 @@ public class CarrierConfigManager { //6: CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS //8: CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER }); - sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE, new String[] { - String.valueOf(false) + ": 7", //7: CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER - String.valueOf(true) + ": 8" //8: CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER + sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE, + new String[] { + false + ": 7", //7: CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER + true + ": 8" //8: CARRIER_ACTION_DISABLE_DEFAULT_URL_HANDLER }); sDefaults.putStringArray(KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY, null); @@ -9026,9 +10038,9 @@ public class CarrierConfigManager { // Rat families: {GPRS, EDGE}, {EVDO, EVDO_A, EVDO_B}, {UMTS, HSPA, HSDPA, HSUPA, HSPAP}, // {LTE, LTE_CA} - // Order is important - lowest precidence first + // Order is important - lowest precedence first sDefaults.putStringArray(KEY_RATCHET_RAT_FAMILIES, - new String[]{"1,2","7,8,12","3,11,9,10,15","14,19"}); + new String[]{"1,2", "7,8,12", "3,11,9,10,15", "14,19"}); sDefaults.putBoolean(KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL, false); sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, false); sDefaults.putBoolean(KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL, true); @@ -9059,8 +10071,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false); sDefaults.putBoolean(KEY_HIDE_PRESET_APN_DETAILS_BOOL, false); sDefaults.putBoolean(KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL, false); - sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY, - null); + sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY, null); sDefaults.putBoolean(KEY_SUPPORT_IMS_CALL_FORWARDING_WHILE_ROAMING_BOOL, true); sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0); sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null); @@ -9096,9 +10107,11 @@ public class CarrierConfigManager { sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, ""); sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ""); sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); + sDefaults.putBoolean(KEY_SHOW_5G_SLICE_ICON_BOOL, true); sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); sDefaults.putInt(KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 0); sDefaults.putBoolean(KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, false); + sDefaults.putBoolean(KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL, true); sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA}); sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true); @@ -9111,6 +10124,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false); sDefaults.putBoolean(KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL, false); sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, + // Boundaries: [-140 dBm, -44 dBm] new int[] { -128, /* SIGNAL_STRENGTH_POOR */ -118, /* SIGNAL_STRENGTH_MODERATE */ @@ -9118,6 +10132,7 @@ public class CarrierConfigManager { -98, /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + // Boundaries: [-34 dB, 3 dB] new int[] { -20, /* SIGNAL_STRENGTH_POOR */ -17, /* SIGNAL_STRENGTH_MODERATE */ @@ -9125,6 +10140,7 @@ public class CarrierConfigManager { -11 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY, + // Boundaries: [-20 dBm, 30 dBm] new int[] { -3, /* SIGNAL_STRENGTH_POOR */ 1, /* SIGNAL_STRENGTH_MODERATE */ @@ -9132,18 +10148,29 @@ public class CarrierConfigManager { 13 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY, + // Boundaries: [-120 dBm, -25 dBm] new int[] { - -115, /* SIGNAL_STRENGTH_POOR */ + -115, /* SIGNAL_STRENGTH_POOR */ -105, /* SIGNAL_STRENGTH_MODERATE */ - -95, /* SIGNAL_STRENGTH_GOOD */ - -85 /* SIGNAL_STRENGTH_GREAT */ + -95, /* SIGNAL_STRENGTH_GOOD */ + -85 /* SIGNAL_STRENGTH_GREAT */ + }); + // TODO(b/249896055): On enabling ECNO measurement part for Signal Bar level indication + // system functionality, below values to be rechecked. + sDefaults.putIntArray(KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY, + // Boundaries: [-24 dBm, 1 dBm] + new int[] { + -24, /* SIGNAL_STRENGTH_POOR */ + -14, /* SIGNAL_STRENGTH_MODERATE */ + -6, /* SIGNAL_STRENGTH_GOOD */ + 1 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY, // Boundaries: [-140 dB, -44 dB] new int[] { -110, /* SIGNAL_STRENGTH_POOR */ - -90, /* SIGNAL_STRENGTH_MODERATE */ - -80, /* SIGNAL_STRENGTH_GOOD */ + -90, /* SIGNAL_STRENGTH_MODERATE */ + -80, /* SIGNAL_STRENGTH_GOOD */ -65, /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY, @@ -9151,17 +10178,26 @@ public class CarrierConfigManager { new int[] { -31, /* SIGNAL_STRENGTH_POOR */ -19, /* SIGNAL_STRENGTH_MODERATE */ - -7, /* SIGNAL_STRENGTH_GOOD */ - 6 /* SIGNAL_STRENGTH_GREAT */ + -7, /* SIGNAL_STRENGTH_GOOD */ + 6 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY, // Boundaries: [-23 dB, 40 dB] new int[] { -5, /* SIGNAL_STRENGTH_POOR */ - 5, /* SIGNAL_STRENGTH_MODERATE */ + 5, /* SIGNAL_STRENGTH_MODERATE */ 15, /* SIGNAL_STRENGTH_GOOD */ 30 /* SIGNAL_STRENGTH_GREAT */ }); + sDefaults.putInt(KEY_GERAN_RSSI_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_UTRAN_RSCP_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_EUTRAN_RSRQ_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_EUTRAN_RSSNR_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_NGRAN_SSRSRQ_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_NGRAN_SSSINR_HYSTERESIS_DB_INT, 2); + sDefaults.putInt(KEY_UTRAN_ECNO_HYSTERESIS_DB_INT, 2); sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, CellSignalStrengthNr.USE_SSRSRP); sDefaults.putBoolean(KEY_SIGNAL_STRENGTH_NR_NSA_USE_LTE_AS_PRIMARY_BOOL, true); @@ -9236,8 +10272,7 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000); sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true); sDefaults.putLong(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000L); - sDefaults.putLong( - KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG, + sDefaults.putLong(KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG, 120000L); sDefaults.putAll(ImsServiceEntitlement.getDefaults()); sDefaults.putAll(Gps.getDefaults()); @@ -9259,7 +10294,7 @@ public class CarrierConfigManager { new int[] { -107, /* SIGNAL_STRENGTH_POOR */ -103, /* SIGNAL_STRENGTH_MODERATE */ - -97, /* SIGNAL_STRENGTH_GOOD */ + -97, /* SIGNAL_STRENGTH_GOOD */ -89, /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true); @@ -9352,6 +10387,20 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, true); sDefaults.putBoolean(KEY_VONR_ENABLED_BOOL, false); sDefaults.putBoolean(KEY_VONR_ON_BY_DEFAULT_BOOL, true); + sDefaults.putIntArray(KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY, new int[0]); + sDefaults.putLong(KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG, + TimeUnit.MINUTES.toMillis(30)); + sDefaults.putLong(KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG, + TimeUnit.MINUTES.toMillis(30)); + sDefaults.putInt(KEY_PREMIUM_CAPABILITY_MAXIMUM_DAILY_NOTIFICATION_COUNT_INT, 2); + sDefaults.putInt(KEY_PREMIUM_CAPABILITY_MAXIMUM_MONTHLY_NOTIFICATION_COUNT_INT, 10); + sDefaults.putLong( + KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG, + TimeUnit.MINUTES.toMillis(30)); + sDefaults.putLong(KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG, + TimeUnit.MINUTES.toMillis(5)); + sDefaults.putString(KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING, null); + sDefaults.putBoolean(KEY_PREMIUM_CAPABILITY_SUPPORTED_ON_LTE_BOOL, false); sDefaults.putStringArray(KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, new String[]{ "source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, " + "target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"}); @@ -9409,7 +10458,6 @@ public class CarrierConfigManager { public static final String KEY_AVOID_5GHZ_WIFI_DIRECT_FOR_LAA_BOOL = KEY_PREFIX + "avoid_5ghz_wifi_direct_for_laa_bool"; - private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putInt(KEY_HOTSPOT_MAX_CLIENT_COUNT, 0); @@ -9456,8 +10504,7 @@ public class CarrierConfigManager { return loader.getConfigForSubIdWithFeature(subId, mContext.getOpPackageName(), mContext.getAttributionTag()); } catch (RemoteException ex) { - Rlog.e(TAG, "Error getting config for subId " + subId + ": " - + ex.toString()); + Rlog.e(TAG, "Error getting config for subId " + subId + ": " + ex); } return null; } @@ -9483,7 +10530,7 @@ public class CarrierConfigManager { * {@link TelephonyManager#hasCarrierPrivileges()}). * * @param subId The subscription ID on which the carrier config should be retrieved. - * @param keys The carrier config keys to retrieve values. + * @param keys The carrier config keys to retrieve values. * @return A {@link PersistableBundle} with key/value mapping for the specified configuration * on success, or an empty (but never null) bundle on failure (for example, when the calling app * has no permission). @@ -9574,8 +10621,7 @@ public class CarrierConfigManager { } loader.overrideConfig(subscriptionId, overrideValues, persistent); } catch (RemoteException ex) { - Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": " - + ex.toString()); + Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": " + ex); } } @@ -9688,7 +10734,7 @@ public class CarrierConfigManager { } loader.notifyConfigChangedForSubId(subId); } catch (RemoteException ex) { - Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex.toString()); + Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex); } } @@ -9712,7 +10758,7 @@ public class CarrierConfigManager { } loader.updateConfigForPhoneId(phoneId, simState); } catch (RemoteException ex) { - Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex.toString()); + Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex); } } @@ -9734,8 +10780,7 @@ public class CarrierConfigManager { } return loader.getDefaultCarrierServicePackageName(); } catch (RemoteException ex) { - Rlog.e(TAG, "getDefaultCarrierServicePackageName ICarrierConfigLoader is null" - + ex.toString()); + Rlog.e(TAG, "getDefaultCarrierServicePackageName ICarrierConfigLoader is null" + ex); ex.rethrowAsRuntimeException(); } return ""; diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java index c13801887572..eac4d1682aa9 100644 --- a/telephony/java/android/telephony/CarrierRestrictionRules.java +++ b/telephony/java/android/telephony/CarrierRestrictionRules.java @@ -27,6 +27,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Objects; /** @@ -103,12 +104,15 @@ public final class CarrierRestrictionRules implements Parcelable { private int mCarrierRestrictionDefault; @MultiSimPolicy private int mMultiSimPolicy; + @TelephonyManager.CarrierRestrictionStatus + private int mCarrierRestrictionStatus; private CarrierRestrictionRules() { mAllowedCarriers = new ArrayList<CarrierIdentifier>(); mExcludedCarriers = new ArrayList<CarrierIdentifier>(); mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED; mMultiSimPolicy = MULTISIM_POLICY_NONE; + mCarrierRestrictionStatus = TelephonyManager.CARRIER_RESTRICTION_STATUS_UNKNOWN; } private CarrierRestrictionRules(Parcel in) { @@ -119,6 +123,7 @@ public final class CarrierRestrictionRules implements Parcelable { in.readTypedList(mExcludedCarriers, CarrierIdentifier.CREATOR); mCarrierRestrictionDefault = in.readInt(); mMultiSimPolicy = in.readInt(); + mCarrierRestrictionStatus = in.readInt(); } /** @@ -276,8 +281,8 @@ public final class CarrierRestrictionRules implements Parcelable { if (str.length() != pattern.length()) { return false; } - String lowerCaseStr = str.toLowerCase(); - String lowerCasePattern = pattern.toLowerCase(); + String lowerCaseStr = str.toLowerCase(Locale.ROOT); + String lowerCasePattern = pattern.toLowerCase(Locale.ROOT); for (int i = 0; i < lowerCasePattern.length(); i++) { if (lowerCasePattern.charAt(i) != lowerCaseStr.charAt(i) @@ -288,6 +293,11 @@ public final class CarrierRestrictionRules implements Parcelable { return true; } + /** @hide */ + public int getCarrierRestrictionStatus() { + return mCarrierRestrictionStatus; + } + /** * {@link Parcelable#writeToParcel} */ @@ -297,6 +307,7 @@ public final class CarrierRestrictionRules implements Parcelable { out.writeTypedList(mExcludedCarriers); out.writeInt(mCarrierRestrictionDefault); out.writeInt(mMultiSimPolicy); + out.writeInt(mCarrierRestrictionStatus); } /** @@ -398,5 +409,17 @@ public final class CarrierRestrictionRules implements Parcelable { mRules.mMultiSimPolicy = multiSimPolicy; return this; } + + /** + * Set the device's carrier restriction status + * + * @param carrierRestrictionStatus device restriction status + * @hide + */ + public @NonNull + Builder setCarrierRestrictionStatus(int carrierRestrictionStatus) { + mRules.mCarrierRestrictionStatus = carrierRestrictionStatus; + return this; + } } } diff --git a/telephony/java/android/telephony/CellBroadcastIdRange.aidl b/telephony/java/android/telephony/CellBroadcastIdRange.aidl new file mode 100644 index 000000000000..ddaceffc19cb --- /dev/null +++ b/telephony/java/android/telephony/CellBroadcastIdRange.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022, 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 android.telephony; + +parcelable CellBroadcastIdRange; diff --git a/telephony/java/android/telephony/CellBroadcastIdRange.java b/telephony/java/android/telephony/CellBroadcastIdRange.java new file mode 100644 index 000000000000..abee80f76f83 --- /dev/null +++ b/telephony/java/android/telephony/CellBroadcastIdRange.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Describes a particular cell broadcast message identifier range. + * @hide + */ +@SystemApi +public final class CellBroadcastIdRange implements Parcelable { + + @IntRange(from = 0, to = 0xFFFF) + private int mStartId; + @IntRange(from = 0, to = 0xFFFF) + private int mEndId; + private int mType; + private boolean mIsEnabled; + + /** + * Create a new CellBroacastRange + * + * @param startId first message identifier as specified in TS 23.041 (3GPP) + * or C.R1001-G (3GPP2). The value must be between 0 and 0xFFFF. + * @param endId last message identifier as specified in TS 23.041 (3GPP) + * or C.R1001-G (3GPP2). The value must be between 0 and 0xFFFF. + * @param type the message format as defined in {@link SmsCbMessage} + * @param isEnabled whether the range is enabled + * + * @throws IllegalArgumentException if endId < startId or invalid value + */ + public CellBroadcastIdRange(@IntRange(from = 0, to = 0xFFFF) int startId, + @IntRange(from = 0, to = 0xFFFF) int endId, + @android.telephony.SmsCbMessage.MessageFormat int type, boolean isEnabled) + throws IllegalArgumentException { + if (startId < 0 || endId < 0 || startId > 0xFFFF || endId > 0xFFFF) { + throw new IllegalArgumentException("invalid id"); + } + if (endId < startId) { + throw new IllegalArgumentException("endId must be greater than or equal to startId"); + } + mStartId = startId; + mEndId = endId; + mType = type; + mIsEnabled = isEnabled; + } + + /** + * Return the first message identifier of this range as specified in TS 23.041 (3GPP) + * or C.R1001-G (3GPP2) + */ + @IntRange(from = 0, to = 0xFFFF) + public int getStartId() { + return mStartId; + } + + /** + * Return the last message identifier of this range as specified in TS 23.041 (3GPP) + * or C.R1001-G (3GPP2) + */ + @IntRange(from = 0, to = 0xFFFF) + public int getEndId() { + return mEndId; + } + + /** + * Return the message format of this range as defined in {@link SmsCbMessage} + */ + public @android.telephony.SmsCbMessage.MessageFormat int getType() { + return mType; + } + + /** + * Return whether the range is enabled + */ + public boolean isEnabled() { + return mIsEnabled; + } + + /** + * {@link Parcelable#writeToParcel} + */ + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mStartId); + out.writeInt(mEndId); + out.writeInt(mType); + out.writeBoolean(mIsEnabled); + } + + /** + * {@link Parcelable.Creator} + * + */ + public static final @NonNull Parcelable.Creator<CellBroadcastIdRange> CREATOR = + new Creator<CellBroadcastIdRange>() { + @NonNull + @Override + public CellBroadcastIdRange createFromParcel(Parcel in) { + int startId = in.readInt(); + int endId = in.readInt(); + int type = in.readInt(); + boolean isEnabled = in.readBoolean(); + + return new CellBroadcastIdRange(startId, endId, type, isEnabled); + } + + @NonNull + @Override + public CellBroadcastIdRange[] newArray(int size) { + return new CellBroadcastIdRange[size]; + } + }; + + /** + * {@link Parcelable#describeContents} + */ + @Override + public int describeContents() { + return 0; + } + + @Override + public int hashCode() { + return Objects.hash(mStartId, mEndId, mType, mIsEnabled); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CellBroadcastIdRange)) { + return false; + } + + CellBroadcastIdRange other = (CellBroadcastIdRange) obj; + + return mStartId == other.mStartId && mEndId == other.mEndId && mType == other.mType + && mIsEnabled == other.mIsEnabled; + } + + @Override + public String toString() { + return "CellBroadcastIdRange[" + mStartId + ", " + mEndId + ", " + mType + ", " + + mIsEnabled + "]"; + } +} diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index ba3a192074bc..5eace5433128 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -23,6 +23,9 @@ import android.annotation.Nullable; import android.os.Parcel; import android.telephony.cdma.CdmaCellLocation; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + import java.util.Objects; /** @@ -242,8 +245,8 @@ public final class CellIdentityCdma extends CellIdentity { .append(":{ mNetworkId=").append(mNetworkId) .append(" mSystemId=").append(mSystemId) .append(" mBasestationId=").append(mBasestationId) - .append(" mLongitude=").append(mLongitude) - .append(" mLatitude=").append(mLatitude) + .append(" mLongitude=").append(Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mLongitude)) + .append(" mLatitude=").append(Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mLatitude)) .append(" mAlphaLong=").append(mAlphaLong) .append(" mAlphaShort=").append(mAlphaShort) .append("}").toString(); diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index 297940e9c8c6..03519a364a36 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -155,6 +155,16 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa */ private int mParametersUseForLevel; + /** + * Timing advance value for a one way trip from cell to device in microseconds. + * Approximate distance is calculated using 300m/us * timingAdvance. + * + * Reference: 3GPP TS 36.213 section 4.2.3. + * + * Range: [0, 1282] + */ + private int mTimingAdvance; + /** @hide */ public CellSignalStrengthNr() { setDefaultValues(); @@ -169,10 +179,11 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa * @param ssRsrp SS reference signal received power. * @param ssRsrq SS reference signal received quality. * @param ssSinr SS signal-to-noise and interference ratio. + * @param timingAdvance Timing advance. * @hide */ public CellSignalStrengthNr(int csiRsrp, int csiRsrq, int csiSinr, int csiCqiTableIndex, - List<Byte> csiCqiReport, int ssRsrp, int ssRsrq, int ssSinr) { + List<Byte> csiCqiReport, int ssRsrp, int ssRsrq, int ssSinr, int timingAdvance) { mCsiRsrp = inRangeOrUnavailable(csiRsrp, -156, -31); mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3); mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23); @@ -183,6 +194,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa mSsRsrp = inRangeOrUnavailable(ssRsrp, -156, -31); mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20); mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40); + mTimingAdvance = inRangeOrUnavailable(timingAdvance, 0, 1282); updateLevel(null, null); } @@ -198,7 +210,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa public CellSignalStrengthNr( int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) { this(csiRsrp, csiRsrq, csiSinr, CellInfo.UNAVAILABLE, Collections.emptyList(), - ssRsrp, ssRsrq, ssSinr); + ssRsrp, ssRsrq, ssSinr, CellInfo.UNAVAILABLE); } /** @@ -302,6 +314,22 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa return mCsiCqiReport; } + /** + * Get the timing advance value for a one way trip from cell to device for NR in microseconds. + * {@link android.telephony.CellInfo#UNAVAILABLE} is reported when there is no + * active RRC connection. + * + * Reference: 3GPP TS 36.213 section 4.2.3. + * Range: 0 us to 1282 us. + * + * @return the NR timing advance if available or + * {@link android.telephony.CellInfo#UNAVAILABLE} if unavailable. + */ + @IntRange(from = 0, to = 1282) + public int getTimingAdvanceMicros() { + return mTimingAdvance; + } + @Override public int describeContents() { return 0; @@ -319,6 +347,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa dest.writeInt(mSsRsrq); dest.writeInt(mSsSinr); dest.writeInt(mLevel); + dest.writeInt(mTimingAdvance); } private CellSignalStrengthNr(Parcel in) { @@ -331,6 +360,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa mSsRsrq = in.readInt(); mSsSinr = in.readInt(); mLevel = in.readInt(); + mTimingAdvance = in.readInt(); } /** @hide */ @@ -346,6 +376,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa mSsSinr = CellInfo.UNAVAILABLE; mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; mParametersUseForLevel = USE_SSRSRP; + mTimingAdvance = CellInfo.UNAVAILABLE; } /** {@inheritDoc} */ @@ -495,6 +526,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa mSsSinr = s.mSsSinr; mLevel = s.mLevel; mParametersUseForLevel = s.mParametersUseForLevel; + mTimingAdvance = s.mTimingAdvance; } /** @hide */ @@ -506,7 +538,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa @Override public int hashCode() { return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mCsiCqiTableIndex, - mCsiCqiReport, mSsRsrp, mSsRsrq, mSsSinr, mLevel); + mCsiCqiReport, mSsRsrp, mSsRsrq, mSsSinr, mLevel, mTimingAdvance); } private static final CellSignalStrengthNr sInvalid = new CellSignalStrengthNr(); @@ -525,7 +557,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa && mCsiCqiTableIndex == o.mCsiCqiTableIndex && mCsiCqiReport.equals(o.mCsiCqiReport) && mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr - && mLevel == o.mLevel; + && mLevel == o.mLevel && mTimingAdvance == o.mTimingAdvance; } return false; } @@ -543,6 +575,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa .append(" ssSinr = " + mSsSinr) .append(" level = " + mLevel) .append(" parametersUseForLevel = " + mParametersUseForLevel) + .append(" timingAdvance = " + mTimingAdvance) .append(" }") .toString(); } diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java index ca6dc2d55da3..5e5e028625b6 100644 --- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java +++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -24,6 +25,8 @@ import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -33,6 +36,69 @@ import java.util.Objects; */ @SystemApi public final class DataSpecificRegistrationInfo implements Parcelable { + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = "LTE_ATTACH_TYPE_", + value = { + LTE_ATTACH_TYPE_UNKNOWN, + LTE_ATTACH_TYPE_EPS_ONLY, + LTE_ATTACH_TYPE_COMBINED, + }) + public @interface LteAttachResultType {} + + /** + * Default value. + * Attach type is unknown. + */ + public static final int LTE_ATTACH_TYPE_UNKNOWN = 0; + + /** + * LTE is attached with EPS only. + * + * Reference: 3GPP TS 24.301 9.9.3 EMM information elements. + */ + public static final int LTE_ATTACH_TYPE_EPS_ONLY = 1; + + /** + * LTE combined EPS and IMSI attach. + * + * Reference: 3GPP TS 24.301 9.9.3 EMM information elements. + */ + public static final int LTE_ATTACH_TYPE_COMBINED = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = {"LTE_ATTACH_EXTRA_INFO_"}, + value = { + LTE_ATTACH_EXTRA_INFO_NONE, + LTE_ATTACH_EXTRA_INFO_CSFB_NOT_PREFERRED, + LTE_ATTACH_EXTRA_INFO_SMS_ONLY + }) + public @interface LteAttachExtraInfo {} + + /** + * Default value. + */ + public static final int LTE_ATTACH_EXTRA_INFO_NONE = 0; + + /** + * CSFB is not preferred. + * Applicable for LTE only. + * + * Reference: 3GPP TS 24.301 9.9.3 EMM information elements. + */ + public static final int LTE_ATTACH_EXTRA_INFO_CSFB_NOT_PREFERRED = 1 << 0; + + /** + * Attached for SMS only. + * Applicable for LTE only. + * + * Reference: 3GPP TS 24.301 9.9.3 EMM information elements. + */ + public static final int LTE_ATTACH_EXTRA_INFO_SMS_ONLY = 1 << 1; + /** * @hide * The maximum number of simultaneous Data Calls that @@ -75,6 +141,22 @@ public final class DataSpecificRegistrationInfo implements Parcelable { @Nullable private final VopsSupportInfo mVopsSupportInfo; + /** The type of network attachment */ + private final @LteAttachResultType int mLteAttachResultType; + + /** LTE attach extra info */ + private final @LteAttachExtraInfo int mLteAttachExtraInfo; + + private DataSpecificRegistrationInfo(Builder builder) { + this.maxDataCalls = builder.mMaxDataCalls; + this.isDcNrRestricted = builder.mIsDcNrRestricted; + this.isNrAvailable = builder.mIsNrAvailable; + this.isEnDcAvailable = builder.mIsEnDcAvailable; + this.mVopsSupportInfo = builder.mVopsSupportInfo; + this.mLteAttachResultType = builder.mLteAttachResultType; + this.mLteAttachExtraInfo = builder.mLteAttachExtraInfo; + } + /** * @hide */ @@ -87,6 +169,8 @@ public final class DataSpecificRegistrationInfo implements Parcelable { this.isNrAvailable = isNrAvailable; this.isEnDcAvailable = isEnDcAvailable; this.mVopsSupportInfo = vops; + this.mLteAttachResultType = LTE_ATTACH_TYPE_UNKNOWN; + this.mLteAttachExtraInfo = LTE_ATTACH_EXTRA_INFO_NONE; } /** @@ -101,6 +185,8 @@ public final class DataSpecificRegistrationInfo implements Parcelable { isNrAvailable = dsri.isNrAvailable; isEnDcAvailable = dsri.isEnDcAvailable; mVopsSupportInfo = dsri.mVopsSupportInfo; + mLteAttachResultType = dsri.mLteAttachResultType; + mLteAttachExtraInfo = dsri.mLteAttachExtraInfo; } private DataSpecificRegistrationInfo(/* @NonNull */ Parcel source) { @@ -109,6 +195,8 @@ public final class DataSpecificRegistrationInfo implements Parcelable { isNrAvailable = source.readBoolean(); isEnDcAvailable = source.readBoolean(); mVopsSupportInfo = source.readParcelable(VopsSupportInfo.class.getClassLoader(), android.telephony.VopsSupportInfo.class); + mLteAttachResultType = source.readInt(); + mLteAttachExtraInfo = source.readInt(); } @Override @@ -118,6 +206,8 @@ public final class DataSpecificRegistrationInfo implements Parcelable { dest.writeBoolean(isNrAvailable); dest.writeBoolean(isEnDcAvailable); dest.writeParcelable(mVopsSupportInfo, flags); + dest.writeInt(mLteAttachResultType); + dest.writeInt(mLteAttachExtraInfo); } @Override @@ -134,6 +224,8 @@ public final class DataSpecificRegistrationInfo implements Parcelable { .append(" isDcNrRestricted = " + isDcNrRestricted) .append(" isNrAvailable = " + isNrAvailable) .append(" isEnDcAvailable = " + isEnDcAvailable) + .append(" mLteAttachResultType = " + mLteAttachResultType) + .append(" mLteAttachExtraInfo = " + mLteAttachExtraInfo) .append(" " + mVopsSupportInfo) .append(" }") .toString(); @@ -142,7 +234,8 @@ public final class DataSpecificRegistrationInfo implements Parcelable { @Override public int hashCode() { return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, - isEnDcAvailable, mVopsSupportInfo); + isEnDcAvailable, mVopsSupportInfo, + mLteAttachResultType, mLteAttachExtraInfo); } @Override @@ -156,7 +249,9 @@ public final class DataSpecificRegistrationInfo implements Parcelable { && this.isDcNrRestricted == other.isDcNrRestricted && this.isNrAvailable == other.isNrAvailable && this.isEnDcAvailable == other.isEnDcAvailable - && Objects.equals(mVopsSupportInfo, other.mVopsSupportInfo); + && Objects.equals(mVopsSupportInfo, other.mVopsSupportInfo) + && this.mLteAttachResultType == other.mLteAttachResultType + && this.mLteAttachExtraInfo == other.mLteAttachExtraInfo; } public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR = @@ -196,4 +291,105 @@ public final class DataSpecificRegistrationInfo implements Parcelable { public VopsSupportInfo getVopsSupportInfo() { return mVopsSupportInfo; } + + /** + * Provides the LTE attach type. + */ + public @LteAttachResultType int getLteAttachResultType() { + return mLteAttachResultType; + } + + /** + * Provides the extra information of LTE attachment. + * + * @return the bitwise OR of {@link LteAttachExtraInfo}. + */ + public @LteAttachExtraInfo int getLteAttachExtraInfo() { + return mLteAttachExtraInfo; + } + + /** + * Builds {@link DataSpecificRegistrationInfo} instances, which may include optional parameters. + * @hide + */ + public static final class Builder { + private final int mMaxDataCalls; + + private boolean mIsDcNrRestricted; + private boolean mIsNrAvailable; + private boolean mIsEnDcAvailable; + private @Nullable VopsSupportInfo mVopsSupportInfo; + private @LteAttachResultType int mLteAttachResultType = LTE_ATTACH_TYPE_UNKNOWN; + private @LteAttachExtraInfo int mLteAttachExtraInfo = LTE_ATTACH_EXTRA_INFO_NONE; + + public Builder(int maxDataCalls) { + mMaxDataCalls = maxDataCalls; + } + + /** + * Ses whether the use of dual connectivity with NR is restricted. + * @param isDcNrRestricted {@code true} if the use of dual connectivity with NR is + * restricted. + */ + public @NonNull Builder setDcNrRestricted(boolean isDcNrRestricted) { + mIsDcNrRestricted = isDcNrRestricted; + return this; + } + + /** + * Sets whether NR is supported by the selected PLMN. + * @param isNrAvailable {@code true} if NR is supported. + */ + public @NonNull Builder setNrAvailable(boolean isNrAvailable) { + mIsNrAvailable = isNrAvailable; + return this; + } + + /** + * Sets whether E-UTRA-NR Dual Connectivity (EN-DC) is supported by the primary serving + * cell. + * @param isEnDcAvailable {@code true} if EN_DC is supported. + */ + public @NonNull Builder setEnDcAvailable(boolean isEnDcAvailable) { + mIsEnDcAvailable = isEnDcAvailable; + return this; + } + + /** + * Sets the network support info for VoPS and Emergency bearer support. + * @param vops The network support info for VoPS and Emergency bearer support. + */ + @Nullable + public @NonNull Builder setVopsSupportInfo(VopsSupportInfo vops) { + mVopsSupportInfo = vops; + return this; + } + + /** + * Sets the LTE attach type. + * @param lteAttachResultType the Lte attach type + */ + public @NonNull Builder setLteAttachResultType( + @LteAttachResultType int lteAttachResultType) { + mLteAttachResultType = lteAttachResultType; + return this; + } + + /** + * Sets the extra information of LTE attachment. + * @param lteAttachExtraInfo the extra information of LTE attachment. + */ + public @NonNull Builder setLteAttachExtraInfo( + @LteAttachExtraInfo int lteAttachExtraInfo) { + mLteAttachExtraInfo = lteAttachExtraInfo; + return this; + } + + /** + * @return a built {@link DataSpecificRegistrationInfo} instance. + */ + public @NonNull DataSpecificRegistrationInfo build() { + return new DataSpecificRegistrationInfo(this); + } + } } diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index 2704418935d9..6997f3c79bc3 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -360,6 +360,11 @@ public final class DisconnectCause { */ public static final int INCOMING_AUTO_REJECTED = 81; + /** + * Indicates that the call was unable to be made because the satellite modem is enabled. + * @hide + */ + public static final int SATELLITE_ENABLED = 82; //********************************************************************************************* // When adding a disconnect type: @@ -379,168 +384,170 @@ public final class DisconnectCause { @UnsupportedAppUsage public static @NonNull String toString(int cause) { switch (cause) { - case NOT_DISCONNECTED: - return "NOT_DISCONNECTED"; - case INCOMING_MISSED: - return "INCOMING_MISSED"; - case NORMAL: - return "NORMAL"; - case LOCAL: - return "LOCAL"; - case BUSY: - return "BUSY"; - case CONGESTION: - return "CONGESTION"; - case INVALID_NUMBER: - return "INVALID_NUMBER"; - case NUMBER_UNREACHABLE: - return "NUMBER_UNREACHABLE"; - case SERVER_UNREACHABLE: - return "SERVER_UNREACHABLE"; - case INVALID_CREDENTIALS: - return "INVALID_CREDENTIALS"; - case OUT_OF_NETWORK: - return "OUT_OF_NETWORK"; - case SERVER_ERROR: - return "SERVER_ERROR"; - case TIMED_OUT: - return "TIMED_OUT"; - case LOST_SIGNAL: - return "LOST_SIGNAL"; - case LIMIT_EXCEEDED: - return "LIMIT_EXCEEDED"; - case INCOMING_REJECTED: - return "INCOMING_REJECTED"; - case POWER_OFF: - return "POWER_OFF"; - case OUT_OF_SERVICE: - return "OUT_OF_SERVICE"; - case ICC_ERROR: - return "ICC_ERROR"; - case CALL_BARRED: - return "CALL_BARRED"; - case FDN_BLOCKED: - return "FDN_BLOCKED"; - case CS_RESTRICTED: - return "CS_RESTRICTED"; - case CS_RESTRICTED_NORMAL: - return "CS_RESTRICTED_NORMAL"; - case CS_RESTRICTED_EMERGENCY: - return "CS_RESTRICTED_EMERGENCY"; - case UNOBTAINABLE_NUMBER: - return "UNOBTAINABLE_NUMBER"; - case CDMA_LOCKED_UNTIL_POWER_CYCLE: - return "CDMA_LOCKED_UNTIL_POWER_CYCLE"; - case CDMA_DROP: - return "CDMA_DROP"; - case CDMA_INTERCEPT: - return "CDMA_INTERCEPT"; - case CDMA_REORDER: - return "CDMA_REORDER"; - case CDMA_SO_REJECT: - return "CDMA_SO_REJECT"; - case CDMA_RETRY_ORDER: - return "CDMA_RETRY_ORDER"; - case CDMA_ACCESS_FAILURE: - return "CDMA_ACCESS_FAILURE"; - case CDMA_PREEMPTED: - return "CDMA_PREEMPTED"; - case CDMA_NOT_EMERGENCY: - return "CDMA_NOT_EMERGENCY"; - case CDMA_ACCESS_BLOCKED: - return "CDMA_ACCESS_BLOCKED"; - case EMERGENCY_ONLY: - return "EMERGENCY_ONLY"; - case NO_PHONE_NUMBER_SUPPLIED: - return "NO_PHONE_NUMBER_SUPPLIED"; - case DIALED_MMI: - return "DIALED_MMI"; - case VOICEMAIL_NUMBER_MISSING: - return "VOICEMAIL_NUMBER_MISSING"; - case CDMA_CALL_LOST: - return "CDMA_CALL_LOST"; - case EXITED_ECM: - return "EXITED_ECM"; - case DIAL_MODIFIED_TO_USSD: - return "DIAL_MODIFIED_TO_USSD"; - case DIAL_MODIFIED_TO_SS: - return "DIAL_MODIFIED_TO_SS"; - case DIAL_MODIFIED_TO_DIAL: - return "DIAL_MODIFIED_TO_DIAL"; - case DIAL_MODIFIED_TO_DIAL_VIDEO: - return "DIAL_MODIFIED_TO_DIAL_VIDEO"; - case DIAL_VIDEO_MODIFIED_TO_SS: - return "DIAL_VIDEO_MODIFIED_TO_SS"; - case DIAL_VIDEO_MODIFIED_TO_USSD: - return "DIAL_VIDEO_MODIFIED_TO_USSD"; - case DIAL_VIDEO_MODIFIED_TO_DIAL: - return "DIAL_VIDEO_MODIFIED_TO_DIAL"; - case DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO: - return "DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO"; - case ERROR_UNSPECIFIED: - return "ERROR_UNSPECIFIED"; - case OUTGOING_FAILURE: - return "OUTGOING_FAILURE"; - case OUTGOING_CANCELED: - return "OUTGOING_CANCELED"; - case IMS_MERGED_SUCCESSFULLY: - return "IMS_MERGED_SUCCESSFULLY"; - case CDMA_ALREADY_ACTIVATED: - return "CDMA_ALREADY_ACTIVATED"; - case VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: - return "VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED"; - case CALL_PULLED: - return "CALL_PULLED"; - case ANSWERED_ELSEWHERE: - return "ANSWERED_ELSEWHERE"; - case MAXIMUM_NUMBER_OF_CALLS_REACHED: - return "MAXIMUM_NUMER_OF_CALLS_REACHED"; - case DATA_DISABLED: - return "DATA_DISABLED"; - case DATA_LIMIT_REACHED: - return "DATA_LIMIT_REACHED"; - case DIALED_CALL_FORWARDING_WHILE_ROAMING: - return "DIALED_CALL_FORWARDING_WHILE_ROAMING"; - case IMEI_NOT_ACCEPTED: - return "IMEI_NOT_ACCEPTED"; - case WIFI_LOST: - return "WIFI_LOST"; - case IMS_ACCESS_BLOCKED: - return "IMS_ACCESS_BLOCKED"; - case LOW_BATTERY: - return "LOW_BATTERY"; - case DIAL_LOW_BATTERY: - return "DIAL_LOW_BATTERY"; - case EMERGENCY_TEMP_FAILURE: - return "EMERGENCY_TEMP_FAILURE"; - case EMERGENCY_PERM_FAILURE: - return "EMERGENCY_PERM_FAILURE"; - case NORMAL_UNSPECIFIED: - return "NORMAL_UNSPECIFIED"; - case IMS_SIP_ALTERNATE_EMERGENCY_CALL: - return "IMS_SIP_ALTERNATE_EMERGENCY_CALL"; - case ALREADY_DIALING: - return "ALREADY_DIALING"; - case CANT_CALL_WHILE_RINGING: - return "CANT_CALL_WHILE_RINGING"; - case CALLING_DISABLED: - return "CALLING_DISABLED"; - case TOO_MANY_ONGOING_CALLS: - return "TOO_MANY_ONGOING_CALLS"; - case OTASP_PROVISIONING_IN_PROCESS: - return "OTASP_PROVISIONING_IN_PROCESS"; - case MEDIA_TIMEOUT: - return "MEDIA_TIMEOUT"; - case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE: - return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE"; - case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: - return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION"; - case OUTGOING_EMERGENCY_CALL_PLACED: - return "OUTGOING_EMERGENCY_CALL_PLACED"; + case NOT_DISCONNECTED: + return "NOT_DISCONNECTED"; + case INCOMING_MISSED: + return "INCOMING_MISSED"; + case NORMAL: + return "NORMAL"; + case LOCAL: + return "LOCAL"; + case BUSY: + return "BUSY"; + case CONGESTION: + return "CONGESTION"; + case INVALID_NUMBER: + return "INVALID_NUMBER"; + case NUMBER_UNREACHABLE: + return "NUMBER_UNREACHABLE"; + case SERVER_UNREACHABLE: + return "SERVER_UNREACHABLE"; + case INVALID_CREDENTIALS: + return "INVALID_CREDENTIALS"; + case OUT_OF_NETWORK: + return "OUT_OF_NETWORK"; + case SERVER_ERROR: + return "SERVER_ERROR"; + case TIMED_OUT: + return "TIMED_OUT"; + case LOST_SIGNAL: + return "LOST_SIGNAL"; + case LIMIT_EXCEEDED: + return "LIMIT_EXCEEDED"; + case INCOMING_REJECTED: + return "INCOMING_REJECTED"; + case POWER_OFF: + return "POWER_OFF"; + case OUT_OF_SERVICE: + return "OUT_OF_SERVICE"; + case ICC_ERROR: + return "ICC_ERROR"; + case CALL_BARRED: + return "CALL_BARRED"; + case FDN_BLOCKED: + return "FDN_BLOCKED"; + case CS_RESTRICTED: + return "CS_RESTRICTED"; + case CS_RESTRICTED_NORMAL: + return "CS_RESTRICTED_NORMAL"; + case CS_RESTRICTED_EMERGENCY: + return "CS_RESTRICTED_EMERGENCY"; + case UNOBTAINABLE_NUMBER: + return "UNOBTAINABLE_NUMBER"; + case CDMA_LOCKED_UNTIL_POWER_CYCLE: + return "CDMA_LOCKED_UNTIL_POWER_CYCLE"; + case CDMA_DROP: + return "CDMA_DROP"; + case CDMA_INTERCEPT: + return "CDMA_INTERCEPT"; + case CDMA_REORDER: + return "CDMA_REORDER"; + case CDMA_SO_REJECT: + return "CDMA_SO_REJECT"; + case CDMA_RETRY_ORDER: + return "CDMA_RETRY_ORDER"; + case CDMA_ACCESS_FAILURE: + return "CDMA_ACCESS_FAILURE"; + case CDMA_PREEMPTED: + return "CDMA_PREEMPTED"; + case CDMA_NOT_EMERGENCY: + return "CDMA_NOT_EMERGENCY"; + case CDMA_ACCESS_BLOCKED: + return "CDMA_ACCESS_BLOCKED"; + case EMERGENCY_ONLY: + return "EMERGENCY_ONLY"; + case NO_PHONE_NUMBER_SUPPLIED: + return "NO_PHONE_NUMBER_SUPPLIED"; + case DIALED_MMI: + return "DIALED_MMI"; + case VOICEMAIL_NUMBER_MISSING: + return "VOICEMAIL_NUMBER_MISSING"; + case CDMA_CALL_LOST: + return "CDMA_CALL_LOST"; + case EXITED_ECM: + return "EXITED_ECM"; + case DIAL_MODIFIED_TO_USSD: + return "DIAL_MODIFIED_TO_USSD"; + case DIAL_MODIFIED_TO_SS: + return "DIAL_MODIFIED_TO_SS"; + case DIAL_MODIFIED_TO_DIAL: + return "DIAL_MODIFIED_TO_DIAL"; + case DIAL_MODIFIED_TO_DIAL_VIDEO: + return "DIAL_MODIFIED_TO_DIAL_VIDEO"; + case DIAL_VIDEO_MODIFIED_TO_SS: + return "DIAL_VIDEO_MODIFIED_TO_SS"; + case DIAL_VIDEO_MODIFIED_TO_USSD: + return "DIAL_VIDEO_MODIFIED_TO_USSD"; + case DIAL_VIDEO_MODIFIED_TO_DIAL: + return "DIAL_VIDEO_MODIFIED_TO_DIAL"; + case DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO: + return "DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO"; + case ERROR_UNSPECIFIED: + return "ERROR_UNSPECIFIED"; + case OUTGOING_FAILURE: + return "OUTGOING_FAILURE"; + case OUTGOING_CANCELED: + return "OUTGOING_CANCELED"; + case IMS_MERGED_SUCCESSFULLY: + return "IMS_MERGED_SUCCESSFULLY"; + case CDMA_ALREADY_ACTIVATED: + return "CDMA_ALREADY_ACTIVATED"; + case VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED: + return "VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED"; + case CALL_PULLED: + return "CALL_PULLED"; + case ANSWERED_ELSEWHERE: + return "ANSWERED_ELSEWHERE"; + case MAXIMUM_NUMBER_OF_CALLS_REACHED: + return "MAXIMUM_NUMER_OF_CALLS_REACHED"; + case DATA_DISABLED: + return "DATA_DISABLED"; + case DATA_LIMIT_REACHED: + return "DATA_LIMIT_REACHED"; + case DIALED_CALL_FORWARDING_WHILE_ROAMING: + return "DIALED_CALL_FORWARDING_WHILE_ROAMING"; + case IMEI_NOT_ACCEPTED: + return "IMEI_NOT_ACCEPTED"; + case WIFI_LOST: + return "WIFI_LOST"; + case IMS_ACCESS_BLOCKED: + return "IMS_ACCESS_BLOCKED"; + case LOW_BATTERY: + return "LOW_BATTERY"; + case DIAL_LOW_BATTERY: + return "DIAL_LOW_BATTERY"; + case EMERGENCY_TEMP_FAILURE: + return "EMERGENCY_TEMP_FAILURE"; + case EMERGENCY_PERM_FAILURE: + return "EMERGENCY_PERM_FAILURE"; + case NORMAL_UNSPECIFIED: + return "NORMAL_UNSPECIFIED"; + case IMS_SIP_ALTERNATE_EMERGENCY_CALL: + return "IMS_SIP_ALTERNATE_EMERGENCY_CALL"; + case ALREADY_DIALING: + return "ALREADY_DIALING"; + case CANT_CALL_WHILE_RINGING: + return "CANT_CALL_WHILE_RINGING"; + case CALLING_DISABLED: + return "CALLING_DISABLED"; + case TOO_MANY_ONGOING_CALLS: + return "TOO_MANY_ONGOING_CALLS"; + case OTASP_PROVISIONING_IN_PROCESS: + return "OTASP_PROVISIONING_IN_PROCESS"; + case MEDIA_TIMEOUT: + return "MEDIA_TIMEOUT"; + case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE: + return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE"; + case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION: + return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION"; + case OUTGOING_EMERGENCY_CALL_PLACED: + return "OUTGOING_EMERGENCY_CALL_PLACED"; case INCOMING_AUTO_REJECTED: return "INCOMING_AUTO_REJECTED"; - default: - return "INVALID: " + cause; + case SATELLITE_ENABLED: + return "SATELLITE_ENABLED"; + default: + return "INVALID: " + cause; } } } diff --git a/telephony/java/android/telephony/DomainSelectionService.aidl b/telephony/java/android/telephony/DomainSelectionService.aidl new file mode 100644 index 000000000000..b9d2ba89eca9 --- /dev/null +++ b/telephony/java/android/telephony/DomainSelectionService.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +parcelable DomainSelectionService.SelectionAttributes; diff --git a/telephony/java/android/telephony/DomainSelectionService.java b/telephony/java/android/telephony/DomainSelectionService.java new file mode 100644 index 000000000000..abcce5f61aee --- /dev/null +++ b/telephony/java/android/telephony/DomainSelectionService.java @@ -0,0 +1,864 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Intent; +import android.os.Build; +import android.os.CancellationSignal; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; +import android.telephony.Annotation.DisconnectCauses; +import android.telephony.Annotation.PreciseDisconnectCauses; +import android.telephony.ims.ImsReasonInfo; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.IDomainSelectionServiceController; +import com.android.internal.telephony.IDomainSelector; +import com.android.internal.telephony.ITransportSelectorCallback; +import com.android.internal.telephony.ITransportSelectorResultCallback; +import com.android.internal.telephony.IWwanSelectorCallback; +import com.android.internal.telephony.IWwanSelectorResultCallback; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * Main domain selection implementation for various telephony features. + * + * The telephony framework will bind to the {@link DomainSelectionService}. + * + * @hide + */ +public class DomainSelectionService extends Service { + + private static final String LOG_TAG = "DomainSelectionService"; + + /** + * The intent that must be defined as an intent-filter in the AndroidManifest of the + * {@link DomainSelectionService}. + * + * @hide + */ + public static final String SERVICE_INTERFACE = "android.telephony.DomainSelectionService"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "SELECTOR_TYPE_", + value = { + SELECTOR_TYPE_CALLING, + SELECTOR_TYPE_SMS, + SELECTOR_TYPE_UT}) + public @interface SelectorType {} + + /** Indicates the domain selector type for calling. */ + public static final int SELECTOR_TYPE_CALLING = 1; + /** Indicates the domain selector type for sms. */ + public static final int SELECTOR_TYPE_SMS = 2; + /** Indicates the domain selector type for supplementary services. */ + public static final int SELECTOR_TYPE_UT = 3; + + /** Indicates that the modem can scan for emergency service as per modem’s implementation. */ + public static final int SCAN_TYPE_NO_PREFERENCE = 0; + + /** Indicates that the modem will scan for emergency service in limited service mode. */ + public static final int SCAN_TYPE_LIMITED_SERVICE = 1; + + /** Indicates that the modem will scan for emergency service in full service mode. */ + public static final int SCAN_TYPE_FULL_SERVICE = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "SCAN_TYPE_", + value = { + SCAN_TYPE_NO_PREFERENCE, + SCAN_TYPE_LIMITED_SERVICE, + SCAN_TYPE_FULL_SERVICE}) + public @interface EmergencyScanType {} + + /** + * Contains attributes required to determine the domain for a telephony service. + */ + public static final class SelectionAttributes implements Parcelable { + + private static final String TAG = "SelectionAttributes"; + + private int mSlotId; + private int mSubId; + private @Nullable String mCallId; + private @Nullable String mNumber; + private @SelectorType int mSelectorType; + private boolean mIsVideoCall; + private boolean mIsEmergency; + private boolean mIsExitedFromAirplaneMode; + //private @Nullable UtAttributes mUtAttributes; + private @Nullable ImsReasonInfo mImsReasonInfo; + private @PreciseDisconnectCauses int mCause; + private @Nullable EmergencyRegResult mEmergencyRegResult; + + /** + * @param slotId The slot identifier. + * @param subId The subscription identifier. + * @param callId The call identifier. + * @param number The dialed number. + * @param selectorType Indicates the requested domain selector type. + * @param video Indicates it's a video call. + * @param emergency Indicates it's emergency service. + * @param exited {@code true} if the request caused the device to move out of airplane mode. + * @param imsReasonInfo The reason why the last PS attempt failed. + * @param cause The reason why the last CS attempt failed. + * @param regResult The current registration result for emergency services. + */ + private SelectionAttributes(int slotId, int subId, @Nullable String callId, + @Nullable String number, @SelectorType int selectorType, + boolean video, boolean emergency, boolean exited, + /*UtAttributes attr,*/ + @Nullable ImsReasonInfo imsReasonInfo, @PreciseDisconnectCauses int cause, + @Nullable EmergencyRegResult regResult) { + mSlotId = slotId; + mSubId = subId; + mCallId = callId; + mNumber = number; + mSelectorType = selectorType; + mIsVideoCall = video; + mIsEmergency = emergency; + mIsExitedFromAirplaneMode = exited; + //mUtAttributes = attr; + mImsReasonInfo = imsReasonInfo; + mCause = cause; + mEmergencyRegResult = regResult; + } + + /** + * Copy constructor. + * + * @param s Source selection attributes. + * @hide + */ + public SelectionAttributes(@NonNull SelectionAttributes s) { + mSlotId = s.mSlotId; + mSubId = s.mSubId; + mCallId = s.mCallId; + mNumber = s.mNumber; + mSelectorType = s.mSelectorType; + mIsEmergency = s.mIsEmergency; + mIsExitedFromAirplaneMode = s.mIsExitedFromAirplaneMode; + //mUtAttributes = s.mUtAttributes; + mImsReasonInfo = s.mImsReasonInfo; + mCause = s.mCause; + mEmergencyRegResult = s.mEmergencyRegResult; + } + + /** + * Constructs a SelectionAttributes object from the given parcel. + */ + private SelectionAttributes(@NonNull Parcel in) { + readFromParcel(in); + } + + /** + * @return The slot identifier. + */ + public int getSlotId() { + return mSlotId; + } + + /** + * @return The subscription identifier. + */ + public int getSubId() { + return mSubId; + } + + /** + * @return The call identifier. + */ + public @Nullable String getCallId() { + return mCallId; + } + + /** + * @return The dialed number. + */ + public @Nullable String getNumber() { + return mNumber; + } + + /** + * @return The domain selector type. + */ + public @SelectorType int getSelectorType() { + return mSelectorType; + } + + /** + * @return {@code true} if the request is for a video call. + */ + public boolean isVideoCall() { + return mIsVideoCall; + } + + /** + * @return {@code true} if the request is for emergency services. + */ + public boolean isEmergency() { + return mIsEmergency; + } + + /** + * @return {@code true} if the request caused the device to move out of airplane mode. + */ + public boolean isExitedFromAirplaneMode() { + return mIsExitedFromAirplaneMode; + } + + /* + public @Nullable UtAttributes getUtAttributes(); + return mUtAttributes; + } + */ + + /** + * @return The PS disconnect cause if trying over PS resulted in a failure and + * reselection is required. + */ + public @Nullable ImsReasonInfo getPsDisconnectCause() { + return mImsReasonInfo; + } + + /** + * @return The CS disconnect cause if trying over CS resulted in a failure and + * reselection is required. + */ + public @PreciseDisconnectCauses int getCsDisconnectCause() { + return mCause; + } + + /** + * @return The current registration state of cellular network. + */ + public @Nullable EmergencyRegResult getEmergencyRegResult() { + return mEmergencyRegResult; + } + + @Override + public @NonNull String toString() { + return "{ slotId=" + mSlotId + + ", subId=" + mSubId + + ", callId=" + mCallId + + ", number=" + (Build.IS_DEBUGGABLE ? mNumber : "***") + + ", type=" + mSelectorType + + ", videoCall=" + mIsVideoCall + + ", emergency=" + mIsEmergency + + ", airplaneMode=" + mIsExitedFromAirplaneMode + + ", reasonInfo=" + mImsReasonInfo + + ", cause=" + mCause + + ", regResult=" + mEmergencyRegResult + + " }"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SelectionAttributes that = (SelectionAttributes) o; + return mSlotId == that.mSlotId && mSubId == that.mSubId + && TextUtils.equals(mCallId, that.mCallId) + && TextUtils.equals(mNumber, that.mNumber) + && mSelectorType == that.mSelectorType && mIsVideoCall == that.mIsVideoCall + && mIsEmergency == that.mIsEmergency + && mIsExitedFromAirplaneMode == that.mIsExitedFromAirplaneMode + //&& equalsHandlesNulls(mUtAttributes, that.mUtAttributes) + && equalsHandlesNulls(mImsReasonInfo, that.mImsReasonInfo) + && mCause == that.mCause + && equalsHandlesNulls(mEmergencyRegResult, that.mEmergencyRegResult); + } + + @Override + public int hashCode() { + return Objects.hash(mCallId, mNumber, mImsReasonInfo, + mIsVideoCall, mIsEmergency, mIsExitedFromAirplaneMode, mEmergencyRegResult, + mSlotId, mSubId, mSelectorType, mCause); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mSlotId); + out.writeInt(mSubId); + out.writeString8(mCallId); + out.writeString8(mNumber); + out.writeInt(mSelectorType); + out.writeBoolean(mIsVideoCall); + out.writeBoolean(mIsEmergency); + out.writeBoolean(mIsExitedFromAirplaneMode); + //out.writeParcelable(mUtAttributes, 0); + out.writeParcelable(mImsReasonInfo, 0); + out.writeInt(mCause); + out.writeParcelable(mEmergencyRegResult, 0); + } + + private void readFromParcel(@NonNull Parcel in) { + mSlotId = in.readInt(); + mSubId = in.readInt(); + mCallId = in.readString8(); + mNumber = in.readString8(); + mSelectorType = in.readInt(); + mIsVideoCall = in.readBoolean(); + mIsEmergency = in.readBoolean(); + mIsExitedFromAirplaneMode = in.readBoolean(); + //mUtAttributes = s.mUtAttributes; + mImsReasonInfo = in.readParcelable(ImsReasonInfo.class.getClassLoader(), + android.telephony.ims.ImsReasonInfo.class); + mCause = in.readInt(); + mEmergencyRegResult = in.readParcelable(EmergencyRegResult.class.getClassLoader(), + EmergencyRegResult.class); + } + + public static final @NonNull Creator<SelectionAttributes> CREATOR = + new Creator<SelectionAttributes>() { + @Override + public SelectionAttributes createFromParcel(@NonNull Parcel in) { + return new SelectionAttributes(in); + } + + @Override + public SelectionAttributes[] newArray(int size) { + return new SelectionAttributes[size]; + } + }; + + private static boolean equalsHandlesNulls(Object a, Object b) { + return (a == null) ? (b == null) : a.equals(b); + } + + /** + * Builder class creating a new instance. + */ + public static final class Builder { + private final int mSlotId; + private final int mSubId; + private @Nullable String mCallId; + private @Nullable String mNumber; + private final @SelectorType int mSelectorType; + private boolean mIsVideoCall; + private boolean mIsEmergency; + private boolean mIsExitedFromAirplaneMode; + //private @Nullable UtAttributes mUtAttributes; + private @Nullable ImsReasonInfo mImsReasonInfo; + private @PreciseDisconnectCauses int mCause; + private @Nullable EmergencyRegResult mEmergencyRegResult; + + /** + * Default constructor for Builder. + */ + public Builder(int slotId, int subId, @SelectorType int selectorType) { + mSlotId = slotId; + mSubId = subId; + mSelectorType = selectorType; + } + + /** + * Sets the call identifier. + * + * @param callId The call identifier. + * @return The same instance of the builder. + */ + public @NonNull Builder setCallId(@NonNull String callId) { + mCallId = callId; + return this; + } + + /** + * Sets the dialed number. + * + * @param number The dialed number. + * @return The same instance of the builder. + */ + public @NonNull Builder setNumber(@NonNull String number) { + mNumber = number; + return this; + } + + /** + * Sets whether it's a video call or not. + * + * @param video Indicates it's a video call. + * @return The same instance of the builder. + */ + public @NonNull Builder setVideoCall(boolean video) { + mIsVideoCall = video; + return this; + } + + /** + * Sets whether it's an emergency service or not. + * + * @param emergency Indicates it's emergency service. + * @return The same instance of the builder. + */ + public @NonNull Builder setEmergency(boolean emergency) { + mIsEmergency = emergency; + return this; + } + + /** + * Sets whether the request caused the device to move out of airplane mode. + * + * @param exited {@code true} if the request caused the device to move out of + * airplane mode. + * @return The same instance of the builder. + */ + public @NonNull Builder setExitedFromAirplaneMode(boolean exited) { + mIsExitedFromAirplaneMode = exited; + return this; + } + + /** + * Sets the Ut service attributes. + * Only applicable for SELECTOR_TYPE_UT + * + * @param attr Ut services attributes. + * @return The same instance of the builder. + */ + /* + public @NonNull Builder setUtAttributes(@NonNull UtAttributes attr); + mUtAttributes = attr; + return this; + } + */ + + /** + * Sets an optional reason why the last PS attempt failed. + * + * @param info The reason why the last PS attempt failed. + * @return The same instance of the builder. + */ + public @NonNull Builder setPsDisconnectCause(@NonNull ImsReasonInfo info) { + mImsReasonInfo = info; + return this; + } + + /** + * Sets an optional reason why the last CS attempt failed. + * + * @param cause The reason why the last CS attempt failed. + * @return The same instance of the builder. + */ + public @NonNull Builder setCsDisconnectCause(@PreciseDisconnectCauses int cause) { + mCause = cause; + return this; + } + + /** + * Sets the current registration result for emergency services. + * + * @param regResult The current registration result for emergency services. + * @return The same instance of the builder. + */ + public @NonNull Builder setEmergencyRegResult(@NonNull EmergencyRegResult regResult) { + mEmergencyRegResult = regResult; + return this; + } + + /** + * Build the SelectionAttributes. + * @return The SelectionAttributes object. + */ + public @NonNull SelectionAttributes build() { + return new SelectionAttributes(mSlotId, mSubId, mCallId, mNumber, mSelectorType, + mIsVideoCall, mIsEmergency, mIsExitedFromAirplaneMode, /*mUtAttributes,*/ + mImsReasonInfo, mCause, mEmergencyRegResult); + } + } + } + + /** + * A wrapper class for ITransportSelectorCallback interface. + */ + private final class TransportSelectorCallbackWrapper implements TransportSelectorCallback { + private static final String TAG = "TransportSelectorCallbackWrapper"; + + private final @NonNull ITransportSelectorCallback mCallback; + private final @NonNull Executor mExecutor; + + private @Nullable ITransportSelectorResultCallbackAdapter mResultCallback; + private @Nullable DomainSelectorWrapper mSelectorWrapper; + + TransportSelectorCallbackWrapper(@NonNull ITransportSelectorCallback cb, + @NonNull Executor executor) { + mCallback = cb; + mExecutor = executor; + } + + @Override + public void onCreated(@NonNull DomainSelector selector) { + try { + mSelectorWrapper = new DomainSelectorWrapper(selector, mExecutor); + mCallback.onCreated(mSelectorWrapper.getCallbackBinder()); + } catch (Exception e) { + Rlog.e(TAG, "onCreated e=" + e); + } + } + + @Override + public void onWlanSelected(boolean useEmergencyPdn) { + try { + mCallback.onWlanSelected(useEmergencyPdn); + } catch (Exception e) { + Rlog.e(TAG, "onWlanSelected e=" + e); + } + } + + @Override + public @NonNull WwanSelectorCallback onWwanSelected() { + WwanSelectorCallback callback = null; + try { + IWwanSelectorCallback cb = mCallback.onWwanSelected(); + callback = new WwanSelectorCallbackWrapper(cb, mExecutor); + } catch (Exception e) { + Rlog.e(TAG, "onWwanSelected e=" + e); + } + + return callback; + } + + @Override + public void onWwanSelected(Consumer<WwanSelectorCallback> consumer) { + try { + mResultCallback = new ITransportSelectorResultCallbackAdapter(consumer, mExecutor); + mCallback.onWwanSelectedAsync(mResultCallback); + } catch (Exception e) { + Rlog.e(TAG, "onWwanSelected e=" + e); + executeMethodAsyncNoException(mExecutor, + () -> consumer.accept(null), TAG, "onWwanSelectedAsync-Exception"); + } + } + + @Override + public void onSelectionTerminated(@DisconnectCauses int cause) { + try { + mCallback.onSelectionTerminated(cause); + mSelectorWrapper = null; + } catch (Exception e) { + Rlog.e(TAG, "onSelectionTerminated e=" + e); + } + } + + private class ITransportSelectorResultCallbackAdapter + extends ITransportSelectorResultCallback.Stub { + private final @NonNull Consumer<WwanSelectorCallback> mConsumer; + private final @NonNull Executor mExecutor; + + ITransportSelectorResultCallbackAdapter( + @NonNull Consumer<WwanSelectorCallback> consumer, + @NonNull Executor executor) { + mConsumer = consumer; + mExecutor = executor; + } + + @Override + public void onCompleted(@NonNull IWwanSelectorCallback cb) { + if (mConsumer == null) return; + + WwanSelectorCallback callback = new WwanSelectorCallbackWrapper(cb, mExecutor); + executeMethodAsyncNoException(mExecutor, + () -> mConsumer.accept(callback), TAG, "onWwanSelectedAsync-Completed"); + } + } + } + + /** + * A wrapper class for IDomainSelector interface. + */ + private final class DomainSelectorWrapper { + private static final String TAG = "DomainSelectorWrapper"; + + private @NonNull IDomainSelector mCallbackBinder; + + DomainSelectorWrapper(@NonNull DomainSelector cb, @NonNull Executor executor) { + mCallbackBinder = new IDomainSelectorAdapter(cb, executor); + } + + private class IDomainSelectorAdapter extends IDomainSelector.Stub { + private final @NonNull WeakReference<DomainSelector> mDomainSelectorWeakRef; + private final @NonNull Executor mExecutor; + + IDomainSelectorAdapter(@NonNull DomainSelector domainSelector, + @NonNull Executor executor) { + mDomainSelectorWeakRef = + new WeakReference<DomainSelector>(domainSelector); + mExecutor = executor; + } + + @Override + public void cancelSelection() { + final DomainSelector domainSelector = mDomainSelectorWeakRef.get(); + if (domainSelector == null) return; + + executeMethodAsyncNoException(mExecutor, + () -> domainSelector.cancelSelection(), TAG, "cancelSelection"); + } + + @Override + public void reselectDomain(@NonNull SelectionAttributes attr) { + final DomainSelector domainSelector = mDomainSelectorWeakRef.get(); + if (domainSelector == null) return; + + executeMethodAsyncNoException(mExecutor, + () -> domainSelector.reselectDomain(attr), TAG, "reselectDomain"); + } + + @Override + public void finishSelection() { + final DomainSelector domainSelector = mDomainSelectorWeakRef.get(); + if (domainSelector == null) return; + + executeMethodAsyncNoException(mExecutor, + () -> domainSelector.finishSelection(), TAG, "finishSelection"); + } + } + + public @NonNull IDomainSelector getCallbackBinder() { + return mCallbackBinder; + } + } + + /** + * A wrapper class for IWwanSelectorCallback and IWwanSelectorResultCallback. + */ + private final class WwanSelectorCallbackWrapper + implements WwanSelectorCallback, CancellationSignal.OnCancelListener { + private static final String TAG = "WwanSelectorCallbackWrapper"; + + private final @NonNull IWwanSelectorCallback mCallback; + private final @NonNull Executor mExecutor; + + private @Nullable IWwanSelectorResultCallbackAdapter mResultCallback; + + WwanSelectorCallbackWrapper(@NonNull IWwanSelectorCallback cb, + @NonNull Executor executor) { + mCallback = cb; + mExecutor = executor; + } + + @Override + public void onCancel() { + try { + mCallback.onCancel(); + } catch (Exception e) { + Rlog.e(TAG, "onCancel e=" + e); + } + } + + @Override + public void onRequestEmergencyNetworkScan(@NonNull List<Integer> preferredNetworks, + @EmergencyScanType int scanType, @NonNull CancellationSignal signal, + @NonNull Consumer<EmergencyRegResult> consumer) { + try { + if (signal != null) signal.setOnCancelListener(this); + mResultCallback = new IWwanSelectorResultCallbackAdapter(consumer, mExecutor); + mCallback.onRequestEmergencyNetworkScan( + preferredNetworks.stream().mapToInt(Integer::intValue).toArray(), + scanType, mResultCallback); + } catch (Exception e) { + Rlog.e(TAG, "onRequestEmergencyNetworkScan e=" + e); + } + } + + @Override + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, + boolean useEmergencyPdn) { + try { + mCallback.onDomainSelected(domain, useEmergencyPdn); + } catch (Exception e) { + Rlog.e(TAG, "onDomainSelected e=" + e); + } + } + + private class IWwanSelectorResultCallbackAdapter + extends IWwanSelectorResultCallback.Stub { + private final @NonNull Consumer<EmergencyRegResult> mConsumer; + private final @NonNull Executor mExecutor; + + IWwanSelectorResultCallbackAdapter(@NonNull Consumer<EmergencyRegResult> consumer, + @NonNull Executor executor) { + mConsumer = consumer; + mExecutor = executor; + } + + @Override + public void onComplete(@NonNull EmergencyRegResult result) { + if (mConsumer == null) return; + + executeMethodAsyncNoException(mExecutor, + () -> mConsumer.accept(result), TAG, "onScanComplete"); + } + } + } + + private final Object mExecutorLock = new Object(); + + /** Executor used to execute methods called remotely by the framework. */ + private @NonNull Executor mExecutor; + + /** + * Selects a domain for the given operation. + * + * @param attr Required to determine the domain. + * @param callback The callback instance being registered. + */ + public void onDomainSelection(@NonNull SelectionAttributes attr, + @NonNull TransportSelectorCallback callback) { + } + + /** + * Notifies the change in {@link ServiceState} for a specific slot. + * + * @param slotId For which the state changed. + * @param subId For which the state changed. + * @param serviceState Updated {@link ServiceState}. + */ + public void onServiceStateUpdated(int slotId, int subId, @NonNull ServiceState serviceState) { + } + + /** + * Notifies the change in {@link BarringInfo} for a specific slot. + * + * @param slotId For which the state changed. + * @param subId For which the state changed. + * @param info Updated {@link BarringInfo}. + */ + public void onBarringInfoUpdated(int slotId, int subId, @NonNull BarringInfo info) { + } + + private final IBinder mDomainSelectionServiceController = + new IDomainSelectionServiceController.Stub() { + @Override + public void selectDomain(@NonNull SelectionAttributes attr, + @NonNull ITransportSelectorCallback callback) throws RemoteException { + executeMethodAsync(getCachedExecutor(), + () -> DomainSelectionService.this.onDomainSelection(attr, + new TransportSelectorCallbackWrapper(callback, getCachedExecutor())), + LOG_TAG, "onDomainSelection"); + } + + @Override + public void updateServiceState(int slotId, int subId, @NonNull ServiceState serviceState) { + executeMethodAsyncNoException(getCachedExecutor(), + () -> DomainSelectionService.this.onServiceStateUpdated(slotId, + subId, serviceState), LOG_TAG, "onServiceStateUpdated"); + } + + @Override + public void updateBarringInfo(int slotId, int subId, @NonNull BarringInfo info) { + executeMethodAsyncNoException(getCachedExecutor(), + () -> DomainSelectionService.this.onBarringInfoUpdated(slotId, subId, info), + LOG_TAG, "onBarringInfoUpdated"); + } + }; + + private static void executeMethodAsync(@NonNull Executor executor, @NonNull Runnable r, + @NonNull String tag, @NonNull String errorLogName) throws RemoteException { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor).join(); + } catch (CancellationException | CompletionException e) { + Rlog.w(tag, "Binder - " + errorLogName + " exception: " + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + + private void executeMethodAsyncNoException(@NonNull Executor executor, @NonNull Runnable r, + @NonNull String tag, @NonNull String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor).join(); + } catch (CancellationException | CompletionException e) { + Rlog.w(tag, "Binder - " + errorLogName + " exception: " + e.getMessage()); + } + } + + /** @hide */ + @Override + public IBinder onBind(Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + Log.i(LOG_TAG, "DomainSelectionService Bound."); + return mDomainSelectionServiceController; + } + return null; + } + + /** + * The DomainSelectionService will be able to define an {@link Executor} that the service + * can use to execute the methods. It has set the default executor as Runnable::run, + * + * @return An {@link Executor} to be used. + */ + @SuppressLint("OnNameExpected") + public @NonNull Executor getExecutor() { + return Runnable::run; + } + + /** + * Gets the {@link Executor} which executes methods of this service. + * This method should be private when this service is implemented in a separated process + * other than telephony framework. + * @return {@link Executor} instance. + * @hide + */ + public @NonNull Executor getCachedExecutor() { + synchronized (mExecutorLock) { + if (mExecutor == null) { + Executor e = getExecutor(); + mExecutor = (e != null) ? e : Runnable::run; + } + return mExecutor; + } + } + + /** + * Returns a string representation of the domain. + * @param domain The domain. + * @return The name of the domain. + * @hide + */ + public static @NonNull String getDomainName(@NetworkRegistrationInfo.Domain int domain) { + return NetworkRegistrationInfo.domainToString(domain); + } +} diff --git a/telephony/java/android/telephony/DomainSelector.java b/telephony/java/android/telephony/DomainSelector.java new file mode 100644 index 000000000000..087183122670 --- /dev/null +++ b/telephony/java/android/telephony/DomainSelector.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +import android.annotation.NonNull; +import android.telephony.DomainSelectionService.SelectionAttributes; + +/** + * Implemented as part of the {@link DomainSelectionService} to implement domain selection + * for a specific use case. + * @hide + */ +public interface DomainSelector { + /** + * Cancel an ongoing selection operation. It is up to the DomainSelectionService + * to clean up all ongoing operations with the framework. + */ + void cancelSelection(); + + /** + * Reselect a domain due to the call not setting up properly. + * + * @param attr attributes required to select the domain. + */ + void reselectDomain(@NonNull SelectionAttributes attr); + + /** + * Finish the selection procedure and clean everything up. + */ + void finishSelection(); +} diff --git a/telephony/java/android/telephony/EmergencyRegResult.aidl b/telephony/java/android/telephony/EmergencyRegResult.aidl new file mode 100644 index 000000000000..f7229621c0c1 --- /dev/null +++ b/telephony/java/android/telephony/EmergencyRegResult.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +parcelable EmergencyRegResult; diff --git a/telephony/java/android/telephony/EmergencyRegResult.java b/telephony/java/android/telephony/EmergencyRegResult.java new file mode 100644 index 000000000000..5aed41254cf6 --- /dev/null +++ b/telephony/java/android/telephony/EmergencyRegResult.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.util.Objects; + +/** + * Contains attributes required to determine the domain for a telephony service + * @hide + */ +public final class EmergencyRegResult implements Parcelable { + + /** + * Indicates the cellular network type of the acquired system. + */ + private @AccessNetworkConstants.RadioAccessNetworkType int mAccessNetworkType; + + /** + * Registration state of the acquired system. + */ + private @NetworkRegistrationInfo.RegistrationState int mRegState; + + /** + * EMC domain indicates the current domain of the acquired system. + */ + private @NetworkRegistrationInfo.Domain int mDomain; + + /** + * Indicates whether the network supports voice over PS network. + */ + private boolean mIsVopsSupported; + + /** + * This indicates if camped network support VoLTE emergency bearers. + * This should only be set if the UE is in LTE mode. + */ + private boolean mIsEmcBearerSupported; + + /** + * The value of the network provided EMC in 5G Registration ACCEPT. + * This should be set only if the UE is in 5G mode. + */ + private int mNwProvidedEmc; + + /** + * The value of the network provided EMF(EPS Fallback) in 5G Registration ACCEPT. + * This should be set only if the UE is in 5G mode. + */ + private int mNwProvidedEmf; + + /** 3-digit Mobile Country Code, 000..999, empty string if unknown. */ + private @NonNull String mMcc; + + /** 2 or 3-digit Mobile Network Code, 00..999, empty string if unknown. */ + private @NonNull String mMnc; + + /** + * The ISO-3166-1 alpha-2 country code equivalent for the network's country code, + * empty string if unknown. + */ + private @NonNull String mIso; + + /** + * Constructor + * @param accessNetwork Indicates the network type of the acquired system. + * @param regState Indicates the registration state of the acquired system. + * @param domain Indicates the current domain of the acquired system. + * @param isVopsSupported Indicates whether the network supports voice over PS network. + * @param isEmcBearerSupported Indicates if camped network support VoLTE emergency bearers. + * @param emc The value of the network provided EMC in 5G Registration ACCEPT. + * @param emf The value of the network provided EMF(EPS Fallback) in 5G Registration ACCEPT. + * @param mcc Mobile country code, empty string if unknown. + * @param mnc Mobile network code, empty string if unknown. + * @param iso The ISO-3166-1 alpha-2 country code equivalent, empty string if unknown. + * @hide + */ + public EmergencyRegResult( + @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, + @NetworkRegistrationInfo.RegistrationState int regState, + @NetworkRegistrationInfo.Domain int domain, + boolean isVopsSupported, boolean isEmcBearerSupported, int emc, int emf, + @NonNull String mcc, @NonNull String mnc, @NonNull String iso) { + mAccessNetworkType = accessNetwork; + mRegState = regState; + mDomain = domain; + mIsVopsSupported = isVopsSupported; + mIsEmcBearerSupported = isEmcBearerSupported; + mNwProvidedEmc = emc; + mNwProvidedEmf = emf; + mMcc = mcc; + mMnc = mnc; + mIso = iso; + } + + /** + * Copy constructors + * + * @param s Source emergency scan result + * @hide + */ + public EmergencyRegResult(@NonNull EmergencyRegResult s) { + mAccessNetworkType = s.mAccessNetworkType; + mRegState = s.mRegState; + mDomain = s.mDomain; + mIsVopsSupported = s.mIsVopsSupported; + mIsEmcBearerSupported = s.mIsEmcBearerSupported; + mNwProvidedEmc = s.mNwProvidedEmc; + mNwProvidedEmf = s.mNwProvidedEmf; + mMcc = s.mMcc; + mMnc = s.mMnc; + mIso = s.mIso; + } + + /** + * Construct a EmergencyRegResult object from the given parcel. + */ + private EmergencyRegResult(@NonNull Parcel in) { + readFromParcel(in); + } + + /** + * Returns the cellular access network type of the acquired system. + * + * @return the cellular network type. + */ + public @AccessNetworkConstants.RadioAccessNetworkType int getAccessNetwork() { + return mAccessNetworkType; + } + + /** + * Returns the registration state of the acquired system. + * + * @return the registration state. + */ + public @NetworkRegistrationInfo.RegistrationState int getRegState() { + return mRegState; + } + + /** + * Returns the current domain of the acquired system. + * + * @return the current domain. + */ + public @NetworkRegistrationInfo.Domain int getDomain() { + return mDomain; + } + + /** + * Returns whether the network supports voice over PS network. + * + * @return {@code true} if the network supports voice over PS network. + */ + public boolean isVopsSupported() { + return mIsVopsSupported; + } + + /** + * Returns whether camped network support VoLTE emergency bearers. + * This is not valid if the UE is not in LTE mode. + * + * @return {@code true} if the network supports VoLTE emergency bearers. + */ + public boolean isEmcBearerSupported() { + return mIsEmcBearerSupported; + } + + /** + * Returns the value of the network provided EMC in 5G Registration ACCEPT. + * This is not valid if UE is not in 5G mode. + * + * @return the value of the network provided EMC. + */ + public int getNwProvidedEmc() { + return mNwProvidedEmc; + } + + /** + * Returns the value of the network provided EMF(EPS Fallback) in 5G Registration ACCEPT. + * This is not valid if UE is not in 5G mode. + * + * @return the value of the network provided EMF. + */ + public int getNwProvidedEmf() { + return mNwProvidedEmf; + } + + /** + * Returns 3-digit Mobile Country Code. + * + * @return Mobile Country Code. + */ + public @NonNull String getMcc() { + return mMcc; + } + + /** + * Returns 2 or 3-digit Mobile Network Code. + * + * @return Mobile Network Code. + */ + public @NonNull String getMnc() { + return mMnc; + } + + /** + * Returns the ISO-3166-1 alpha-2 country code is provided in lowercase 2 character format. + * + * @return Country code. + */ + public @NonNull String getIso() { + return mIso; + } + + @Override + public @NonNull String toString() { + return "{ accessNetwork=" + + AccessNetworkConstants.AccessNetworkType.toString(mAccessNetworkType) + + ", regState=" + NetworkRegistrationInfo.registrationStateToString(mRegState) + + ", domain=" + NetworkRegistrationInfo.domainToString(mDomain) + + ", vops=" + mIsVopsSupported + + ", emcBearer=" + mIsEmcBearerSupported + + ", emc=" + mNwProvidedEmc + + ", emf=" + mNwProvidedEmf + + ", mcc=" + mMcc + + ", mnc=" + mMnc + + ", iso=" + mIso + + " }"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EmergencyRegResult that = (EmergencyRegResult) o; + return mAccessNetworkType == that.mAccessNetworkType + && mRegState == that.mRegState + && mDomain == that.mDomain + && mIsVopsSupported == that.mIsVopsSupported + && mIsEmcBearerSupported == that.mIsEmcBearerSupported + && mNwProvidedEmc == that.mNwProvidedEmc + && mNwProvidedEmf == that.mNwProvidedEmf + && TextUtils.equals(mMcc, that.mMcc) + && TextUtils.equals(mMnc, that.mMnc) + && TextUtils.equals(mIso, that.mIso); + } + + @Override + public int hashCode() { + return Objects.hash(mAccessNetworkType, mRegState, mDomain, + mIsVopsSupported, mIsEmcBearerSupported, + mNwProvidedEmc, mNwProvidedEmf, + mMcc, mMnc, mIso); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mAccessNetworkType); + out.writeInt(mRegState); + out.writeInt(mDomain); + out.writeBoolean(mIsVopsSupported); + out.writeBoolean(mIsEmcBearerSupported); + out.writeInt(mNwProvidedEmc); + out.writeInt(mNwProvidedEmf); + out.writeString8(mMcc); + out.writeString8(mMnc); + out.writeString8(mIso); + } + + private void readFromParcel(@NonNull Parcel in) { + mAccessNetworkType = in.readInt(); + mRegState = in.readInt(); + mDomain = in.readInt(); + mIsVopsSupported = in.readBoolean(); + mIsEmcBearerSupported = in.readBoolean(); + mNwProvidedEmc = in.readInt(); + mNwProvidedEmf = in.readInt(); + mMcc = in.readString8(); + mMnc = in.readString8(); + mIso = in.readString8(); + } + + public static final @NonNull Creator<EmergencyRegResult> CREATOR = + new Creator<EmergencyRegResult>() { + @Override + public EmergencyRegResult createFromParcel(@NonNull Parcel in) { + return new EmergencyRegResult(in); + } + + @Override + public EmergencyRegResult[] newArray(int size) { + return new EmergencyRegResult[size]; + } + }; +} diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java index 2d0135ae1c99..64b3c0a203e3 100644 --- a/telephony/java/android/telephony/ModemActivityInfo.java +++ b/telephony/java/android/telephony/ModemActivityInfo.java @@ -567,14 +567,14 @@ public final class ModemActivityInfo implements Parcelable { /** @hide */ @TestApi public boolean isEmpty() { - boolean isTxPowerEmpty = false; - boolean isRxPowerEmpty = false; + boolean isTxPowerEmpty = true; + boolean isRxPowerEmpty = true; for (int i = 0; i < getSpecificInfoLength(); i++) { - if (mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) { - isTxPowerEmpty = true; + if (!mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) { + isTxPowerEmpty = false; } - if (mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) { - isRxPowerEmpty = true; + if (!mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) { + isRxPowerEmpty = false; } } return isTxPowerEmpty diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index f1f13bc6bb55..b0552b4a18a3 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -20,6 +20,9 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -39,6 +42,16 @@ import java.util.stream.Collectors; * Description of a mobile network registration info */ public final class NetworkRegistrationInfo implements Parcelable { + + /** + * A new registration state, REGISTRATION_STATE_EMERGENCY, is added to + * {@link NetworkRegistrationInfo}. This change will affect the result of getRegistration(). + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public static final long RETURN_REGISTRATION_STATE_EMERGENCY = 255938466L; + /** * Network domain * @hide @@ -64,7 +77,8 @@ public final class NetworkRegistrationInfo implements Parcelable { @IntDef(prefix = "REGISTRATION_STATE_", value = {REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, REGISTRATION_STATE_HOME, REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, REGISTRATION_STATE_DENIED, - REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING}) + REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING, + REGISTRATION_STATE_EMERGENCY}) public @interface RegistrationState {} /** @@ -103,6 +117,18 @@ public final class NetworkRegistrationInfo implements Parcelable { */ @SystemApi public static final int REGISTRATION_STATE_ROAMING = 5; + /** + * Emergency attached in EPS or in 5GS. + * IMS service will skip emergency registration if the device is in + * emergency attached state. {@link #mEmergencyOnly} can be true + * even in case it's not in emergency attached state. + * + * Reference: 3GPP TS 24.301 9.9.3.11 EPS attach type. + * Reference: 3GPP TS 24.501 9.11.3.6 5GS registration result. + * @hide + */ + @SystemApi + public static final int REGISTRATION_STATE_EMERGENCY = 6; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -313,8 +339,12 @@ public final class NetworkRegistrationInfo implements Parcelable { @Nullable VopsSupportInfo vopsSupportInfo) { this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause, emergencyOnly, availableServices, cellIdentity, rplmn, null, - new DataSpecificRegistrationInfo(maxDataCalls, isDcNrRestricted, isNrAvailable, - isEndcAvailable, vopsSupportInfo)); + new DataSpecificRegistrationInfo.Builder(maxDataCalls) + .setDcNrRestricted(isDcNrRestricted) + .setNrAvailable(isNrAvailable) + .setEnDcAvailable(isEndcAvailable) + .setVopsSupportInfo(vopsSupportInfo) + .build()); } private NetworkRegistrationInfo(Parcel source) { @@ -411,6 +441,15 @@ public final class NetworkRegistrationInfo implements Parcelable { @Deprecated @SystemApi public @RegistrationState int getRegistrationState() { + if (mRegistrationState == REGISTRATION_STATE_EMERGENCY) { + if (!CompatChanges.isChangeEnabled(RETURN_REGISTRATION_STATE_EMERGENCY)) { + if (mAccessNetworkTechnology == TelephonyManager.NETWORK_TYPE_LTE) { + return REGISTRATION_STATE_DENIED; + } else if (mAccessNetworkTechnology == TelephonyManager.NETWORK_TYPE_NR) { + return REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + } + } + } return mRegistrationState; } @@ -676,6 +715,7 @@ public final class NetworkRegistrationInfo implements Parcelable { case REGISTRATION_STATE_DENIED: return "DENIED"; case REGISTRATION_STATE_UNKNOWN: return "UNKNOWN"; case REGISTRATION_STATE_ROAMING: return "ROAMING"; + case REGISTRATION_STATE_EMERGENCY: return "EMERGENCY"; } return "Unknown reg state " + registrationState; } diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java index 63e3468ac19b..48170dfd0e54 100644 --- a/telephony/java/android/telephony/PhoneCapability.java +++ b/telephony/java/android/telephony/PhoneCapability.java @@ -90,7 +90,9 @@ public final class PhoneCapability implements Parcelable { /** * mMaxActiveVoiceSubscriptions defines the maximum subscriptions that can support * simultaneous voice calls. For a dual sim dual standby (DSDS) device it would be one, but - * for a dual sim dual active device it would be 2. + * for a dual sim dual active (DSDA) device, or a DSDS device that supports "virtual DSDA" ( + * using the data line of 1 SIM to temporarily provide IMS voice connectivity to the other SIM) + * it would be 2. * * @hide */ @@ -99,7 +101,7 @@ public final class PhoneCapability implements Parcelable { /** * mMaxActiveDataSubscriptions defines the maximum subscriptions that can support * simultaneous data connections. - * For example, for L+L device it should be 2. + * For example, for dual sim dual active L+L device it should be 2. * * @hide */ @@ -114,14 +116,20 @@ public final class PhoneCapability implements Parcelable { */ private final boolean mNetworkValidationBeforeSwitchSupported; - /** @hide */ + /** + * List of logical modem information. + * + * @hide + */ + @NonNull private final List<ModemInfo> mLogicalModemList; /** - * List of logical modem information. + * Device NR capabilities. * * @hide */ + @NonNull private final int[] mDeviceNrCapabilities; /** @hide */ @@ -136,6 +144,18 @@ public final class PhoneCapability implements Parcelable { this.mDeviceNrCapabilities = deviceNrCapabilities; } + private PhoneCapability(@NonNull Builder builder) { + this.mMaxActiveVoiceSubscriptions = builder.mMaxActiveVoiceSubscriptions; + this.mMaxActiveDataSubscriptions = builder.mMaxActiveDataSubscriptions; + // Make sure it's not null. + this.mLogicalModemList = builder.mLogicalModemList == null ? new ArrayList<>() + : builder.mLogicalModemList; + this.mNetworkValidationBeforeSwitchSupported = + builder.mNetworkValidationBeforeSwitchSupported; + this.mDeviceNrCapabilities = builder.mDeviceNrCapabilities; + + } + @Override public String toString() { return "mMaxActiveVoiceSubscriptions=" + mMaxActiveVoiceSubscriptions @@ -264,4 +284,121 @@ public final class PhoneCapability implements Parcelable { public @NonNull @DeviceNrCapability int[] getDeviceNrCapabilities() { return mDeviceNrCapabilities == null ? (new int[0]) : mDeviceNrCapabilities; } + + + /** + * Builder for {@link PhoneCapability}. + * + * @hide + */ + public static class Builder { + /** + * mMaxActiveVoiceSubscriptions defines the maximum subscriptions that can support + * simultaneous voice calls. For a dual sim dual standby (DSDS) device it would be one, but + * for a dual sim dual active (DSDA) device, or a DSDS device that supports "virtual DSDA" + * (using the data line of 1 SIM to temporarily provide IMS voice connectivity to the other + * SIM) it would be 2. + * + * @hide + */ + private int mMaxActiveVoiceSubscriptions = 0; + + /** + * mMaxActiveDataSubscriptions defines the maximum subscriptions that can support + * simultaneous data connections. For example, for L+L device it should be 2. + * + * @hide + */ + private int mMaxActiveDataSubscriptions = 0; + + /** + * Whether modem supports both internet PDN up so that we can do ping test before tearing + * down the other one. + * + * @hide + */ + private boolean mNetworkValidationBeforeSwitchSupported = false; + + /** + * List of logical modem information. + * + * @hide + */ + @NonNull + private List<ModemInfo> mLogicalModemList = new ArrayList<>(); + + /** + * Device NR capabilities. + * + * @hide + */ + @NonNull + private int[] mDeviceNrCapabilities = new int[0]; + + /** + * Default constructor. + */ + public Builder() { + } + + public Builder(@NonNull PhoneCapability phoneCapability) { + mMaxActiveVoiceSubscriptions = phoneCapability.mMaxActiveVoiceSubscriptions; + mMaxActiveDataSubscriptions = phoneCapability.mMaxActiveDataSubscriptions; + mNetworkValidationBeforeSwitchSupported = + phoneCapability.mNetworkValidationBeforeSwitchSupported; + mLogicalModemList = phoneCapability.mLogicalModemList; + mDeviceNrCapabilities = phoneCapability.mDeviceNrCapabilities; + } + + /** + * Sets the max active voice subscriptions supported by the device. + */ + public Builder setMaxActiveVoiceSubscriptions(int maxActiveVoiceSubscriptions) { + mMaxActiveVoiceSubscriptions = maxActiveVoiceSubscriptions; + return this; + } + + /** + * Sets the max active voice subscriptions supported by the device. + */ + public Builder setMaxActiveDataSubscriptions(int maxActiveDataSubscriptions) { + mMaxActiveDataSubscriptions = maxActiveDataSubscriptions; + return this; + } + + /** + * Sets the max active data subscriptions supported by the device. Can be fewer than the + * active voice subscriptions. + */ + public Builder setNetworkValidationBeforeSwitchSupported( + boolean networkValidationBeforeSwitchSupported) { + mNetworkValidationBeforeSwitchSupported = networkValidationBeforeSwitchSupported; + return this; + } + + /** + * Sets the logical modem list of the device. + */ + public Builder setLogicalModemList(@NonNull List<ModemInfo> logicalModemList) { + mLogicalModemList = logicalModemList; + return this; + } + + /** + * Sets the NR capabilities supported by the device. + */ + public Builder setDeviceNrCapabilities(@NonNull int[] deviceNrCapabilities) { + mDeviceNrCapabilities = deviceNrCapabilities; + return this; + } + + /** + * Build the {@link PhoneCapability}. + * + * @return The {@link PhoneCapability} instance. + */ + public PhoneCapability build() { + return new PhoneCapability(this); + } + } } diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 1273aa3abbc9..cf0561db2ae3 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -27,7 +27,6 @@ import android.content.Intent; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; -import android.os.Build; import android.os.PersistableBundle; import android.provider.Contacts; import android.provider.ContactsContract; @@ -1527,10 +1526,14 @@ public class PhoneNumberUtils { * Formats the specified {@code phoneNumber} to the E.164 representation. * * @param phoneNumber the phone number to format. - * @param defaultCountryIso the ISO 3166-1 two letters country code. + * @param defaultCountryIso the ISO 3166-1 two letters country code in UPPER CASE. * @return the E.164 representation, or null if the given phone number is not valid. */ public static String formatNumberToE164(String phoneNumber, String defaultCountryIso) { + if (defaultCountryIso != null) { + defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT); + } + return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.E164); } @@ -1538,10 +1541,14 @@ public class PhoneNumberUtils { * Formats the specified {@code phoneNumber} to the RFC3966 representation. * * @param phoneNumber the phone number to format. - * @param defaultCountryIso the ISO 3166-1 two letters country code. + * @param defaultCountryIso the ISO 3166-1 two letters country code in UPPER CASE. * @return the RFC3966 representation, or null if the given phone number is not valid. */ public static String formatNumberToRFC3966(String phoneNumber, String defaultCountryIso) { + if (defaultCountryIso != null) { + defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT); + } + return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.RFC3966); } @@ -1592,6 +1599,10 @@ public class PhoneNumberUtils { return false; } + if (defaultCountryIso != null) { + defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT); + } + PhoneNumberUtil util = PhoneNumberUtil.getInstance(); try { PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso); @@ -1620,6 +1631,10 @@ public class PhoneNumberUtils { return phoneNumber; } + if (defaultCountryIso != null) { + defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT); + } + PhoneNumberUtil util = PhoneNumberUtil.getInstance(); String result = null; try { @@ -1672,6 +1687,10 @@ public class PhoneNumberUtils { */ public static String formatNumber( String phoneNumber, String phoneNumberE164, String defaultCountryIso) { + if (defaultCountryIso != null) { + defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT); + } + int len = phoneNumber.length(); for (int i = 0; i < len; i++) { if (!isDialable(phoneNumber.charAt(i))) { @@ -1782,266 +1801,21 @@ public class PhoneNumberUtils { public static boolean isEmergencyNumber(int subId, String number) { // Return true only if the specified number *exactly* matches // one of the emergency numbers listed by the RIL / SIM. - return isEmergencyNumberInternal(subId, number, true /* useExactMatch */); - } - - /** - * Checks if given number might *potentially* result in - * a call to an emergency service on the current network. - * - * Specifically, this method will return true if the specified number - * is an emergency number according to the list managed by the RIL or - * SIM, *or* if the specified number simply starts with the same - * digits as any of the emergency numbers listed in the RIL / SIM. - * - * This method is intended for internal use by the phone app when - * deciding whether to allow ACTION_CALL intents from 3rd party apps - * (where we're required to *not* allow emergency calls to be placed.) - * - * @param number the number to look up. - * @return true if the number is in the list of emergency numbers - * listed in the RIL / SIM, *or* if the number starts with the - * same digits as any of those emergency numbers. - * - * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)} - * instead. - * - * @hide - */ - @Deprecated - public static boolean isPotentialEmergencyNumber(String number) { - return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number); - } - - /** - * Checks if given number might *potentially* result in - * a call to an emergency service on the current network. - * - * Specifically, this method will return true if the specified number - * is an emergency number according to the list managed by the RIL or - * SIM, *or* if the specified number simply starts with the same - * digits as any of the emergency numbers listed in the RIL / SIM. - * - * This method is intended for internal use by the phone app when - * deciding whether to allow ACTION_CALL intents from 3rd party apps - * (where we're required to *not* allow emergency calls to be placed.) - * - * @param subId the subscription id of the SIM. - * @param number the number to look up. - * @return true if the number is in the list of emergency numbers - * listed in the RIL / SIM, *or* if the number starts with the - * same digits as any of those emergency numbers. - * - * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)} - * instead. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Deprecated - public static boolean isPotentialEmergencyNumber(int subId, String number) { - // Check against the emergency numbers listed by the RIL / SIM, - // and *don't* require an exact match. - return isEmergencyNumberInternal(subId, number, false /* useExactMatch */); - } - - /** - * Helper function for isEmergencyNumber(String) and - * isPotentialEmergencyNumber(String). - * - * @param number the number to look up. - * - * @param useExactMatch if true, consider a number to be an emergency - * number only if it *exactly* matches a number listed in - * the RIL / SIM. If false, a number is considered to be an - * emergency number if it simply starts with the same digits - * as any of the emergency numbers listed in the RIL / SIM. - * (Setting useExactMatch to false allows you to identify - * number that could *potentially* result in emergency calls - * since many networks will actually ignore trailing digits - * after a valid emergency number.) - * - * @return true if the number is in the list of emergency numbers - * listed in the RIL / sim, otherwise return false. - */ - private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) { - return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, useExactMatch); - } - - /** - * Helper function for isEmergencyNumber(String) and - * isPotentialEmergencyNumber(String). - * - * @param subId the subscription id of the SIM. - * @param number the number to look up. - * - * @param useExactMatch if true, consider a number to be an emergency - * number only if it *exactly* matches a number listed in - * the RIL / SIM. If false, a number is considered to be an - * emergency number if it simply starts with the same digits - * as any of the emergency numbers listed in the RIL / SIM. - * (Setting useExactMatch to false allows you to identify - * number that could *potentially* result in emergency calls - * since many networks will actually ignore trailing digits - * after a valid emergency number.) - * - * @return true if the number is in the list of emergency numbers - * listed in the RIL / sim, otherwise return false. - */ - private static boolean isEmergencyNumberInternal(int subId, String number, - boolean useExactMatch) { - return isEmergencyNumberInternal(subId, number, null, useExactMatch); - } - - /** - * Checks if a given number is an emergency number for a specific country. - * - * @param number the number to look up. - * @param defaultCountryIso the specific country which the number should be checked against - * @return if the number is an emergency number for the specific country, then return true, - * otherwise false - * - * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)} - * instead. - * - * @hide - */ - @Deprecated - @UnsupportedAppUsage - public static boolean isEmergencyNumber(String number, String defaultCountryIso) { - return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso); - } - - /** - * Checks if a given number is an emergency number for a specific country. - * - * @param subId the subscription id of the SIM. - * @param number the number to look up. - * @param defaultCountryIso the specific country which the number should be checked against - * @return if the number is an emergency number for the specific country, then return true, - * otherwise false - * - * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)} - * instead. - * - * @hide - */ - @Deprecated - public static boolean isEmergencyNumber(int subId, String number, String defaultCountryIso) { - return isEmergencyNumberInternal(subId, number, - defaultCountryIso, - true /* useExactMatch */); - } - - /** - * Checks if a given number might *potentially* result in a call to an - * emergency service, for a specific country. - * - * Specifically, this method will return true if the specified number - * is an emergency number in the specified country, *or* if the number - * simply starts with the same digits as any emergency number for that - * country. - * - * This method is intended for internal use by the phone app when - * deciding whether to allow ACTION_CALL intents from 3rd party apps - * (where we're required to *not* allow emergency calls to be placed.) - * - * @param number the number to look up. - * @param defaultCountryIso the specific country which the number should be checked against - * @return true if the number is an emergency number for the specific - * country, *or* if the number starts with the same digits as - * any of those emergency numbers. - * - * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)} - * instead. - * - * @hide - */ - @Deprecated - public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) { - return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso); - } - - /** - * Checks if a given number might *potentially* result in a call to an - * emergency service, for a specific country. - * - * Specifically, this method will return true if the specified number - * is an emergency number in the specified country, *or* if the number - * simply starts with the same digits as any emergency number for that - * country. - * - * This method is intended for internal use by the phone app when - * deciding whether to allow ACTION_CALL intents from 3rd party apps - * (where we're required to *not* allow emergency calls to be placed.) - * - * @param subId the subscription id of the SIM. - * @param number the number to look up. - * @param defaultCountryIso the specific country which the number should be checked against - * @return true if the number is an emergency number for the specific - * country, *or* if the number starts with the same digits as - * any of those emergency numbers. - * - * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)} - * instead. - * - * @hide - */ - @Deprecated - public static boolean isPotentialEmergencyNumber(int subId, String number, - String defaultCountryIso) { - return isEmergencyNumberInternal(subId, number, - defaultCountryIso, - false /* useExactMatch */); - } - - /** - * Helper function for isEmergencyNumber(String, String) and - * isPotentialEmergencyNumber(String, String). - * - * @param number the number to look up. - * @param defaultCountryIso the specific country which the number should be checked against - * @param useExactMatch if true, consider a number to be an emergency - * number only if it *exactly* matches a number listed in - * the RIL / SIM. If false, a number is considered to be an - * emergency number if it simply starts with the same digits - * as any of the emergency numbers listed in the RIL / SIM. - * - * @return true if the number is an emergency number for the specified country. - */ - private static boolean isEmergencyNumberInternal(String number, - String defaultCountryIso, - boolean useExactMatch) { - return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, defaultCountryIso, - useExactMatch); + return isEmergencyNumberInternal(subId, number); } /** - * Helper function for isEmergencyNumber(String, String) and - * isPotentialEmergencyNumber(String, String). + * Helper function for isEmergencyNumber(String, String) and. * * @param subId the subscription id of the SIM. * @param number the number to look up. - * @param defaultCountryIso the specific country which the number should be checked against - * @param useExactMatch if true, consider a number to be an emergency - * number only if it *exactly* matches a number listed in - * the RIL / SIM. If false, a number is considered to be an - * emergency number if it simply starts with the same digits - * as any of the emergency numbers listed in the RIL / SIM. - * * @return true if the number is an emergency number for the specified country. * @hide */ - private static boolean isEmergencyNumberInternal(int subId, String number, - String defaultCountryIso, - boolean useExactMatch) { - // TODO: clean up all the callers that pass in a defaultCountryIso, since it's ignored now. + private static boolean isEmergencyNumberInternal(int subId, String number) { + //TODO: remove subid later. Keep it for now in case we need it later. try { - if (useExactMatch) { return TelephonyManager.getDefault().isEmergencyNumber(number); - } else { - return TelephonyManager.getDefault().isPotentialEmergencyNumber(number); - } } catch (RuntimeException ex) { Rlog.e(LOG_TAG, "isEmergencyNumberInternal: RuntimeException: " + ex); } @@ -2061,143 +1835,7 @@ public class PhoneNumberUtils { */ @Deprecated public static boolean isLocalEmergencyNumber(Context context, String number) { - return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number); - } - - /** - * Checks if a given number is an emergency number for the country that the user is in. - * - * @param subId the subscription id of the SIM. - * @param number the number to look up. - * @param context the specific context which the number should be checked against - * @return true if the specified number is an emergency number for the country the user - * is currently in. - * - * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)} - * instead. - * - * @hide - */ - @Deprecated - @UnsupportedAppUsage - public static boolean isLocalEmergencyNumber(Context context, int subId, String number) { - return isLocalEmergencyNumberInternal(subId, number, - context, - true /* useExactMatch */); - } - - /** - * Checks if a given number might *potentially* result in a call to an - * emergency service, for the country that the user is in. The current - * country is determined using the CountryDetector. - * - * Specifically, this method will return true if the specified number - * is an emergency number in the current country, *or* if the number - * simply starts with the same digits as any emergency number for the - * current country. - * - * This method is intended for internal use by the phone app when - * deciding whether to allow ACTION_CALL intents from 3rd party apps - * (where we're required to *not* allow emergency calls to be placed.) - * - * @param number the number to look up. - * @param context the specific context which the number should be checked against - * @return true if the specified number is an emergency number for a local country, based on the - * CountryDetector. - * - * @see android.location.CountryDetector - * - * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)} - * instead. - * - * @hide - */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static boolean isPotentialLocalEmergencyNumber(Context context, String number) { - return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number); - } - - /** - * Checks if a given number might *potentially* result in a call to an - * emergency service, for the country that the user is in. The current - * country is determined using the CountryDetector. - * - * Specifically, this method will return true if the specified number - * is an emergency number in the current country, *or* if the number - * simply starts with the same digits as any emergency number for the - * current country. - * - * This method is intended for internal use by the phone app when - * deciding whether to allow ACTION_CALL intents from 3rd party apps - * (where we're required to *not* allow emergency calls to be placed.) - * - * @param subId the subscription id of the SIM. - * @param number the number to look up. - * @param context the specific context which the number should be checked against - * @return true if the specified number is an emergency number for a local country, based on the - * CountryDetector. - * - * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)} - * instead. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Deprecated - public static boolean isPotentialLocalEmergencyNumber(Context context, int subId, - String number) { - return isLocalEmergencyNumberInternal(subId, number, - context, - false /* useExactMatch */); - } - - /** - * Helper function for isLocalEmergencyNumber() and - * isPotentialLocalEmergencyNumber(). - * - * @param number the number to look up. - * @param context the specific context which the number should be checked against - * @param useExactMatch if true, consider a number to be an emergency - * number only if it *exactly* matches a number listed in - * the RIL / SIM. If false, a number is considered to be an - * emergency number if it simply starts with the same digits - * as any of the emergency numbers listed in the RIL / SIM. - * - * @return true if the specified number is an emergency number for a - * local country, based on the CountryDetector. - * - * @see android.location.CountryDetector - * @hide - */ - private static boolean isLocalEmergencyNumberInternal(String number, - Context context, - boolean useExactMatch) { - return isLocalEmergencyNumberInternal(getDefaultVoiceSubId(), number, context, - useExactMatch); - } - - /** - * Helper function for isLocalEmergencyNumber() and - * isPotentialLocalEmergencyNumber(). - * - * @param subId the subscription id of the SIM. - * @param number the number to look up. - * @param context the specific context which the number should be checked against - * @param useExactMatch if true, consider a number to be an emergency - * number only if it *exactly* matches a number listed in - * the RIL / SIM. If false, a number is considered to be an - * emergency number if it simply starts with the same digits - * as any of the emergency numbers listed in the RIL / SIM. - * - * @return true if the specified number is an emergency number for a - * local country, based on the CountryDetector. - * @hide - */ - private static boolean isLocalEmergencyNumberInternal(int subId, String number, - Context context, - boolean useExactMatch) { - return isEmergencyNumberInternal(subId, number, null /* unused */, useExactMatch); + return isEmergencyNumberInternal(getDefaultVoiceSubId(), number); } /** @@ -3282,7 +2920,11 @@ public class PhoneNumberUtils { PhoneNumberUtil util = PhoneNumberUtil.getInstance(); PhoneNumber n1; PhoneNumber n2; - defaultCountryIso = defaultCountryIso.toUpperCase(); + + if (defaultCountryIso != null) { + defaultCountryIso = defaultCountryIso.toUpperCase(Locale.ROOT); + } + try { n1 = util.parseAndKeepRawInput(number1, defaultCountryIso); n2 = util.parseAndKeepRawInput(number2, defaultCountryIso); diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java index 98eeacf1a416..f4336096ed3b 100644 --- a/telephony/java/android/telephony/PreciseCallState.java +++ b/telephony/java/android/telephony/PreciseCallState.java @@ -66,6 +66,11 @@ public final class PreciseCallState implements Parcelable { public static final int PRECISE_CALL_STATE_DISCONNECTED = 7; /** Call state: Disconnecting. */ public static final int PRECISE_CALL_STATE_DISCONNECTING = 8; + /** + * Call state: Incoming in pre-alerting state i.e. prior to entering + * {@link #PRECISE_CALL_STATE_INCOMING}. + */ + public static final int PRECISE_CALL_STATE_INCOMING_SETUP = 9; private @PreciseCallStates int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID; private @PreciseCallStates int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID; diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java index 3b4cf75e7919..1cfd22cc4d65 100644 --- a/telephony/java/android/telephony/PreciseDisconnectCause.java +++ b/telephony/java/android/telephony/PreciseDisconnectCause.java @@ -235,6 +235,23 @@ public final class PreciseDisconnectCause { /** Call failed/dropped because of a network detach. */ public static final int NETWORK_DETACH = 261; + /** + * Dialing emergency calls is currently unavailable. + * The call should be redialed on the other subscription silently. + * If there is no other subscription available, the call may be redialed + * on this subscription again. + * @hide + */ + public static final int EMERGENCY_TEMP_FAILURE = 325; + /** + * Dialing emergency calls is currently unavailable. + * The call should be redialed on the other subscription silently. + * Even if there is no other subscription available, the call should not + * be redialed on this subscription again. + * @hide + */ + public static final int EMERGENCY_PERM_FAILURE = 326; + /** Mobile station (MS) is locked until next power cycle. */ public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; /** Drop call. */ diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java index f1e90118a559..90d6f89553b7 100644 --- a/telephony/java/android/telephony/RadioAccessFamily.java +++ b/telephony/java/android/telephony/RadioAccessFamily.java @@ -24,6 +24,8 @@ import android.telephony.TelephonyManager.PrefNetworkMode; import com.android.internal.telephony.RILConstants; +import java.util.Locale; + /** * Object to indicate the phone radio type and access technology. @@ -367,7 +369,7 @@ public class RadioAccessFamily implements Parcelable { } public static int rafTypeFromString(String rafList) { - rafList = rafList.toUpperCase(); + rafList = rafList.toUpperCase(Locale.ROOT); String[] rafs = rafList.split("\\|"); int result = 0; for(String raf : rafs) { diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 03e019d2edde..523d0b0e55f4 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -138,12 +138,11 @@ public class ServiceState implements Parcelable { */ public static final int FREQUENCY_RANGE_MMWAVE = 4; - private static final List<Integer> FREQUENCY_RANGE_ORDER = Arrays.asList( - FREQUENCY_RANGE_UNKNOWN, - FREQUENCY_RANGE_LOW, - FREQUENCY_RANGE_MID, - FREQUENCY_RANGE_HIGH, - FREQUENCY_RANGE_MMWAVE); + /** + * Number of frequency ranges. + * @hide + */ + public static final int FREQUENCY_RANGE_COUNT = 5; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -1214,13 +1213,8 @@ public class ServiceState implements Parcelable { /** * Initialize the service state. Set everything to the default value. - * - * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is - * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device - * is on AP-assisted mode, where IWLAN should be reported through WLAN. - * {@link NetworkRegistrationInfo}. */ - private void init(boolean legacyMode) { + private void init() { if (DBG) Rlog.d(LOG_TAG, "init"); mVoiceRegState = STATE_OUT_OF_SERVICE; mDataRegState = STATE_OUT_OF_SERVICE; @@ -1252,13 +1246,11 @@ public class ServiceState implements Parcelable { .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) .build()); - if (!legacyMode) { - addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) - .build()); - } + addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) + .build()); } mOperatorAlphaLongRaw = null; mOperatorAlphaShortRaw = null; @@ -1267,11 +1259,11 @@ public class ServiceState implements Parcelable { } public void setStateOutOfService() { - init(true); + init(); } public void setStateOff() { - init(true); + init(); mVoiceRegState = STATE_POWER_OFF; mDataRegState = STATE_POWER_OFF; } @@ -1279,14 +1271,11 @@ public class ServiceState implements Parcelable { /** * Set the service state to out-of-service * - * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is - * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device - * is on AP-assisted mode, where IWLAN should be reported through WLAN. * @param powerOff {@code true} if this is a power off case (i.e. Airplane mode on). * @hide */ - public void setOutOfService(boolean legacyMode, boolean powerOff) { - init(legacyMode); + public void setOutOfService(boolean powerOff) { + init(); if (powerOff) { mVoiceRegState = STATE_POWER_OFF; mDataRegState = STATE_POWER_OFF; @@ -1452,7 +1441,7 @@ public class ServiceState implements Parcelable { */ @UnsupportedAppUsage private void setFromNotifierBundle(Bundle m) { - ServiceState ssFromBundle = m.getParcelable(EXTRA_SERVICE_STATE); + ServiceState ssFromBundle = m.getParcelable(EXTRA_SERVICE_STATE, android.telephony.ServiceState.class); if (ssFromBundle != null) { copyFrom(ssFromBundle); } @@ -2115,15 +2104,6 @@ public class ServiceState implements Parcelable { } /** - * @hide - */ - public static final int getBetterNRFrequencyRange(int range1, int range2) { - return FREQUENCY_RANGE_ORDER.indexOf(range1) > FREQUENCY_RANGE_ORDER.indexOf(range2) - ? range1 - : range2; - } - - /** * Returns a copy of self with location-identifying information removed. * Always clears the NetworkRegistrationInfo's CellIdentity fields, but if removeCoarseLocation * is true, clears other info as well. diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index f74ef0fe764a..f1af68f5cfee 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -906,12 +906,12 @@ public class SignalStrength implements Parcelable { @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private void setFromNotifierBundle(Bundle m) { - mCdma = m.getParcelable("Cdma"); - mGsm = m.getParcelable("Gsm"); - mWcdma = m.getParcelable("Wcdma"); - mTdscdma = m.getParcelable("Tdscdma"); - mLte = m.getParcelable("Lte"); - mNr = m.getParcelable("Nr"); + mCdma = m.getParcelable("Cdma", android.telephony.CellSignalStrengthCdma.class); + mGsm = m.getParcelable("Gsm", android.telephony.CellSignalStrengthGsm.class); + mWcdma = m.getParcelable("Wcdma", android.telephony.CellSignalStrengthWcdma.class); + mTdscdma = m.getParcelable("Tdscdma", android.telephony.CellSignalStrengthTdscdma.class); + mLte = m.getParcelable("Lte", android.telephony.CellSignalStrengthLte.class); + mNr = m.getParcelable("Nr", android.telephony.CellSignalStrengthNr.class); } /** diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java index 3c1824539d1f..80f1de1b2e8a 100644 --- a/telephony/java/android/telephony/SignalThresholdInfo.java +++ b/telephony/java/android/telephony/SignalThresholdInfo.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; @@ -100,24 +101,34 @@ public final class SignalThresholdInfo implements Parcelable { */ public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8; + /** + * The ratio between the received energy from the pilot signal CPICH per chip (Ec) to the + * noise density (No). + * Range: -24 dBm to 1 dBm. + * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#UTRAN} + * Reference: 3GPP TS 25.215 5.1.5 + */ + public static final int SIGNAL_MEASUREMENT_TYPE_ECNO = 9; + /** @hide */ - @IntDef(prefix = {"SIGNAL_MEASUREMENT_TYPE_"}, value = { - SIGNAL_MEASUREMENT_TYPE_UNKNOWN, - SIGNAL_MEASUREMENT_TYPE_RSSI, - SIGNAL_MEASUREMENT_TYPE_RSCP, - SIGNAL_MEASUREMENT_TYPE_RSRP, - SIGNAL_MEASUREMENT_TYPE_RSRQ, - SIGNAL_MEASUREMENT_TYPE_RSSNR, - SIGNAL_MEASUREMENT_TYPE_SSRSRP, - SIGNAL_MEASUREMENT_TYPE_SSRSRQ, - SIGNAL_MEASUREMENT_TYPE_SSSINR - }) + @IntDef( + prefix = {"SIGNAL_MEASUREMENT_TYPE_"}, + value = { + SIGNAL_MEASUREMENT_TYPE_UNKNOWN, + SIGNAL_MEASUREMENT_TYPE_RSSI, + SIGNAL_MEASUREMENT_TYPE_RSCP, + SIGNAL_MEASUREMENT_TYPE_RSRP, + SIGNAL_MEASUREMENT_TYPE_RSRQ, + SIGNAL_MEASUREMENT_TYPE_RSSNR, + SIGNAL_MEASUREMENT_TYPE_SSRSRP, + SIGNAL_MEASUREMENT_TYPE_SSRSRQ, + SIGNAL_MEASUREMENT_TYPE_SSSINR, + SIGNAL_MEASUREMENT_TYPE_ECNO + }) @Retention(RetentionPolicy.SOURCE) - public @interface SignalMeasurementType { - } + public @interface SignalMeasurementType {} - @SignalMeasurementType - private final int mSignalMeasurementType; + @SignalMeasurementType private final int mSignalMeasurementType; /** * A hysteresis time in milliseconds to prevent flapping. @@ -149,8 +160,7 @@ public final class SignalThresholdInfo implements Parcelable { /** * The radio access network type associated with the signal thresholds. */ - @AccessNetworkConstants.RadioAccessNetworkType - private final int mRan; + @AccessNetworkConstants.RadioAccessNetworkType private final int mRan; /** * Indicates the hysteresisMs is disabled. @@ -160,12 +170,18 @@ public final class SignalThresholdInfo implements Parcelable { public static final int HYSTERESIS_MS_DISABLED = 0; /** - * Indicates the hysteresisDb is disabled. + * Indicates the default hysteresis value in dB. * * @hide */ - public static final int HYSTERESIS_DB_DISABLED = 0; + private static final int HYSTERESIS_DB_DEFAULT = 2; + /** + * Indicates the hysteresisDb value is not set and to be initialised to default value. + * + * @hide + */ + public static final int HYSTERESIS_DB_MINIMUM = 0; /** * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSI}. @@ -280,6 +296,20 @@ public final class SignalThresholdInfo implements Parcelable { public static final int SIGNAL_SSSINR_MAX_VALUE = 40; /** + * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_ECNO}. + * + * @hide + */ + public static final int SIGNAL_ECNO_MIN_VALUE = -24; + + /** + * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_ECNO}. + * + * @hide + */ + public static final int SIGNAL_ECNO_MAX_VALUE = 1; + + /** * The minimum number of thresholds allowed in each SignalThresholdInfo. * * @hide @@ -303,9 +333,13 @@ public final class SignalThresholdInfo implements Parcelable { * @param thresholds threshold value * @param isEnabled isEnabled */ - private SignalThresholdInfo(@AccessNetworkConstants.RadioAccessNetworkType int ran, - @SignalMeasurementType int signalMeasurementType, int hysteresisMs, int hysteresisDb, - @NonNull int[] thresholds, boolean isEnabled) { + private SignalThresholdInfo( + @AccessNetworkConstants.RadioAccessNetworkType int ran, + @SignalMeasurementType int signalMeasurementType, + int hysteresisMs, + int hysteresisDb, + @NonNull int[] thresholds, + boolean isEnabled) { Objects.requireNonNull(thresholds, "thresholds must not be null"); validateRanWithMeasurementType(ran, signalMeasurementType); validateThresholdRange(signalMeasurementType, thresholds); @@ -313,7 +347,7 @@ public final class SignalThresholdInfo implements Parcelable { mRan = ran; mSignalMeasurementType = signalMeasurementType; mHysteresisMs = hysteresisMs < 0 ? HYSTERESIS_MS_DISABLED : hysteresisMs; - mHysteresisDb = hysteresisDb < 0 ? HYSTERESIS_DB_DISABLED : hysteresisDb; + mHysteresisDb = hysteresisDb; mThresholds = thresholds; mIsEnabled = isEnabled; } @@ -325,7 +359,7 @@ public final class SignalThresholdInfo implements Parcelable { private int mRan = AccessNetworkConstants.AccessNetworkType.UNKNOWN; private int mSignalMeasurementType = SIGNAL_MEASUREMENT_TYPE_UNKNOWN; private int mHysteresisMs = HYSTERESIS_MS_DISABLED; - private int mHysteresisDb = HYSTERESIS_DB_DISABLED; + private int mHysteresisDb = HYSTERESIS_DB_DEFAULT; private int[] mThresholds = null; private boolean mIsEnabled = false; @@ -335,7 +369,8 @@ public final class SignalThresholdInfo implements Parcelable { * @param ran The radio access network type * @return the builder to facilitate the chaining */ - public @NonNull Builder setRadioAccessNetworkType( + @NonNull + public Builder setRadioAccessNetworkType( @AccessNetworkConstants.RadioAccessNetworkType int ran) { mRan = ran; return this; @@ -347,7 +382,8 @@ public final class SignalThresholdInfo implements Parcelable { * @param signalMeasurementType The signal measurement type * @return the builder to facilitate the chaining */ - public @NonNull Builder setSignalMeasurementType( + @NonNull + public Builder setSignalMeasurementType( @SignalMeasurementType int signalMeasurementType) { mSignalMeasurementType = signalMeasurementType; return this; @@ -361,20 +397,27 @@ public final class SignalThresholdInfo implements Parcelable { * @return the builder to facilitate the chaining * @hide */ - public @NonNull Builder setHysteresisMs(int hysteresisMs) { + @NonNull + public Builder setHysteresisMs(int hysteresisMs) { mHysteresisMs = hysteresisMs; return this; } /** - * Set the interval in dB defining the required magnitude change between reports. A value of - * zero disabled dB-based hysteresis restrictions. + * Set the interval in dB defining the required minimum magnitude change to report a + * signal strength change. A value of zero disables dB-based hysteresis restrictions. + * Note: + * <p>Default hysteresis db value is 2. Minimum hysteresis db value allowed to set is 0. + * If hysteresis db value is not set, default hysteresis db value of 2 will be used. * * @param hysteresisDb the interval in dB * @return the builder to facilitate the chaining - * @hide */ - public @NonNull Builder setHysteresisDb(int hysteresisDb) { + @NonNull + public Builder setHysteresisDb(@IntRange(from = 0) int hysteresisDb) { + if (hysteresisDb < 0) { + throw new IllegalArgumentException("hysteresis db value should not be less than 0"); + } mHysteresisDb = hysteresisDb; return this; } @@ -399,9 +442,11 @@ public final class SignalThresholdInfo implements Parcelable { * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR + * @see #SIGNAL_MEASUREMENT_TYPE_ECNO * @see #getThresholds() for more details on signal strength thresholds */ - public @NonNull Builder setThresholds(@NonNull int[] thresholds) { + @NonNull + public Builder setThresholds(@NonNull int[] thresholds) { return setThresholds(thresholds, false /*isSystem*/); } @@ -415,20 +460,23 @@ public final class SignalThresholdInfo implements Parcelable { * * @hide */ - public @NonNull Builder setThresholds(@NonNull int[] thresholds, boolean isSystem) { + @NonNull + public Builder setThresholds(@NonNull int[] thresholds, boolean isSystem) { Objects.requireNonNull(thresholds, "thresholds must not be null"); - if (!isSystem && (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED - || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED)) { + if (!isSystem + && (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED + || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED)) { throw new IllegalArgumentException( - "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED - + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED); + "thresholds length must between " + + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED + + " and " + + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED); } mThresholds = thresholds.clone(); Arrays.sort(mThresholds); return this; } - /** * Set if the modem should trigger the report based on the criteria. * @@ -436,7 +484,8 @@ public final class SignalThresholdInfo implements Parcelable { * @return the builder to facilitate the chaining * @hide */ - public @NonNull Builder setIsEnabled(boolean isEnabled) { + @NonNull + public Builder setIsEnabled(boolean isEnabled) { mIsEnabled = isEnabled; return this; } @@ -450,9 +499,15 @@ public final class SignalThresholdInfo implements Parcelable { * the thresholds is out of range, or the RAN is not allowed to set with the signal * measurement type */ - public @NonNull SignalThresholdInfo build() { - return new SignalThresholdInfo(mRan, mSignalMeasurementType, mHysteresisMs, - mHysteresisDb, mThresholds, mIsEnabled); + @NonNull + public SignalThresholdInfo build() { + return new SignalThresholdInfo( + mRan, + mSignalMeasurementType, + mHysteresisMs, + mHysteresisDb, + mThresholds, + mIsEnabled); } } @@ -461,7 +516,8 @@ public final class SignalThresholdInfo implements Parcelable { * * @return radio access network type */ - public @AccessNetworkConstants.RadioAccessNetworkType int getRadioAccessNetworkType() { + @AccessNetworkConstants.RadioAccessNetworkType + public int getRadioAccessNetworkType() { return mRan; } @@ -470,7 +526,8 @@ public final class SignalThresholdInfo implements Parcelable { * * @return the SignalMeasurementType value */ - public @SignalMeasurementType int getSignalMeasurementType() { + @SignalMeasurementType + public int getSignalMeasurementType() { return mSignalMeasurementType; } @@ -479,7 +536,11 @@ public final class SignalThresholdInfo implements Parcelable { return mHysteresisMs; } - /** @hide */ + /** + * Get measurement hysteresis db. + * + * @return hysteresis db value + */ public int getHysteresisDb() { return mHysteresisDb; } @@ -508,8 +569,10 @@ public final class SignalThresholdInfo implements Parcelable { * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR + * @see #SIGNAL_MEASUREMENT_TYPE_ECNO */ - public @NonNull int[] getThresholds() { + @NonNull + public int[] getThresholds() { return mThresholds.clone(); } @@ -574,11 +637,17 @@ public final class SignalThresholdInfo implements Parcelable { @Override public int hashCode() { - return Objects.hash(mRan, mSignalMeasurementType, mHysteresisMs, mHysteresisDb, - Arrays.hashCode(mThresholds), mIsEnabled); + return Objects.hash( + mRan, + mSignalMeasurementType, + mHysteresisMs, + mHysteresisDb, + Arrays.hashCode(mThresholds), + mIsEnabled); } - public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR = + @NonNull + public static final Parcelable.Creator<SignalThresholdInfo> CREATOR = new Parcelable.Creator<SignalThresholdInfo>() { @Override public SignalThresholdInfo createFromParcel(Parcel in) { @@ -594,13 +663,20 @@ public final class SignalThresholdInfo implements Parcelable { @Override public String toString() { return new StringBuilder("SignalThresholdInfo{") - .append("mRan=").append(mRan) - .append(" mSignalMeasurementType=").append(mSignalMeasurementType) - .append(" mHysteresisMs=").append(mHysteresisMs) - .append(" mHysteresisDb=").append(mHysteresisDb) - .append(" mThresholds=").append(Arrays.toString(mThresholds)) - .append(" mIsEnabled=").append(mIsEnabled) - .append("}").toString(); + .append("mRan=") + .append(mRan) + .append(" mSignalMeasurementType=") + .append(mSignalMeasurementType) + .append(" mHysteresisMs=") + .append(mHysteresisMs) + .append(" mHysteresisDb=") + .append(mHysteresisDb) + .append(" mThresholds=") + .append(Arrays.toString(mThresholds)) + .append(" mIsEnabled=") + .append(mIsEnabled) + .append("}") + .toString(); } /** @@ -624,6 +700,8 @@ public final class SignalThresholdInfo implements Parcelable { return threshold >= SIGNAL_SSRSRQ_MIN_VALUE && threshold <= SIGNAL_SSRSRQ_MAX_VALUE; case SIGNAL_MEASUREMENT_TYPE_SSSINR: return threshold >= SIGNAL_SSSINR_MIN_VALUE && threshold <= SIGNAL_SSSINR_MAX_VALUE; + case SIGNAL_MEASUREMENT_TYPE_ECNO: + return threshold >= SIGNAL_ECNO_MIN_VALUE && threshold <= SIGNAL_ECNO_MAX_VALUE; default: return false; } @@ -640,6 +718,7 @@ public final class SignalThresholdInfo implements Parcelable { return ran == AccessNetworkConstants.AccessNetworkType.GERAN || ran == AccessNetworkConstants.AccessNetworkType.CDMA2000; case SIGNAL_MEASUREMENT_TYPE_RSCP: + case SIGNAL_MEASUREMENT_TYPE_ECNO: return ran == AccessNetworkConstants.AccessNetworkType.UTRAN; case SIGNAL_MEASUREMENT_TYPE_RSRP: case SIGNAL_MEASUREMENT_TYPE_RSRQ: @@ -663,13 +742,15 @@ public final class SignalThresholdInfo implements Parcelable { } } - private void validateThresholdRange(@SignalMeasurementType int signalMeasurement, - int[] thresholds) { + private void validateThresholdRange( + @SignalMeasurementType int signalMeasurement, int[] thresholds) { for (int threshold : thresholds) { if (!isValidThreshold(signalMeasurement, threshold)) { throw new IllegalArgumentException( - "invalid signal measurement type: " + signalMeasurement - + " with threshold: " + threshold); + "invalid signal measurement type: " + + signalMeasurement + + " with threshold: " + + threshold); } } } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 1cf2969ea9b5..40488b15a37c 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -46,6 +46,7 @@ import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.IPhoneSubInfo; import com.android.internal.telephony.ISms; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.SmsRawData; @@ -297,6 +298,106 @@ public final class SmsManager { */ public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1; + // RP-Cause Values For MO SMS as per TS 124 011, table 8.4. + + /** @hide */ + @IntDef(prefix = { "SMS_RP_CAUSE" }, value = { + SmsManager.SMS_RP_CAUSE_UNALLOCATED_NUMBER, + SmsManager.SMS_RP_CAUSE_OPERATOR_DETERMINED_BARRING, + SmsManager.SMS_RP_CAUSE_CALL_BARRING, + SmsManager.SMS_RP_CAUSE_RESERVED, + SmsManager.SMS_RP_CAUSE_SHORT_MESSAGE_TRANSFER_REJECTED, + SmsManager.SMS_RP_CAUSE_DESTINATION_OUT_OF_ORDER, + SmsManager.SMS_RP_CAUSE_UNIDENTIFIED_SUBSCRIBER, + SmsManager.SMS_RP_CAUSE_FACILITY_REJECTED, + SmsManager.SMS_RP_CAUSE_UNKNOWN_SUBSCRIBER, + SmsManager.SMS_RP_CAUSE_NETWORK_OUT_OF_ORDER, + SmsManager.SMS_RP_CAUSE_TEMPORARY_FAILURE, + SmsManager.SMS_RP_CAUSE_CONGESTION, + SmsManager.SMS_RP_CAUSE_RESOURCES_UNAVAILABLE, + SmsManager.SMS_RP_CAUSE_FACILITY_NOT_SUBSCRIBED, + SmsManager.SMS_RP_CAUSE_FACILITY_NOT_IMPLEMENTED, + SmsManager.SMS_RP_CAUSE_INVALID_MESSAGE_REFERENCE_VALUE, + SmsManager.SMS_RP_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE, + SmsManager.SMS_RP_CAUSE_INVALID_MANDATORY_INFORMATION, + SmsManager.SMS_RP_CAUSE_MESSAGE_TYPE_NON_EXISTENT, + SmsManager.SMS_RP_CAUSE_MESSAGE_INCOMPATIBLE_WITH_PROTOCOL_STATE, + SmsManager.SMS_RP_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT, + SmsManager.SMS_RP_CAUSE_PROTOCOL_ERROR, + SmsManager.SMS_RP_CAUSE_INTERWORKING_UNSPECIFIED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SMS_RP_CAUSE {} + + /** Unallocated Number Cause */ + public static final int SMS_RP_CAUSE_UNALLOCATED_NUMBER = 1; + + /** RP-Cause for Operator Barring */ + public static final int SMS_RP_CAUSE_OPERATOR_DETERMINED_BARRING = 8; + + /** RP-Cause Value for Call Barring */ + public static final int SMS_RP_CAUSE_CALL_BARRING = 10; + + /** RP-Cause value for Reserved Number */ + public static final int SMS_RP_CAUSE_RESERVED = 11; + + /** RP-Cause Value for Message Transfer Rejected by Network */ + public static final int SMS_RP_CAUSE_SHORT_MESSAGE_TRANSFER_REJECTED = 21; + + /** RP-Cause Value for Destination is Out of Order */ + public static final int SMS_RP_CAUSE_DESTINATION_OUT_OF_ORDER = 27; + + /** RP-Cause Value when Subscriber is not Identified */ + public static final int SMS_RP_CAUSE_UNIDENTIFIED_SUBSCRIBER = 28; + + /** RP-Cause Value when SMS Facility if Rejected by Operator */ + public static final int SMS_RP_CAUSE_FACILITY_REJECTED = 29; + + /** RP-Cause Value when Subscriber is not Identified */ + public static final int SMS_RP_CAUSE_UNKNOWN_SUBSCRIBER = 30; + + /** RP-Cause Value when network is out of order*/ + public static final int SMS_RP_CAUSE_NETWORK_OUT_OF_ORDER = 38; + + /** RP-Cause Value For Temporary failure*/ + public static final int SMS_RP_CAUSE_TEMPORARY_FAILURE = 41; + + /** RP-Cause Value for SMS Failure due to Congestion in network*/ + public static final int SMS_RP_CAUSE_CONGESTION = 42; + + /** RP-Cause Value when Network Resources are unavailable */ + public static final int SMS_RP_CAUSE_RESOURCES_UNAVAILABLE = 47; + + /** RP-Cause Value when SMS Facilty is not subscribed by Reote device */ + public static final int SMS_RP_CAUSE_FACILITY_NOT_SUBSCRIBED = 50; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_FACILITY_NOT_IMPLEMENTED = 69; + + /** RP-Cause Value when RP-MessageRefere */ + public static final int SMS_RP_CAUSE_INVALID_MESSAGE_REFERENCE_VALUE = 81; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE = 95; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_INVALID_MANDATORY_INFORMATION = 96; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_MESSAGE_TYPE_NON_EXISTENT = 97; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_MESSAGE_INCOMPATIBLE_WITH_PROTOCOL_STATE = 98; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT = 99; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_PROTOCOL_ERROR = 111; + + /** RP-Cause Value when network does not provide the received service */ + public static final int SMS_RP_CAUSE_INTERWORKING_UNSPECIFIED = 127; + /** @hide */ @IntDef(prefix = { "PREMIUM_SMS_CONSENT" }, value = { SmsManager.PREMIUM_SMS_CONSENT_UNKNOWN, @@ -1914,8 +2015,10 @@ public final class SmsManager { * @see #disableCellBroadcastRange(int, int, int) * * @throws IllegalArgumentException if endMessageId < startMessageId + * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} instead. * {@hide} */ + @Deprecated @SystemApi public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, @android.telephony.SmsCbMessage.MessageFormat int ranType) { @@ -1974,8 +2077,10 @@ public final class SmsManager { * @see #enableCellBroadcastRange(int, int, int) * * @throws IllegalArgumentException if endMessageId < startMessageId + * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} instead. * {@hide} */ + @Deprecated @SystemApi public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, @android.telephony.SmsCbMessage.MessageFormat int ranType) { @@ -2269,7 +2374,21 @@ public final class SmsManager { RESULT_RIL_SIM_ABSENT, RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED, RESULT_RIL_ACCESS_BARRED, - RESULT_RIL_BLOCKED_DUE_TO_CALL + RESULT_RIL_BLOCKED_DUE_TO_CALL, + RESULT_RIL_GENERIC_ERROR, + RESULT_RIL_INVALID_RESPONSE, + RESULT_RIL_SIM_PIN2, + RESULT_RIL_SIM_PUK2, + RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE, + RESULT_RIL_SIM_ERROR, + RESULT_RIL_INVALID_SIM_STATE, + RESULT_RIL_NO_SMS_TO_ACK, + RESULT_RIL_SIM_BUSY, + RESULT_RIL_SIM_FULL, + RESULT_RIL_NO_SUBSCRIPTION, + RESULT_RIL_NO_NETWORK_FOUND, + RESULT_RIL_DEVICE_IN_USE, + RESULT_RIL_ABORTED }) @Retention(RetentionPolicy.SOURCE) public @interface Result {} @@ -2428,8 +2547,6 @@ public final class SmsManager { /** * User is not associated with the subscription. - * TODO(b/263279115): Make this error code public. - * @hide */ public static final int RESULT_USER_NOT_ALLOWED = 33; @@ -2542,7 +2659,7 @@ public final class SmsManager { public static final int RESULT_RIL_SIM_ABSENT = 120; /** - * 1X voice and SMS are not allowed simulteneously. + * 1X voice and SMS are not allowed simultaneously. */ public static final int RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED = 121; @@ -2561,6 +2678,73 @@ public final class SmsManager { */ public static final int RESULT_RIL_GENERIC_ERROR = 124; + /** + * A RIL internal error when one of the RIL layers receives an unrecognized response from a + * lower layer. + */ + public static final int RESULT_RIL_INVALID_RESPONSE = 125; + + /** + * Operation requires SIM PIN2 to be entered + */ + public static final int RESULT_RIL_SIM_PIN2 = 126; + + /** + * Operation requires SIM PUK2 to be entered + */ + public static final int RESULT_RIL_SIM_PUK2 = 127; + + /** + * Fail to find CDMA subscription from specified location + */ + public static final int RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE = 128; + + /** + * Received error from SIM card + */ + public static final int RESULT_RIL_SIM_ERROR = 129; + + /** + * Cannot process the request in current SIM state + */ + public static final int RESULT_RIL_INVALID_SIM_STATE = 130; + + /** + * ACK received when there is no SMS to ack + */ + public static final int RESULT_RIL_NO_SMS_TO_ACK = 131; + + /** + * SIM is busy + */ + public static final int RESULT_RIL_SIM_BUSY = 132; + + /** + * The target EF is full + */ + public static final int RESULT_RIL_SIM_FULL = 133; + + /** + * Device does not have subscription + */ + public static final int RESULT_RIL_NO_SUBSCRIPTION = 134; + + /** + * Network cannot be found + */ + public static final int RESULT_RIL_NO_NETWORK_FOUND = 135; + + /** + * Operation cannot be performed because the device is currently in use + */ + public static final int RESULT_RIL_DEVICE_IN_USE = 136; + + /** + * Operation aborted + */ + public static final int RESULT_RIL_ABORTED = 137; + + // SMS receiving results sent as a "result" extra in {@link Intents.SMS_REJECTED_ACTION} /** @@ -3052,6 +3236,43 @@ public final class SmsManager { } } + /** + * Set Storage Availability in SmsStorageMonitor + * @param storageAvailable storage availability to be set true or false + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @TestApi + public void setStorageMonitorMemoryStatusOverride(boolean storageAvailable) { + try { + ISms iccISms = getISmsServiceOrThrow(); + if (iccISms != null) { + iccISms.setStorageMonitorMemoryStatusOverride(getSubscriptionId(), + storageAvailable); + } + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + } + + /** + * Clear the memory status override set by + * {@link #setStorageMonitorMemoryStatusOverride(boolean)} + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @TestApi + public void clearStorageMonitorMemoryStatusOverride() { + try { + ISms iccISms = getISmsServiceOrThrow(); + if (iccISms != null) { + iccISms.clearStorageMonitorMemoryStatusOverride(getSubscriptionId()); + } + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + } + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"SMS_CATEGORY_"}, @@ -3264,8 +3485,10 @@ public final class SmsManager { /** * Reset all cell broadcast ranges. Previously enabled ranges will become invalid after this. + * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} with empty list instead * @hide */ + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public void resetAllCellBroadcastRanges() { @@ -3284,4 +3507,41 @@ public final class SmsManager { private static String formatCrossStackMessageId(long id) { return "{x-message-id:" + id + "}"; } + + /** + * Fetches the EF_PSISMSC value from the UICC that contains the Public Service Identity of + * the SM-SC (either a SIP URI or tel URI). The EF_PSISMSC of ISIM and USIM can be found in + * DF_TELECOM. + * The EF_PSISMSC value is used by the ME to submit SMS over IP as defined in 24.341 [55]. + * + * @return Uri : Public Service Identity of SM-SC from the ISIM or USIM if the ISIM is not + * available. + * @throws SecurityException if the caller does not have the required permission/privileges. + * @throws IllegalStateException in case of telephony service is not available. + * @hide + */ + @NonNull + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) + public Uri getSmscIdentity() { + Uri smscUri = Uri.EMPTY; + try { + IPhoneSubInfo info = TelephonyManager.getSubscriberInfoService(); + if (info == null) { + Rlog.e(TAG, "getSmscIdentity(): IPhoneSubInfo instance is NULL"); + throw new IllegalStateException("Telephony service is not available"); + } + /** Fetches the SIM EF_PSISMSC value based on subId and appType */ + smscUri = info.getSmscIdentity(getSubscriptionId(), TelephonyManager.APPTYPE_ISIM); + if (Uri.EMPTY.equals(smscUri)) { + /** Fallback in case where ISIM is not available */ + smscUri = info.getSmscIdentity(getSubscriptionId(), TelephonyManager.APPTYPE_USIM); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "getSmscIdentity(): Exception : " + ex); + ex.rethrowAsRuntimeException(); + } + return smscUri; + } } diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 2ddc98aca90c..faf97b57594e 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -947,29 +947,30 @@ public class SubscriptionInfo implements Parcelable { } /** - * Get ICCID stripped PII information on user build. + * Get stripped PII information from the id. * - * @param iccId The original ICCID. + * @param id The raw id (e.g. ICCID, IMSI, etc...). * @return The stripped string. * * @hide */ - public static String givePrintableIccid(String iccId) { - String iccIdToPrint = null; - if (iccId != null) { - if (iccId.length() > 9 && !TelephonyUtils.IS_DEBUGGABLE) { - iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9)); + @Nullable + public static String getPrintableId(@Nullable String id) { + String idToPrint = null; + if (id != null) { + if (id.length() > 9 && !TelephonyUtils.IS_DEBUGGABLE) { + idToPrint = id.substring(0, 9) + Rlog.pii(false, id.substring(9)); } else { - iccIdToPrint = iccId; + idToPrint = id; } } - return iccIdToPrint; + return idToPrint; } @Override public String toString() { - String iccIdToPrint = givePrintableIccid(mIccId); - String cardStringToPrint = givePrintableIccid(mCardString); + String iccIdToPrint = getPrintableId(mIccId); + String cardStringToPrint = getPrintableId(mCardString); return "[SubscriptionInfo: id=" + mId + " iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex @@ -1536,7 +1537,7 @@ public class SubscriptionInfo implements Parcelable { */ @NonNull public Builder setGroupUuid(@Nullable String groupUuid) { - mGroupUuid = groupUuid == null ? null : ParcelUuid.fromString(groupUuid); + mGroupUuid = TextUtils.isEmpty(groupUuid) ? null : ParcelUuid.fromString(groupUuid); return this; } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 96dc44a5f9fa..64e43568e4d6 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -91,8 +91,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; /** - * SubscriptionManager is the application interface to SubscriptionController - * and provides information about the current Telephony Subscriptions. + * Subscription manager provides the mobile subscription information. */ @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @@ -119,13 +118,12 @@ public class SubscriptionManager { public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE; /** - * Indicates the caller wants the default phone id. - * Used in SubscriptionController and Phone but do we really need it??? + * Indicates the default phone id. * @hide */ public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE; - /** Indicates the caller wants the default slot id. NOT used remove? */ + /** Indicates the default slot index. */ /** @hide */ public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE; @@ -141,29 +139,10 @@ public class SubscriptionManager { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final Uri CONTENT_URI = SimInfo.CONTENT_URI; - private static final String CACHE_KEY_DEFAULT_SUB_ID_PROPERTY = - "cache_key.telephony.get_default_sub_id"; - - private static final String CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY = - "cache_key.telephony.get_default_data_sub_id"; - - private static final String CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY = - "cache_key.telephony.get_default_sms_sub_id"; - - private static final String CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY = - "cache_key.telephony.get_active_data_sub_id"; - - private static final String CACHE_KEY_SLOT_INDEX_PROPERTY = - "cache_key.telephony.get_slot_index"; - /** The IPC cache key shared by all subscription manager service cacheable properties. */ private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY = "cache_key.telephony.subscription_manager_service"; - /** The temporarily cache key to indicate whether subscription manager service is enabled. */ - private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY = - "cache_key.telephony.subscription_manager_service_enabled"; - /** @hide */ public static final String GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME = "getSimSpecificSettings"; @@ -199,13 +178,24 @@ public class SubscriptionManager { } @Override - public T recompute(Void aVoid) { + public T recompute(Void query) { + // This always throws on any error. The exceptions must be handled outside + // the cache. + try { + return mInterfaceMethod.applyOrThrow(TelephonyManager.getSubscriptionService()); + } catch (Exception re) { + throw new RuntimeException(re); + } + } + + @Override + public T query(Void query) { T result = mDefaultValue; try { ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { - result = mInterfaceMethod.applyOrThrow(iSub); + result = super.query(query); } } catch (Exception ex) { Rlog.w(LOG_TAG, "Failed to recompute cache key for " + mCacheKeyProperty); @@ -234,12 +224,24 @@ public class SubscriptionManager { @Override public T recompute(Integer query) { + // This always throws on any error. The exceptions must be handled outside + // the cache. + try { + return mInterfaceMethod.applyOrThrow( + TelephonyManager.getSubscriptionService(), query); + } catch (Exception re) { + throw new RuntimeException(re); + } + } + + @Override + public T query(Integer query) { T result = mDefaultValue; try { ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { - result = mInterfaceMethod.applyOrThrow(iSub, query); + result = super.query(query); } } catch (Exception ex) { Rlog.w(LOG_TAG, "Failed to recompute cache key for " + mCacheKeyProperty); @@ -250,83 +252,41 @@ public class SubscriptionManager { } } - private static VoidPropertyInvalidatedCache<Integer> sDefaultSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId, - CACHE_KEY_DEFAULT_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSubIdCache = new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sDefaultDataSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId, - CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultDataSubIdCache = new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sDefaultSmsSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId, - CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSmsSubIdCache = new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sActiveDataSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId, - CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetActiveDataSubscriptionIdCache = new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static IntegerPropertyInvalidatedCache<Integer> sSlotIndexCache = - new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex, - CACHE_KEY_SLOT_INDEX_PROPERTY, - INVALID_SIM_SLOT_INDEX); - private static IntegerPropertyInvalidatedCache<Integer> sGetSlotIndexCache = new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SIM_SLOT_INDEX); - private static IntegerPropertyInvalidatedCache<Integer> sSubIdCache = - new IntegerPropertyInvalidatedCache<>(ISub::getSubId, - CACHE_KEY_SLOT_INDEX_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static IntegerPropertyInvalidatedCache<Integer> sGetSubIdCache = new IntegerPropertyInvalidatedCache<>(ISub::getSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - /** Cache depends on getDefaultSubId, so we use the defaultSubId cache key */ - private static IntegerPropertyInvalidatedCache<Integer> sPhoneIdCache = - new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId, - CACHE_KEY_DEFAULT_SUB_ID_PROPERTY, - INVALID_PHONE_INDEX); - private static IntegerPropertyInvalidatedCache<Integer> sGetPhoneIdCache = new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_PHONE_INDEX); - //TODO: Removed before U AOSP public release. - private static VoidPropertyInvalidatedCache<Boolean> sIsSubscriptionManagerServiceEnabled = - new VoidPropertyInvalidatedCache<>(ISub::isSubscriptionManagerServiceEnabled, - CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY, - false); - /** * Generates a content {@link Uri} used to receive updates on simInfo change * on the given subscriptionId @@ -1432,17 +1392,6 @@ public class SubscriptionManager { mContext = context; } - /** - * @return {@code true} if the new subscription manager service is used. This is temporary and - * will be removed before Android 14 release. - * - * @hide - */ - //TODO: Removed before U AOSP public release. - public static boolean isSubscriptionManagerServiceEnabled() { - return sIsSubscriptionManagerServiceEnabled.query(null); - } - private NetworkPolicyManager getNetworkPolicyManager() { return (NetworkPolicyManager) mContext .getSystemService(Context.NETWORK_POLICY_SERVICE); @@ -1497,7 +1446,7 @@ public class SubscriptionManager { + " listener=" + listener); } // We use the TelephonyRegistry as it runs in the system and thus is always - // available. Where as SubscriptionController could crash and not be available + // available. TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { @@ -1527,7 +1476,7 @@ public class SubscriptionManager { + " listener=" + listener); } // We use the TelephonyRegistry as it runs in the system and thus is always - // available where as SubscriptionController could crash and not be available + // available. TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { @@ -1585,7 +1534,7 @@ public class SubscriptionManager { } // We use the TelephonyRegistry as it runs in the system and thus is always - // available where as SubscriptionController could crash and not be available + // available. TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { @@ -2126,9 +2075,9 @@ public class SubscriptionManager { Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null"); return; } - int result = iSub.removeSubInfo(uniqueId, subscriptionType); - if (result < 0) { - Log.e(LOG_TAG, "Removal of subscription didn't succeed: error = " + result); + boolean result = iSub.removeSubInfo(uniqueId, subscriptionType); + if (!result) { + Log.e(LOG_TAG, "Removal of subscription didn't succeed"); } else { logd("successfully removed subscription"); } @@ -2213,8 +2162,7 @@ public class SubscriptionManager { * subscriptionId doesn't have an associated slot index. */ public static int getSlotIndex(int subscriptionId) { - if (isSubscriptionManagerServiceEnabled()) return sGetSlotIndexCache.query(subscriptionId); - return sSlotIndexCache.query(subscriptionId); + return sGetSlotIndexCache.query(subscriptionId); } /** @@ -2271,15 +2219,13 @@ public class SubscriptionManager { return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } - if (isSubscriptionManagerServiceEnabled()) return sGetSubIdCache.query(slotIndex); - return sSubIdCache.query(slotIndex); + return sGetSubIdCache.query(slotIndex); } /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public static int getPhoneId(int subId) { - if (isSubscriptionManagerServiceEnabled()) return sGetPhoneIdCache.query(subId); - return sPhoneIdCache.query(subId); + return sGetPhoneIdCache.query(subId); } private static void logd(String msg) { @@ -2300,8 +2246,7 @@ public class SubscriptionManager { * @return the "system" default subscription id. */ public static int getDefaultSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSubIdCache.query(null); - return sDefaultSubIdCache.query(null); + return sGetDefaultSubIdCache.query(null); } /** @@ -2389,8 +2334,7 @@ public class SubscriptionManager { * @return the default SMS subscription Id. */ public static int getDefaultSmsSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSmsSubIdCache.query(null); - return sDefaultSmsSubIdCache.query(null); + return sGetDefaultSmsSubIdCache.query(null); } /** @@ -2424,8 +2368,7 @@ public class SubscriptionManager { * @return the default data subscription Id. */ public static int getDefaultDataSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) return sGetDefaultDataSubIdCache.query(null); - return sDefaultDataSubIdCache.query(null); + return sGetDefaultDataSubIdCache.query(null); } /** @@ -2663,10 +2606,10 @@ public class SubscriptionManager { * @param columnName Column name in subscription database. * * @return Value in string format associated with {@code subscriptionId} and {@code columnName} - * from the database. + * from the database. Empty string if the {@code subscriptionId} is invalid (for backward + * compatible). * - * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not - * exposed. + * @throws IllegalArgumentException if the field is not exposed. * * @see android.provider.Telephony.SimInfo for all the columns. * @@ -3119,10 +3062,10 @@ public class SubscriptionManager { * * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} returns * true). To check for permissions for non-embedded subscription as well, + * see {@link 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) { @@ -3136,12 +3079,12 @@ public class SubscriptionManager { * * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} returns * true). To check for permissions for non-embedded subscription as well, + * see {@link 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 */ @@ -3298,12 +3241,13 @@ public class SubscriptionManager { * @param subId sub id * @param callbackIntent pending intent that will be sent after operation is done. * - * to-be-deprecated this API is a duplicate of {@link EuiccManager#switchToSubscription(int, + * @deprecated this API is a duplicate of {@link EuiccManager#switchToSubscription(int, * PendingIntent)} and does not support Multiple Enabled Profile(MEP). Apps should use * {@link EuiccManager#switchToSubscription(int, PendingIntent)} or * {@link EuiccManager#switchToSubscription(int, int, PendingIntent)} instead. */ @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) + @Deprecated public void switchToSubscription(int subId, @NonNull PendingIntent callbackIntent) { Preconditions.checkNotNull(callbackIntent, "callbackIntent cannot be null"); EuiccManager euiccManager = new EuiccManager(mContext); @@ -3507,8 +3451,8 @@ public class SubscriptionManager { * or carrier privilege permission on the subscription. * {@link TelephonyManager#hasCarrierPrivileges()} * - * <p>Starting with API level 33, this method will return an empty List if the caller does - * not have access to device identifiers. + * <p>Starting with API level 33, the caller also needs permission to access device identifiers + * to get the list of subscriptions associated with a group UUID. * This method can be invoked if one of the following requirements is met: * <ul> * <li>If the app has carrier privilege permission. @@ -3888,10 +3832,7 @@ public class SubscriptionManager { * @see TelephonyCallback.ActiveDataSubscriptionIdListener */ public static int getActiveDataSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) { - return sGetActiveDataSubscriptionIdCache.query(null); - } - return sActiveDataSubIdCache.query(null); + return sGetActiveDataSubscriptionIdCache.query(null); } /** @@ -3910,56 +3851,16 @@ public class SubscriptionManager { } /** @hide */ - public static void invalidateDefaultSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SUB_ID_PROPERTY); - } - - /** @hide */ - public static void invalidateDefaultDataSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY); - } - - /** @hide */ - public static void invalidateDefaultSmsSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY); - } - - /** @hide */ - public static void invalidateActiveDataSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY); - } - - /** @hide */ - public static void invalidateSlotIndexCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SLOT_INDEX_PROPERTY); - } - - /** @hide */ public static void invalidateSubscriptionManagerServiceCaches() { PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY); } - /** @hide */ - //TODO: Removed before U AOSP public release. - public static void invalidateSubscriptionManagerServiceEnabledCaches() { - PropertyInvalidatedCache.invalidateCache( - CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY); - } - /** * Allows a test process to disable client-side caching operations. * * @hide */ public static void disableCaching() { - sDefaultSubIdCache.disableLocal(); - sDefaultDataSubIdCache.disableLocal(); - sActiveDataSubIdCache.disableLocal(); - sDefaultSmsSubIdCache.disableLocal(); - sSlotIndexCache.disableLocal(); - sSubIdCache.disableLocal(); - sPhoneIdCache.disableLocal(); - sGetDefaultSubIdCache.disableLocal(); sGetDefaultDataSubIdCache.disableLocal(); sGetActiveDataSubscriptionIdCache.disableLocal(); @@ -3967,8 +3868,6 @@ public class SubscriptionManager { sGetSlotIndexCache.disableLocal(); sGetSubIdCache.disableLocal(); sGetPhoneIdCache.disableLocal(); - - sIsSubscriptionManagerServiceEnabled.disableLocal(); } /** @@ -3976,14 +3875,6 @@ public class SubscriptionManager { * * @hide */ public static void clearCaches() { - sDefaultSubIdCache.clear(); - sDefaultDataSubIdCache.clear(); - sActiveDataSubIdCache.clear(); - sDefaultSmsSubIdCache.clear(); - sSlotIndexCache.clear(); - sSubIdCache.clear(); - sPhoneIdCache.clear(); - sGetDefaultSubIdCache.clear(); sGetDefaultDataSubIdCache.clear(); sGetActiveDataSubscriptionIdCache.clear(); @@ -3991,8 +3882,6 @@ public class SubscriptionManager { sGetSlotIndexCache.clear(); sGetSubIdCache.clear(); sGetPhoneIdCache.clear(); - - sIsSubscriptionManagerServiceEnabled.clear(); } /** @@ -4331,7 +4220,6 @@ public class SubscriptionManager { * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public void setSubscriptionUserHandle(int subscriptionId, @Nullable UserHandle userHandle) { if (!isValidSubscriptionId(subscriptionId)) { @@ -4363,11 +4251,9 @@ public class SubscriptionManager { * * @throws IllegalArgumentException if subscription is invalid. * @throws SecurityException if the caller doesn't have permissions required. - * @throws IllegalStateException if subscription service is not available. * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public @Nullable UserHandle getSubscriptionUserHandle(int subscriptionId) { if (!isValidSubscriptionId(subscriptionId)) { @@ -4380,8 +4266,7 @@ public class SubscriptionManager { if (iSub != null) { return iSub.getSubscriptionUserHandle(subscriptionId); } else { - throw new IllegalStateException("[getSubscriptionUserHandle]: " - + "subscription service unavailable"); + Log.e(LOG_TAG, "[getSubscriptionUserHandle]: subscription service unavailable"); } } catch (RemoteException ex) { ex.rethrowAsRuntimeException(); @@ -4400,7 +4285,6 @@ public class SubscriptionManager { * * @throws IllegalArgumentException if subscription is invalid. * @throws SecurityException if the caller doesn't have permissions required. - * @throws IllegalStateException if subscription service is not available. * * @hide */ @@ -4417,8 +4301,8 @@ public class SubscriptionManager { if (iSub != null) { return iSub.isSubscriptionAssociatedWithUser(subscriptionId, userHandle); } else { - throw new IllegalStateException("[isSubscriptionAssociatedWithUser]: " - + "subscription service unavailable"); + Log.e(LOG_TAG, "[isSubscriptionAssociatedWithUser]: subscription service " + + "unavailable"); } } catch (RemoteException ex) { ex.rethrowAsRuntimeException(); @@ -4445,7 +4329,7 @@ public class SubscriptionManager { if (iSub != null) { return iSub.getSubscriptionInfoListAssociatedWithUser(userHandle); } else { - throw new IllegalStateException("[getSubscriptionInfoListAssociatedWithUser]: " + Log.e(LOG_TAG, "[getSubscriptionInfoListAssociatedWithUser]: " + "subscription service unavailable"); } } catch (RemoteException ex) { @@ -4454,4 +4338,3 @@ public class SubscriptionManager { return new ArrayList<>(); } } - diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java index 8308821b59ff..c2f5b8f3e7da 100644 --- a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java +++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java @@ -23,6 +23,7 @@ import android.os.TelephonyServiceManager; import android.telephony.euicc.EuiccCardManager; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsManager; +import android.telephony.satellite.SatelliteManager; import com.android.internal.util.Preconditions; @@ -98,6 +99,11 @@ public class TelephonyFrameworkInitializer { context -> SmsManager.getSmsManagerForContextAndSubscriptionId(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) ); + SystemServiceRegistry.registerContextAwareService( + Context.SATELLITE_SERVICE, + SatelliteManager.class, + context -> new SatelliteManager(context) + ); } /** @hide */ diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index fa60031f2a66..2a6099a18fab 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -54,6 +54,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -125,7 +126,6 @@ import com.android.internal.telephony.IccLogicalChannelRequest; import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.SmsApplication; import com.android.telephony.Rlog; import java.io.IOException; @@ -140,6 +140,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -234,6 +235,54 @@ public class TelephonyManager { public static final int NETWORK_SELECTION_MODE_AUTO = 1; public static final int NETWORK_SELECTION_MODE_MANUAL = 2; + /** + * Reasons for Radio being powered off. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"RADIO_POWER_REASON_"}, + value = { + RADIO_POWER_REASON_USER, + RADIO_POWER_REASON_THERMAL, + RADIO_POWER_REASON_CARRIER, + RADIO_POWER_REASON_NEARBY_DEVICE}) + public @interface RadioPowerReason {} + + /** + * This reason is used when users want to turn off radio, e.g., users turn on airplane mode. + * + * @hide + */ + @SystemApi + public static final int RADIO_POWER_REASON_USER = 0; + /** + * This reason is used when radio needs to be turned off due to thermal. + * + * @hide + */ + @SystemApi + public static final int RADIO_POWER_REASON_THERMAL = 1; + /** + * This reason is used when carriers want to turn off radio. A privileged app can request to + * turn off radio via the system service + * {@link com.android.carrierdefaultapp.CaptivePortalLoginActivity}, which subsequently calls + * the system APIs {@link requestRadioPowerOffForReason} and + * {@link clearRadioPowerOffForReason}. + * + * @hide + */ + @SystemApi + public static final int RADIO_POWER_REASON_CARRIER = 2; + /** + * Used to reduce power on a battery-constrained device when Telephony services are available + * via a paired device which is nearby. + * + * @hide + */ + @SystemApi + public static final int RADIO_POWER_REASON_NEARBY_DEVICE = 3; + /** The otaspMode passed to PhoneStateListener#onOtaspChanged */ /** @hide */ static public final int OTASP_UNINITIALIZED = 0; @@ -364,6 +413,9 @@ public class TelephonyManager { /** @hide */ public static final int INVALID_PORT_INDEX = -1; + /** @hide */ + public static final String PROPERTY_ENABLE_NULL_CIPHER_TOGGLE = "enable_null_cipher_toggle"; + private final Context mContext; private final int mSubId; @UnsupportedAppUsage @@ -2909,7 +2961,11 @@ public class TelephonyManager { public static final int NETWORK_TYPE_HSUPA = TelephonyProtoEnums.NETWORK_TYPE_HSUPA; // = 9. /** Current network is HSPA */ public static final int NETWORK_TYPE_HSPA = TelephonyProtoEnums.NETWORK_TYPE_HSPA; // = 10. - /** Current network is iDen */ + /** + * Current network is iDen + * @deprecated Legacy network type no longer being used starting in Android U. + */ + @Deprecated public static final int NETWORK_TYPE_IDEN = TelephonyProtoEnums.NETWORK_TYPE_IDEN; // = 11. /** Current network is EVDO revision B*/ public static final int NETWORK_TYPE_EVDO_B = TelephonyProtoEnums.NETWORK_TYPE_EVDO_B; // = 12. @@ -3257,15 +3313,14 @@ public class TelephonyManager { case NETWORK_TYPE_TD_SCDMA: return NETWORK_TYPE_BITMASK_TD_SCDMA; case NETWORK_TYPE_LTE: - return NETWORK_TYPE_BITMASK_LTE; case NETWORK_TYPE_LTE_CA: - return NETWORK_TYPE_BITMASK_LTE_CA; + return NETWORK_TYPE_BITMASK_LTE; case NETWORK_TYPE_NR: return NETWORK_TYPE_BITMASK_NR; case NETWORK_TYPE_IWLAN: return NETWORK_TYPE_BITMASK_IWLAN; case NETWORK_TYPE_IDEN: - return (1 << (NETWORK_TYPE_IDEN - 1)); + return NETWORK_TYPE_BITMASK_IDEN; default: return NETWORK_TYPE_BITMASK_UNKNOWN; } @@ -3456,7 +3511,15 @@ public class TelephonyManager { public static final String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE"; /** - * @return true if a ICC card is present + * This API is used to check if there is an ICC card present in the device. + * + * An ICC card is a smart card that contains a subscriber identity module (SIM) and is used + * to identify and authenticate users to a mobile network. + * + * Note: In case of embedded SIM there is an ICC card always present irrespective + * of whether an active SIM profile is present or not so this API would always return true. + * + * @return true if a ICC card is present. */ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) public boolean hasIccCard() { @@ -4847,7 +4910,7 @@ public class TelephonyManager { return; } ParcelUuid resultUuid = - result.getParcelable(KEY_CALL_COMPOSER_PICTURE_HANDLE); + result.getParcelable(KEY_CALL_COMPOSER_PICTURE_HANDLE, android.os.ParcelUuid.class); if (resultUuid == null) { Log.e(TAG, "Got null uuid without an error" + " while uploading call composer pic"); @@ -5945,6 +6008,7 @@ public class TelephonyManager { * Returns the IMS private user identity (IMPI) that was loaded from the ISIM. * @return the IMPI, or null if not present or not loaded * @hide + * @deprecated use {@link #getImsPrivateUserIdentity()} */ @UnsupportedAppUsage public String getIsimImpi() { @@ -5963,6 +6027,35 @@ public class TelephonyManager { } /** + * Returns the IMS private user identity (IMPI) of the subscription that was loaded from the + * ISIM records {@link #APPTYPE_ISIM}. This value is fetched from the Elementary file EF_IMPI. + * The contents of the file is a <b>Ip Multimedia Service Private User Identity</b> of the user + * as defined in the section 4.2.2 of 3GPP TS 131 103. + * + * @return IMPI (IMS private user identity) of type string. + * @throws IllegalStateException in case the ISIM has’t been loaded + * @throws SecurityException if the caller does not have the required permission/privileges + * @hide + */ + @NonNull + @RequiresPermission(android.Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) + public String getImsPrivateUserIdentity() { + try { + IPhoneSubInfo info = getSubscriberInfoService(); + if (info == null) { + Rlog.e(TAG, "getImsPrivateUserIdentity(): IPhoneSubInfo instance is NULL"); + throw new RuntimeException("IMPI error: Subscriber Info is null"); + } + return info.getImsPrivateUserIdentity(getSubId(), getOpPackageName(), + getAttributionTag()); + } catch (RemoteException | NullPointerException | IllegalArgumentException ex) { + Rlog.e(TAG, "getImsPrivateUserIdentity() Exception = " + ex); + throw new RuntimeException(ex.getMessage()); + } + } + + /** * Returns the IMS home network domain name that was loaded from the ISIM {@see #APPTYPE_ISIM}. * @return the IMS domain name. Returns {@code null} if ISIM hasn't been loaded or IMS domain * hasn't been loaded or isn't present on the ISIM. @@ -5995,6 +6088,7 @@ public class TelephonyManager { * @return an array of IMPU strings, with one IMPU per string, or null if * not present or not loaded * @hide + * @deprecated use {@link #getImsPublicUserIdentities()} */ @UnsupportedAppUsage @Nullable @@ -6015,6 +6109,39 @@ public class TelephonyManager { } /** + * Returns the IMS public user identities (IMPU) of the subscription that was loaded from the + * ISIM records {@link #APPTYPE_ISIM}. This value is fetched from the Elementary file EF_IMPU. + * The contents of the file are <b>Ip Multimedia Service Public User Identities</b> of the user + * as defined in the section 4.2.4 of 3GPP TS 131 103. It contains one or more records. + * + * @return List of public user identities of type android.net.Uri or empty list if + * EF_IMPU is not available. + * @throws IllegalStateException in case the ISIM hasn’t been loaded + * @throws SecurityException if the caller does not have the required permission/privilege + * @hide + */ + @NonNull + @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_NUMBERS, + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) + public List<Uri> getImsPublicUserIdentities() { + try { + IPhoneSubInfo info = getSubscriberInfoService(); + if (info == null) { + throw new RuntimeException("IMPU error: Subscriber Info is null"); + } + return info.getImsPublicUserIdentities(getSubId(), getOpPackageName(), + getAttributionTag()); + } catch (IllegalArgumentException | NullPointerException ex) { + Rlog.e(TAG, "getImsPublicUserIdentities Exception = " + ex); + } catch (RemoteException ex) { + Rlog.e(TAG, "getImsPublicUserIdentities Exception = " + ex); + ex.rethrowAsRuntimeException(); + } + return Collections.EMPTY_LIST; + } + + /** * Device call state: No activity. */ public static final int CALL_STATE_IDLE = 0; @@ -6784,11 +6911,11 @@ public class TelephonyManager { * * @hide */ - public void setCellInfoListRate(int rateInMillis) { + public void setCellInfoListRate(int rateInMillis, int subId) { try { ITelephony telephony = getITelephony(); if (telephony != null) - telephony.setCellInfoListRate(rateInMillis); + telephony.setCellInfoListRate(rateInMillis, subId); } catch (RemoteException ex) { } catch (NullPointerException ex) { } @@ -7684,7 +7811,7 @@ public class TelephonyManager { * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * TODO: remove this one. use {@link #rebootModem()} for reset type 1 and - * {@link #resetRadioConfig()} for reset type 3 + * {@link #resetRadioConfig()} for reset type 3 (b/116476729) * * @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset * @return true on success; false on any failure. @@ -8184,6 +8311,37 @@ public class TelephonyManager { public static final int AUTHTYPE_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM; /** Authentication type for UICC challenge is EAP AKA. See RFC 4187 for details. */ public static final int AUTHTYPE_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA; + /** + * Authentication type for GBA Bootstrap Challenge. + * Pass this authentication type into the {@link #getIccAuthentication} API to perform a GBA + * Bootstrap challenge (BSF), with {@code data} (generated according to the procedure defined in + * 3GPP 33.220 Section 5.3.2 step.4) in base64 encoding. + * This method will return the Bootstrapping response in base64 encoding when ICC authentication + * is completed. + * Ref 3GPP 33.220 Section 5.3.2. + */ + public static final int AUTHTYPE_GBA_BOOTSTRAP = PhoneConstants.AUTH_CONTEXT_GBA_BOOTSTRAP; + /** + * Authentication type for GBA Network Application Functions (NAF) key External Challenge. + * Pass this authentication type into the {@link #getIccAuthentication} API to perform a GBA + * Network Applications Functions (NAF) key External challenge using the NAF_ID parameter + * as the {@code data} in base64 encoding. + * This method will return the Ks_Ext_Naf key in base64 encoding when ICC authentication + * is completed. + * Ref 3GPP 33.220 Section 5.3.2. + */ + public static final int AUTHTYPE_GBA_NAF_KEY_EXTERNAL = + PhoneConstants.AUTHTYPE_GBA_NAF_KEY_EXTERNAL; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + AUTHTYPE_EAP_SIM, + AUTHTYPE_EAP_AKA, + AUTHTYPE_GBA_BOOTSTRAP, + AUTHTYPE_GBA_NAF_KEY_EXTERNAL + }) + public @interface AuthType {} /** * Returns the response of authentication for the default subscription. @@ -8198,8 +8356,9 @@ public class TelephonyManager { * </ul> * * @param appType the icc application type, like {@link #APPTYPE_USIM} - * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or - * {@link #AUTHTYPE_EAP_SIM} + * @param authType the authentication type, any one of {@link #AUTHTYPE_EAP_AKA} or + * {@link #AUTHTYPE_EAP_SIM} or {@link #AUTHTYPE_GBA_BOOTSTRAP} or + * {@link #AUTHTYPE_GBA_NAF_KEY_EXTERNAL} * @param data authentication challenge data, base64 encoded. * See 3GPP TS 31.102 7.1.2 for more details. * @return the response of authentication. This value will be null in the following cases: @@ -8213,7 +8372,7 @@ public class TelephonyManager { // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since // it's not public API. @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) - public String getIccAuthentication(int appType, int authType, String data) { + public String getIccAuthentication(int appType,@AuthType int authType, String data) { return getIccAuthentication(getSubId(), appType, authType, data); } @@ -8226,8 +8385,9 @@ public class TelephonyManager { * * @param subId subscription ID used for authentication * @param appType the icc application type, like {@link #APPTYPE_USIM} - * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or - * {@link #AUTHTYPE_EAP_SIM} + * @param authType the authentication type, any one of {@link #AUTHTYPE_EAP_AKA} or + * {@link #AUTHTYPE_EAP_SIM} or {@link #AUTHTYPE_GBA_BOOTSTRAP} or + * {@link #AUTHTYPE_GBA_NAF_KEY_EXTERNAL} * @param data authentication challenge data, base64 encoded. * See 3GPP TS 31.102 7.1.2 for more details. * @return the response of authentication. This value will be null in the following cases only @@ -8240,7 +8400,7 @@ public class TelephonyManager { * @hide */ @UnsupportedAppUsage - public String getIccAuthentication(int subId, int appType, int authType, String data) { + public String getIccAuthentication(int subId, int appType,@AuthType int authType, String data) { try { IPhoneSubInfo info = getSubscriberInfoService(); if (info == null) @@ -8333,6 +8493,51 @@ public class TelephonyManager { } /** + * Fetches the sim service table from the EFUST/EFIST based on the application type + * {@link #APPTYPE_USIM} or {@link #APPTYPE_ISIM}. The return value is hexaString format + * representing X bytes (x >= 1). Each bit of every byte indicates which optional services + * are available for the given application type. + * The USIM service table EF is described in as per Section 4.2.8 of 3GPP TS 31.102. + * The ISIM service table EF is described in as per Section 4.2.7 of 3GPP TS 31.103. + * The list of services mapped to the exact nth byte of response as mentioned in Section 4.2 + * .7 of 3GPP TS 31.103. Eg. Service n°1: Local Phone Book, Service n°2: Fixed Dialling + * Numbers (FDN) - Bit 1 and 2 of the 1st Byte represent service Local Phone Book and Fixed + * Dialling Numbers (FDN)respectively. The coding format for each service type should be + * interpreted as bit = 1: service available;bit = 0:service not available. + * + * @param appType of type int of either {@link #APPTYPE_USIM} or {@link #APPTYPE_ISIM}. + * @return HexString represents sim service table else null. + * @throws SecurityException if the caller does not have the required permission/privileges + * @hide + */ + + @Nullable + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) + public String getSimServiceTable(int appType) { + try { + IPhoneSubInfo info = getSubscriberInfoService(); + if (info == null) { + Rlog.e(TAG, "getSimServiceTable(): IPhoneSubInfo is null"); + return null; + } + //Fetches the sim service table based on subId and appType + if (appType == APPTYPE_ISIM) { + return info.getIsimIst(getSubId()); + } else if ((appType == APPTYPE_USIM)) { + return info.getSimServiceTable(getSubId(), APPTYPE_USIM); + } else { + return null; + } + } catch (RemoteException ex) { + Rlog.e(TAG, "getSimServiceTable(): RemoteException=" + ex.getMessage()); + } catch (NullPointerException ex) { + Rlog.e(TAG, "getSimServiceTable(): NullPointerException=" + ex.getMessage()); + } + return null; + } + + /** * Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot. * Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to * recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad @@ -9299,7 +9504,6 @@ public class TelephonyManager { ALLOWED_NETWORK_TYPES_REASON_POWER, ALLOWED_NETWORK_TYPES_REASON_CARRIER, ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, - ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, }) @Retention(RetentionPolicy.SOURCE) public @interface AllowedNetworkTypesReason { @@ -9338,15 +9542,6 @@ public class TelephonyManager { public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; /** - * To indicate allowed network type change is requested by an update to the - * {@link android.os.UserManager.DISALLOW_CELLULAR_2G} user restriction. - * - * @hide - */ - @SystemApi - public static final int ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS = 4; - - /** * Set the allowed network types of the device and provide the reason triggering the allowed * network change. * <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or @@ -9370,7 +9565,6 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE} permissions. * <ol> * <li>{@code TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}</li> - * <li>{@code TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS}</li> * </ol> */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -9445,7 +9639,6 @@ public class TelephonyManager { case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: - case ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS: return true; } return false; @@ -10312,7 +10505,7 @@ public class TelephonyManager { protected void onReceiveResult(int resultCode, Bundle ussdResponse) { Rlog.d(TAG, "USSD:" + resultCode); checkNotNull(ussdResponse, "ussdResponse cannot be null."); - UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE); + UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE, android.telephony.UssdResponse.class); if (resultCode == USSD_RETURN_SUCCESS) { callback.onReceiveUssdResponse(telephonyManager, response.getUssdRequest(), @@ -10398,34 +10591,155 @@ public class TelephonyManager { } } - /** @hide */ + /** + * @deprecated - use the APIs {@link requestRadioPowerOffForReason} and + * {@link clearRadioPowerOffForReason}. + * + * @hide + */ + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean setRadio(boolean turnOn) { + boolean result = true; + try { + if (turnOn) { + clearRadioPowerOffForReason(RADIO_POWER_REASON_USER); + } else { + requestRadioPowerOffForReason(RADIO_POWER_REASON_USER); + } + } catch (Exception e) { + String calledFunction = + turnOn ? "clearRadioPowerOffForReason" : "requestRadioPowerOffForReason"; + Log.e(TAG, "Error calling " + calledFunction, e); + result = false; + } + return result; + } + + /** + * @deprecated - use the APIs {@link requestRadioPowerOffForReason} and + * {@link clearRadioPowerOffForReason}. + * + * @hide + */ + @Deprecated + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) + public boolean setRadioPower(boolean turnOn) { + boolean result = true; + try { + if (turnOn) { + clearRadioPowerOffForReason(RADIO_POWER_REASON_USER); + } else { + requestRadioPowerOffForReason(RADIO_POWER_REASON_USER); + } + } catch (Exception e) { + String calledFunction = + turnOn ? "clearRadioPowerOffForReason" : "requestRadioPowerOffForReason"; + Log.e(TAG, "Error calling " + calledFunction, e); + result = false; + } + return result; + } + + /** + * Vote on powering off the radio for a reason. The radio will be turned on only when there is + * no reason to power it off. When any of the voters want to power it off, it will be turned + * off. In case of emergency, the radio will be turned on even if there are some reasons for + * powering it off, and these radio off votes will be cleared. + * Multiple apps can vote for the same reason and the last vote will take effect. Each app is + * responsible for its vote. A powering-off vote of a reason will be maintained until it is + * cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call + * is made, or the device is rebooted. When an app comes backup from a crash, it needs to make + * sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to + * check its vote. + * + * @param reason The reason for powering off radio. + * @throws SecurityException if the caller does not have MODIFY_PHONE_STATE permission. + * @throws IllegalStateException if the Telephony service is not currently available. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) + public void requestRadioPowerOffForReason(@RadioPowerReason int reason) { try { ITelephony telephony = getITelephony(); - if (telephony != null) - return telephony.setRadio(turnOn); + if (telephony != null) { + if (!telephony.requestRadioPowerOffForReason(getSubId(), reason)) { + throw new IllegalStateException("Telephony service is not available."); + } + } else { + throw new IllegalStateException("Telephony service is null."); + } } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#setRadio", e); + Log.e(TAG, "Error calling ITelephony#requestRadioPowerOffForReason", e); + e.rethrowAsRuntimeException(); } - return false; } - /** @hide */ + /** + * Remove the vote on powering off the radio for a reason, as requested by + * {@link requestRadioPowerOffForReason}. + * + * @param reason The reason for powering off radio. + * @throws SecurityException if the caller does not have MODIFY_PHONE_STATE permission. + * @throws IllegalStateException if the Telephony service is not currently available. + * + * @hide + */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) - public boolean setRadioPower(boolean turnOn) { + public void clearRadioPowerOffForReason(@RadioPowerReason int reason) { try { ITelephony telephony = getITelephony(); - if (telephony != null) - return telephony.setRadioPower(turnOn); + if (telephony != null) { + if (!telephony.clearRadioPowerOffForReason(getSubId(), reason)) { + throw new IllegalStateException("Telephony service is not available."); + } + } else { + throw new IllegalStateException("Telephony service is null."); + } } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#setRadioPower", e); + Log.e(TAG, "Error calling ITelephony#clearRadioPowerOffForReason", e); + e.rethrowAsRuntimeException(); } - return false; + } + + /** + * Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}. + * If the reason set is empty, the radio is on in all cases. + * + * @return Set of reasons for powering off radio. + * @throws SecurityException if the caller does not have READ_PRIVILEGED_PHONE_STATE permission. + * @throws IllegalStateException if the Telephony service is not currently available. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) + @NonNull + public Set<Integer> getRadioPowerOffReasons() { + Set<Integer> result = new HashSet<>(); + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + result.addAll(telephony.getRadioPowerOffReasons(getSubId(), + mContext.getOpPackageName(), mContext.getAttributionTag())); + } else { + throw new IllegalStateException("Telephony service is null."); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#getRadioPowerOffReasons", e); + e.rethrowAsRuntimeException(); + } + return result; } /** @@ -11703,8 +12017,9 @@ public class TelephonyManager { } /** - * Gets the default Respond Via Message application, updating the cache if there is no - * respond-via-message application currently configured. + * Get the component name of the default app to direct respond-via-message intent for the + * user associated with this subscription, update the cache if there is no respond-via-message + * application currently configured for this user. * @return component name of the app and class to direct Respond Via Message intent to, or * {@code null} if the functionality is not supported. * @hide @@ -11713,11 +12028,20 @@ public class TelephonyManager { @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public @Nullable ComponentName getAndUpdateDefaultRespondViaMessageApplication() { - return SmsApplication.getDefaultRespondViaMessageApplication(mContext, true); + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getDefaultRespondViaMessageApplication(getSubId(), true); + } + } catch (RemoteException e) { + Log.e(TAG, "Error in getAndUpdateDefaultRespondViaMessageApplication: " + e); + } + return null; } /** - * Gets the default Respond Via Message application. + * Get the component name of the default app to direct respond-via-message intent for the + * user associated with this subscription. * @return component name of the app and class to direct Respond Via Message intent to, or * {@code null} if the functionality is not supported. * @hide @@ -11726,7 +12050,15 @@ public class TelephonyManager { @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) public @Nullable ComponentName getDefaultRespondViaMessageApplication() { - return SmsApplication.getDefaultRespondViaMessageApplication(mContext, false); + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getDefaultRespondViaMessageApplication(getSubId(), false); + } + } catch (RemoteException e) { + Log.e(TAG, "Error in getDefaultRespondViaMessageApplication: " + e); + } + return null; } /** @@ -12890,6 +13222,104 @@ public class TelephonyManager { } /** + * Carrier restriction status value is unknown, in case modem did not provide any + * information about carrier restriction status. + */ + public static final int CARRIER_RESTRICTION_STATUS_UNKNOWN = 0; + + /** The device is not restricted to a carrier */ + public static final int CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED = 1; + + /** The device is restricted to a carrier. */ + public static final int CARRIER_RESTRICTION_STATUS_RESTRICTED = 2; + + /** The device is restricted to the carrier of the calling application. */ + public static final int CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER = 3; + + /** @hide */ + @IntDef(prefix = {"CARRIER_RESTRICTION_STATUS_"}, value = { + CARRIER_RESTRICTION_STATUS_UNKNOWN, + CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED, + CARRIER_RESTRICTION_STATUS_RESTRICTED, + CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER + }) + + public @interface CarrierRestrictionStatus { + } + + /** + * Get the carrier restriction status of the device. + * <p>To fetch the carrier restriction status of the device the calling application needs to be + * allowlisted to Android at <a href="https://android.googlesource.com/platform/packages/services/Telephony/+/master/assets/CarrierRestrictionOperatorDetails.json">here</a>. + * The calling application also needs the READ_PHONE_STATE permission. + * The return value of the API is as follows. + * <ul> + * <li>return {@link #CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER} if the caller + * and the device locked by the network are same</li> + * <li>return {@link #CARRIER_RESTRICTION_STATUS_RESTRICTED} if the caller and the + * device locked by the network are different</li> + * <li>return {@link #CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED} if the device is + * not locked</li> + * <li>return {@link #CARRIER_RESTRICTION_STATUS_UNKNOWN} if the device locking + * state is unavailable or radio does not supports the feature</li> + * </ul> + * + * @param executor The executor on which the result listener will be called. + * @param resultListener {@link Consumer} that will be called with the result fetched + * from the radio of type {@link CarrierRestrictionStatus} + * @throws SecurityException if the caller does not have the required permission/privileges or + * if the caller is not pre-registered. + */ + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public void getCarrierRestrictionStatus(@NonNull Executor executor, + @NonNull @CarrierRestrictionStatus + Consumer<Integer> resultListener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(@CarrierRestrictionStatus int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + try { + ITelephony service = getITelephony(); + if (service != null) { + service.getCarrierRestrictionStatus(internalCallback, getOpPackageName()); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "getCarrierRestrictionStatus: RemoteException = " + ex); + throw ex.rethrowAsRuntimeException(); + } + } + + /** + * Test API to verify carrier restriction status allow list i.e. + * packages/services/Telephony/assets/CarrierRestrictionOperatorDetails.json. + * + * @param pkgName : packaga name of the entry to verify + * @param carrierId : carrier Id of the entry + * @return {@code List<String>} : list of registered shaIds + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public List<String> getShaIdFromAllowList(String pkgName, int carrierId) { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.getShaIdFromAllowList(pkgName, carrierId); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "getShaIdFromAllowList: RemoteException = " + ex); + throw ex.rethrowAsRuntimeException(); + } + return Collections.EMPTY_LIST; + } + + /** * Used to enable or disable carrier data by the system based on carrier signalling or * carrier privileged apps. Different from {@link #setDataEnabled(boolean)} which is linked to * user settings, carrier data on/off won't affect user settings but will bypass the @@ -12929,20 +13359,21 @@ public class TelephonyManager { * * @param enabled control enable or disable radio. * @see #resetAllCarrierActions() + * + * @deprecated - use the APIs {@link requestRadioPowerOffForReason} and + * {@link clearRadioPowerOffForReason}. + * * @hide */ + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public void setRadioEnabled(boolean enabled) { - try { - ITelephony service = getITelephony(); - if (service != null) { - service.carrierActionSetRadioEnabled( - getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled); - } - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#carrierActionSetRadioEnabled", e); + if (enabled) { + clearRadioPowerOffForReason(RADIO_POWER_REASON_CARRIER); + } else { + requestRadioPowerOffForReason(RADIO_POWER_REASON_CARRIER); } } @@ -13628,7 +14059,8 @@ public class TelephonyManager { NETWORK_TYPE_BITMASK_LTE, NETWORK_TYPE_BITMASK_LTE_CA, NETWORK_TYPE_BITMASK_NR, - NETWORK_TYPE_BITMASK_IWLAN + NETWORK_TYPE_BITMASK_IWLAN, + NETWORK_TYPE_BITMASK_IDEN }) public @interface NetworkTypeBitMask {} @@ -13688,6 +14120,11 @@ public class TelephonyManager { */ public static final long NETWORK_TYPE_BITMASK_HSPA = (1 << (NETWORK_TYPE_HSPA -1)); /** + * network type bitmask indicating the support of radio tech iDen. + * @hide + */ + public static final long NETWORK_TYPE_BITMASK_IDEN = (1 << (NETWORK_TYPE_IDEN - 1)); + /** * network type bitmask indicating the support of radio tech HSPAP. */ public static final long NETWORK_TYPE_BITMASK_HSPAP = (1 << (NETWORK_TYPE_HSPAP -1)); @@ -13705,12 +14142,13 @@ public class TelephonyManager { */ public static final long NETWORK_TYPE_BITMASK_LTE = (1 << (NETWORK_TYPE_LTE -1)); /** - * NOT USED; this bitmask is exposed accidentally, will be deprecated in U. + * NOT USED; this bitmask is exposed accidentally. * If used, will be converted to {@link #NETWORK_TYPE_BITMASK_LTE}. * network type bitmask indicating the support of radio tech LTE CA (carrier aggregation). * - * @see #NETWORK_TYPE_BITMASK_LTE + * @deprecated Please use {@link #NETWORK_TYPE_BITMASK_LTE} instead. Deprecated in Android U. */ + @Deprecated public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1)); /** @@ -14088,8 +14526,11 @@ public class TelephonyManager { * network; {@code false} if it is not; or throw an SecurityException if the caller does not * have the required permission/privileges * @throws IllegalStateException if the Telephony process is not currently available. + * + * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)} instead. * @hide */ + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) @@ -14484,7 +14925,10 @@ public class TelephonyManager { /** * The extra used with an {@link #ACTION_NETWORK_COUNTRY_CHANGED} to specify the - * the country code in ISO-3166-1 alpha-2 format. + * the country code in ISO-3166-1 alpha-2 format. This is the same country code returned by + * {@link #getNetworkCountryIso()}. This might be an empty string when the country code is not + * available. + * * <p class="note"> * Retrieve with {@link android.content.Intent#getStringExtra(String)}. */ @@ -14493,11 +14937,11 @@ public class TelephonyManager { /** * The extra used with an {@link #ACTION_NETWORK_COUNTRY_CHANGED} to specify the - * last known the country code in ISO-3166-1 alpha-2 format. + * last known the country code in ISO-3166-1 alpha-2 format. This might be an empty string when + * the country code was never available. The last known country code persists across reboot. + * * <p class="note"> * Retrieve with {@link android.content.Intent#getStringExtra(String)}. - * - * @hide */ public static final String EXTRA_LAST_KNOWN_NETWORK_COUNTRY = "android.telephony.extra.LAST_KNOWN_NETWORK_COUNTRY"; @@ -14650,21 +15094,132 @@ public class TelephonyManager { * @return a Pair of (major version, minor version) or (-1,-1) if unknown. * * @hide + * + * @deprecated Use {@link #getHalVersion} instead. */ + @Deprecated @UnsupportedAppUsage @TestApi public Pair<Integer, Integer> getRadioHalVersion() { + return getHalVersion(HAL_SERVICE_RADIO); + } + + /** @hide */ + public static final int HAL_SERVICE_RADIO = 0; + + /** + * HAL service type that supports the HAL APIs implementation of IRadioData + * {@link RadioDataProxy} + * @hide + */ + @TestApi + public static final int HAL_SERVICE_DATA = 1; + + /** + * HAL service type that supports the HAL APIs implementation of IRadioMessaging + * {@link RadioMessagingProxy} + * @hide + */ + @TestApi + public static final int HAL_SERVICE_MESSAGING = 2; + + /** + * HAL service type that supports the HAL APIs implementation of IRadioModem + * {@link RadioModemProxy} + * @hide + */ + @TestApi + public static final int HAL_SERVICE_MODEM = 3; + + /** + * HAL service type that supports the HAL APIs implementation of IRadioNetwork + * {@link RadioNetworkProxy} + * @hide + */ + @TestApi + public static final int HAL_SERVICE_NETWORK = 4; + + /** + * HAL service type that supports the HAL APIs implementation of IRadioSim + * {@link RadioSimProxy} + * @hide + */ + @TestApi + public static final int HAL_SERVICE_SIM = 5; + + /** + * HAL service type that supports the HAL APIs implementation of IRadioVoice + * {@link RadioVoiceProxy} + * @hide + */ + @TestApi + public static final int HAL_SERVICE_VOICE = 6; + + /** + * HAL service type that supports the HAL APIs implementation of IRadioIms + * {@link RadioImsProxy} + * @hide + */ + @TestApi + public static final int HAL_SERVICE_IMS = 7; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"HAL_SERVICE_"}, + value = { + HAL_SERVICE_RADIO, + HAL_SERVICE_DATA, + HAL_SERVICE_MESSAGING, + HAL_SERVICE_MODEM, + HAL_SERVICE_NETWORK, + HAL_SERVICE_SIM, + HAL_SERVICE_VOICE, + HAL_SERVICE_IMS, + }) + public @interface HalService {} + + /** + * The HAL Version indicating that the version is unknown or invalid. + * @hide + */ + @TestApi + public static final Pair HAL_VERSION_UNKNOWN = new Pair(-1, -1); + + /** + * The HAL Version indicating that the version is unsupported. + * @hide + */ + @TestApi + public static final Pair HAL_VERSION_UNSUPPORTED = new Pair(-2, -2); + + /** + * Retrieve the HAL Version of a specific service for this device. + * + * Get the HAL version for a specific HAL interface for test purposes. + * + * @param halService the service id to query. + * @return a Pair of (major version, minor version), HAL_VERSION_UNKNOWN if unknown + * or HAL_VERSION_UNSUPPORTED if unsupported. + * + * @hide + */ + @TestApi + public @NonNull Pair<Integer, Integer> getHalVersion(@HalService int halService) { try { ITelephony service = getITelephony(); if (service != null) { - int version = service.getRadioHalVersion(); - if (version == -1) return new Pair<Integer, Integer>(-1, -1); - return new Pair<Integer, Integer>(version / 100, version % 100); + int version = service.getHalVersion(halService); + if (version != -1) { + return new Pair<Integer, Integer>(version / 100, version % 100); + } + } else { + throw new IllegalStateException("telephony service is null."); } } catch (RemoteException e) { - Log.e(TAG, "getRadioHalVersion() RemoteException", e); + Log.e(TAG, "getHalVersion() RemoteException", e); + e.rethrowAsRuntimeException(); } - return new Pair<Integer, Integer>(-1, -1); + return HAL_VERSION_UNKNOWN; } /** @@ -15354,6 +15909,7 @@ public class TelephonyManager { * This policy can be enabled and disabled via {@link #setMobileDataPolicyEnabled}. * @hide */ + @SystemApi public static final int MOBILE_DATA_POLICY_AUTO_DATA_SWITCH = 3; /** @@ -15875,9 +16431,33 @@ public class TelephonyManager { } /** - * Whether device can connect to 5G network when two SIMs are active. + * Setup sIPhoneSubInfo for testing. + * + * @hide + */ + @VisibleForTesting + public static void setupIPhoneSubInfoForTest(IPhoneSubInfo iPhoneSubInfo) { + synchronized (sCacheLock) { + sIPhoneSubInfo = iPhoneSubInfo; + } + } + + /** + * Setup sISub for testing. + * * @hide - * TODO b/153669716: remove or make system API. + */ + @VisibleForTesting + public static void setupISubForTest(ISub iSub) { + synchronized (sCacheLock) { + sISub = iSub; + } + } + + /** + * Whether device can connect to 5G network when two SIMs are active. + * + * @hide TODO b/153669716: remove or make system API. */ public boolean canConnectTo5GInDsdsMode() { ITelephony telephony = getITelephony(); @@ -16192,7 +16772,8 @@ public class TelephonyManager { * may encounter an {@link IllegalStateException} when trying to register more callbacks. * * @param executor The executor of where the callback will execute. - * @param callback The {@link TelephonyCallback} object to register. + * @param callback The {@link TelephonyCallback} object to register. The caller should hold a + * reference to the callback. The framework only holds a weak reference. */ public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor, @NonNull TelephonyCallback callback) { @@ -16287,7 +16868,8 @@ public class TelephonyManager { * @param includeLocationData Specifies if the caller would like to receive * location related information. * @param executor The executor of where the callback will execute. - * @param callback The {@link TelephonyCallback} object to register. + * @param callback The {@link TelephonyCallback} object to register. The caller should hold a + * reference to the callback. The framework only holds a weak reference. */ public void registerTelephonyCallback(@IncludeLocationData int includeLocationData, @NonNull @CallbackExecutor Executor executor, @@ -16824,7 +17406,7 @@ public class TelephonyManager { } NetworkSlicingConfig slicingConfig = - result.getParcelable(KEY_SLICING_CONFIG_HANDLE); + result.getParcelable(KEY_SLICING_CONFIG_HANDLE, android.telephony.data.NetworkSlicingConfig.class); executor.execute(() -> callback.onResult(slicingConfig)); } }); @@ -16834,6 +17416,307 @@ public class TelephonyManager { } /** + * A premium capability that boosts the network to allow for real-time interactive traffic + * by prioritizing low latency communication. + * Corresponds to {@link NetworkCapabilities#NET_CAPABILITY_PRIORITIZE_LATENCY}. + */ + public static final int PREMIUM_CAPABILITY_PRIORITIZE_LATENCY = + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY; + + /** + * Purchasable premium capabilities. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "PREMIUM_CAPABILITY_" }, value = { + PREMIUM_CAPABILITY_PRIORITIZE_LATENCY}) + public @interface PremiumCapability {} + + /** + * Returns the premium capability {@link PremiumCapability} as a String. + * + * @param capability The premium capability. + * @return The premium capability as a String. + * @hide + */ + public static String convertPremiumCapabilityToString(@PremiumCapability int capability) { + switch (capability) { + case PREMIUM_CAPABILITY_PRIORITIZE_LATENCY: + return "PRIORITIZE_LATENCY"; + default: + return "UNKNOWN (" + capability + ")"; + } + } + + /** + * Check whether the given premium capability is available for purchase from the carrier. + * If this is {@code true}, the capability can be purchased from the carrier using + * {@link #purchasePremiumCapability(int, Executor, Consumer)}. + * + * @param capability The premium capability to check. + * @return Whether the given premium capability is available to purchase. + * @throws SecurityException if the caller does not hold permission READ_BASIC_PHONE_STATE. + */ + @RequiresPermission(android.Manifest.permission.READ_BASIC_PHONE_STATE) + public boolean isPremiumCapabilityAvailableForPurchase(@PremiumCapability int capability) { + try { + ITelephony telephony = getITelephony(); + if (telephony == null) { + throw new IllegalStateException("telephony service is null."); + } + return telephony.isPremiumCapabilityAvailableForPurchase(capability, getSubId()); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + return false; + } + + /** + * Purchase premium capability request was successful. + * Once the purchase result is successful, the network must set up a slicing configuration + * for the purchased premium capability within the timeout specified by + * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG}. + * During the setup time, subsequent attempts will return + * {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP}. + * After setup is complete, subsequent attempts will return + * {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED} until the boost expires. + * The expiry time is determined by the type or duration of boost purchased from the carrier, + * provided at {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING}. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS = 1; + + /** + * Purchase premium capability failed because the request is throttled. + * If purchasing premium capabilities is throttled, it will be for the amount of time + * specified by {@link CarrierConfigManager + * #KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG}. + * If displaying the performance boost notification is throttled, it will be for the amount of + * time specified by {@link CarrierConfigManager + * #KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG}. + * We will show the performance boost notification to the user up to the daily and monthly + * maximum number of times specified by + * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_MAXIMUM_DAILY_NOTIFICATION_COUNT_INT} and + * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_MAXIMUM_MONTHLY_NOTIFICATION_COUNT_INT}. + * Subsequent attempts will return the same error until the request is no longer throttled + * or throttling conditions change. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED = 2; + + /** + * Purchase premium capability failed because it is already purchased and available. + * Subsequent attempts will return the same error until the performance boost expires. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED = 3; + + /** + * Purchase premium capability failed because a request was already made and is in progress. + * This may have been requested by either the same app or another app. + * Subsequent attempts will return the same error until the previous request completes. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS = 4; + + /** + * Purchase premium capability failed because the requesting application is not in the + * foreground. Subsequent attempts will return the same error until the requesting application + * moves to the foreground. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND = 5; + + /** + * Purchase premium capability failed because the user canceled the operation. + * Subsequent attempts will be throttled for the amount of time specified by + * {@link CarrierConfigManager + * #KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG} + * and return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED}. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED = 6; + + /** + * Purchase premium capability failed because the carrier disabled or does not support + * the capability, as specified in + * {@link CarrierConfigManager#KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY}. + * Subsequent attempts will return the same error until the carrier enables the feature. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED = 7; + + /** + * Purchase premium capability failed because the carrier app did not indicate success. + * Subsequent attempts will be throttled for the amount of time specified by + * {@link CarrierConfigManager + * #KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG} + * and return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED}. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR = 8; + + /** + * Purchase premium capability failed because we did not receive a response from the user + * for the performance boost notification within the time specified by + * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG}. + * The performance boost notification will be automatically dismissed and subsequent attempts + * will be throttled for the amount of time specified by + * {@link CarrierConfigManager + * #KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG} + * and return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED}. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT = 9; + + /** + * Purchase premium capability failed because the device does not support the feature. + * Subsequent attempts will return the same error. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED = 10; + + /** + * Purchase premium capability failed because the telephony service is unavailable + * or there was an error in the phone process. + * Subsequent attempts will return the same error until request conditions are satisfied. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_REQUEST_FAILED = 11; + + /** + * Purchase premium capability failed because the network is not available. + * Subsequent attempts will return the same error until network conditions change. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE = 12; + + /** + * Purchase premium capability failed because the entitlement check failed. + * Subsequent attempts will be throttled for the amount of time specified by + * {@link CarrierConfigManager + * #KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG} + * and return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED}. + * Throttling will be reevaluated when the network is no longer congested. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED = 13; + + /** + * Purchase premium capability failed because the request was not made on the default data + * subscription, indicated by {@link SubscriptionManager#getDefaultDataSubscriptionId()}. + * Subsequent attempts will return the same error until the request is made on the default + * data subscription. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION = 14; + + /** + * Purchase premium capability was successful and is waiting for the network to setup the + * slicing configuration. If the setup is complete within the time specified by + * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG}, + * subsequent requests will return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED} + * until the purchase expires. If the setup is not complete within the time specified above, + * applications can request the premium capability again. + */ + public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP = 15; + + /** + * Results of the purchase premium capability request. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "PURCHASE_PREMIUM_CAPABILITY_RESULT_" }, value = { + PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS, + PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, + PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED, + PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS, + PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND, + PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED, + PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, + PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR, + PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT, + PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED, + PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE, + PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED, + PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION, + PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP}) + public @interface PurchasePremiumCapabilityResult {} + + /** + * Returns the purchase result {@link PurchasePremiumCapabilityResult} as a String. + * + * @param result The purchase premium capability result. + * @return The purchase result as a String. + * @hide + */ + public static String convertPurchaseResultToString( + @PurchasePremiumCapabilityResult int result) { + switch (result) { + case PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS: + return "SUCCESS"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED: + return "THROTTLED"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED: + return "ALREADY_PURCHASED"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS: + return "ALREADY_IN_PROGRESS"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND: + return "NOT_FOREGROUND"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED: + return "USER_CANCELED"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED: + return "CARRIER_DISABLED"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR: + return "CARRIER_ERROR"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT: + return "TIMEOUT"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED: + return "FEATURE_NOT_SUPPORTED"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_REQUEST_FAILED: + return "REQUEST_FAILED"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE: + return "NETWORK_NOT_AVAILABLE"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED: + return "ENTITLEMENT_CHECK_FAILED"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION: + return "NOT_DEFAULT_DATA_SUBSCRIPTION"; + case PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP: + return "PENDING_NETWORK_SETUP"; + default: + return "UNKNOWN (" + result + ")"; + } + } + + /** + * Purchase the given premium capability from the carrier. + * This requires user action to purchase the boost from the carrier. + * If this returns {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS} or + * {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED}, applications can request + * the premium capability via {@link ConnectivityManager#requestNetwork}. + * + * @param capability The premium capability to purchase. + * @param executor The callback executor for the response. + * @param callback The result of the purchase request. + * One of {@link PurchasePremiumCapabilityResult}. + * @throws SecurityException if the caller does not hold permissions + * READ_BASIC_PHONE_STATE or INTERNET. + * @see #isPremiumCapabilityAvailableForPurchase(int) to check whether the capability is valid. + */ + @RequiresPermission(allOf = {android.Manifest.permission.READ_BASIC_PHONE_STATE, + android.Manifest.permission.INTERNET}) + public void purchasePremiumCapability(@PremiumCapability int capability, + @NonNull @CallbackExecutor Executor executor, + @NonNull @PurchasePremiumCapabilityResult Consumer<Integer> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> callback.accept(result)); + } + }; + + try { + ITelephony telephony = getITelephony(); + if (telephony == null) { + callback.accept(PURCHASE_PREMIUM_CAPABILITY_RESULT_REQUEST_FAILED); + return; + } + telephony.purchasePremiumCapability(capability, internalCallback, getSubId()); + } catch (RemoteException ex) { + callback.accept(PURCHASE_PREMIUM_CAPABILITY_RESULT_REQUEST_FAILED); + } + } + + /** * Get last known cell identity. * Require {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and * com.android.phone.permission.ACCESS_LAST_KNOWN_CELL_ID, otherwise throws SecurityException. @@ -17054,6 +17937,411 @@ public class TelephonyManager { } /** + * Captures parameters for collection of emergency + * call diagnostic data + * @hide + */ + public static class EmergencyCallDiagnosticParams { + + private boolean mCollectTelecomDumpSys; + private boolean mCollectTelephonyDumpsys; + private boolean mCollectLogcat; + + //logcat lines with this time or greater are collected + //how much is collected is dependent on internal implementation. + //Time represented as milliseconds since January 1, 1970 UTC + private long mLogcatStartTimeMillis; + + + public boolean isTelecomDumpSysCollectionEnabled() { + return mCollectTelecomDumpSys; + } + + public void setTelecomDumpSysCollection(boolean collectTelecomDumpSys) { + mCollectTelecomDumpSys = collectTelecomDumpSys; + } + + public boolean isTelephonyDumpSysCollectionEnabled() { + return mCollectTelephonyDumpsys; + } + + public void setTelephonyDumpSysCollection(boolean collectTelephonyDumpsys) { + mCollectTelephonyDumpsys = collectTelephonyDumpsys; + } + + public boolean isLogcatCollectionEnabled() { + return mCollectLogcat; + } + + public long getLogcatStartTime() + { + return mLogcatStartTimeMillis; + } + + public void setLogcatCollection(boolean collectLogcat, long startTimeMillis) { + mCollectLogcat = collectLogcat; + if(mCollectLogcat) + { + mLogcatStartTimeMillis = startTimeMillis; + } + } + + @Override + public String toString() { + return "EmergencyCallDiagnosticParams{" + + "mCollectTelecomDumpSys=" + mCollectTelecomDumpSys + + ", mCollectTelephonyDumpsys=" + mCollectTelephonyDumpsys + + ", mCollectLogcat=" + mCollectLogcat + + ", mLogcatStartTimeMillis=" + mLogcatStartTimeMillis + + '}'; + } + } + + /** + * Request telephony to persist state for debugging emergency call failures. + * + * @param dropboxTag Tag to use when persisting data to dropbox service. + * + * @see params Parameters controlling what is collected + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.DUMP) + public void persistEmergencyCallDiagnosticData(@NonNull String dropboxTag, + @NonNull EmergencyCallDiagnosticParams params) { + try { + ITelephony telephony = ITelephony.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getTelephonyServiceRegisterer() + .get()); + if (telephony != null) { + telephony.persistEmergencyCallDiagnosticData(dropboxTag, + params.isLogcatCollectionEnabled(), + params.getLogcatStartTime(), + params.isTelecomDumpSysCollectionEnabled(), + params.isTelephonyDumpSysCollectionEnabled()); + } + } catch (RemoteException e) { + Log.e(TAG, "Error while persistEmergencyCallDiagnosticData: " + e); + } + } + + /** + * Set the UE's ability to accept/reject null ciphered and null integrity-protected connections. + * + * The modem is required to ignore this in case of an emergency call. + * + * <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE</p> + * + * @param enabled if null ciphered and null integrity protected connections are permitted + * @throws IllegalStateException if the Telephony process is not currently available + * @throws SecurityException if the caller does not have the required privileges + * @throws UnsupportedOperationException if the modem does not support disabling null ciphers. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void setNullCipherAndIntegrityEnabled(boolean enabled) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.setNullCipherAndIntegrityEnabled(enabled); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "setNullCipherAndIntegrityEnabled RemoteException", ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Get the value of the global preference for null cipher and integriy enablement. + * Note: This does not return the state of the modem, only the persisted global preference. + * + * <p>Requires permission: android.Manifest.READ_PHONE_STATE</p> + * + * @throws IllegalStateException if the Telephony process is not currently available + * @throws SecurityException if the caller does not have the required privileges + * @throws UnsupportedOperationException if the modem does not support disabling null ciphers. + * @hide + */ + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + public boolean isNullCipherAndIntegrityPreferenceEnabled() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isNullCipherAndIntegrityPreferenceEnabled(); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "isNullCipherAndIntegrityPreferenceEnabled RemoteException", ex); + ex.rethrowFromSystemServer(); + } + return true; + } + + /** + * Get current cell broadcast message identifier ranges. + * + * @throws SecurityException if the caller does not have the required permission + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) + @NonNull + public List<CellBroadcastIdRange> getCellBroadcastIdRanges() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getCellBroadcastIdRanges(getSubId()); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + return new ArrayList<>(); + } + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"CELL_BROADCAST_RESULT_"}, value = { + CELL_BROADCAST_RESULT_UNKNOWN, + CELL_BROADCAST_RESULT_SUCCESS, + CELL_BROADCAST_RESULT_UNSUPPORTED, + CELL_BROADCAST_RESULT_FAIL_CONFIG, + CELL_BROADCAST_RESULT_FAIL_ACTIVATION}) + public @interface CellBroadcastResult {} + + /** + * The result of the cell broadcast request is unknown + * @hide + */ + @SystemApi + public static final int CELL_BROADCAST_RESULT_UNKNOWN = -1; + + /** + * The cell broadcast request is successful. + * @hide + */ + @SystemApi + public static final int CELL_BROADCAST_RESULT_SUCCESS = 0; + + /** + * The cell broadcast request is not supported. + * @hide + */ + @SystemApi + public static final int CELL_BROADCAST_RESULT_UNSUPPORTED = 1; + + /** + * The cell broadcast request is failed due to the error to set config + * @hide + */ + @SystemApi + public static final int CELL_BROADCAST_RESULT_FAIL_CONFIG = 2; + + /** + * The cell broadcast request is failed due to the error to set activation + * @hide + */ + @SystemApi + public static final int CELL_BROADCAST_RESULT_FAIL_ACTIVATION = 3; + + /** + * Callback mode type + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EMERGENCY_CALLBACK_MODE_"}, value = { + EMERGENCY_CALLBACK_MODE_CALL, + EMERGENCY_CALLBACK_MODE_SMS}) + public @interface EmergencyCallbackModeType {} + + /** + * The callback mode is due to emergency call. + * @hide + */ + public static final int EMERGENCY_CALLBACK_MODE_CALL = 1; + + /** + * The callback mode is due to emergency SMS. + * @hide + */ + public static final int EMERGENCY_CALLBACK_MODE_SMS = 2; + + /** + * The reason for changing callback mode. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"STOP_REASON_"}, + value = { + STOP_REASON_UNKNOWN, + STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED, + STOP_REASON_NORMAL_SMS_SENT, + STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED, + STOP_REASON_EMERGENCY_SMS_SENT, + STOP_REASON_TIMER_EXPIRED, + STOP_REASON_USER_ACTION, + }) + public @interface EmergencyCallbackModeStopReason {} + + /** + * unknown reason. + * @hide + */ + public static final int STOP_REASON_UNKNOWN = 0; + + /** + * The call back mode is exited due to a new normal call is originated. + * @hide + */ + public static final int STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED = 1; + + /** + * The call back mode is exited due to a new normal SMS is originated. + * @hide + */ + public static final int STOP_REASON_NORMAL_SMS_SENT = 2; + + /** + * The call back mode is exited due to a new emergency call is originated. + * @hide + */ + public static final int STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED = 3; + + /** + * The call back mode is exited due to a new emergency SMS is originated. + * @hide + */ + public static final int STOP_REASON_EMERGENCY_SMS_SENT = 4; + + /** + * The call back mode is exited due to timer expiry. + * @hide + */ + public static final int STOP_REASON_TIMER_EXPIRED = 5; + + /** + * The call back mode is exited due to user action. + * @hide + */ + public static final int STOP_REASON_USER_ACTION = 6; + + /** + * Set reception of cell broadcast messages with the list of the given ranges + * + * <p>The ranges set previously will be overridden by the new one. Empty list + * can be used to clear the ranges. + * + * @param ranges the list of {@link CellBroadcastIdRange} to be set. + * @param executor The {@link Executor} that will be used to call the callback. + * @param callback A callback called on the supplied {@link Executor} to notify + * the result when the operation completes. + * @throws SecurityException if the caller does not have the required permission + * @throws IllegalArgumentException when the ranges are invalid. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) + public void setCellBroadcastIdRanges(@NonNull List<CellBroadcastIdRange> ranges, + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Integer> callback) { + IIntegerConsumer consumer = callback == null ? null : new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + final long identity = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.accept(result)); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + }; + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.setCellBroadcastIdRanges(getSubId(), ranges, consumer); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + } + + /** + * Returns whether the domain selection service is supported. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}. + * + * @return {@code true} if the domain selection service is supported. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING) + public boolean isDomainSelectionSupported() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isDomainSelectionSupported(); + } + } catch (RemoteException ex) { + Rlog.w(TAG, "RemoteException", ex); + } + return false; + } + + /** + * Returns the primary IMEI (International Mobile Equipment Identity) of the device as + * mentioned in GSMA TS.37. {@link #getImei(int)} returns the IMEI that belongs to the selected + * slotID whereas this API {@link #getPrimaryImei()} returns primary IMEI of the device. + * A single SIM device with only one IMEI will be set by default as primary IMEI. + * A multi-SIM device with multiple IMEIs will have one of the IMEIs set as primary as + * mentioned in GSMA TS37_2.2_REQ_8. + * + * <p>Requires one of the following permissions + * <ul> + * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this + * is a privileged permission that can only be granted to apps preloaded on the device. + * <li>If the calling app is the device owner of a fully-managed device, a profile + * owner of an organization-owned device, or their delegates (see {@link + * android.app.admin.DevicePolicyManager#getEnrollmentSpecificId()}). + * <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) on any + * active subscription. + * <li>If the calling app is the default SMS role holder (see {@link + * RoleManager#isRoleHeld(String)}). + * <li>If the calling app has been granted the + * {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} permission. + * </ul> + * + * @return Primary IMEI of type string + * @throws UnsupportedOperationException if the radio doesn't support this feature. + * @throws SecurityException if the caller does not have the required permission/privileges + */ + @NonNull + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) + public String getPrimaryImei() { + try { + ITelephony telephony = getITelephony(); + if (telephony == null) { + Rlog.e(TAG, "getPrimaryImei(): IPhoneSubInfo instance is NULL"); + throw new IllegalStateException("Telephony service not available."); + } + return telephony.getPrimaryImei(getOpPackageName(), getAttributionTag()); + } catch (RemoteException ex) { + Rlog.e(TAG, "getPrimaryImei() RemoteException : " + ex); + throw ex.rethrowAsRuntimeException(); + } + } + + /** * Convert SIM state into string. * * @param state SIM state. diff --git a/telephony/java/android/telephony/TransportSelectorCallback.java b/telephony/java/android/telephony/TransportSelectorCallback.java new file mode 100644 index 000000000000..04752e418466 --- /dev/null +++ b/telephony/java/android/telephony/TransportSelectorCallback.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +import android.annotation.NonNull; +import android.telephony.Annotation.DisconnectCauses; + +import java.util.function.Consumer; + +/** + * A callback class used to receive the transport selection result. + * @hide + */ +public interface TransportSelectorCallback { + /** + * Notify that {@link DomainSelector} instance has been created for the selection request. + * + * @param selector the {@link DomainSelector} instance created. + */ + void onCreated(@NonNull DomainSelector selector); + + /** + * Notify that WLAN transport has been selected. + * + * @param useEmergencyPdn Indicates whether Wi-Fi emergency services use emergency PDN or not. + */ + void onWlanSelected(boolean useEmergencyPdn); + + /** + * Notify that WWAN transport has been selected. + */ + @NonNull WwanSelectorCallback onWwanSelected(); + + /** + * Notify that WWAN transport has been selected. + * + * @param consumer The callback to receive the result. + */ + void onWwanSelected(Consumer<WwanSelectorCallback> consumer); + + /** + * Notify that selection has terminated because there is no decision that can be made + * or a timeout has occurred. The call should be terminated when this method is called. + * + * @param cause indicates the reason. + */ + void onSelectionTerminated(@DisconnectCauses int cause); +} diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java index e5e8f0a41048..6c069d4ee843 100644 --- a/telephony/java/android/telephony/UiccCardInfo.java +++ b/telephony/java/android/telephony/UiccCardInfo.java @@ -166,7 +166,7 @@ public final class UiccCardInfo implements Parcelable { + " Please Use UiccPortInfo API instead"); } //always return ICCID from first port. - return getPorts().stream().findFirst().get().getIccId(); + return mPortList.isEmpty() ? null : mPortList.get(0).getIccId(); } /** diff --git a/telephony/java/android/telephony/UiccPortInfo.java b/telephony/java/android/telephony/UiccPortInfo.java index 6fb0470d6225..41e743c43272 100644 --- a/telephony/java/android/telephony/UiccPortInfo.java +++ b/telephony/java/android/telephony/UiccPortInfo.java @@ -165,7 +165,7 @@ public final class UiccPortInfo implements Parcelable{ return "UiccPortInfo (isActive=" + mIsActive + ", iccId=" - + SubscriptionInfo.givePrintableIccid(mIccId) + + SubscriptionInfo.getPrintableId(mIccId) + ", portIndex=" + mPortIndex + ", mLogicalSlotIndex=" diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java index 5e02532e85a8..dda73497e647 100644 --- a/telephony/java/android/telephony/UiccSlotInfo.java +++ b/telephony/java/android/telephony/UiccSlotInfo.java @@ -139,14 +139,16 @@ public class UiccSlotInfo implements Parcelable { public UiccSlotInfo(boolean isEuicc, String cardId, @CardStateInfo int cardStateInfo, boolean isExtendedApduSupported, boolean isRemovable, @NonNull List<UiccPortInfo> portList) { - this.mIsActive = portList.get(0).isActive(); this.mIsEuicc = isEuicc; this.mCardId = cardId; this.mCardStateInfo = cardStateInfo; - this.mLogicalSlotIdx = portList.get(0).getLogicalSlotIndex(); this.mIsExtendedApduSupported = isExtendedApduSupported; this.mIsRemovable = isRemovable; this.mPortList = portList; + this.mIsActive = !portList.isEmpty() && portList.get(0).isActive(); + this.mLogicalSlotIdx = portList.isEmpty() + ? SubscriptionManager.INVALID_PHONE_INDEX + : portList.get(0).getLogicalSlotIndex(); } /** @@ -164,8 +166,7 @@ public class UiccSlotInfo implements Parcelable { throw new UnsupportedOperationException("getIsActive() is not supported by " + "UiccSlotInfo. Please Use UiccPortInfo API instead"); } - //always return status from first port. - return getPorts().stream().findFirst().get().isActive(); + return mIsActive; } public boolean getIsEuicc() { @@ -202,9 +203,7 @@ public class UiccSlotInfo implements Parcelable { throw new UnsupportedOperationException("getLogicalSlotIdx() is not supported by " + "UiccSlotInfo. Please use UiccPortInfo API instead"); } - //always return logical slot index from first port. - //portList always have at least one element. - return getPorts().stream().findFirst().get().getLogicalSlotIndex(); + return mLogicalSlotIdx; } /** @@ -281,7 +280,7 @@ public class UiccSlotInfo implements Parcelable { + ", mIsEuicc=" + mIsEuicc + ", mCardId=" - + SubscriptionInfo.givePrintableIccid(mCardId) + + SubscriptionInfo.getPrintableId(mCardId) + ", cardState=" + mCardStateInfo + ", mIsExtendedApduSupported=" diff --git a/telephony/java/android/telephony/VisualVoicemailService.java b/telephony/java/android/telephony/VisualVoicemailService.java index fe30eb7bb005..a530917a271c 100644 --- a/telephony/java/android/telephony/VisualVoicemailService.java +++ b/telephony/java/android/telephony/VisualVoicemailService.java @@ -157,14 +157,14 @@ public abstract class VisualVoicemailService extends Service { @Override public void handleMessage(final Message msg) { final PhoneAccountHandle handle = msg.getData() - .getParcelable(DATA_PHONE_ACCOUNT_HANDLE); + .getParcelable(DATA_PHONE_ACCOUNT_HANDLE, android.telecom.PhoneAccountHandle.class); VisualVoicemailTask task = new VisualVoicemailTask(msg.replyTo, msg.arg1); switch (msg.what) { case MSG_ON_CELL_SERVICE_CONNECTED: onCellServiceConnected(task, handle); break; case MSG_ON_SMS_RECEIVED: - VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS); + VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS, android.telephony.VisualVoicemailSms.class); onSmsReceived(task, sms); break; case MSG_ON_SIM_REMOVED: diff --git a/telephony/java/android/telephony/WwanSelectorCallback.java b/telephony/java/android/telephony/WwanSelectorCallback.java new file mode 100644 index 000000000000..f9c2620cfaf8 --- /dev/null +++ b/telephony/java/android/telephony/WwanSelectorCallback.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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 android.telephony; + +import android.annotation.NonNull; +import android.os.CancellationSignal; +import android.telephony.DomainSelectionService.EmergencyScanType; + +import java.util.List; +import java.util.function.Consumer; + +/** + * A callback class used to receive the domain selection result. + * @hide + */ +public interface WwanSelectorCallback { + /** + * Notify the framework that the {@link DomainSelectionService} has requested an emergency + * network scan as part of selection. + * + * @param preferredNetworks the ordered list of preferred networks to scan. + * @param scanType indicates the scan preference, such as full service or limited service. + * @param signal notifies when the operation is canceled. + * @param consumer the handler of the response. + */ + void onRequestEmergencyNetworkScan(@NonNull List<Integer> preferredNetworks, + @EmergencyScanType int scanType, + @NonNull CancellationSignal signal, @NonNull Consumer<EmergencyRegResult> consumer); + + /** + * Notifies the FW that the domain has been selected. After this method is called, + * this interface can be discarded. + * + * @param domain The selected domain. + * @param useEmergencyPdn Indicates whether emergency services use emergency PDN or not. + */ + void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, boolean useEmergencyPdn); +} diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java index d808cabaaa92..d4cb5ac8a64c 100644 --- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java +++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java @@ -21,6 +21,9 @@ import android.os.Build; import android.os.Bundle; import android.telephony.CellLocation; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + /** * Represents the cell location on a CDMA phone. * @@ -197,8 +200,8 @@ public class CdmaCellLocation extends CellLocation { @Override public String toString() { return "[" + this.mBaseStationId + "," - + this.mBaseStationLatitude + "," - + this.mBaseStationLongitude + "," + + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, this.mBaseStationLatitude) + "," + + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, this.mBaseStationLongitude) + "," + this.mSystemId + "," + this.mNetworkId + "]"; } diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index b32f04633247..28ea5a681730 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -43,6 +43,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -1337,6 +1338,14 @@ public class ApnSetting implements Parcelable { public ContentValues toContentValues() { ContentValues apnValue = new ContentValues(); apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric)); + // If the APN is editable, the user may be able to set an invalid numeric. The numeric must + // always be 5 or 6 characters (depending on the length of the MNC), so skip if it is + // potentially invalid. + if (!TextUtils.isEmpty(mOperatorNumeric) + && (mOperatorNumeric.length() == 5 || mOperatorNumeric.length() == 6)) { + apnValue.put(Telephony.Carriers.MCC, mOperatorNumeric.substring(0, 3)); + apnValue.put(Telephony.Carriers.MNC, mOperatorNumeric.substring(3)); + } apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName)); apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName)); apnValue.put(Telephony.Carriers.PROXY, nullToEmpty(mProxyAddress)); @@ -1356,6 +1365,7 @@ public class ApnSetting implements Parcelable { getProtocolStringFromInt(mRoamingProtocol)); apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled); apnValue.put(Telephony.Carriers.MVNO_TYPE, getMvnoTypeStringFromInt(mMvnoType)); + apnValue.put(Telephony.Carriers.MVNO_MATCH_DATA, nullToEmpty(mMvnoMatchData)); apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask); apnValue.put(Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK, mLingeringNetworkTypeBitmask); @@ -1442,7 +1452,7 @@ public class ApnSetting implements Parcelable { */ @SystemApi public static @ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) { - return APN_TYPE_STRING_MAP.getOrDefault(apnType.toLowerCase(), 0); + return APN_TYPE_STRING_MAP.getOrDefault(apnType.toLowerCase(Locale.ROOT), 0); } /** @@ -1457,7 +1467,7 @@ public class ApnSetting implements Parcelable { } else { int result = 0; for (String str : types.split(",")) { - Integer type = APN_TYPE_STRING_MAP.get(str.toLowerCase()); + Integer type = APN_TYPE_STRING_MAP.get(str.toLowerCase(Locale.ROOT)); if (type != null) { result |= type; } @@ -1468,7 +1478,8 @@ public class ApnSetting implements Parcelable { /** @hide */ public static int getMvnoTypeIntFromString(String mvnoType) { - String mvnoTypeString = TextUtils.isEmpty(mvnoType) ? mvnoType : mvnoType.toLowerCase(); + String mvnoTypeString = TextUtils.isEmpty(mvnoType) + ? mvnoType : mvnoType.toLowerCase(Locale.ROOT); Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoTypeString); return mvnoTypeInt == null ? UNSPECIFIED_INT : mvnoTypeInt; } diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl index ba2b62d14bec..8e2707735f63 100644 --- a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl +++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl @@ -27,4 +27,5 @@ interface IQualifiedNetworksService oneway void createNetworkAvailabilityProvider(int slotId, IQualifiedNetworksServiceCallback callback); oneway void removeNetworkAvailabilityProvider(int slotId); oneway void reportThrottleStatusChanged(int slotId, in List<ThrottleStatus> statuses); + oneway void reportEmergencyDataNetworkPreferredTransportChanged (int slotId, int transportType); } diff --git a/telephony/java/android/telephony/data/QosBearerSession.java b/telephony/java/android/telephony/data/QosBearerSession.java index dd080856d450..1668193e076c 100644 --- a/telephony/java/android/telephony/data/QosBearerSession.java +++ b/telephony/java/android/telephony/data/QosBearerSession.java @@ -102,12 +102,11 @@ public final class QosBearerSession implements Parcelable{ QosBearerSession other = (QosBearerSession) o; return this.qosBearerSessionId == other.qosBearerSessionId - && this.qos.equals(other.qos) + && Objects.equals(this.qos, other.qos) && this.qosBearerFilterList.size() == other.qosBearerFilterList.size() && this.qosBearerFilterList.containsAll(other.qosBearerFilterList); } - public static final @NonNull Parcelable.Creator<QosBearerSession> CREATOR = new Parcelable.Creator<QosBearerSession>() { @Override diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java index fb973361e398..56f0f9f13772 100644 --- a/telephony/java/android/telephony/data/QualifiedNetworksService.java +++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java @@ -68,6 +68,7 @@ public abstract class QualifiedNetworksService extends Service { private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS = 3; private static final int QNS_UPDATE_QUALIFIED_NETWORKS = 4; private static final int QNS_APN_THROTTLE_STATUS_CHANGED = 5; + private static final int QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED = 6; private final HandlerThread mHandlerThread; @@ -193,6 +194,20 @@ public abstract class QualifiedNetworksService extends Service { } /** + * The framework calls this method when the preferred transport type used to set up + * emergency data network is changed. + * + * This method is meant to be overridden. + * + * @param transportType transport type changed to be preferred + */ + public void reportEmergencyDataNetworkPreferredTransportChanged( + @AccessNetworkConstants.TransportType int transportType) { + Log.d(TAG, "reportEmergencyDataNetworkPreferredTransportChanged: " + + AccessNetworkConstants.transportTypeToString(transportType)); + } + + /** * Called when the qualified networks provider is removed. The extended class should * implement this method to perform cleanup works. */ @@ -237,6 +252,13 @@ public abstract class QualifiedNetworksService extends Service { } break; + case QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED: + if (provider != null) { + int transportType = (int) message.arg2; + provider.reportEmergencyDataNetworkPreferredTransportChanged(transportType); + } + break; + case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER: if (provider != null) { provider.close(); @@ -332,6 +354,14 @@ public abstract class QualifiedNetworksService extends Service { mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses) .sendToTarget(); } + + @Override + public void reportEmergencyDataNetworkPreferredTransportChanged(int slotIndex, + @AccessNetworkConstants.TransportType int transportType) { + mHandler.obtainMessage( + QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED, + slotIndex, transportType).sendToTarget(); + } } private void log(String s) { diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index d9d5c14735ea..64bcf7171ade 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -25,6 +25,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; +import android.util.SparseArray; +import android.util.SparseIntArray; import com.android.telephony.Rlog; @@ -247,6 +249,17 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu private final List<String> mEmergencyUrns; private final int mEmergencyNumberSourceBitmask; private final int mEmergencyCallRouting; + /** + * The source of the EmergencyNumber in the order of precedence. + */ + private static final int[] EMERGENCY_NUMBER_SOURCE_PRECEDENCE; + static { + EMERGENCY_NUMBER_SOURCE_PRECEDENCE = new int[4]; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[0] = EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[1] = EMERGENCY_NUMBER_SOURCE_SIM; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[2] = EMERGENCY_NUMBER_SOURCE_DATABASE; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[3] = EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG; + } /** @hide */ public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc, @@ -601,19 +614,44 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu */ public static void mergeSameNumbersInEmergencyNumberList( List<EmergencyNumber> emergencyNumberList) { + mergeSameNumbersInEmergencyNumberList(emergencyNumberList, false); + } + + /** + * In-place merge same emergency numbers in the emergency number list. + * + * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’ and 'mnc' fields. + * If mergeServiceCategoriesAndUrns is true ignore comparing of 'urns' and + * 'categories' fields and determine these fields from most precedent number. Else compare + * to get unique combination of EmergencyNumber. + * Multiple Emergency Number Sources should be merged into one bitfield for the + * same EmergencyNumber. + * + * @param emergencyNumberList the emergency number list to process + * @param mergeServiceCategoriesAndUrns {@code true} determine service category and urns + * from most precedent number. {@code false} compare those fields for determing duplicate. + * + * @hide + */ + public static void mergeSameNumbersInEmergencyNumberList( + @NonNull List<EmergencyNumber> emergencyNumberList, + boolean mergeServiceCategoriesAndUrns) { if (emergencyNumberList == null) { return; } + Set<Integer> duplicatedEmergencyNumberPosition = new HashSet<>(); for (int i = 0; i < emergencyNumberList.size(); i++) { for (int j = 0; j < i; j++) { - if (areSameEmergencyNumbers( - emergencyNumberList.get(i), emergencyNumberList.get(j))) { - Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: " - + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j)); + if (areSameEmergencyNumbers(emergencyNumberList.get(i), + emergencyNumberList.get(j), mergeServiceCategoriesAndUrns)) { + Rlog.e(LOG_TAG, "Found unexpected duplicate numbers " + + emergencyNumberList.get(i) + + " vs " + emergencyNumberList.get(j)); // Set the merged emergency number in the current position - emergencyNumberList.set(i, mergeSameEmergencyNumbers( - emergencyNumberList.get(i), emergencyNumberList.get(j))); + emergencyNumberList.set(i, + mergeSameEmergencyNumbers(emergencyNumberList.get(i), + emergencyNumberList.get(j), mergeServiceCategoriesAndUrns)); // Mark the emergency number has been merged duplicatedEmergencyNumberPosition.add(j); } @@ -632,18 +670,24 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu /** * Check if two emergency numbers are the same. * - * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and - * 'categories', and 'routing' fields. Multiple Emergency Number Sources should be + * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' fields. + * If mergeServiceCategoriesAndUrns is true ignore comparing of 'urns' and + * 'categories' fields and determine these fields from most precedent number. Else compare + * to get unique combination of EmergencyNumber. + * Multiple Emergency Number Sources should be * merged into one bitfield for the same EmergencyNumber. * * @param first first EmergencyNumber to compare * @param second second EmergencyNumber to compare + * @param ignoreServiceCategoryAndUrns {@code true} Ignore comparing of service category + * and Urns so that they can be determined from most precedent number. {@code false} compare + * those fields for determing duplicate. * @return true if they are the same EmergencyNumbers; false otherwise. * * @hide */ public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first, - @NonNull EmergencyNumber second) { + @NonNull EmergencyNumber second, boolean ignoreServiceCategoryAndUrns) { if (!first.getNumber().equals(second.getNumber())) { return false; } @@ -653,15 +697,14 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu if (!first.getMnc().equals(second.getMnc())) { return false; } - if (first.getEmergencyServiceCategoryBitmask() - != second.getEmergencyServiceCategoryBitmask()) { - return false; - } - if (!first.getEmergencyUrns().equals(second.getEmergencyUrns())) { - return false; - } - if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) { - return false; + if (!ignoreServiceCategoryAndUrns) { + if (first.getEmergencyServiceCategoryBitmask() + != second.getEmergencyServiceCategoryBitmask()) { + return false; + } + if (!first.getEmergencyUrns().equals(second.getEmergencyUrns())) { + return false; + } } // Never merge two numbers if one of them is from test mode but the other one is not; // This supports to remove a number from the test mode. @@ -684,18 +727,133 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu */ public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first, @NonNull EmergencyNumber second) { - if (areSameEmergencyNumbers(first, second)) { + if (areSameEmergencyNumbers(first, second, false)) { + int routing = first.getEmergencyCallRouting(); + + if (second.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) { + routing = second.getEmergencyCallRouting(); + } + return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(), first.getEmergencyServiceCategoryBitmask(), first.getEmergencyUrns(), first.getEmergencyNumberSourceBitmask() | second.getEmergencyNumberSourceBitmask(), - first.getEmergencyCallRouting()); + routing); } return null; } /** + * Get merged EmergencyUrns list from two same emergency numbers. + * By giving priority to the urns from first number. + * + * @param firstEmergencyUrns first number's Urns + * @param secondEmergencyUrns second number's Urns + * @return a merged Urns + * + * @hide + */ + private static List<String> mergeEmergencyUrns(@NonNull List<String> firstEmergencyUrns, + @NonNull List<String> secondEmergencyUrns) { + List<String> mergedUrns = new ArrayList<String>(); + mergedUrns.addAll(firstEmergencyUrns); + for (String urn : secondEmergencyUrns) { + if (!firstEmergencyUrns.contains(urn)) { + mergedUrns.add(urn); + } + } + return mergedUrns; + } + + /** + * Get the highest precedence source of the given Emergency number. Then get service catergory + * and urns list fill in the respective map with key as source. + * + * @param num EmergencyNumber to get the source, service category & urns + * @param serviceCategoryArray Array to store the category of the given EmergencyNumber + * with key as highest precedence source + * @param urnsArray Array to store the list of Urns of the given EmergencyNumber + * with key as highest precedence source + * + * @hide + */ + private static void fillServiceCategoryAndUrns(@NonNull EmergencyNumber num, + @NonNull SparseIntArray serviceCategoryArray, + @NonNull SparseArray<List<String>> urnsArray) { + int numberSrc = num.getEmergencyNumberSourceBitmask(); + for (Integer source : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) { + if ((numberSrc & source) == source) { + if (!num.isInEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED)) { + serviceCategoryArray.put(source, num.getEmergencyServiceCategoryBitmask()); + } + urnsArray.put(source, num.getEmergencyUrns()); + break; + } + } + } + + /** + * Get a merged EmergencyNumber from two same emergency numbers from + * Emergency number list. Two emergency numbers are the same if + * {@link #areSameEmergencyNumbers} returns {@code true}. + * + * @param first first EmergencyNumber to compare + * @param second second EmergencyNumber to compare + * @param mergeServiceCategoriesAndUrns {@code true} then determine service category and urns + * Service catetory : set from most precedence source number(N/W, SIM, DB, modem_cfg) + * Urns : merge from both with first priority from most precedence source number + * {@code false} then call {@link #mergeSameEmergencyNumbers} to merge. + * @return a merged EmergencyNumber or null if they are not the same EmergencyNumber + * + * @hide + */ + public static @NonNull EmergencyNumber mergeSameEmergencyNumbers( + @NonNull EmergencyNumber first, @NonNull EmergencyNumber second, + boolean mergeServiceCategoriesAndUrns) { + if (!mergeServiceCategoriesAndUrns) { + return mergeSameEmergencyNumbers(first, second); + } + + int routing = first.getEmergencyCallRouting(); + int serviceCategory = first.getEmergencyServiceCategoryBitmask(); + List<String> mergedEmergencyUrns = new ArrayList<String>(); + //Maps to store the service category and urns of both the first and second emergency number + // with key as most precedent source + SparseIntArray serviceCategoryArray = new SparseIntArray(2); + SparseArray<List<String>> urnsArray = new SparseArray(2); + + fillServiceCategoryAndUrns(first, serviceCategoryArray, urnsArray); + fillServiceCategoryAndUrns(second, serviceCategoryArray, urnsArray); + + if (second.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) { + routing = second.getEmergencyCallRouting(); + } + + // Determine serviceCategory of most precedence number + for (int sourceOfCategory : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) { + if (serviceCategoryArray.indexOfKey(sourceOfCategory) >= 0) { + serviceCategory = serviceCategoryArray.get(sourceOfCategory); + break; + } + } + + // Merge Urns in precedence number + for (int sourceOfUrn : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) { + if (urnsArray.contains(sourceOfUrn)) { + mergedEmergencyUrns = mergeEmergencyUrns(mergedEmergencyUrns, + urnsArray.get(sourceOfUrn)); + } + } + + return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(), + serviceCategory, mergedEmergencyUrns, + first.getEmergencyNumberSourceBitmask() + | second.getEmergencyNumberSourceBitmask(), + routing); + } + + /** * Validate Emergency Number address that only contains the dialable character * {@link PhoneNumberUtils#isDialable(char)} * diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java index 2f8316e38363..611f97b70c8c 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -116,7 +116,10 @@ public class EuiccCardManager { /** Resets the default SM-DP+ address. */ public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 1 << 2; - /** Result code when the requested profile is not found */ + /** Result code when the requested profile is not found. + * {@link #RESULT_PROFILE_NOT_FOUND} is not used in Android U+, + * use {@link #RESULT_PROFILE_DOES_NOT_EXIST} instead. + **/ public static final int RESULT_PROFILE_NOT_FOUND = 1; /** Result code of execution with no error. */ @@ -131,6 +134,9 @@ public class EuiccCardManager { /** Result code indicating the caller is not the active LPA. */ public static final int RESULT_CALLER_NOT_ALLOWED = -3; + /** Result code when the requested profile does not exist */ + public static final int RESULT_PROFILE_DOES_NOT_EXIST = -4; + /** * Callback to receive the result of an eUICC card API. * @@ -222,7 +228,7 @@ public class EuiccCardManager { /** * Requests the enabled profile for a given port on an eUicc. Callback with result code - * {@link RESULT_PROFILE_NOT_FOUND} and {@code NULL} EuiccProfile if there is no enabled + * {@link RESULT_PROFILE_DOES_NOT_EXIST} and {@code NULL} EuiccProfile if there is no enabled * profile on the target port. * * @param cardId The Id of the eUICC. diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index 1252dc178cb9..ed4627631dd5 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -48,6 +48,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; /** @@ -81,6 +82,47 @@ public class EuiccManager { public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; + + /** + * Intent action to transfer an embedded subscriptions. + * + * <p> Action sent by apps (such as the Settings app) to the Telephony framework to transfer an + * embedded subscription. + * + * <p> Requires that the calling app has the + * {@code android.Manifest.permission#MODIFY_PHONE_STATE} permission. + * + * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if + * {@link #isEnabled} is false. + * + * @hide + */ + @SystemApi + @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public static final String ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS = + "android.telephony.euicc.action.TRANSFER_EMBEDDED_SUBSCRIPTIONS"; + + /** + * Intent action to convert the physical subscription to an embedded subscription. + * + * <p> Action sent by apps (such as the Settings app) to the Telephony framework to convert + * physical sim to embedded sim. + * + * <p> Requires that the calling app has the + * {@code android.Manifest.permission#MODIFY_PHONE_STATE} permission. + * + * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if + * {@link #isEnabled} is false. + * + * @hide + */ + @SystemApi + @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public static final String ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION = + "android.telephony.euicc.action.CONVERT_TO_EMBEDDED_SUBSCRIPTION"; + /** * Broadcast Action: The eUICC OTA status is changed. * <p class="note"> @@ -840,6 +882,16 @@ public class EuiccManager { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long SHOULD_RESOLVE_PORT_INDEX_FOR_APPS = 224562872L; + /** + * Starting with Android U, a port is available if it is active without an enabled profile + * on it or calling app can activate a new profile on the selected port without any user + * interaction. + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public static final long INACTIVE_PORT_AVAILABILITY_CHECK = 240273417L; + private final Context mContext; private int mCardId; @@ -1001,7 +1053,7 @@ public class EuiccManager { public void startResolutionActivity(Activity activity, int requestCode, Intent resultIntent, PendingIntent callbackIntent) throws IntentSender.SendIntentException { PendingIntent resolutionIntent = - resultIntent.getParcelableExtra(EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT); + resultIntent.getParcelableExtra(EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, android.app.PendingIntent.class); if (resolutionIntent == null) { throw new IllegalArgumentException("Invalid result intent"); } @@ -1032,7 +1084,7 @@ public class EuiccManager { if (!isEnabled()) { PendingIntent callbackIntent = resolutionIntent.getParcelableExtra( - EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT); + EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT, android.app.PendingIntent.class); if (callbackIntent != null) { sendUnavailableError(callbackIntent); } @@ -1524,7 +1576,7 @@ public class EuiccManager { return false; } try { - return getIEuiccController().isSupportedCountry(countryIso.toUpperCase()); + return getIEuiccController().isSupportedCountry(countryIso.toUpperCase(Locale.ROOT)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1571,6 +1623,10 @@ public class EuiccManager { * Returns whether the passing portIndex is available. * A port is available if it is active without enabled profile on it or * calling app has carrier privilege over the profile installed on the selected port. + * + * <p> From Android U, a port is available if it is active without an enabled profile on it or + * calling app can activate a new profile on the selected port without any user interaction. + * * Always returns false if the cardId is a physical card. * * @param portIndex is an enumeration of the ports available on the UICC. diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index e6d7df34f755..d07edeb971ea 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -27,6 +27,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.telecom.VideoProfile; +import android.telephony.CallState; import android.telephony.emergency.EmergencyNumber; import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting; import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories; @@ -78,8 +79,11 @@ public final class ImsCallProfile implements Parcelable { public static final int SERVICE_TYPE_EMERGENCY = 2; /** - * Call types + * This value is returned if there is no valid IMS call type defined for the call. For example, + * if an ongoing call is circuit-switched and {@link CallState#getImsCallType()} is called, this + * value will be returned. */ + public static final int CALL_TYPE_NONE = 0; /** * IMSPhone to support IR.92 & IR.94 (voice + video upgrade/downgrade) */ diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index d65286f26447..ecd703960d08 100755 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -18,10 +18,12 @@ package android.telephony.ims; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Bundle; import android.os.Message; import android.os.RemoteException; import android.telephony.CallQuality; import android.telephony.ims.aidl.IImsCallSessionListener; +import android.telephony.ims.stub.ImsCallSessionImplBase; import android.util.ArraySet; import android.util.Log; @@ -99,7 +101,6 @@ public class ImsCallSession { * Listener for events relating to an IMS session, such as when a session is being * recieved ("on ringing") or a call is outgoing ("on calling"). * <p>Many of these events are also received by {@link ImsCall.Listener}.</p> - * @hide */ public static class Listener { /** @@ -519,20 +520,30 @@ public class ImsCallSession { @NonNull Set<RtpHeaderExtension> extensions) { // no-op } + + /** + * Called when radio to send ANBRQ message to the access network to query the desired + * bitrate. + */ + public void callSessionSendAnbrQuery(int mediaType, int direction, int bitsPerSecond) { + // no-op + } } private final IImsCallSession miSession; private boolean mClosed = false; + private String mCallId = null; private Listener mListener; private Executor mListenerExecutor = Runnable::run; + private IImsCallSessionListenerProxy mIImsCallSessionListenerProxy = null; - /** @hide */ public ImsCallSession(IImsCallSession iSession) { miSession = iSession; + mIImsCallSessionListenerProxy = new IImsCallSessionListenerProxy(); if (iSession != null) { try { - iSession.setListener(new IImsCallSessionListenerProxy()); + iSession.setListener(mIImsCallSessionListenerProxy); } catch (RemoteException e) { } } else { @@ -540,13 +551,19 @@ public class ImsCallSession { } } - /** @hide */ public ImsCallSession(IImsCallSession iSession, Listener listener, Executor executor) { this(iSession); setListener(listener, executor); } /** + * returns the IImsCallSessionListenerProxy for the ImsCallSession + */ + public final IImsCallSessionListenerProxy getIImsCallSessionListenerProxy() { + return mIImsCallSessionListenerProxy; + } + + /** * Closes this object. This object is not usable after being closed. */ public void close() { @@ -567,16 +584,34 @@ public class ImsCallSession { * Gets the call ID of the session. * * @return the call ID + * If null is returned for getCallId, then that means that the call ID has not been set yet. */ public String getCallId() { if (mClosed) { return null; } - try { - return miSession.getCallId(); - } catch (RemoteException e) { - return null; + if (mCallId != null) { + return mCallId; + } else { + try { + return mCallId = miSession.getCallId(); + } catch (RemoteException e) { + return null; + } + } + } + + /** + * Sets the call ID of the session. + * + * @param callId Call ID of the session, which is transferred from + * {@link android.telephony.ims.feature.MmTelFeature#notifyIncomingCall( + * ImsCallSessionImplBase, String, Bundle)} + */ + public void setCallId(String callId) { + if (callId != null) { + mCallId = callId; } } @@ -635,7 +670,6 @@ public class ImsCallSession { * Gets the video call provider for the session. * * @return The video call provider. - * @hide */ public IImsVideoCallProvider getVideoCallProvider() { if (mClosed) { @@ -712,7 +746,6 @@ public class ImsCallSession { /** * Gets the native IMS call session. - * @hide */ public IImsCallSession getSession() { return miSession; @@ -742,7 +775,6 @@ public class ImsCallSession { * * @param listener to listen to the session events of this object * @param executor an Executor that will execute callbacks - * @hide */ public void setListener(Listener listener, Executor executor) { mListener = listener; @@ -1201,6 +1233,27 @@ public class ImsCallSession { } /** + * Deliver the bitrate for the indicated media type, direction and bitrate to the upper layer. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate received from the NW through the Recommended + * bitrate MAC Control Element message and ImsStack converts this value from MAC bitrate + * to audio/video codec bitrate (defined in TS26.114). + */ + public void callSessionNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { + if (mClosed) { + return; + } + + try { + miSession.callSessionNotifyAnbr(mediaType, direction, bitsPerSecond); + } catch (RemoteException e) { + Log.e(TAG, "callSessionNotifyAnbr" + e); + } + } + + /** * A listener type for receiving notification on IMS call session events. * When an event is generated for an {@link IImsCallSession}, * the application is notified by having one of the methods called on @@ -1693,6 +1746,26 @@ public class ImsCallSession { } }, mListenerExecutor); } + + /** + * ANBR Query received. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate requested by the other party UE through + * RTP CMR, RTCPAPP or TMMBR, and ImsStack converts this value to the MAC bitrate + * (defined in TS36.321, range: 0 ~ 8000 kbit/s). + */ + @Override + public void callSessionSendAnbrQuery(int mediaType, int direction, + int bitsPerSecond) { + Log.d(TAG, "callSessionSendAnbrQuery in ImsCallSession"); + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mListener != null) { + mListener.callSessionSendAnbrQuery(mediaType, direction, bitsPerSecond); + } + }, mListenerExecutor); + } } /** @@ -1706,10 +1779,8 @@ public class ImsCallSession { StringBuilder sb = new StringBuilder(); sb.append("[ImsCallSession objId:"); sb.append(System.identityHashCode(this)); - sb.append(" state:"); - sb.append(State.toString(getState())); sb.append(" callId:"); - sb.append(getCallId()); + sb.append(mCallId != null ? mCallId : "[UNINITIALIZED]"); sb.append("]"); return sb.toString(); } diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java index 3533c0907fac..5946535ce3af 100644 --- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java +++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java @@ -16,6 +16,7 @@ package android.telephony.ims; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -25,6 +26,9 @@ import android.telephony.CallQuality; import android.telephony.ServiceState; import android.telephony.ims.aidl.IImsCallSessionListener; import android.telephony.ims.stub.ImsCallSessionImplBase; +import android.telephony.ims.stub.ImsCallSessionImplBase.MediaStreamDirection; +import android.telephony.ims.stub.ImsCallSessionImplBase.MediaStreamType; +import android.util.Log; import com.android.ims.internal.IImsCallSession; @@ -45,6 +49,7 @@ import java.util.concurrent.Executor; // ImsCallSessionListenerConverter is also changed. @SystemApi public class ImsCallSessionListener { + private static final String TAG = "ImsCallSessionListener"; private final IImsCallSessionListener mListener; private Executor mExecutor = null; @@ -823,6 +828,30 @@ public class ImsCallSessionListener { } /** + * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114. + * This API triggers radio to send ANBRQ message to the access network to query the + * desired bitrate. + * + * @param mediaType {@link ImsCallSessionImplBase.MediaStreamType} is used to identify + * media stream such as audio or video. + * @param direction {@link ImsCallSessionImplBase.MediaStreamDirection} of this packet + * stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate requested by the other party UE through + * RTP CMR, RTCPAPP or TMMBR, and ImsStack converts this value to the MAC bitrate + * (defined in TS36.321, range: 0 ~ 8000 kbit/s). + * @hide + */ + public final void callSessionSendAnbrQuery(@MediaStreamType int mediaType, + @MediaStreamDirection int direction, @IntRange(from = 0) int bitsPerSecond) { + Log.d(TAG, "callSessionSendAnbrQuery in imscallsessonListener"); + try { + mListener.callSessionSendAnbrQuery(mediaType, direction, bitsPerSecond); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** * Set default Executor from ImsService. * @param executor The default executor to use when executing the methods by the vendor * implementation of {@link ImsCallSessionImplBase} for conference call. diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 883824ffc889..caee4e2ca277 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -549,7 +549,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. @@ -611,7 +610,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. @@ -659,7 +657,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. @@ -872,7 +869,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. @@ -947,7 +943,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. @@ -1121,7 +1116,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. @@ -1236,7 +1230,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. @@ -1425,7 +1418,6 @@ public class ImsMmTelManager implements RegistrationManager { * <li>The caller has carrier privileges (see * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any * active subscription.</li> - * <li>The caller is the default SMS app for the device.</li> * </ul> * <p>The profile owner is an app that owns a managed profile on the device; for more details * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java index e00ea0ea4d5e..4439e5c35d83 100644 --- a/telephony/java/android/telephony/ims/ImsRcsManager.java +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -540,6 +540,8 @@ public class ImsRcsManager { try { return imsRcsController.isCapable(mSubId, capability, radioTech); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException e) { Log.w(TAG, "Error calling IImsRcsController#isCapable", e); throw new ImsException("Remote IMS Service is not available", @@ -577,6 +579,8 @@ public class ImsRcsManager { try { return imsRcsController.isAvailable(mSubId, capability, radioTech); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException e) { Log.w(TAG, "Error calling IImsRcsController#isAvailable", e); throw new ImsException("Remote IMS Service is not available", diff --git a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java index b77d3063e2cc..50c438c7678e 100644 --- a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java +++ b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java @@ -65,6 +65,7 @@ public final class ImsRegistrationAttributes implements Parcelable { public static final class Builder { private final int mRegistrationTech; private Set<String> mFeatureTags = Collections.emptySet(); + private @Nullable SipDetails mSipDetails; /** * Build a new instance of {@link ImsRegistrationAttributes}. @@ -100,13 +101,22 @@ public final class ImsRegistrationAttributes implements Parcelable { } /** + * Set the SIP information. + * @param details The SIP information related to this IMS registration. + */ + public @NonNull Builder setSipDetails(@NonNull SipDetails details) { + mSipDetails = details; + return this; + } + + /** * @return A new instance created from this builder. */ public @NonNull ImsRegistrationAttributes build() { return new ImsRegistrationAttributes(mRegistrationTech, RegistrationManager.getAccessType(mRegistrationTech), getAttributeFlags(mRegistrationTech), - mFeatureTags); + mFeatureTags, mSipDetails); } /** @@ -125,6 +135,28 @@ public final class ImsRegistrationAttributes implements Parcelable { private final int mTransportType; private final int mImsAttributeFlags; private final ArrayList<String> mFeatureTags; + private final @Nullable SipDetails mSipDetails; + /** + * Create a new {@link ImsRegistrationAttributes} instance. + * This is for backward compatibility. + * + * @param registrationTech The technology that IMS has been registered on. + * @param transportType The transport type that IMS has been registered on. + * @param imsAttributeFlags The attributes associated with the IMS registration. + * @param featureTags The feature tags included in the IMS registration. + * @hide + */ + public ImsRegistrationAttributes( + @ImsRegistrationImplBase.ImsRegistrationTech int registrationTech, + @AccessNetworkConstants.TransportType int transportType, + @ImsAttributeFlag int imsAttributeFlags, + @Nullable Set<String> featureTags) { + mRegistrationTech = registrationTech; + mTransportType = transportType; + mImsAttributeFlags = imsAttributeFlags; + mFeatureTags = new ArrayList<>(featureTags); + mSipDetails = null; + } /** * Create a new {@link ImsRegistrationAttributes} instance. @@ -133,6 +165,7 @@ public final class ImsRegistrationAttributes implements Parcelable { * @param transportType The transport type that IMS has been registered on. * @param imsAttributeFlags The attributes associated with the IMS registration. * @param featureTags The feature tags included in the IMS registration. + * @param details The SIP information associated with the IMS registration. * @see Builder * @hide */ @@ -140,11 +173,13 @@ public final class ImsRegistrationAttributes implements Parcelable { @ImsRegistrationImplBase.ImsRegistrationTech int registrationTech, @AccessNetworkConstants.TransportType int transportType, @ImsAttributeFlag int imsAttributeFlags, - @Nullable Set<String> featureTags) { + @Nullable Set<String> featureTags, + @Nullable SipDetails details) { mRegistrationTech = registrationTech; mTransportType = transportType; mImsAttributeFlags = imsAttributeFlags; mFeatureTags = new ArrayList<>(featureTags); + mSipDetails = details; } /**@hide*/ @@ -154,6 +189,8 @@ public final class ImsRegistrationAttributes implements Parcelable { mImsAttributeFlags = source.readInt(); mFeatureTags = new ArrayList<>(); source.readList(mFeatureTags, null /*classloader*/, java.lang.String.class); + mSipDetails = source.readParcelable(null /*loader*/, + android.telephony.ims.SipDetails.class); } /** @@ -202,6 +239,13 @@ public final class ImsRegistrationAttributes implements Parcelable { return new ArraySet<>(mFeatureTags); } + /** + * @return The SIP information associated with the IMS registration. + */ + public @Nullable SipDetails getSipDetails() { + return mSipDetails; + } + @Override public int describeContents() { return 0; @@ -213,6 +257,7 @@ public final class ImsRegistrationAttributes implements Parcelable { dest.writeInt(mTransportType); dest.writeInt(mImsAttributeFlags); dest.writeList(mFeatureTags); + dest.writeParcelable(mSipDetails, flags); } public static final @NonNull Creator<ImsRegistrationAttributes> CREATOR = @@ -236,17 +281,20 @@ public final class ImsRegistrationAttributes implements Parcelable { return mRegistrationTech == that.mRegistrationTech && mTransportType == that.mTransportType && mImsAttributeFlags == that.mImsAttributeFlags - && Objects.equals(mFeatureTags, that.mFeatureTags); + && Objects.equals(mFeatureTags, that.mFeatureTags) + && Objects.equals(mSipDetails, that.mSipDetails); } @Override public int hashCode() { - return Objects.hash(mRegistrationTech, mTransportType, mImsAttributeFlags, mFeatureTags); + return Objects.hash(mRegistrationTech, mTransportType, mImsAttributeFlags, mFeatureTags, + mSipDetails); } @Override public String toString() { return "ImsRegistrationAttributes { transportType= " + mTransportType + ", attributeFlags=" - + mImsAttributeFlags + ", featureTags=[" + mFeatureTags + "]}"; + + mImsAttributeFlags + ", featureTags=[" + mFeatureTags + "]" + + ",SipDetails=" + mSipDetails + "}"; } } diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index 4477f81a378d..4c37f7d3184c 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -51,6 +51,7 @@ import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -138,12 +139,25 @@ public class ImsService extends Service { public static final long CAPABILITY_SIP_DELEGATE_CREATION = 1 << 1; /** + * This ImsService supports the terminal based call waiting service. + * <p> + * In order for the IMS service to support the service, IMS service shall + * override {@link MmTelFeature#setTerminalBasedCallWaitingStatus}. + * If ImsService has this capability, Android platform will handle the synchronization + * between the network based call waiting service over circuit-switched networks and the + * terminal based call waiting service of IMS service, and will handle the received + * circuit-switched waiting calls. Otherwise, this functionality of Android platform shall + * be disabled. + */ + public static final long CAPABILITY_TERMINAL_BASED_CALL_WAITING = 1 << 2; + + /** * Used for internal correctness checks of capabilities set by the ImsService implementation and * tracks the index of the largest defined flag in the capabilities long. * @hide */ public static final long CAPABILITY_MAX_INDEX = - Long.numberOfTrailingZeros(CAPABILITY_SIP_DELEGATE_CREATION); + Long.numberOfTrailingZeros(CAPABILITY_TERMINAL_BASED_CALL_WAITING); /** * @hide @@ -154,7 +168,8 @@ public class ImsService extends Service { // CAPABILITY_EMERGENCY_OVER_MMTEL is not included here because it is managed by // whether or not ImsFeature.FEATURE_EMERGENCY_MMTEL feature is set and should // not be set by users of ImsService. - CAPABILITY_SIP_DELEGATE_CREATION + CAPABILITY_SIP_DELEGATE_CREATION, + CAPABILITY_TERMINAL_BASED_CALL_WAITING }) @Retention(RetentionPolicy.SOURCE) public @interface ImsServiceCapability {} @@ -186,6 +201,8 @@ public class ImsService extends Service { new SparseArray<>(); private IImsServiceControllerListener mListener; + private final Object mListenerLock = new Object(); + private final Object mExecutorLock = new Object(); private Executor mExecutor; /** @@ -196,10 +213,6 @@ public class ImsService extends Service { * vendor use Runnable::run. */ public ImsService() { - mExecutor = ImsService.this.getExecutor(); - if (mExecutor == null) { - mExecutor = Runnable::run; - } } /** @@ -223,7 +236,30 @@ public class ImsService extends Service { protected final IBinder mImsServiceController = new IImsServiceController.Stub() { @Override public void setListener(IImsServiceControllerListener l) { - mListener = l; + synchronized (mListenerLock) { + if (mListener != null && mListener.asBinder().isBinderAlive()) { + try { + mListener.asBinder().unlinkToDeath(mDeathRecipient, 0); + } catch (NoSuchElementException e) { + Log.w(LOG_TAG, "IImsServiceControllerListener does not exist"); + } + } + + mListener = l; + if (mListener == null) { + executeMethodAsync(() -> releaseResource(), "releaseResource"); + return; + } + + try { + mListener.asBinder().linkToDeath(mDeathRecipient, 0); + Log.i(LOG_TAG, "setListener: register linkToDeath"); + } catch (RemoteException e) { + // RemoteException means target binder process was crashed + // release resource + executeMethodAsync(() -> releaseResource(), "releaseResource"); + } + } } @Override @@ -315,7 +351,7 @@ public class ImsService extends Service { ImsConfigImplBase c = ImsService.this.getConfigForSubscription(slotId, subId); if (c != null) { - c.setDefaultExecutor(mExecutor); + c.setDefaultExecutor(getCachedExecutor()); return c.getIImsConfig(); } else { return null; @@ -329,7 +365,7 @@ public class ImsService extends Service { ImsRegistrationImplBase r = ImsService.this.getRegistrationForSubscription(slotId, subId); if (r != null) { - r.setDefaultExecutor(mExecutor); + r.setDefaultExecutor(getCachedExecutor()); return r.getBinder(); } else { return null; @@ -342,7 +378,7 @@ public class ImsService extends Service { return executeMethodAsyncForResult(() -> { SipTransportImplBase s = ImsService.this.getSipTransport(slotId); if (s != null) { - s.setDefaultExecutor(mExecutor); + s.setDefaultExecutor(getCachedExecutor()); return s.getBinder(); } else { return null; @@ -362,28 +398,19 @@ public class ImsService extends Service { ImsService.this.disableImsForSubscription(slotId, subId), "disableIms"); } - // Call the methods with a clean calling identity on the executor and wait indefinitely for - // the future to return. - private void executeMethodAsync(Runnable r, String errorLogName) { - try { - CompletableFuture.runAsync( - () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); - } catch (CancellationException | CompletionException e) { - Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " - + e.getMessage()); - } + @Override + public void resetIms(int slotId, int subId) { + executeMethodAsync(() -> + ImsService.this.resetImsInternal(slotId, subId), "resetIms"); } + }; - private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) { - CompletableFuture<T> future = CompletableFuture.supplyAsync( - () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); - try { - return future.get(); - } catch (ExecutionException | InterruptedException e) { - Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " - + e.getMessage()); - return null; - } + private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.w(LOG_TAG, + "IImsServiceControllerListener binder to framework has died. Cleaning up"); + executeMethodAsync(() -> releaseResource(), "releaseResource"); } }; @@ -399,11 +426,21 @@ public class ImsService extends Service { return null; } + private Executor getCachedExecutor() { + synchronized (mExecutorLock) { + if (mExecutor == null) { + Executor e = ImsService.this.getExecutor(); + mExecutor = (e != null) ? e : Runnable::run; + } + return mExecutor; + } + } + private IImsMmTelFeature createMmTelFeatureInternal(int slotId, int subscriptionId) { MmTelFeature f = createMmTelFeatureForSubscription(slotId, subscriptionId); if (f != null) { setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); - f.setDefaultExecutor(mExecutor); + f.setDefaultExecutor(getCachedExecutor()); return f.getBinder(); } else { Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned."); @@ -415,7 +452,7 @@ public class ImsService extends Service { MmTelFeature f = createEmergencyOnlyMmTelFeature(slotId); if (f != null) { setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); - f.setDefaultExecutor(mExecutor); + f.setDefaultExecutor(getCachedExecutor()); return f.getBinder(); } else { Log.e(LOG_TAG, "createEmergencyOnlyMmTelFeatureInternal: null feature returned."); @@ -426,7 +463,7 @@ public class ImsService extends Service { private IImsRcsFeature createRcsFeatureInternal(int slotId, int subId) { RcsFeature f = createRcsFeatureForSubscription(slotId, subId); if (f != null) { - f.setDefaultExecutor(mExecutor); + f.setDefaultExecutor(getCachedExecutor()); setupFeature(f, slotId, ImsFeature.FEATURE_RCS); return f.getBinder(); } else { @@ -488,6 +525,9 @@ public class ImsService extends Service { } private void removeImsFeature(int slotId, int featureType) { + // clear cached data + notifySubscriptionRemoved(slotId); + synchronized (mFeaturesBySlot) { // get ImsFeature associated with the slot/feature SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); @@ -505,7 +545,6 @@ public class ImsService extends Service { f.onFeatureRemoved(); features.remove(featureType); } - } /** @@ -550,6 +589,63 @@ public class ImsService extends Service { return createFlag; } + private void releaseResource() { + Log.w(LOG_TAG, "cleaning up features"); + synchronized (mFeaturesBySlot) { + SparseArray<ImsFeature> features; + ImsFeature imsFeature; + + for (int i = 0; i < mFeaturesBySlot.size(); i++) { + features = mFeaturesBySlot.valueAt(i); + if (features == null) { + continue; + } + + for (int index = 0; index < features.size(); index++) { + imsFeature = features.valueAt(index); + if (imsFeature != null) { + imsFeature.onFeatureRemoved(); + } + } + features.clear(); + } + mFeaturesBySlot.clear(); + } + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), + getCachedExecutor()).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " + + e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), getCachedExecutor()); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " + + e.getMessage()); + return null; + } + } + + private void resetImsInternal(int slotId, int subId) { + try { + resetIms(slotId); + } catch (UnsupportedOperationException e) { + disableImsForSubscription(slotId, subId); + } + } + /** * When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService} * currently supports. This will trigger the framework to set up the {@link ImsFeature}s that @@ -572,10 +668,14 @@ public class ImsService extends Service { */ public final void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) throws RemoteException { - if (mListener == null) { - throw new IllegalStateException("Framework is not ready"); + IImsServiceControllerListener l; + synchronized (mListenerLock) { + if (mListener == null) { + throw new IllegalStateException("Framework is not ready"); + } + l = mListener; } - mListener.onUpdateSupportedImsFeatures(c); + l.onUpdateSupportedImsFeatures(c); } /** @@ -627,6 +727,24 @@ public class ImsService extends Service { } /** + * The subscription has removed. The ImsService should notify ImsRegistrationImplBase and + * ImsConfigImplBase the SIM state was changed. + * @param slotId The slot ID which has removed. + */ + private void notifySubscriptionRemoved(int slotId) { + ImsRegistrationImplBase registrationImplBase = + getRegistration(slotId); + if (registrationImplBase != null) { + registrationImplBase.clearRegistrationCache(); + } + + ImsConfigImplBase imsConfigImplBase = getConfig(slotId); + if (imsConfigImplBase != null) { + imsConfigImplBase.clearConfigurationCache(); + } + } + + /** * The framework has enabled IMS for the slot specified, the ImsService should register for IMS * and perform all appropriate initialization to bring up all ImsFeatures. * @deprecated Use {@link #enableImsForSubscription} instead. @@ -645,6 +763,19 @@ public class ImsService extends Service { } /** + * The framework has reset IMS for the slot specified. The ImsService must deregister + * and release all resources for IMS. After resetIms is called, either + * {@link #enableImsForSubscription(int, int)} or {@link #disableImsForSubscription(int, int)} + * will be called for the same slotId. + * + * @param slotId The slot ID that IMS will be reset for. + * @hide + */ + public void resetIms(int slotId) { + throw new UnsupportedOperationException(); + } + + /** * When called, the framework is requesting that a new {@link MmTelFeature} is created for the * specified subscription. * diff --git a/telephony/java/android/telephony/ims/MediaQualityStatus.aidl b/telephony/java/android/telephony/ims/MediaQualityStatus.aidl new file mode 100644 index 000000000000..e570f6c906c3 --- /dev/null +++ b/telephony/java/android/telephony/ims/MediaQualityStatus.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 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 android.telephony.ims; + +parcelable MediaQualityStatus;
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/MediaQualityStatus.java b/telephony/java/android/telephony/ims/MediaQualityStatus.java new file mode 100644 index 000000000000..76394feaed66 --- /dev/null +++ b/telephony/java/android/telephony/ims/MediaQualityStatus.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.AccessNetworkConstants.TransportType; + +import java.util.Objects; + +/** + * A representation of Media quality status. + * + * @hide + */ +@SystemApi +public final class MediaQualityStatus implements Parcelable { + public static final int MEDIA_SESSION_TYPE_AUDIO = 1; + public static final int MEDIA_SESSION_TYPE_VIDEO = 2; + + private final String mImsCallSessionId; + private final int mMediaSessionType; + private final int mTransportType; + private final int mRtpPacketLossRate; + private final int mRtpJitterMillis; + private final long mRtpInactivityTimeMillis; + + /** @hide */ + @IntDef( + value = { + MEDIA_SESSION_TYPE_AUDIO, + MEDIA_SESSION_TYPE_VIDEO, + }) + public @interface MediaSessionType {} + + /** + * The constructor for MediaQualityStatus, which represents the media quality for each session + * type ({@link #MEDIA_SESSION_TYPE_AUDIO} or {@link #MEDIA_SESSION_TYPE_VIDEO}) of the IMS call + * + * @param imsCallSessionId IMS call session id of this quality status + * @param mediaSessionType media session type of this quality status + * @param transportType transport type of this quality status + * @param rtpPacketLossRate measured RTP packet loss rate in percentage + * @param rtpJitterMillis measured RTP jitter(RFC3550) in milliseconds + * @param rptInactivityTimeMillis measured RTP inactivity time in milliseconds + */ + public MediaQualityStatus(@NonNull String imsCallSessionId, + @MediaSessionType int mediaSessionType, @TransportType int transportType, + @IntRange(from = 0, to = 100) int rtpPacketLossRate, + @IntRange(from = 0) int rtpJitterMillis, + @IntRange(from = 0) long rptInactivityTimeMillis) { + mImsCallSessionId = imsCallSessionId; + mMediaSessionType = mediaSessionType; + mTransportType = transportType; + mRtpPacketLossRate = rtpPacketLossRate; + mRtpJitterMillis = rtpJitterMillis; + mRtpInactivityTimeMillis = rptInactivityTimeMillis; + } + + /** + * Retrieves call session ID for this quality status + */ + @NonNull + public String getCallSessionId() { + return mImsCallSessionId; + } + + /** + * Retrieves media session type of this quality status + */ + public @MediaSessionType int getMediaSessionType() { + return mMediaSessionType; + } + + + /** + * Retrieves Transport type for which this media quality was measured. + */ + public @TransportType int getTransportType() { + return mTransportType; + } + + /** + * Retrieves measured RTP packet loss rate in percentage. + */ + @IntRange(from = 0, to = 100) + public int getRtpPacketLossRate() { + return mRtpPacketLossRate; + } + + /** + * Retrieves measured RTP jitter(RFC3550) value in milliseconds + */ + @IntRange(from = 0) + public int getRtpJitterMillis() { + return mRtpJitterMillis; + } + + /** + * Retrieves measured RTP inactivity time in milliseconds + */ + @IntRange(from = 0) + public long getRtpInactivityMillis() { + return mRtpInactivityTimeMillis; + } + + /** + * Creates a new instance of {@link MediaQualityStatus} from a parcel. + * @param in The parceled data to read. + */ + private MediaQualityStatus(@NonNull Parcel in) { + mImsCallSessionId = in.readString(); + mMediaSessionType = in.readInt(); + mTransportType = in.readInt(); + mRtpPacketLossRate = in.readInt(); + mRtpJitterMillis = in.readInt(); + mRtpInactivityTimeMillis = in.readLong(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mImsCallSessionId); + dest.writeInt(mMediaSessionType); + dest.writeInt(mTransportType); + dest.writeInt(mRtpPacketLossRate); + dest.writeInt(mRtpJitterMillis); + dest.writeLong(mRtpInactivityTimeMillis); + } + + public static final @NonNull Creator<MediaQualityStatus> CREATOR = + new Creator<MediaQualityStatus>() { + @Override + public MediaQualityStatus createFromParcel(@NonNull Parcel in) { + return new MediaQualityStatus(in); + } + + @Override + public MediaQualityStatus[] newArray(int size) { + return new MediaQualityStatus[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MediaQualityStatus that = (MediaQualityStatus) o; + return mImsCallSessionId != null && mImsCallSessionId.equals(that.mImsCallSessionId) + && mMediaSessionType == that.mMediaSessionType + && mTransportType == that.mTransportType + && mRtpPacketLossRate == that.mRtpPacketLossRate + && mRtpJitterMillis == that.mRtpJitterMillis + && mRtpInactivityTimeMillis == that.mRtpInactivityTimeMillis; + } + + @Override + public int hashCode() { + return Objects.hash(mImsCallSessionId, mMediaSessionType, mTransportType, + mRtpPacketLossRate, mRtpJitterMillis, mRtpInactivityTimeMillis); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("MediaThreshold{mImsCallSessionId="); + sb.append(mImsCallSessionId); + sb.append(", mMediaSessionType="); + sb.append(mMediaSessionType); + sb.append(", mTransportType="); + sb.append(mTransportType); + sb.append(", mRtpPacketLossRate="); + sb.append(mRtpPacketLossRate); + sb.append(", mRtpJitterMillis="); + sb.append(mRtpJitterMillis); + sb.append(", mRtpInactivityTimeMillis="); + sb.append(mRtpInactivityTimeMillis); + sb.append("}"); + return sb.toString(); + } +} diff --git a/telephony/java/android/telephony/ims/MediaThreshold.aidl b/telephony/java/android/telephony/ims/MediaThreshold.aidl new file mode 100644 index 000000000000..dede418fb0e2 --- /dev/null +++ b/telephony/java/android/telephony/ims/MediaThreshold.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 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 android.telephony.ims; + +parcelable MediaThreshold;
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/MediaThreshold.java b/telephony/java/android/telephony/ims/MediaThreshold.java new file mode 100644 index 000000000000..343aa4aab023 --- /dev/null +++ b/telephony/java/android/telephony/ims/MediaThreshold.java @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.ims.feature.MmTelFeature; + +import java.util.Arrays; +import java.util.Objects; +import java.util.TreeSet; + +/** + * A MediaThreshold represents a series of packet loss rate, jitter and rtp inactivity time + * thresholds which when crossed should result in a {@link MediaQualityStatus} report being + * generated by the {@link ImsService} via {@link MmTelFeature#notifyMediaQualityStatusChanged( + * MediaQualityStatus)} + * + * <p/> + * A {@link MediaQualityStatus} should be triggered when any of various + * attributes pass one of the thresholds defined here. + * + * @hide + */ +@SystemApi +public final class MediaThreshold implements Parcelable { + private final int[] mRtpPacketLossRate; + private final int[] mRtpJitter; + private final long[] mRtpInactivityTimeMillis; + + /** + * Retrieves threshold values for RTP packet loss rate in percentage. + * + * @return int array including threshold values for packet loss rate + * + * @hide + */ + @NonNull + @SystemApi + public int[] getThresholdsRtpPacketLossRate() { + return mRtpPacketLossRate; + } + + /** + * Retrieves threshold values for jitter(RFC3550) in milliseconds. + * + * @return int array including threshold values for RTP jitter. + */ + @NonNull + public int[] getThresholdsRtpJitterMillis() { + return mRtpJitter; + } + + /** + * Retrieves threshold values for RTP inactivity time in milliseconds. + * + * @return int array including threshold values for RTP inactivity time. + */ + @NonNull + public long[] getThresholdsRtpInactivityTimeMillis() { + return mRtpInactivityTimeMillis; + } + + private MediaThreshold( + int[] packetLossRateThresholds, + int[] jitterThresholds, + long[] inactivityTimeThresholds) { + mRtpPacketLossRate = packetLossRateThresholds; + mRtpJitter = jitterThresholds; + mRtpInactivityTimeMillis = inactivityTimeThresholds; + } + + /** + * Creates a new instance of {@link MediaThreshold} from a parcel. + * @param in The parceled data to read. + */ + private MediaThreshold(@NonNull Parcel in) { + mRtpPacketLossRate = in.createIntArray(); + mRtpJitter = in.createIntArray(); + mRtpInactivityTimeMillis = in.createLongArray(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeIntArray(mRtpPacketLossRate); + dest.writeIntArray(mRtpJitter); + dest.writeLongArray(mRtpInactivityTimeMillis); + } + + public static final @NonNull Creator<MediaThreshold> CREATOR = + new Creator<MediaThreshold>() { + @Override + public MediaThreshold createFromParcel(@NonNull Parcel in) { + return new MediaThreshold(in); + } + + @Override + public MediaThreshold[] newArray(int size) { + return new MediaThreshold[size]; + } + }; + + /** + * Returns whether the RTP packet loss rate threshold is valid or not. + * + * @param packetLossRate packet loss rate + * @return the threshold is valid or not. + * @hide + */ + public static boolean isValidRtpPacketLossRate(int packetLossRate) { + return (packetLossRate >= 0 && packetLossRate <= 100); + } + + /** + * Returns whether the RTP jitter threshold is valid or not. + * + * @param jitter jitter value in milliseconds + * @return the threshold is valid or not. + * @hide + */ + public static boolean isValidJitterMillis(int jitter) { + return (jitter >= 0 && jitter <= 10000); + } + + /** + * Returns whether the RTP packet loss rate threshold is valid or not. + * + * @param inactivityTime packet loss rate + * @return the threshold is valid or not. + * @hide + */ + public static boolean isValidRtpInactivityTimeMillis(long inactivityTime) { + return (inactivityTime >= 0 && inactivityTime <= 60000); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MediaThreshold that = (MediaThreshold) o; + return Arrays.equals(mRtpPacketLossRate, that.mRtpPacketLossRate) + && Arrays.equals(mRtpJitter, that.mRtpJitter) + && Arrays.equals(mRtpInactivityTimeMillis, that.mRtpInactivityTimeMillis); + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(mRtpPacketLossRate), Arrays.hashCode(mRtpJitter), + Arrays.hashCode(mRtpInactivityTimeMillis)); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("MediaThreshold{mRtpPacketLossRate="); + for (int i : mRtpPacketLossRate) { + sb.append(" ").append(i); + } + sb.append(", mRtpJitter="); + for (int b : mRtpJitter) { + sb.append(" ").append(b); + } + sb.append(", mRtpInactivityTimeMillis="); + for (long i : mRtpInactivityTimeMillis) { + sb.append(" ").append(i); + } + sb.append("}"); + return sb.toString(); + } + + /** + * Provides a convenient way to set the fields of an {@link MediaThreshold} when creating a + * new instance. + * + * <p>The example below shows how you might create a new {@code RtpThreshold}: + * + * <pre><code> + * + * RtpThreshold = new RtpThreshold.Builder() + * .setRtpSessionType({@link MediaQualityStatus#MEDIA_SESSION_TYPE_AUDIO} or + * {@link MediaQualityStatus#MEDIA_SESSION_TYPE_VIDEO}) + * .setThresholdsRtpPacketLossRate(int[] packetLossRateThresholds) + * .setThresholdsRtpJitterMillis(int[] jitterThresholds) + * .setThresholdsRtpInactivityTimeMillis(int[] inactivityTimeThresholds) + * .build(); + * </code></pre> + * + * @hide + */ + public static final class Builder { + private int[] mRtpPacketLossRate = null; + private int[] mRtpJitter = null; + private long[] mRtpInactivityTimeMillis = null; + + /** + * Default constructor for the Builder. + * + * @hide + */ + public Builder() { + } + + /** + * Set threshold values for RTP packet loss rate in percentage. + * <p/> + * The packet loss calculation should be done at least once per + * second. It should be calculated with at least the last 3 seconds + * of data. + * + * @param packetLossRateThresholds int array for threshold values. + * @return The same instance of the builder. + * + * @hide + */ + @NonNull + public Builder setThresholdsRtpPacketLossRate(int[] packetLossRateThresholds) { + if (packetLossRateThresholds.length > 0) { + TreeSet<Integer> thresholds = new TreeSet<>(); + for (Integer value : packetLossRateThresholds) { + if (isValidRtpPacketLossRate(value)) { + thresholds.add(value); + } + } + int[] targetArray = new int[thresholds.size()]; + int i = 0; + for (int element : thresholds) { + targetArray[i++] = element; + } + this.mRtpPacketLossRate = targetArray; + } else { + this.mRtpPacketLossRate = packetLossRateThresholds; + } + return this; + } + + + /** + * Set threshold values for RTP jitter in Milliseconds. + * + * @param jitterThresholds int array including threshold values for Jitter. + * @return The same instance of the builder. + * + * @hide + */ + @NonNull + public Builder setThresholdsRtpJitterMillis(int[] jitterThresholds) { + if (jitterThresholds.length > 0) { + TreeSet<Integer> thresholds = new TreeSet<>(); + for (Integer value : jitterThresholds) { + if (isValidJitterMillis(value)) { + thresholds.add(value); + } + } + int[] targetArray = new int[thresholds.size()]; + int i = 0; + for (int element : thresholds) { + targetArray[i++] = element; + } + this.mRtpJitter = targetArray; + } else { + this.mRtpJitter = jitterThresholds; + } + return this; + } + + /** + * Set threshold values for RTP inactivity time. + * + * @param inactivityTimeThresholds int array including threshold + * values for RTP inactivity time. + * @return The same instance of the builder. + * + * @hide + */ + @NonNull + public Builder setThresholdsRtpInactivityTimeMillis(long[] inactivityTimeThresholds) { + if (inactivityTimeThresholds.length > 0) { + TreeSet<Long> thresholds = new TreeSet<>(); + for (Long value : inactivityTimeThresholds) { + if (isValidRtpInactivityTimeMillis(value)) { + thresholds.add(value); + } + } + long[] targetArray = new long[thresholds.size()]; + int i = 0; + for (long element : thresholds) { + targetArray[i++] = element; + } + this.mRtpInactivityTimeMillis = targetArray; + } else { + this.mRtpInactivityTimeMillis = inactivityTimeThresholds; + } + return this; + } + + /** + * Build the {@link MediaThreshold} + * + * @return the {@link MediaThreshold} object + * + * @hide + */ + @NonNull + public MediaThreshold build() { + mRtpPacketLossRate = mRtpPacketLossRate != null ? mRtpPacketLossRate : new int[0]; + mRtpJitter = mRtpJitter != null ? mRtpJitter : new int[0]; + mRtpInactivityTimeMillis = + mRtpInactivityTimeMillis != null ? mRtpInactivityTimeMillis : new long[0]; + return new MediaThreshold(mRtpPacketLossRate, mRtpJitter, mRtpInactivityTimeMillis); + } + } +} diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 945b0850d25e..37a6a7ebf953 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -54,6 +54,9 @@ import java.util.concurrent.Executor; * IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning * applications and may vary. It is up to the carrier and OEM applications to ensure that the * correct provisioning keys are being used when integrating with a vendor's ImsService. + * + * Use {@link android.telephony.ims.ImsManager#getProvisioningManager(int)} to get an instance of + * this manager. */ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS) public class ProvisioningManager { @@ -1685,7 +1688,8 @@ public class ProvisioningManager { /** * Notify the framework that an RCS autoconfiguration XML file has been received for - * provisioning. + * provisioning. This API is only valid if the device supports IMS, which can be checked using + * {@link PackageManager#hasSystemFeature}. * * <p>Requires Permission: * <ul> @@ -1923,7 +1927,8 @@ public class ProvisioningManager { /** * Reconfiguration triggered by the RCS application. Most likely cause - * is the 403 forbidden to a HTTP request. + * is the 403 forbidden to a HTTP request. This API is only valid if the device supports IMS, + * which can be checked using {@link PackageManager#hasSystemFeature} * * <p>When this api is called, the RCS configuration for the associated * subscription will be removed, and the application which has registered diff --git a/telephony/java/android/telephony/ims/PublishAttributes.aidl b/telephony/java/android/telephony/ims/PublishAttributes.aidl new file mode 100644 index 000000000000..c569cd75eadd --- /dev/null +++ b/telephony/java/android/telephony/ims/PublishAttributes.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 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 android.telephony.ims; + +parcelable PublishAttributes; diff --git a/telephony/java/android/telephony/ims/PublishAttributes.java b/telephony/java/android/telephony/ims/PublishAttributes.java new file mode 100644 index 000000000000..b987f1cb562d --- /dev/null +++ b/telephony/java/android/telephony/ims/PublishAttributes.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.ims.RcsUceAdapter.PublishState; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * This class provides detailed information related to publish state, SIP information and + * presence tuples in publication. + * This allows the application can check the detailed information of publication. + * @hide + */ +@SystemApi +public final class PublishAttributes implements Parcelable { + + private final @PublishState int mPublishState; + private List<RcsContactPresenceTuple> mPresenceTuples; + private @Nullable SipDetails mSipDetails; + + /** + * Builder for creating {@link Builder} instances. + * @hide + */ + public static final class Builder { + private PublishAttributes mAttributes; + /** + * Build a new instance of {@link PublishAttributes}. + * + * @param publishState The current publication state {@link RcsUceAdapter.PublishState}. + */ + public Builder(@PublishState int publishState) { + mAttributes = new PublishAttributes(publishState); + } + + /** + * Sets the SIP information in received response to a publish operation. + * @param details The {@link SipDetails} in received response. + * @return The same instance of the builder. + */ + public @NonNull Builder setSipDetails(@Nullable SipDetails details) { + mAttributes.mSipDetails = details; + return this; + } + + /** + * The tuple elements associated with the presence element portion of the PIDF document + * successfully sent to the network. + * @param tuples The list of the {@link RcsContactPresenceTuple} sent to the server. + * The contact URI should not be included in this tuples. + * @return this The same instance of the builder. + */ + public @NonNull Builder setPresenceTuples(@NonNull List<RcsContactPresenceTuple> tuples) { + mAttributes.mPresenceTuples = tuples; + return this; + } + + /** + * @return a new PublishAttributes from this Builder. + */ + public @NonNull PublishAttributes build() { + return mAttributes; + } + } + + /** + * Generate the attributes related to the publication. + * + * @param publishState The current publication state. + * See {@link RcsUceAdapter.PublishState}. + */ + private PublishAttributes(@PublishState int publishState) { + mPublishState = publishState; + } + + /** + * Get the current publication state when the publishing state has changed or + * the publishing operation has done. + * @return The current publication state. See {@link RcsUceAdapter.PublishState}. + */ + public @PublishState int getPublishState() { + return mPublishState; + } + + /** + * Get the presence tuples from the PIDF on which the publishing was successful. + * @return The list of the {@link RcsContactPresenceTuple} sent to the server. If publish is + * not successful yet, the value is empty. + */ + public @NonNull List<RcsContactPresenceTuple> getPresenceTuples() { + if (mPresenceTuples == null) { + return Collections.emptyList(); + } + return mPresenceTuples; + } + + /** + * Get the SipDetails set in ImsService. + * @return The {@link SipDetails} received in response. This value may be null if + * the device doesn't support the collection of this information. + */ + public @Nullable SipDetails getSipDetails() { + return mSipDetails; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mPublishState); + dest.writeList(mPresenceTuples); + dest.writeParcelable(mSipDetails, 0); + } + + public static final @NonNull Creator<PublishAttributes> CREATOR = + new Creator<PublishAttributes>() { + @Override + public PublishAttributes createFromParcel(Parcel source) { + return new PublishAttributes(source); + } + + @Override + public PublishAttributes[] newArray(int size) { + return new PublishAttributes[size]; + } + }; + + /** + * Construct a PublishAttributes object from the given parcel. + */ + private PublishAttributes(Parcel in) { + mPublishState = in.readInt(); + mPresenceTuples = new ArrayList<>(); + in.readList(mPresenceTuples, null, RcsContactPresenceTuple.class); + mSipDetails = in.readParcelable(SipDetails.class.getClassLoader(), + android.telephony.ims.SipDetails.class); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PublishAttributes that = (PublishAttributes) o; + return mPublishState == that.mPublishState + && Objects.equals(mPresenceTuples, that.mPresenceTuples) + && Objects.equals(mSipDetails, that.mSipDetails); + } + + @Override + public int hashCode() { + return Objects.hash(mPublishState, mPresenceTuples, mSipDetails); + } + + @Override + public String toString() { + return "PublishAttributes { publishState= " + mPublishState + + ", presenceTuples=[" + mPresenceTuples + "]" + "SipDetails=" + mSipDetails + "}"; + } +} + diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java index fd8d8a76353b..32d686d4e28c 100644 --- a/telephony/java/android/telephony/ims/RcsConfig.java +++ b/telephony/java/android/telephony/ims/RcsConfig.java @@ -36,6 +36,7 @@ import org.xmlpull.v1.XmlPullParserFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -188,16 +189,17 @@ public final class RcsConfig { String tag = null; while (eventType != XmlPullParser.END_DOCUMENT && current != null) { if (eventType == XmlPullParser.START_TAG) { - tag = xpp.getName().trim().toLowerCase(); + tag = xpp.getName().trim().toLowerCase(Locale.ROOT); if (TAG_CHARACTERISTIC.equals(tag)) { int count = xpp.getAttributeCount(); String type = null; if (count > 0) { for (int i = 0; i < count; i++) { - String name = xpp.getAttributeName(i).trim().toLowerCase(); + String name = xpp.getAttributeName(i).trim() + .toLowerCase(Locale.ROOT); if (ATTRIBUTE_TYPE.equals(name)) { type = xpp.getAttributeValue(xpp.getAttributeNamespace(i), - name).trim().toLowerCase(); + name).trim().toLowerCase(Locale.ROOT); break; } } @@ -211,10 +213,11 @@ public final class RcsConfig { String value = null; if (count > 1) { for (int i = 0; i < count; i++) { - String name = xpp.getAttributeName(i).trim().toLowerCase(); + String name = xpp.getAttributeName(i).trim() + .toLowerCase(Locale.ROOT); if (ATTRIBUTE_NAME.equals(name)) { key = xpp.getAttributeValue(xpp.getAttributeNamespace(i), - name).trim().toLowerCase(); + name).trim().toLowerCase(Locale.ROOT); } else if (ATTRIBUTE_VALUE.equals(name)) { value = xpp.getAttributeValue(xpp.getAttributeNamespace(i), name).trim(); @@ -226,7 +229,7 @@ public final class RcsConfig { } } } else if (eventType == XmlPullParser.END_TAG) { - tag = xpp.getName().trim().toLowerCase(); + tag = xpp.getName().trim().toLowerCase(Locale.ROOT); if (TAG_CHARACTERISTIC.equals(tag)) { current = current.getParent(); } @@ -254,7 +257,7 @@ public final class RcsConfig { * @return Returns the config value if it exists, or defaultVal. */ public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) { - String value = mCurrent.getParmValue(tag.trim().toLowerCase()); + String value = mCurrent.getParmValue(tag.trim().toLowerCase(Locale.ROOT)); return value != null ? value : defaultVal; } @@ -296,21 +299,21 @@ public final class RcsConfig { * @return Returns true if it exists, or false. */ public boolean hasConfig(@NonNull String tag) { - return mCurrent.hasParm(tag.trim().toLowerCase()); + return mCurrent.hasParm(tag.trim().toLowerCase(Locale.ROOT)); } /** * Return the Characteristic with the given type */ public @Nullable Characteristic getCharacteristic(@NonNull String type) { - return mCurrent.getSubByType(type.trim().toLowerCase()); + return mCurrent.getSubByType(type.trim().toLowerCase(Locale.ROOT)); } /** * Check whether the Characteristic with the given type exists */ public boolean hasCharacteristic(@NonNull String type) { - return mCurrent.getSubByType(type.trim().toLowerCase()) != null; + return mCurrent.getSubByType(type.trim().toLowerCase(Locale.ROOT)) != null; } /** diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 91dc38ff9ddb..3bb9be0252cd 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; @@ -382,8 +383,21 @@ public class RcsUceAdapter { /** * Notifies the callback when the publish state has changed. * @param publishState The latest update to the publish state. + * + * @deprecated Replaced by {@link #onPublishStateChange}, deprecated for + * sip information. */ + @Deprecated void onPublishStateChange(@PublishState int publishState); + + /** + * Notifies the callback when the publish state has changed or the publish operation is + * done. + * @param attributes The latest information related to the publish. + */ + default void onPublishStateChange(@NonNull PublishAttributes attributes) { + onPublishStateChange(attributes.getPublishState()); + }; } /** @@ -404,13 +418,13 @@ public class RcsUceAdapter { } @Override - public void onPublishStateChanged(int publishState) { + public void onPublishUpdated(@NonNull PublishAttributes attributes) { if (mPublishStateChangeListener == null) return; final long callingIdentity = Binder.clearCallingIdentity(); try { mExecutor.execute(() -> - mPublishStateChangeListener.onPublishStateChange(publishState)); + mPublishStateChangeListener.onPublishStateChange(attributes)); } finally { restoreCallingIdentity(callingIdentity); } @@ -433,12 +447,12 @@ public class RcsUceAdapter { /** * A callback for the response to a UCE request. The method * {@link CapabilitiesCallback#onCapabilitiesReceived} will be called zero or more times as the - * capabilities are received for each requested contact. + * capabilities are fetched from multiple sources, both cached on the device and on the network. * <p> * This request will take a varying amount of time depending on if the contacts requested are * cached or if it requires a network query. The timeout time of these requests can vary * depending on the network, however in poor cases it could take up to a minute for a request - * to timeout. In that time only a subset of capabilities may have been retrieved. + * to timeout. In that time, only a subset of capabilities may have been retrieved. * <p> * After {@link CapabilitiesCallback#onComplete} or {@link CapabilitiesCallback#onError} has * been called, the reference to this callback will be discarded on the service side. @@ -449,18 +463,29 @@ public class RcsUceAdapter { public interface CapabilitiesCallback { /** - * Notify this application that the pending capability request has returned successfully - * for one or more of the requested contacts. + * The pending capability request has completed successfully for one or more of the + * requested contacts. + * This may be called one or more times before the request is fully completed, as + * capabilities may need to be fetched from multiple sources both on device and on the + * network. Once the capabilities of all the requested contacts have been received, + * {@link #onComplete()} will be called. If there was an error during the capability + * exchange process, {@link #onError(int, long)} will be called instead. * @param contactCapabilities List of capabilities associated with each contact requested. */ void onCapabilitiesReceived(@NonNull List<RcsContactUceCapability> contactCapabilities); /** - * The pending request has completed successfully due to all requested contacts information - * being delivered. The callback {@link #onCapabilitiesReceived(List)} - * for each contacts is required to be called before {@link #onComplete} is called. + * Called when the pending request has completed successfully due to all requested contacts + * information being delivered. The callback {@link #onCapabilitiesReceived(List)} will be + * called one or more times and will contain the contacts in the request that the device has + * received capabilities for. + * + * @see #onComplete(SipDetails) onComplete(SipDetails) provides more information related to + * the underlying SIP transaction used to perform the capabilities exchange. Either this + * method or the alternate method should be implemented to determine when the request has + * completed successfully. */ - void onComplete(); + default void onComplete() {} /** * The pending request has resulted in an error and may need to be retried, depending on the @@ -468,8 +493,50 @@ public class RcsUceAdapter { * @param errorCode The reason for the framework being unable to process the request. * @param retryIntervalMillis The time in milliseconds the requesting application should * wait before retrying, if non-zero. + * + * @see #onError(int, long, SipDetails) onError(int, long, SipDetails) provides more + * information related to the underlying SIP transaction that resulted in an error. Either + * this method or the alternative method should be implemented to determine when the + * request has completed with an error. */ - void onError(@ErrorCode int errorCode, long retryIntervalMillis); + default void onError(@ErrorCode int errorCode, long retryIntervalMillis) {} + + /** + * Called when the pending request has completed successfully due to all requested contacts + * information being delivered. The callback {@link #onCapabilitiesReceived(List)} will be + * called one or more times and will contain the contacts in the request that the device has + * received capabilities for. + * + * This method contains more information about the underlying SIP transaction if it exists. + * If this information is not needed, {@link #onComplete()} can be implemented + * instead. + * + * @param details The SIP information related to this request if the device supports + * supplying this information. This parameter will be {@code null} if this + * information is not available. + */ + default void onComplete(@Nullable SipDetails details) { + onComplete(); + }; + + /** + * The pending request has resulted in an error and may need to be retried, depending on the + * error code. + * + * This method contains more information about the underlying SIP transaction if it exists. + * If this information is not needed, {@link #onError(int, long)} can be implemented + * instead. + * @param errorCode The reason for the framework being unable to process the request. + * @param retryIntervalMillis The time in milliseconds the requesting application should + * wait before retrying, if non-zero. + * @param details The SIP information related to this request if the device supports + * supplying this information. This parameter will be {@code null} if this + * information is not available. + */ + default void onError(@ErrorCode int errorCode, long retryIntervalMillis, + @Nullable SipDetails details) { + onError(errorCode, retryIntervalMillis); + }; } private final Context mContext; @@ -554,19 +621,20 @@ public class RcsUceAdapter { } } @Override - public void onComplete() { + public void onComplete(@Nullable SipDetails details) { final long callingIdentity = Binder.clearCallingIdentity(); try { - executor.execute(() -> c.onComplete()); + executor.execute(() -> c.onComplete(details)); } finally { restoreCallingIdentity(callingIdentity); } } @Override - public void onError(int errorCode, long retryAfterMilliseconds) { + public void onError(int errorCode, long retryAfterMilliseconds, + @Nullable SipDetails details) { final long callingIdentity = Binder.clearCallingIdentity(); try { - executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds)); + executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds, details)); } finally { restoreCallingIdentity(callingIdentity); } @@ -650,19 +718,20 @@ public class RcsUceAdapter { } } @Override - public void onComplete() { + public void onComplete(@Nullable SipDetails details) { final long callingIdentity = Binder.clearCallingIdentity(); try { - executor.execute(() -> c.onComplete()); + executor.execute(() -> c.onComplete(details)); } finally { restoreCallingIdentity(callingIdentity); } } @Override - public void onError(int errorCode, long retryAfterMilliseconds) { + public void onError(int errorCode, long retryAfterMilliseconds, + @Nullable SipDetails details) { final long callingIdentity = Binder.clearCallingIdentity(); try { - executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds)); + executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds, details)); } finally { restoreCallingIdentity(callingIdentity); } diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index 9996b868afc7..873ce6064cca 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Binder; @@ -36,7 +37,6 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -75,6 +75,41 @@ public interface RegistrationManager { */ int REGISTRATION_STATE_REGISTERED = 2; + /** @hide */ + @IntDef(prefix = {"SUGGESTED_ACTION_"}, + value = { + SUGGESTED_ACTION_NONE, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SuggestedAction {} + + /** + * Default value. No action is suggested when IMS registration fails. + * @hide + */ + @SystemApi + public static final int SUGGESTED_ACTION_NONE = 0; + + /** + * Indicates that the IMS registration is failed with fatal error such as 403 or 404 + * on all P-CSCF addresses. The radio shall block the current PLMN or disable + * the RAT as per the carrier requirements. + * @hide + */ + @SystemApi + public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK = 1; + + /** + * Indicates that the IMS registration on current PLMN failed multiple times. + * The radio shall block the current PLMN or disable the RAT during EPS or 5GS mobility + * management timer value as per the carrier requirements. + * @hide + */ + @SystemApi + public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT = 2; + /**@hide*/ // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN // and WWAN are more accurate constants. @@ -167,12 +202,32 @@ public interface RegistrationManager { } @Override - public void onDeregistered(ImsReasonInfo info) { + public void onDeregistered(ImsReasonInfo info, + @SuggestedAction int suggestedAction, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) { if (mLocalCallback == null) return; final long callingIdentity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> mLocalCallback.onUnregistered(info)); + mExecutor.execute(() -> mLocalCallback.onUnregistered(info, + suggestedAction, imsRadioTech)); + } finally { + restoreCallingIdentity(callingIdentity); + } + } + + @Override + public void onDeregisteredWithDetails(ImsReasonInfo info, + @SuggestedAction int suggestedAction, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, + @NonNull SipDetails details) { + if (mLocalCallback == null) return; + + final long callingIdentity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mLocalCallback.onUnregistered(info, suggestedAction, + imsRadioTech)); + mExecutor.execute(() -> mLocalCallback.onUnregistered(info, details)); } finally { restoreCallingIdentity(callingIdentity); } @@ -258,6 +313,37 @@ public interface RegistrationManager { } /** + * Notifies the framework when the IMS Provider is unregistered from the IMS network. + * + * Since this callback is only required for the communication between telephony framework + * and ImsService, it is made hidden. + * + * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + * @param suggestedAction the expected behavior of radio protocol stack. + * @param imsRadioTech the network type on which IMS registration has failed. + * @hide + */ + public void onUnregistered(@NonNull ImsReasonInfo info, + @SuggestedAction int suggestedAction, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) { + // Default impl to keep backwards compatibility with old implementations + onUnregistered(info); + } + + /** + * Notifies the framework when the IMS Provider is unregistered from the IMS network. + * + * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + * @param details the {@link SipDetails} related to disconnected Ims registration. + * + * @hide + */ + @SystemApi + public void onUnregistered(@NonNull ImsReasonInfo info, + @NonNull SipDetails details) { + } + + /** * A failure has occurred when trying to handover registration to another technology type. * * @param imsTransportType The transport type that has failed to handover registration to. diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java index 94e9afbe9e38..25ebdd0b8b40 100644 --- a/telephony/java/android/telephony/ims/SipDelegateManager.java +++ b/telephony/java/android/telephony/ims/SipDelegateManager.java @@ -513,4 +513,69 @@ public class SipDelegateManager { // ignore it } } + + /** + * Register a new callback, which is used to notify the registrant of changes + * to the state of the Sip Sessions managed remotely by the IMS stack. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} + * + * @param executor the Executor that will be used to call the {@link SipDialogStateCallback}. + * @param callback The callback instance being registered. + * @throws ImsException in the case that the callback can not be registered. + * See {@link ImsException#getCode} for more information on when this is called. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void registerSipDialogStateCallback(@NonNull Executor executor, + @NonNull SipDialogStateCallback callback) throws ImsException { + Objects.requireNonNull(callback, "Must include a non-null SipDialogStateCallback."); + Objects.requireNonNull(executor, "Must include a non-null Executor."); + + callback.attachExecutor(executor); + try { + IImsRcsController controller = mBinderCache.listenOnBinder( + callback, callback::binderDied); + if (controller == null) { + throw new ImsException("Telephony server is down", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + controller.registerSipDialogStateCallback(mSubId, callback.getCallbackBinder()); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } catch (IllegalStateException e) { + throw new IllegalStateException(e.getMessage()); + } + } + + /** + * Unregisters a previously registered callback. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} + * + * @param callback The callback instance to be unregistered. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void unregisterSipDialogStateCallback(@NonNull SipDialogStateCallback callback) + throws ImsException { + Objects.requireNonNull(callback, "Must include a non-null SipDialogStateCallback."); + + IImsRcsController controller = mBinderCache.removeRunnable(callback); + try { + if (controller == null) { + throw new ImsException("Telephony server is down", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + controller.unregisterSipDialogStateCallback(mSubId, callback.getCallbackBinder()); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } catch (IllegalStateException e) { + throw new IllegalStateException(e.getMessage()); + } + } } diff --git a/telephony/java/android/telephony/ims/SipDetails.aidl b/telephony/java/android/telephony/ims/SipDetails.aidl new file mode 100644 index 000000000000..476d806c881a --- /dev/null +++ b/telephony/java/android/telephony/ims/SipDetails.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 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 android.telephony.ims; + +parcelable SipDetails; diff --git a/telephony/java/android/telephony/ims/SipDetails.java b/telephony/java/android/telephony/ims/SipDetails.java new file mode 100644 index 000000000000..fe58eb31b115 --- /dev/null +++ b/telephony/java/android/telephony/ims/SipDetails.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Contains the information for SIP. + */ +public final class SipDetails implements Parcelable { + /** + * Define a SIP method type related to this information. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "METHOD_", value = { + METHOD_UNKNOWN, + METHOD_REGISTER, + METHOD_PUBLISH, + METHOD_SUBSCRIBE + }) + public @interface Method {} + + public static final int METHOD_UNKNOWN = 0; + + /** + * Indicates information related to the SIP registration method. + * See RFC 3261 for details. + */ + public static final int METHOD_REGISTER = 1; + /** + * Indicates information related to the SIP publication method. + * See RFC 3903 for details. + */ + public static final int METHOD_PUBLISH = 2; + /** + * Indicates information related to the SIP subscription method. + * See RFC 3856 for details. + */ + public static final int METHOD_SUBSCRIBE = 3; + + /** + * Builder for creating {@link SipDetails} instances. + * @hide + */ + public static final class Builder { + private int mMethod; + // Command Sequence value defined in RFC3261 Section 8.1.1.5 + private int mCseq = 0; + private int mResponseCode = 0; + private String mResponsePhrase = ""; + private int mReasonHeaderCause = 0; + private String mReasonHeaderText = ""; + private @Nullable String mCallId; + + /** + * Build a new instance of {@link SipDetails}. + * + * @param method Indicates which SIP method this information is for. + */ + public Builder(@Method int method) { + this.mMethod = method; + } + + /** + * Sets the value of the CSeq header field for this SIP method. + * The CSeq header field serves as a way to identify and order transactions. + * It consists of a sequence number and a method. + * The method MUST match that of the request. + * Ref RFC3261 Section 8.1.1.5. + * @param cSeq The value of the CSeq header field. + * @return The same instance of the builder. + */ + public @NonNull Builder setCSeq(int cSeq) { + this.mCseq = cSeq; + return this; + } + + /** + * Sets the SIP response code and reason response for this SIP method. + * Ref RFC3261 Section 21. + * @param responseCode The SIP response code sent from the network for the + * operation token specified. + * @param responsePhrase The optional reason response from the network. If + * there is a reason header included in the response, that should take + * precedence over the reason provided in the status line. If the network + * provided no reason with the SIP code, the string should be empty. + * @return The same instance of the builder. + */ + public Builder setSipResponseCode(int responseCode, + @NonNull String responsePhrase) { + this.mResponseCode = responseCode; + this.mResponsePhrase = responsePhrase; + return this; + } + + + /** + * Sets the detailed information of reason header for this SIP method. + * Ref RFC3326. + * @param reasonHeaderCause The “cause” parameter of the “reason” + * header included in the SIP message. + * @param reasonHeaderText The “text” parameter of the “reason” + * header included in the SIP message. + * @return The same instance of the builder. + */ + public Builder setSipResponseReasonHeader(int reasonHeaderCause, + @NonNull String reasonHeaderText) { + this.mReasonHeaderCause = reasonHeaderCause; + this.mReasonHeaderText = reasonHeaderText; + return this; + } + + + /** + * Sets the value of the Call-ID header field for this SIP method. + * Ref RFC3261 Section 8.1.1.4. + * @param callId The value of the Call-ID header field. + * @return The same instance of the builder. + */ + public @NonNull Builder setCallId(@NonNull String callId) { + this.mCallId = callId; + return this; + } + + /** + * @return a new SipDetails from this Builder. + */ + public @NonNull SipDetails build() { + return new SipDetails(this); + } + } + + private final int mMethod; + private final int mCseq; + private final int mResponseCode; + private final @NonNull String mResponsePhrase; + private final int mReasonHeaderCause; + private final @NonNull String mReasonHeaderText; + private final @Nullable String mCallId; + + private SipDetails(Builder builder) { + mMethod = builder.mMethod; + mCseq = builder.mCseq; + mResponseCode = builder.mResponseCode; + mResponsePhrase = builder.mResponsePhrase; + mReasonHeaderCause = builder.mReasonHeaderCause; + mReasonHeaderText = builder.mReasonHeaderText; + mCallId = builder.mCallId; + } + + /** + * Get the method type of this instance. + * @return The method type associated with this SIP information. + */ + public @Method int getMethod() { + return mMethod; + } + + /** + * Get the value of CSeq header field. + * The CSeq header field serves as a way to identify and order transactions. + * @return The command sequence value associated with this SIP information. + */ + public int getCSeq() { + return mCseq; + } + + /** + * Get the value of response code from the SIP response. + * The SIP response code sent from the network for the operation token specified. + * @return The SIP response code associated with this SIP information. + */ + public int getResponseCode() { + return mResponseCode; + } + + /** + * Get the value of reason from the SIP response. + * The optional reason response from the network. If + * there is a reason header included in the response, that should take + * precedence over the reason provided in the status line. + * @return The optional reason response associated with this SIP information. If the network + * provided no reason with the SIP code, the string should be empty. + */ + public @NonNull String getResponsePhrase() { + return mResponsePhrase; + } + + /** + * Get the "cause" parameter of the "reason" header. + * @return The "cause" parameter of the reason header. If the SIP message from the network + * does not have a reason header, it should be 0. + */ + public int getReasonHeaderCause() { + return mReasonHeaderCause; + } + + /** + * Get the "text" parameter of the "reason" header in the SIP message. + * @return The "text" parameter of the reason header. If the SIP message from the network + * does not have a reason header, it can be empty. + */ + public @NonNull String getReasonHeaderText() { + return mReasonHeaderText; + } + + /** + * Get the value of the Call-ID header field for this SIP method. + * @return The Call-ID value associated with this SIP information. If the Call-ID value is + * not set when ImsService notifies the framework, this value will be null. + */ + public @Nullable String getCallId() { + return mCallId; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mMethod); + dest.writeInt(mCseq); + dest.writeInt(mResponseCode); + dest.writeString(mResponsePhrase); + dest.writeInt(mReasonHeaderCause); + dest.writeString(mReasonHeaderText); + dest.writeString(mCallId); + } + + public static final @NonNull Creator<SipDetails> CREATOR = + new Creator<SipDetails>() { + @Override + public SipDetails createFromParcel(Parcel source) { + return new SipDetails(source); + } + + @Override + public SipDetails[] newArray(int size) { + return new SipDetails[size]; + } + }; + + /** + * Construct a SipDetails object from the given parcel. + */ + private SipDetails(Parcel in) { + mMethod = in.readInt(); + mCseq = in.readInt(); + mResponseCode = in.readInt(); + mResponsePhrase = in.readString(); + mReasonHeaderCause = in.readInt(); + mReasonHeaderText = in.readString(); + mCallId = in.readString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SipDetails that = (SipDetails) o; + return mMethod == that.mMethod + && mCseq == that.mCseq + && mResponseCode == that.mResponseCode + && TextUtils.equals(mResponsePhrase, that.mResponsePhrase) + && mReasonHeaderCause == that.mReasonHeaderCause + && TextUtils.equals(mReasonHeaderText, that.mReasonHeaderText) + && TextUtils.equals(mCallId, that.mCallId); + } + + @Override + public int hashCode() { + return Objects.hash(mMethod, mCseq, mResponseCode, mResponsePhrase, mReasonHeaderCause, + mReasonHeaderText, mCallId); + } + + @Override + public String toString() { + return "SipDetails { methodType= " + mMethod + ", cSeq=" + mCseq + + ", ResponseCode=" + mResponseCode + ", ResponseCPhrase=" + mResponsePhrase + + ", ReasonHeaderCause=" + mReasonHeaderCause + + ", ReasonHeaderText=" + mReasonHeaderText + ", callId=" + mCallId + "}"; + } +} diff --git a/telephony/java/android/telephony/ims/SipDialogState.aidl b/telephony/java/android/telephony/ims/SipDialogState.aidl new file mode 100644 index 000000000000..0f084c744ce6 --- /dev/null +++ b/telephony/java/android/telephony/ims/SipDialogState.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +parcelable SipDialogState;
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/SipDialogState.java b/telephony/java/android/telephony/ims/SipDialogState.java new file mode 100644 index 000000000000..815c59ae9b2c --- /dev/null +++ b/telephony/java/android/telephony/ims/SipDialogState.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * The state of an ongoing SIP dialog. + * @hide + */ +@SystemApi +public final class SipDialogState implements Parcelable { + + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "STATE_", value = {STATE_EARLY, STATE_CONFIRMED, STATE_CLOSED}) + public @interface SipDialogStateCode {} + /** + * The device has sent out a dialog starting event and is awaiting a confirmation. + */ + public static final int STATE_EARLY = 0; + + /** + * The device has received a 2XX response to the early dialog. + */ + public static final int STATE_CONFIRMED = 1; + + /** + * The device has received either a 3XX+ response to a pending dialog request or a BYE + * request has been sent on this dialog. + */ + public static final int STATE_CLOSED = 2; + + private final int mState; + + /** + * Builder for {@link SipDialogState}. + * @hide + */ + public static final class Builder { + private int mState = STATE_EARLY; + + /** + * constructor + * @param state The state of SipDialog + */ + public Builder(@SipDialogStateCode int state) { + mState = state; + } + + /** + * Build the {@link SipDialogState}. + * @return The {@link SipDialogState} instance. + */ + public @NonNull SipDialogState build() { + return new SipDialogState(this); + } + } + + /** + * set Dialog state + */ + private SipDialogState(@NonNull Builder builder) { + this.mState = builder.mState; + } + + private SipDialogState(Parcel in) { + mState = in.readInt(); + } + + /** + * @return The state of the SIP dialog + */ + public @SipDialogStateCode int getState() { + return mState; + } + + public static final @NonNull Creator<SipDialogState> CREATOR = new Creator<SipDialogState>() { + @Override + public SipDialogState createFromParcel(@NonNull Parcel in) { + return new SipDialogState(in); + } + + @Override + public SipDialogState[] newArray(int size) { + return new SipDialogState[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mState); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SipDialogState sipDialog = (SipDialogState) o; + + return mState == sipDialog.mState; + } + + @Override + public int hashCode() { + return Objects.hash(mState); + } +} diff --git a/telephony/java/android/telephony/ims/SipDialogStateCallback.java b/telephony/java/android/telephony/ims/SipDialogStateCallback.java new file mode 100644 index 000000000000..5730bac09d57 --- /dev/null +++ b/telephony/java/android/telephony/ims/SipDialogStateCallback.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Binder; + +import com.android.internal.telephony.ISipDialogStateCallback; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * This callback is used to notify listeners of SIP Dialog state changes. + * @hide + */ +@SystemApi +public abstract class SipDialogStateCallback { + + private CallbackBinder mCallback; + /** + * @hide + */ + public void attachExecutor(@NonNull @CallbackExecutor Executor executor) { + if (executor == null) { + throw new IllegalArgumentException("SipDialogStateCallback Executor must be non-null"); + } + mCallback = new CallbackBinder(this, executor); + } + + private static class CallbackBinder extends ISipDialogStateCallback.Stub { + private WeakReference<SipDialogStateCallback> mSipDialogStateCallbackWeakRef; + private Executor mExecutor; + + private CallbackBinder(SipDialogStateCallback callback, Executor executor) { + mSipDialogStateCallbackWeakRef = new WeakReference<SipDialogStateCallback>(callback); + mExecutor = executor; + } + + Executor getExecutor() { + return mExecutor; + } + + @Override + public void onActiveSipDialogsChanged(List<SipDialogState> dialogs) { + SipDialogStateCallback callback = mSipDialogStateCallbackWeakRef.get(); + if (callback == null || dialogs == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> callback.onActiveSipDialogsChanged(dialogs))); + } + } + + /** + * The state of one or more SIP dialogs has changed. + * + * @param dialogs A List of SipDialogState objects representing the state of the active + * SIP Dialogs. + */ + public abstract void onActiveSipDialogsChanged(@NonNull List<SipDialogState> dialogs); + + /** + * An unexpected error has occurred and the Telephony process has crashed. This + * has caused this callback to be deregistered. The callback must be re-registered + * in order to continue listening to the IMS service state. + */ + public abstract void onError(); + + /** + * The callback to notify the death of telephony process + * @hide + */ + public final void binderDied() { + if (mCallback != null) { + mCallback.getExecutor().execute(() -> onError()); + } + } + + /** + * Return the callback binder + * @hide + */ + public CallbackBinder getCallbackBinder() { + return mCallback; + } +} diff --git a/telephony/java/android/telephony/ims/SrvccCall.aidl b/telephony/java/android/telephony/ims/SrvccCall.aidl new file mode 100644 index 000000000000..0f0a0795cb2e --- /dev/null +++ b/telephony/java/android/telephony/ims/SrvccCall.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 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 android.telephony.ims; + +parcelable SrvccCall; diff --git a/telephony/java/android/telephony/ims/SrvccCall.java b/telephony/java/android/telephony/ims/SrvccCall.java new file mode 100644 index 000000000000..cdc271ec8070 --- /dev/null +++ b/telephony/java/android/telephony/ims/SrvccCall.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.Annotation.PreciseCallStates; + +import java.util.Objects; + +/** + * A Parcelable object to represent the current state of an IMS call that is being tracked + * in the ImsService when an SRVCC begins. This information will be delivered to modem. + * @see SrvccStartedCallback + * + * @hide + */ +@SystemApi +public final class SrvccCall implements Parcelable { + private static final String TAG = "SrvccCall"; + + /** The IMS call profile */ + private ImsCallProfile mImsCallProfile; + + /** The IMS call id */ + private String mCallId; + + /** The call state */ + private @PreciseCallStates int mCallState; + + private SrvccCall(Parcel in) { + readFromParcel(in); + } + + /** + * Constructs an instance of SrvccCall. + * + * @param callId the call ID associated with the IMS call + * @param callState the state of this IMS call + * @param imsCallProfile the profile associated with this IMS call + * @throws IllegalArgumentException if the callId or the imsCallProfile is null + */ + public SrvccCall(@NonNull String callId, @PreciseCallStates int callState, + @NonNull ImsCallProfile imsCallProfile) { + if (callId == null) throw new IllegalArgumentException("callId is null"); + if (imsCallProfile == null) throw new IllegalArgumentException("imsCallProfile is null"); + + mCallId = callId; + mCallState = callState; + mImsCallProfile = imsCallProfile; + } + + /** + * @return the {@link ImsCallProfile} associated with this IMS call, + * which will be used to get the address, the name, and the audio direction + * including the call in pre-alerting state. + */ + @NonNull + public ImsCallProfile getImsCallProfile() { + return mImsCallProfile; + } + + /** + * @return the call ID associated with this IMS call. + * + * @see android.telephony.ims.stub.ImsCallSessionImplBase#getCallId(). + */ + @NonNull + public String getCallId() { + return mCallId; + } + + /** + * @return the call state of the associated IMS call. + */ + public @PreciseCallStates int getPreciseCallState() { + return mCallState; + } + + @NonNull + @Override + public String toString() { + return "{ callId=" + mCallId + + ", callState=" + mCallState + + ", imsCallProfile=" + mImsCallProfile + + " }"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SrvccCall that = (SrvccCall) o; + return mImsCallProfile.equals(that.mImsCallProfile) + && mCallId.equals(that.mCallId) + && mCallState == that.mCallState; + } + + @Override + public int hashCode() { + int result = Objects.hash(mImsCallProfile, mCallId); + result = 31 * result + mCallState; + return result; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeString(mCallId); + out.writeInt(mCallState); + out.writeParcelable(mImsCallProfile, 0); + } + + private void readFromParcel(Parcel in) { + mCallId = in.readString(); + mCallState = in.readInt(); + mImsCallProfile = in.readParcelable(ImsCallProfile.class.getClassLoader(), + android.telephony.ims.ImsCallProfile.class); + } + + public static final @android.annotation.NonNull Creator<SrvccCall> CREATOR = + new Creator<SrvccCall>() { + @Override + public SrvccCall createFromParcel(Parcel in) { + return new SrvccCall(in); + } + + @Override + public SrvccCall[] newArray(int size) { + return new SrvccCall[size]; + } + }; +} diff --git a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java index c27fa4fc882d..0514df2cea10 100644 --- a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java +++ b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java @@ -23,6 +23,7 @@ import android.os.Binder; import android.os.RemoteException; import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.SipDetails; import android.telephony.ims.stub.CapabilityExchangeEventListener; import android.util.Log; @@ -83,7 +84,11 @@ public class CapabilityExchangeAidlWrapper implements CapabilityExchangeEventLis /** * Receives the status of changes in the publishing connection from ims service * and deliver this callback to the framework. + * + * @deprecated Replaced by {@link #onPublishUpdated(SipDetails)}, deprecated for + * sip information. */ + @Deprecated public void onPublishUpdated(int reasonCode, @NonNull String reasonPhrase, int reasonHeaderCause, @NonNull String reasonHeaderText) throws ImsException { ICapabilityExchangeEventListener listener = mListenerBinder; @@ -91,8 +96,29 @@ public class CapabilityExchangeAidlWrapper implements CapabilityExchangeEventLis return; } try { - listener.onPublishUpdated(reasonCode, reasonPhrase, - reasonHeaderCause, reasonHeaderText); + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setSipResponseCode(reasonCode, reasonPhrase) + .setSipResponseReasonHeader(reasonHeaderCause, reasonHeaderText) + .build(); + listener.onPublishUpdated(details); + } catch (RemoteException e) { + Log.w(LOG_TAG, "onPublishUpdated exception: " + e); + throw new ImsException("Remote is not available", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + } + + /** + * Receives the status of changes in the publishing connection from ims service + * and deliver this callback to the framework. + */ + public void onPublishUpdated(@NonNull SipDetails details) throws ImsException { + ICapabilityExchangeEventListener listener = mListenerBinder; + if (listener == null) { + return; + } + try { + listener.onPublishUpdated(details); } catch (RemoteException e) { Log.w(LOG_TAG, "onPublishUpdated exception: " + e); throw new ImsException("Remote is not available", diff --git a/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl b/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl index c675bc3204f6..21c838040dc7 100644 --- a/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl @@ -18,7 +18,7 @@ package android.telephony.ims.aidl; import android.net.Uri; import android.telephony.ims.aidl.IOptionsRequestCallback; - +import android.telephony.ims.SipDetails; import java.util.List; /** @@ -31,8 +31,7 @@ import java.util.List; oneway interface ICapabilityExchangeEventListener { void onRequestPublishCapabilities(int publishTriggerType); void onUnpublish(); - void onPublishUpdated(int reasonCode, String reasonPhrase, int reasonHeaderCause, - String reasonHeaderText); + void onPublishUpdated(in SipDetails details); void onRemoteCapabilityRequest(in Uri contactUri, in List<String> remoteCapabilities, IOptionsRequestCallback cb); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl index ed0375251ffb..b58a5c79b76c 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl @@ -171,4 +171,17 @@ oneway interface IImsCallSessionListener { * @param extensions the RTP header extensions received. */ void callSessionRtpHeaderExtensionsReceived(in List<RtpHeaderExtension> extensions); + + /** + * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114. + * This API triggers radio to send ANBRQ message to the access network to query the desired + * bitrate. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate requested by the other party UE + * through RTP CMR, RTCPAPP or TMMBR, and ImsStack converts this value to the MAC bitrate + * (defined in TS36.321, range: 0 ~ 8000 kbit/s). + */ + void callSessionSendAnbrQuery(int mediaType, int direction, int bitsPerSecond); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl index 37fec7a73634..2f0eb6cb211b 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl @@ -20,7 +20,10 @@ import android.os.Message; import android.telephony.ims.aidl.IImsMmTelListener; import android.telephony.ims.aidl.IImsSmsListener; import android.telephony.ims.aidl.IImsCapabilityCallback; +import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.CapabilityChangeRequest; +import android.telephony.ims.MediaQualityStatus; +import android.telephony.ims.MediaThreshold; import android.telephony.ims.RtpHeaderExtensionType; import android.telephony.ims.ImsCallProfile; @@ -48,17 +51,27 @@ interface IImsMmTelFeature { void setUiTtyMode(int uiTtyMode, in Message onCompleteMessage); IImsMultiEndpoint getMultiEndpointInterface(); int queryCapabilityStatus(); + void setTerminalBasedCallWaitingStatus(boolean enabled); oneway void addCapabilityCallback(IImsCapabilityCallback c); oneway void removeCapabilityCallback(IImsCapabilityCallback c); oneway void changeCapabilitiesConfiguration(in CapabilityChangeRequest request, IImsCapabilityCallback c); oneway void queryCapabilityConfiguration(int capability, int radioTech, IImsCapabilityCallback c); + oneway void notifySrvccStarted(in ISrvccStartedCallback cb); + oneway void notifySrvccCompleted(); + oneway void notifySrvccFailed(); + oneway void notifySrvccCanceled(); + oneway void setMediaQualityThreshold(int mediaSessionType, in MediaThreshold threshold); + MediaQualityStatus queryMediaQualityStatus(int mediaSessionType); + // SMS APIs void setSmsListener(IImsSmsListener l); oneway void sendSms(in int token, int messageRef, String format, String smsc, boolean retry, in byte[] pdu); + oneway void onMemoryAvailable(int token); oneway void acknowledgeSms(int token, int messageRef, int result); + oneway void acknowledgeSmsWithPdu(int token, int messageRef, int result, in byte[] pdu); oneway void acknowledgeSmsReport(int token, int messageRef, int result); String getSmsFormat(); oneway void onSmsReady(); diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl index 52464703c608..e016c6153247 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl @@ -20,6 +20,9 @@ import android.os.Bundle; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.MediaQualityStatus; +import android.telephony.ims.aidl.IImsCallSessionListener; +import android.telephony.ims.aidl.IImsTrafficSessionCallback; import com.android.ims.internal.IImsCallSession; @@ -31,7 +34,14 @@ import com.android.ims.internal.IImsCallSession; // processed by telephony before the control flow returns to the ImsService to perform // operations on the IImsCallSession. interface IImsMmTelListener { - void onIncomingCall(IImsCallSession c, in Bundle extras); + IImsCallSessionListener onIncomingCall(in IImsCallSession c, in String callId, in Bundle extras); void onRejectedCall(in ImsCallProfile callProfile, in ImsReasonInfo reason); oneway void onVoiceMessageCountUpdate(int count); + oneway void onAudioModeIsVoipChanged(int imsAudioHandler); + oneway void onTriggerEpsFallback(int reason); + oneway void onStartImsTrafficSession(int token, int trafficType, int accessNetworkType, + int trafficDirection, in IImsTrafficSessionCallback callback); + oneway void onModifyImsTrafficSession(int token, int accessNetworkType); + oneway void onStopImsTrafficSession(int token); + oneway void onMediaQualityStatusChanged(in MediaQualityStatus status); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl index 8931a78709ed..8a4a79684b08 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl @@ -30,6 +30,7 @@ import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback; import com.android.ims.ImsFeatureContainer; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.ISipDialogStateCallback; /** * Interface used to interact with the Telephony IMS. @@ -69,6 +70,10 @@ interface IImsRcsController { void destroySipDelegate(int subId, ISipDelegate connection, int reason); void triggerNetworkRegistration(int subId, ISipDelegate connection, int sipCode, String sipReason); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)") + void registerSipDialogStateCallback(int subId, in ISipDialogStateCallback cb); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)") + void unregisterSipDialogStateCallback(int subId, in ISipDialogStateCallback cb); // Internal commands that should not be made public void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback); diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl index 4fd904041365..219c9c88d825 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl @@ -31,4 +31,5 @@ interface IImsRegistration { oneway void triggerFullNetworkRegistration(int sipCode, String sipReason); oneway void triggerUpdateSipDelegateRegistration(); oneway void triggerSipDelegateDeregistration(); + oneway void triggerDeregistration(int reason); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl index 179407c983e5..0a5ea170320b 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl @@ -22,6 +22,7 @@ import android.telephony.ims.stub.ImsFeatureConfiguration; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; +import android.telephony.ims.SipDetails; /** * See {@link ImsManager#RegistrationCallback} for more information. @@ -31,7 +32,8 @@ import android.telephony.ims.ImsRegistrationAttributes; oneway interface IImsRegistrationCallback { void onRegistered(in ImsRegistrationAttributes attr); void onRegistering(in ImsRegistrationAttributes attr); - void onDeregistered(in ImsReasonInfo info); + void onDeregistered(in ImsReasonInfo info, int suggestedAction, int imsRadioTech); + void onDeregisteredWithDetails(in ImsReasonInfo info, int suggestedAction, int imsRadioTech, in SipDetails detail); void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info); void onSubscriberAssociatedUriChanged(in Uri[] uris); -}
\ No newline at end of file +} diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl index ae6166fea02a..fdf43a52685a 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl @@ -47,4 +47,5 @@ interface IImsServiceController { ISipTransport getSipTransport(int slotId); oneway void enableIms(int slotId, int subId); oneway void disableIms(int slotId, int subId); + oneway void resetIms(int slotId, int subId); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl index 5aa58c1ee7ee..ae677cad33b8 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl @@ -24,4 +24,5 @@ oneway interface IImsSmsListener { void onSendSmsResult(int token, int messageRef, int status, int reason, int networkErrorCode); void onSmsStatusReportReceived(int token, in String format, in byte[] pdu); void onSmsReceived(int token, in String format, in byte[] pdu); + void onMemoryAvailableResult(int token, int status, int networkErrorCode); } diff --git a/telephony/java/android/telephony/ims/aidl/IImsTrafficSessionCallback.aidl b/telephony/java/android/telephony/ims/aidl/IImsTrafficSessionCallback.aidl new file mode 100644 index 000000000000..05b97e5c78cf --- /dev/null +++ b/telephony/java/android/telephony/ims/aidl/IImsTrafficSessionCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 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 android.telephony.ims.aidl; + +import android.telephony.ims.feature.ConnectionFailureInfo; + +/** + * {@hide} + */ +oneway interface IImsTrafficSessionCallback { + void onReady(); + void onError(in ConnectionFailureInfo info); +} diff --git a/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl b/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl index b99d8a7d6d38..cd08fcfce6c6 100644 --- a/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl +++ b/telephony/java/android/telephony/ims/aidl/IPublishResponseCallback.aidl @@ -17,6 +17,7 @@ package android.telephony.ims.aidl; import java.util.List; +import android.telephony.ims.SipDetails; /** * Interface used by the framework to receive the response of the publish @@ -25,6 +26,5 @@ import java.util.List; */ oneway interface IPublishResponseCallback { void onCommandError(int code); - void onNetworkResponse(int code, String reason); - void onNetworkRespHeader(int code, String reasonPhrase, int reasonHeaderCause, String reasonHeaderText); + void onNetworkResponse(in SipDetails details); } diff --git a/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl index 0f627b92a24c..acce7484b283 100644 --- a/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl +++ b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl @@ -17,7 +17,7 @@ package android.telephony.ims.aidl; import android.telephony.ims.RcsContactUceCapability; - +import android.telephony.ims.SipDetails; /** * Provides interface for RCS UCE when receive a change. * @@ -25,6 +25,6 @@ import android.telephony.ims.RcsContactUceCapability; */ oneway interface IRcsUceControllerCallback { void onCapabilitiesReceived(in List<RcsContactUceCapability> contactCapabilities); - void onComplete(); - void onError(int errorCode, long retryAfterMilliseconds); + void onComplete(in SipDetails details); + void onError(int errorCode, long retryAfterMilliseconds, in SipDetails details); } diff --git a/telephony/java/android/telephony/ims/aidl/IRcsUcePublishStateCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsUcePublishStateCallback.aidl index b6e84154f80f..e870c26eea5e 100644 --- a/telephony/java/android/telephony/ims/aidl/IRcsUcePublishStateCallback.aidl +++ b/telephony/java/android/telephony/ims/aidl/IRcsUcePublishStateCallback.aidl @@ -16,11 +16,12 @@ package android.telephony.ims.aidl; +import android.telephony.ims.PublishAttributes; /** * Interface for RCS UCE publish state change callbacks. * * {@hide} */ oneway interface IRcsUcePublishStateCallback { - void onPublishStateChanged(int publishState); + void onPublishUpdated(in PublishAttributes attributes); } diff --git a/telephony/java/android/telephony/ims/aidl/ISrvccStartedCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISrvccStartedCallback.aidl new file mode 100644 index 000000000000..a173abffbb8f --- /dev/null +++ b/telephony/java/android/telephony/ims/aidl/ISrvccStartedCallback.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 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 android.telephony.ims.aidl; + +import android.telephony.ims.SrvccCall; + +import java.util.List; + +/** + * {@hide} + */ +oneway interface ISrvccStartedCallback { + void onSrvccCallNotified(in List<SrvccCall> profiles); +} diff --git a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl index 8cc8020df29a..375ecd959f08 100644 --- a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl +++ b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl @@ -18,6 +18,7 @@ package android.telephony.ims.aidl; import android.net.Uri; import android.telephony.ims.RcsContactTerminatedReason; +import android.telephony.ims.SipDetails; import java.util.List; import java.util.Map; @@ -29,8 +30,7 @@ import java.util.Map; */ oneway interface ISubscribeResponseCallback { void onCommandError(int code); - void onNetworkResponse(int code, in String reason); - void onNetworkRespHeader(int code, String reasonPhrase, int reasonHeaderCause, String reasonHeaderText); + void onNetworkResponse(in SipDetails detail); void onNotifyCapabilitiesUpdate(in List<String> pidfXmls); void onResourceTerminated(in List<RcsContactTerminatedReason> uriTerminatedReason); void onTerminated(in String reason, long retryAfterMilliseconds); diff --git a/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java index 65415ea441b5..40cb5ca54990 100644 --- a/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java +++ b/telephony/java/android/telephony/ims/aidl/RcsPublishResponseAidlWrapper.java @@ -16,8 +16,10 @@ package android.telephony.ims.aidl; +import android.annotation.NonNull; import android.os.RemoteException; import android.telephony.ims.ImsException; +import android.telephony.ims.SipDetails; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback; /** @@ -43,20 +45,38 @@ public class RcsPublishResponseAidlWrapper implements PublishResponseCallback { } @Override - public void onNetworkResponse(int code, String reason) throws ImsException { + @Deprecated + public void onNetworkResponse(int code, String reasonPhrase) throws ImsException { + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setSipResponseCode(code, reasonPhrase) + .build(); try { - mResponseBinder.onNetworkResponse(code, reason); + mResponseBinder.onNetworkResponse(details); } catch (RemoteException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } } @Override + @Deprecated public void onNetworkResponse(int code, String reasonPhrase, int reasonHeaderCause, String reasonHeaderText) throws ImsException { + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setSipResponseCode(code, reasonPhrase) + .setSipResponseReasonHeader(reasonHeaderCause, reasonHeaderText) + .build(); try { - mResponseBinder.onNetworkRespHeader(code, reasonPhrase, reasonHeaderCause, - reasonHeaderText); + mResponseBinder.onNetworkResponse(details); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + } + + @Override + public void onNetworkResponse(@NonNull SipDetails details) + throws ImsException { + try { + mResponseBinder.onNetworkResponse(details); } catch (RemoteException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } diff --git a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java index 11118c0617c2..2f54001b80ce 100644 --- a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java +++ b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java @@ -16,10 +16,12 @@ package android.telephony.ims.aidl; +import android.annotation.NonNull; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactTerminatedReason; +import android.telephony.ims.SipDetails; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback; import android.util.Pair; @@ -49,20 +51,37 @@ public class RcsSubscribeResponseAidlWrapper implements SubscribeResponseCallbac } @Override - public void onNetworkResponse(int code, String reason) throws ImsException { + @Deprecated + public void onNetworkResponse(int code, String reasonPhrase) throws ImsException { try { - mResponseBinder.onNetworkResponse(code, reason); + mResponseBinder.onNetworkResponse(new SipDetails.Builder( + SipDetails.METHOD_SUBSCRIBE) + .setSipResponseCode(code, reasonPhrase) + .build()); } catch (RemoteException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } } @Override + @Deprecated public void onNetworkResponse(int code, String reasonPhrase, int reasonHeaderCause, String reasonHeaderText) throws ImsException { try { - mResponseBinder.onNetworkRespHeader(code, reasonPhrase, reasonHeaderCause, - reasonHeaderText); + mResponseBinder.onNetworkResponse(new SipDetails.Builder( + SipDetails.METHOD_SUBSCRIBE) + .setSipResponseCode(code, reasonPhrase) + .setSipResponseReasonHeader(reasonHeaderCause, reasonHeaderText) + .build()); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + } + + @Override + public void onNetworkResponse(@NonNull SipDetails details) throws ImsException { + try { + mResponseBinder.onNetworkResponse(details); } catch (RemoteException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java index 8dcd711a96a9..798e8019502f 100755 --- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java @@ -417,6 +417,21 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub { } /** + * Deliver the bitrate for the indicated media type, direction and bitrate to the upper layer. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate received from the NW through the Recommended + * bitrate MAC Control Element message and ImsStack converts this value from MAC bitrate + * to audio/video codec bitrate (defined in TS26.114). + * @hide + */ + @Override + public void callSessionNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { + // no-op; not supported in compat layer. + } + + /** * There are two different ImsCallSessionListeners that need to reconciled here, we need to * convert the "old" version of the com.android.ims.internal.IImsCallSessionListener to the * "new" version of the Listener android.telephony.ims.ImsCallSessionListener when calling @@ -662,5 +677,11 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub { public void callQualityChanged(CallQuality callQuality) throws RemoteException { mNewListener.callQualityChanged(callQuality); } + + @Override + public void callSessionSendAnbrQuery(int mediaType, int direction, + int bitsPerSecond) throws RemoteException { + mNewListener.callSessionSendAnbrQuery(mediaType, direction, bitsPerSecond); + } } } diff --git a/telephony/java/android/telephony/ims/feature/ConnectionFailureInfo.aidl b/telephony/java/android/telephony/ims/feature/ConnectionFailureInfo.aidl new file mode 100644 index 000000000000..d24e5807d51d --- /dev/null +++ b/telephony/java/android/telephony/ims/feature/ConnectionFailureInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 The Android Open Source Project + 2 + * 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 android.telephony.ims.feature; + +parcelable ConnectionFailureInfo; diff --git a/telephony/java/android/telephony/ims/feature/ConnectionFailureInfo.java b/telephony/java/android/telephony/ims/feature/ConnectionFailureInfo.java new file mode 100644 index 000000000000..88d9aae3e19d --- /dev/null +++ b/telephony/java/android/telephony/ims/feature/ConnectionFailureInfo.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims.feature; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.SparseArray; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Provides details on why transmitting IMS traffic failed. + * + * @hide + */ +public final class ConnectionFailureInfo implements Parcelable { + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = "REASON_", + value = { + REASON_NONE, + REASON_ACCESS_DENIED, + REASON_NAS_FAILURE, + REASON_RACH_FAILURE, + REASON_RLC_FAILURE, + REASON_RRC_REJECT, + REASON_RRC_TIMEOUT, + REASON_NO_SERVICE, + REASON_PDN_NOT_AVAILABLE, + REASON_RF_BUSY, + REASON_UNSPECIFIED + }) + public @interface FailureReason {} + + /** Default value */ + public static final int REASON_NONE = 0; + /** Access class check failed */ + public static final int REASON_ACCESS_DENIED = 1; + /** 3GPP Non-access stratum failure */ + public static final int REASON_NAS_FAILURE = 2; + /** Random access failure */ + public static final int REASON_RACH_FAILURE = 3; + /** Radio link failure */ + public static final int REASON_RLC_FAILURE = 4; + /** Radio connection establishment rejected by network */ + public static final int REASON_RRC_REJECT = 5; + /** Radio connection establishment timed out */ + public static final int REASON_RRC_TIMEOUT = 6; + /** Device currently not in service */ + public static final int REASON_NO_SERVICE = 7; + /** The PDN is no more active */ + public static final int REASON_PDN_NOT_AVAILABLE = 8; + /** Radio resource is busy with another subscription */ + public static final int REASON_RF_BUSY = 9; + /** Unspecified reason */ + public static final int REASON_UNSPECIFIED = 0xFFFF; + + private static final SparseArray<String> sReasonMap; + static { + sReasonMap = new SparseArray<>(); + sReasonMap.set(REASON_NONE, "NONE"); + sReasonMap.set(REASON_ACCESS_DENIED, "ACCESS_DENIED"); + sReasonMap.set(REASON_NAS_FAILURE, "NAS_FAILURE"); + sReasonMap.set(REASON_RACH_FAILURE, "RACH_FAILURE"); + sReasonMap.set(REASON_RLC_FAILURE, "RLC_FAILURE"); + sReasonMap.set(REASON_RRC_REJECT, "RRC_REJECT"); + sReasonMap.set(REASON_RRC_TIMEOUT, "RRC_TIMEOUT"); + sReasonMap.set(REASON_NO_SERVICE, "NO_SERVICE"); + sReasonMap.set(REASON_PDN_NOT_AVAILABLE, "PDN_NOT_AVAILABLE"); + sReasonMap.set(REASON_RF_BUSY, "RF_BUSY"); + sReasonMap.set(REASON_UNSPECIFIED, "UNSPECIFIED"); + } + + /** The reason of failure */ + private final @FailureReason int mReason; + + /** + * Failure cause code from network or modem specific to the failure + * + * Reference: 3GPP TS 24.401 Annex A (Cause values for EPS mobility management) + * Reference: 3GPP TS 24.501 Annex A (Cause values for 5GS mobility management) + */ + private final int mCauseCode; + + /** Retry wait time provided by network in milliseconds */ + private final int mWaitTimeMillis; + + private ConnectionFailureInfo(Parcel in) { + mReason = in.readInt(); + mCauseCode = in.readInt(); + mWaitTimeMillis = in.readInt(); + } + + /** + * Constructor. + * + * @param reason The reason of failure. + * @param causeCode Failure cause code from network or modem specific to the failure. + * See 3GPP TS 24.401 Annex A (Cause values for EPS mobility management) and + * 3GPP TS 24.501 Annex A (Cause values for 5GS mobility management). + * @param waitTimeMillis Retry wait time provided by network in milliseconds. + * @hide + */ + public ConnectionFailureInfo(@FailureReason int reason, int causeCode, int waitTimeMillis) { + mReason = reason; + mCauseCode = causeCode; + mWaitTimeMillis = waitTimeMillis; + } + + /** + * @return the reason for the failure. + */ + public @FailureReason int getReason() { + return mReason; + } + + /** + * @return the cause code from the network or modem specific to the failure. + */ + public int getCauseCode() { + return mCauseCode; + } + + /** + * @return the retry wait time provided by the network in milliseconds. + */ + public int getWaitTimeMillis() { + return mWaitTimeMillis; + } + + /** + * @return the string format of {@link ConnectionFailureInfo} + */ + @NonNull + @Override + public String toString() { + String reason = sReasonMap.get(mReason, "UNKNOWN"); + return "ConnectionFailureInfo :: {" + mReason + " : " + reason + ", " + + mCauseCode + ", " + mWaitTimeMillis + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mReason); + out.writeInt(mCauseCode); + out.writeInt(mWaitTimeMillis); + } + + public static final @NonNull Creator<ConnectionFailureInfo> CREATOR = + new Creator<ConnectionFailureInfo>() { + @Override + public ConnectionFailureInfo createFromParcel(Parcel in) { + return new ConnectionFailureInfo(in); + } + + @Override + public ConnectionFailureInfo[] newArray(int size) { + return new ConnectionFailureInfo[size]; + } + }; +} diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 174675fcde4c..a8fb36b591fa 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -342,8 +342,8 @@ public abstract class ImsFeature { /** * @return The SIM slot index associated with this ImsFeature. * - * @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the - * subscription IDs associated with this slot. + * @see SubscriptionManager#getSubscriptionId(int) for more information on getting the + * subscription ID associated with this slot. * @hide */ @SystemApi diff --git a/telephony/java/android/telephony/ims/feature/ImsTrafficSessionCallback.java b/telephony/java/android/telephony/ims/feature/ImsTrafficSessionCallback.java new file mode 100644 index 000000000000..245ee1511d98 --- /dev/null +++ b/telephony/java/android/telephony/ims/feature/ImsTrafficSessionCallback.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 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 android.telephony.ims.feature; + +import android.annotation.NonNull; + +/** + * A callback class used to receive the result of {@link MmTelFeature#startImsTrafficSession}. + * @hide + */ +public interface ImsTrafficSessionCallback { + + /** The modem is ready to process the IMS traffic. */ + void onReady(); + + /** + * Notifies that any IMS traffic is not sent to network due to any failure + * on cellular networks. IMS service shall call {@link MmTelFeature#stopImsTrafficSession()} + * when receiving this callback. + * + * @param info The information of the failure. + */ + void onError(@NonNull ConnectionFailureInfo info); +} diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index ebe11e938c39..746246c64e8c 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -16,23 +16,35 @@ package android.telephony.ims.feature; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.os.Binder; import android.os.Bundle; import android.os.Message; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.telecom.TelecomManager; +import android.telephony.AccessNetworkConstants; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsCallSession; +import android.telephony.ims.ImsCallSessionListener; +import android.telephony.ims.ImsException; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsService; +import android.telephony.ims.MediaQualityStatus; +import android.telephony.ims.MediaThreshold; import android.telephony.ims.RtpHeaderExtensionType; +import android.telephony.ims.SrvccCall; +import android.telephony.ims.aidl.IImsCallSessionListener; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsMmTelFeature; import android.telephony.ims.aidl.IImsMmTelListener; import android.telephony.ims.aidl.IImsSmsListener; +import android.telephony.ims.aidl.IImsTrafficSessionCallback; +import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.stub.ImsCallSessionImplBase; import android.telephony.ims.stub.ImsEcbmImplBase; import android.telephony.ims.stub.ImsMultiEndpointImplBase; @@ -50,6 +62,8 @@ import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; +import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.concurrent.CancellationException; @@ -57,7 +71,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.function.Supplier; /** @@ -70,8 +86,12 @@ public class MmTelFeature extends ImsFeature { private static final String LOG_TAG = "MmTelFeature"; private Executor mExecutor; + private ImsSmsImplBase mSmsImpl; + private HashMap<ImsTrafficSessionCallback, ImsTrafficSessionCallbackWrapper> mTrafficCallbacks = + new HashMap<>(); /** + * Creates a new MmTelFeature using the Executor set in {@link ImsService#getExecutor} * @hide */ @SystemApi @@ -239,7 +259,7 @@ public class MmTelFeature extends ImsFeature { public void changeCapabilitiesConfiguration(CapabilityChangeRequest request, IImsCapabilityCallback c) { executeMethodAsyncNoException(() -> MmTelFeature.this - .requestChangeEnabledCapabilities(request, c), + .requestChangeEnabledCapabilities(request, c), "changeCapabilitiesConfiguration"); } @@ -251,40 +271,121 @@ public class MmTelFeature extends ImsFeature { } @Override + public void setMediaQualityThreshold(@MediaQualityStatus.MediaSessionType int sessionType, + MediaThreshold mediaThreshold) { + if (mediaThreshold != null) { + executeMethodAsyncNoException(() -> setMediaThreshold(sessionType, mediaThreshold), + "setMediaQualityThreshold"); + } else { + executeMethodAsyncNoException(() -> clearMediaThreshold(sessionType), + "clearMediaQualityThreshold"); + } + } + + @Override + public MediaQualityStatus queryMediaQualityStatus( + @MediaQualityStatus.MediaSessionType int sessionType) + throws RemoteException { + return executeMethodAsyncForResult(() -> MmTelFeature.this.queryMediaQualityStatus( + sessionType), "queryMediaQualityStatus"); + } + + @Override public void setSmsListener(IImsSmsListener l) { executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l), - "setSmsListener"); + "setSmsListener", getImsSmsImpl().getExecutor()); } @Override public void sendSms(int token, int messageRef, String format, String smsc, boolean retry, byte[] pdu) { executeMethodAsyncNoException(() -> MmTelFeature.this - .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms"); + .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms", + getImsSmsImpl().getExecutor()); + } + + @Override + public void onMemoryAvailable(int token) { + executeMethodAsyncNoException(() -> MmTelFeature.this + .onMemoryAvailable(token), "onMemoryAvailable", getImsSmsImpl().getExecutor()); } @Override public void acknowledgeSms(int token, int messageRef, int result) { executeMethodAsyncNoException(() -> MmTelFeature.this - .acknowledgeSms(token, messageRef, result), "acknowledgeSms"); + .acknowledgeSms(token, messageRef, result), "acknowledgeSms", + getImsSmsImpl().getExecutor()); + } + + @Override + public void acknowledgeSmsWithPdu(int token, int messageRef, int result, byte[] pdu) { + executeMethodAsyncNoException(() -> MmTelFeature.this + .acknowledgeSms(token, messageRef, result, pdu), "acknowledgeSms", + getImsSmsImpl().getExecutor()); } @Override public void acknowledgeSmsReport(int token, int messageRef, int result) { executeMethodAsyncNoException(() -> MmTelFeature.this - .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport"); + .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport", + getImsSmsImpl().getExecutor()); } @Override public String getSmsFormat() { return executeMethodAsyncForResultNoException(() -> MmTelFeature.this - .getSmsFormat(), "getSmsFormat"); + .getSmsFormat(), "getSmsFormat", getImsSmsImpl().getExecutor()); } @Override public void onSmsReady() { executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(), - "onSmsReady"); + "onSmsReady", getImsSmsImpl().getExecutor()); + } + + @Override + public void notifySrvccStarted(final ISrvccStartedCallback cb) { + executeMethodAsyncNoException( + () -> MmTelFeature.this.notifySrvccStarted( + (profiles) -> { + try { + cb.onSrvccCallNotified(profiles); + } catch (Exception e) { + Log.e(LOG_TAG, "onSrvccCallNotified e=" + e); + } + }), + "notifySrvccStarted"); + } + + @Override + public void notifySrvccCompleted() { + executeMethodAsyncNoException( + () -> MmTelFeature.this.notifySrvccCompleted(), "notifySrvccCompleted"); + } + + @Override + public void notifySrvccFailed() { + executeMethodAsyncNoException( + () -> MmTelFeature.this.notifySrvccFailed(), "notifySrvccFailed"); + } + + @Override + public void notifySrvccCanceled() { + executeMethodAsyncNoException( + () -> MmTelFeature.this.notifySrvccCanceled(), "notifySrvccCanceled"); + } + + @Override + public void setTerminalBasedCallWaitingStatus(boolean enabled) throws RemoteException { + synchronized (mLock) { + try { + MmTelFeature.this.setTerminalBasedCallWaitingStatus(enabled); + } catch (ServiceSpecificException se) { + throw new ServiceSpecificException(se.errorCode, se.getMessage()); + } catch (Exception e) { + throw new RemoteException(e.getMessage()); + } + } } // Call the methods with a clean calling identity on the executor and wait indefinitely for @@ -310,6 +411,17 @@ public class MmTelFeature extends ImsFeature { } } + private void executeMethodAsyncNoException(Runnable r, String errorLogName, + Executor executor) { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " + + e.getMessage()); + } + } + private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) throws RemoteException { CompletableFuture<T> future = CompletableFuture.supplyAsync( @@ -335,6 +447,19 @@ public class MmTelFeature extends ImsFeature { return null; } } + + private <T> T executeMethodAsyncForResultNoException(Supplier<T> r, + String errorLogName, Executor executor) { + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: " + + e.getMessage()); + return null; + } + } }; /** @@ -490,11 +615,19 @@ public class MmTelFeature extends ImsFeature { /** * Called when the IMS provider receives an incoming call. * @param c The {@link ImsCallSession} associated with the new call. + * @param callId The call ID of the session of the new incoming call. + * @param extras A bundle containing extra parameters related to the call. See + * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. + * @return the listener to listen to the session events. An {@link ImsCallSession} can only + * hold one listener at a time. see {@link ImsCallSessionListener}. + * If this method returns {@code null}, then the call could not be placed. * @hide */ @Override - public void onIncomingCall(IImsCallSession c, Bundle extras) { - + @Nullable + public IImsCallSessionListener onIncomingCall(IImsCallSession c, + String callId, Bundle extras) { + return null; } /** @@ -517,6 +650,200 @@ public class MmTelFeature extends ImsFeature { public void onVoiceMessageCountUpdate(int count) { } + + /** + * Called to set the audio handler for this connection. + * @param imsAudioHandler an {@link ImsAudioHandler} used to handle the audio + * for this IMS call. + * @hide + */ + @Override + public void onAudioModeIsVoipChanged(int imsAudioHandler) { + + } + + /** + * Called when the IMS triggers EPS fallback procedure. + * + * @param reason specifies the reason that causes EPS fallback. + * @hide + */ + @Override + public void onTriggerEpsFallback(@EpsFallbackReason int reason) { + + } + + /** + * Called when the IMS notifies the upcoming traffic type to the radio. + * + * @param token A nonce to identify the request + * @param trafficType The {@link ImsTrafficType} type for IMS traffic. + * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} + * type of the radio access network. + * @param trafficDirection Indicates whether traffic is originated by mobile originated or + * mobile terminated use case eg. MO/MT call/SMS etc. + * @param callback The callback to receive the result. + * @hide + */ + @Override + public void onStartImsTrafficSession(int token, + @ImsTrafficType int trafficType, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + @ImsTrafficDirection int trafficDirection, + IImsTrafficSessionCallback callback) { + + } + + /** + * Called when the IMS notifies the traffic type has been stopped. + * + * @param token A nonce registered with {@link #onStartImsTrafficSession}. + * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} + * type of the radio access network. + * @hide + */ + @Override + public void onModifyImsTrafficSession(int token, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType) { + + } + + /** + * Called when the IMS notifies the traffic type has been stopped. + * + * @param token A nonce registered with {@link #onStartImsTrafficSession}. + * @hide + */ + @Override + public void onStopImsTrafficSession(int token) { + + } + + /** + * Called when the IMS provider notifies {@link MediaQualityStatus}. + * + * @param status media quality status currently measured. + * @hide + */ + @Override + public void onMediaQualityStatusChanged(MediaQualityStatus status) { + + } + } + + /** + * A wrapper class of {@link ImsTrafficSessionCallback}. + * @hide + */ + public static class ImsTrafficSessionCallbackWrapper { + public static final int INVALID_TOKEN = -1; + + private static final int MAX_TOKEN = 0x10000; + + private static final AtomicInteger sTokenGenerator = new AtomicInteger(); + + /** Callback to receive the response */ + private IImsTrafficSessionCallbackStub mCallback = null; + /** Identifier to distinguish each IMS traffic request */ + private int mToken = INVALID_TOKEN; + + private ImsTrafficSessionCallback mImsTrafficSessionCallback; + + private ImsTrafficSessionCallbackWrapper(ImsTrafficSessionCallback callback) { + mImsTrafficSessionCallback = callback; + } + + /** + * Updates the callback. + * + * The mToken should be kept since it is used to identify the traffic notified to the modem + * until calling {@link MmtelFEature#stopImsTrafficSession}. + */ + final void update(@NonNull @CallbackExecutor Executor executor) { + if (executor == null) { + throw new IllegalArgumentException( + "ImsTrafficSessionCallback Executor must be non-null"); + } + + if (mCallback == null) { + // initial start of Ims traffic. + mCallback = new IImsTrafficSessionCallbackStub( + mImsTrafficSessionCallback, executor); + mToken = generateToken(); + } else { + // handover between cellular and Wi-Fi + mCallback.update(executor); + } + } + + /** + * Using a static class and weak reference here to avoid memory leak caused by the + * {@link IImsTrafficSessionCallback.Stub} callback retaining references to the outside + * {@link ImsTrafficSessionCallback}. + */ + private static class IImsTrafficSessionCallbackStub + extends IImsTrafficSessionCallback.Stub { + private WeakReference<ImsTrafficSessionCallback> mImsTrafficSessionCallbackWeakRef; + private Executor mExecutor; + + IImsTrafficSessionCallbackStub(ImsTrafficSessionCallback imsTrafficCallback, + Executor executor) { + mImsTrafficSessionCallbackWeakRef = + new WeakReference<ImsTrafficSessionCallback>(imsTrafficCallback); + mExecutor = executor; + } + + void update(Executor executor) { + mExecutor = executor; + } + + @Override + public void onReady() { + ImsTrafficSessionCallback callback = mImsTrafficSessionCallbackWeakRef.get(); + if (callback == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> callback.onReady())); + } + + @Override + public void onError(ConnectionFailureInfo info) { + ImsTrafficSessionCallback callback = mImsTrafficSessionCallbackWeakRef.get(); + if (callback == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> callback.onError(info))); + } + } + + /** + * Returns the callback binder. + */ + final IImsTrafficSessionCallbackStub getCallbackBinder() { + return mCallback; + } + + /** + * Returns the token. + */ + final int getToken() { + return mToken; + } + + /** + * Resets the members. + * It's called by {@link MmTelFeature#stopImsTrafficSession}. + */ + final void reset() { + mCallback = null; + mToken = INVALID_TOKEN; + } + + private static int generateToken() { + int token = sTokenGenerator.incrementAndGet(); + if (token == MAX_TOKEN) sTokenGenerator.set(0); + return token; + } } /** @@ -566,6 +893,147 @@ public class MmTelFeature extends ImsFeature { public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; + /** @hide */ + @IntDef( + prefix = "AUDIO_HANDLER_", + value = { + AUDIO_HANDLER_ANDROID, + AUDIO_HANDLER_BASEBAND + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ImsAudioHandler {} + + /** + * Audio Handler - Android + * @hide + */ + @SystemApi + public static final int AUDIO_HANDLER_ANDROID = 0; + + /** + * Audio Handler - Baseband + * @hide + */ + @SystemApi + public static final int AUDIO_HANDLER_BASEBAND = 1; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = "EPS_FALLBACK_REASON_", + value = { + EPS_FALLBACK_REASON_INVALID, + EPS_FALLBACK_REASON_NO_NETWORK_TRIGGER, + EPS_FALLBACK_REASON_NO_NETWORK_RESPONSE, + }) + public @interface EpsFallbackReason {} + + /** + * Default value. Internal use only. + * This value should not be used to trigger EPS fallback. + * @hide + */ + public static final int EPS_FALLBACK_REASON_INVALID = -1; + + /** + * If the network only supports the EPS fallback in 5G NR SA for voice calling and the EPS + * Fallback procedure by the network during the call setup is not triggered, UE initiated + * fallback will be triggered with this reason. The modem shall locally release the 5G NR + * SA RRC connection and acquire the LTE network and perform a tracking area update + * procedure. After the EPS fallback procedure is completed, the call setup for voice will + * be established if there is no problem. + * + * @hide + */ + public static final int EPS_FALLBACK_REASON_NO_NETWORK_TRIGGER = 1; + + /** + * If the UE doesn't receive any response for SIP INVITE within a certain timeout in 5G NR + * SA for MO voice calling, the device determines that voice call is not available in 5G and + * terminates all active SIP dialogs and SIP requests and enters IMS non-registered state. + * In that case, UE initiated fallback will be triggered with this reason. The modem shall + * reset modem's data buffer of IMS PDU to prevent the ghost call. After the EPS fallback + * procedure is completed, VoLTE call could be tried if there is no problem. + * + * @hide + */ + public static final int EPS_FALLBACK_REASON_NO_NETWORK_RESPONSE = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = "IMS_TRAFFIC_TYPE_", + value = { + IMS_TRAFFIC_TYPE_NONE, + IMS_TRAFFIC_TYPE_EMERGENCY, + IMS_TRAFFIC_TYPE_EMERGENCY_SMS, + IMS_TRAFFIC_TYPE_VOICE, + IMS_TRAFFIC_TYPE_VIDEO, + IMS_TRAFFIC_TYPE_SMS, + IMS_TRAFFIC_TYPE_REGISTRATION, + IMS_TRAFFIC_TYPE_UT_XCAP + }) + public @interface ImsTrafficType {} + + /** + * Default value for initialization. Internal use only. + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_NONE = -1; + /** + * Emergency call + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_EMERGENCY = 0; + /** + * Emergency SMS + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_EMERGENCY_SMS = 1; + /** + * Voice call + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_VOICE = 2; + /** + * Video call + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_VIDEO = 3; + /** + * SMS over IMS + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_SMS = 4; + /** + * IMS registration and subscription for reg event package (signaling) + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_REGISTRATION = 5; + /** + * Ut/XCAP (XML Configuration Access Protocol) + * @hide + */ + public static final int IMS_TRAFFIC_TYPE_UT_XCAP = 6; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = { "IMS_TRAFFIC_DIRECTION_" }, + value = {IMS_TRAFFIC_DIRECTION_INCOMING, IMS_TRAFFIC_DIRECTION_OUTGOING}) + public @interface ImsTrafficDirection {} + + /** + * Indicates that the traffic is an incoming traffic. + * @hide + */ + public static final int IMS_TRAFFIC_DIRECTION_INCOMING = 0; + /** + * Indicates that the traffic is an outgoing traffic. + * @hide + */ + public static final int IMS_TRAFFIC_DIRECTION_OUTGOING = 1; + private IImsMmTelListener mListener; /** @@ -626,12 +1094,41 @@ public class MmTelFeature extends ImsFeature { } /** + * Notify the framework that the measured media quality has crossed a threshold set by {@link + * MmTelFeature#setMediaThreshold} + * + * @param status current media quality status measured. + * @hide + */ + @SystemApi + public final void notifyMediaQualityStatusChanged( + @NonNull MediaQualityStatus status) { + if (status == null) { + throw new IllegalArgumentException( + "MediaQualityStatus must be non-null!"); + } + Log.i(LOG_TAG, "notifyMediaQualityStatusChanged " + status); + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + listener.onMediaQualityStatusChanged(status); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** * Notify the framework of an incoming call. * @param c The {@link ImsCallSessionImplBase} of the new incoming call. * @param extras A bundle containing extra parameters related to the call. See * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. - * @hide + * @hide + * + * @deprecated use {@link #notifyIncomingCall(ImsCallSessionImplBase, String, Bundle)} instead */ + @Deprecated @SystemApi public final void notifyIncomingCall(@NonNull ImsCallSessionImplBase c, @NonNull Bundle extras) { @@ -645,7 +1142,46 @@ public class MmTelFeature extends ImsFeature { } try { c.setDefaultExecutor(MmTelFeature.this.mExecutor); - listener.onIncomingCall(c.getServiceImpl(), extras); + listener.onIncomingCall(c.getServiceImpl(), null, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Notify the framework of an incoming call. + * @param c The {@link ImsCallSessionImplBase} of the new incoming call. + * @param callId The call ID of the session of the new incoming call. + * @param extras A bundle containing extra parameters related to the call. See + * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. + * @return The listener used by the framework to listen to call session events created + * from the ImsService. + * If this method returns {@code null}, then the call could not be placed. + * @hide + */ + @SystemApi + @Nullable + public final ImsCallSessionListener notifyIncomingCall( + @NonNull ImsCallSessionImplBase c, @NonNull String callId, @NonNull Bundle extras) { + if (c == null || callId == null || extras == null) { + throw new IllegalArgumentException("ImsCallSessionImplBase, callId, and Bundle can " + + "not be null."); + } + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + c.setDefaultExecutor(MmTelFeature.this.mExecutor); + IImsCallSessionListener isl = + listener.onIncomingCall(c.getServiceImpl(), callId, extras); + if (isl != null) { + ImsCallSessionListener iCSL = new ImsCallSessionListener(isl); + iCSL.setDefaultExecutor(MmTelFeature.this.mExecutor); + return iCSL; + } else { + return null; + } } catch (RemoteException e) { throw new RuntimeException(e); } @@ -687,7 +1223,7 @@ public class MmTelFeature extends ImsFeature { throw new IllegalStateException("Session is not available."); } try { - listener.onIncomingCall(c, extras); + listener.onIncomingCall(c, null, extras); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -712,6 +1248,176 @@ public class MmTelFeature extends ImsFeature { } /** + * Sets the audio handler for this connection. The vendor IMS stack will invoke this API + * to inform Telephony/Telecom layers about which audio handlers i.e. either Android or Modem + * shall be used for handling the IMS call audio. + * + * @param imsAudioHandler {@link MmTelFeature#ImsAudioHandler} used to handle the audio + * for this IMS call. + * @hide + */ + @SystemApi + public final void setCallAudioHandler(@ImsAudioHandler int imsAudioHandler) { + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + listener.onAudioModeIsVoipChanged(imsAudioHandler); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Triggers the EPS fallback procedure. + * + * @param reason specifies the reason that causes EPS fallback. + * @hide + */ + public final void triggerEpsFallback(@EpsFallbackReason int reason) { + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + try { + listener.onTriggerEpsFallback(reason); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Starts a new IMS traffic session with the framework. + * + * This API notifies the NAS and RRC layers of the modem that IMS traffic of type + * {@link ImsTrafficType} is starting for the IMS session represented by a + * {@link ImsTrafficSessionCallback}. The {@link ImsTrafficSessionCallback} + * will notify the caller when IMS traffic is ready to start via the + * {@link ImsTrafficSessionCallback#onReady()} callback. If there was an error starting + * IMS traffic for the specified traffic type, {@link ImsTrafficSessionCallback#onError()} will + * be called, which will also notify the caller of the reason of the failure. + * + * If there is a handover that changes the {@link AccessNetworkConstants#RadioAccessNetworkType} + * of this IMS traffic session, then {@link #modifyImsTrafficSession} should be called. This is + * used, for example, when a WiFi <-> cellular handover occurs. + * + * Once the IMS traffic session is finished, {@link #stopImsTrafficSession} must be called. + * + * Note: This API will be used to prioritize RF resources in case of DSDS. The service priority + * is EMERGENCY > EMERGENCY SMS > VOICE > VIDEO > SMS > REGISTRATION > Ut/XCAP. RF + * shall be prioritized to the subscription which handles the higher priority service. + * When both subscriptions are handling the same type of service, then RF shall be + * prioritized to the voice preferred sub. + * + * @param trafficType The {@link ImsTrafficType} type for IMS traffic. + * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} type of + * the radio access network. + * @param trafficDirection Indicates whether traffic is originated by mobile originated or + * mobile terminated use case eg. MO/MT call/SMS etc. + * @param executor The Executor that will be used to call the {@link ImsTrafficSessionCallback}. + * @param callback The session representing the IMS Session associated with a specific + * trafficType. This callback instance should only be used for the specified traffic type + * until {@link #stopImsTrafficSession} is called. + * + * @see modifyImsTrafficSession + * @see stopImsTrafficSession + * + * @hide + */ + public final void startImsTrafficSession(@ImsTrafficType int trafficType, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + @ImsTrafficDirection int trafficDirection, + @NonNull Executor executor, @NonNull ImsTrafficSessionCallback callback) { + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + // TODO: retrieve from the callback list + ImsTrafficSessionCallbackWrapper callbackWrapper = mTrafficCallbacks.get(callback); + if (callbackWrapper == null) { + callbackWrapper = new ImsTrafficSessionCallbackWrapper(callback); + mTrafficCallbacks.put(callback, callbackWrapper); + } + try { + callbackWrapper.update(executor); + listener.onStartImsTrafficSession(callbackWrapper.getToken(), + trafficType, accessNetworkType, trafficDirection, + callbackWrapper.getCallbackBinder()); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Modifies an existing IMS traffic session represented by the associated + * {@link ImsTrafficSessionCallback}. + * + * The {@link ImsTrafficSessionCallback} will notify the caller when IMS traffic is ready to + * start after modification using the {@link ImsTrafficSessionCallback#onReady()} callback. + * If there was an error modifying IMS traffic for the new radio access network type type, + * {@link ImsTrafficSessionCallback#onError()} will be called, which will also notify the + * caller of the reason of the failure. + * + * @param accessNetworkType The {@link AccessNetworkConstants#RadioAccessNetworkType} type of + * the radio access network. + * @param callback The callback registered with {@link #startImsTrafficSession}. + * + * @see startImsTrafficSession + * @see stopImsTrafficSession + * + * @hide + */ + public final void modifyImsTrafficSession( + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + @NonNull ImsTrafficSessionCallback callback) { + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + ImsTrafficSessionCallbackWrapper callbackWrapper = mTrafficCallbacks.get(callback); + if (callbackWrapper == null) { + // should not reach here. + throw new IllegalStateException("Unknown ImsTrafficSessionCallback instance."); + } + try { + listener.onModifyImsTrafficSession(callbackWrapper.getToken(), accessNetworkType); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Notifies the framework that the IMS traffic session represented by the associated + * {@link ImsTrafficSessionCallback} has ended. + * + * @param callback The callback registered with {@link #startImsTrafficSession}. + * + * @see startImsTrafficSession + * @see modifyImsTrafficSession + * + * @hide + */ + public final void stopImsTrafficSession(@NonNull ImsTrafficSessionCallback callback) { + IImsMmTelListener listener = getListener(); + if (listener == null) { + throw new IllegalStateException("Session is not available."); + } + ImsTrafficSessionCallbackWrapper callbackWrapper = mTrafficCallbacks.get(callback); + if (callbackWrapper == null) { + // should not reach here. + throw new IllegalStateException("Unknown ImsTrafficSessionCallback instance."); + } + try { + listener.onStopImsTrafficSession(callbackWrapper.getToken()); + callbackWrapper.reset(); + mTrafficCallbacks.remove(callback); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** * Provides the MmTelFeature with the ability to return the framework Capability Configuration * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and * includes a capability A to enable or disable, this method should return the correct enabled @@ -749,6 +1455,62 @@ public class MmTelFeature extends ImsFeature { } /** + * Called by the framework to pass {@link MediaThreshold}. The MmTelFeature should override this + * method to get Media quality threshold. This will pass the consolidated threshold values from + * Telephony framework. IMS provider needs to monitor media quality of active call and notify + * media quality {@link #notifyMediaQualityStatusChanged(MediaQualityStatus)} when the measured + * media quality crosses at least one of {@link MediaThreshold} set by this. + * + * @param mediaSessionType media session type for this Threshold info. + * @param mediaThreshold media threshold information + * @hide + */ + @SystemApi + public void setMediaThreshold( + @MediaQualityStatus.MediaSessionType int mediaSessionType, + @NonNull MediaThreshold mediaThreshold) { + // Base Implementation - Should be overridden. + Log.d(LOG_TAG, "setMediaThreshold is not supported." + mediaThreshold); + } + + /** + * The MmTelFeature should override this method to clear Media quality thresholds that were + * registered and stop media quality status updates. + * + * @param mediaSessionType media session type + * @hide + */ + @SystemApi + public void clearMediaThreshold(@MediaQualityStatus.MediaSessionType int mediaSessionType) { + // Base Implementation - Should be overridden. + Log.d(LOG_TAG, "clearMediaThreshold is not supported." + mediaSessionType); + } + + /** + * IMS provider should override this method to return currently measured media quality status. + * + * <p/> + * If media quality status is not yet measured after call is active, it needs to notify media + * quality status {@link #notifyMediaQualityStatusChanged(MediaQualityStatus)} when the first + * measurement is done. + * + * @param mediaSessionType media session type + * @return Current media quality status. It could be null if media quality status is not + * measured yet or {@link MediaThreshold} was not set corresponding to the media session + * type. + * + * @hide + */ + @SystemApi + @Nullable + public MediaQualityStatus queryMediaQualityStatus( + @MediaQualityStatus.MediaSessionType int mediaSessionType) { + // Base Implementation - Should be overridden. + Log.d(LOG_TAG, "queryMediaQualityStatus is not supported." + mediaSessionType); + return null; + } + + /** * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. * * @param callSessionType a service type that is specified in {@link ImsCallProfile} @@ -878,6 +1640,19 @@ public class MmTelFeature extends ImsFeature { } /** + * @hide + */ + public @NonNull ImsSmsImplBase getImsSmsImpl() { + synchronized (mLock) { + if (mSmsImpl == null) { + mSmsImpl = getSmsImplementation(); + mSmsImpl.setDefaultExecutor(mExecutor); + } + return mSmsImpl; + } + } + + /** * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service * configuration. * @hide @@ -937,27 +1712,123 @@ public class MmTelFeature extends ImsFeature { // Base Implementation - Should be overridden } + /** + * Notifies the MmTelFeature of the enablement status of terminal based call waiting + * + * If the terminal based call waiting is provisioned, + * IMS controls the enablement of terminal based call waiting which is defined + * in 3GPP TS 24.615. + * + * @param enabled user setting controlling whether or not call waiting is enabled. + * + * @hide + */ + @SystemApi + public void setTerminalBasedCallWaitingStatus(boolean enabled) { + // Base Implementation - Should be overridden by IMS service + throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, + "Not implemented on device."); + } + + /** + * Notifies the MmTelFeature that the network has initiated an SRVCC (Single radio voice + * call continuity) for all IMS calls. When the network initiates an SRVCC, calls from + * the LTE domain are handed over to the legacy circuit switched domain. The modem requires + * knowledge of ongoing calls in the IMS domain in order to complete the SRVCC operation. + * <p> + * @param consumer The callback used to notify the framework of the list of IMS calls and their + * state at the time of the SRVCC. + * + * @hide + */ + @SystemApi + public void notifySrvccStarted(@NonNull Consumer<List<SrvccCall>> consumer) { + // Base Implementation - Should be overridden by IMS service + } + + /** + * Notifies the MmTelFeature that the SRVCC is completed and the calls have been moved + * over to the circuit-switched domain. + * {@link android.telephony.CarrierConfigManager.ImsVoice#KEY_SRVCC_TYPE_INT_ARRAY} + * specifies the calls can be moved. Other calls will be disconnected. + * <p> + * The MmTelFeature may now release all resources related to the IMS calls. + * + * @hide + */ + @SystemApi + public void notifySrvccCompleted() { + // Base Implementation - Should be overridden by IMS service + } + + /** + * Notifies the MmTelFeature that the SRVCC has failed. + * + * The handover can fail by encountering a failure at the radio level + * or temporary MSC server internal errors in handover procedure. + * Refer to 3GPP TS 23.216 section 8 Handover Failure. + * <p> + * IMS service will recover and continue calls over IMS. + * Per TS 24.237 12.2.4.2, UE shall send SIP UPDATE request containing the reason-text + * set to "failure to transition to CS domain". + * + * @hide + */ + @SystemApi + public void notifySrvccFailed() { + // Base Implementation - Should be overridden by IMS service + } + + /** + * Notifies the MmTelFeature that the SRVCC has been canceled. + * + * Since the state of network can be changed, the network can decide to terminate + * the handover procedure before its completion and to return to its state before the handover + * procedure was triggered. + * Refer to 3GPP TS 23.216 section 8.1.3 Handover Cancellation. + * + * <p> + * IMS service will recover and continue calls over IMS. + * Per TS 24.237 12.2.4.2, UE shall send SIP UPDATE request containing the reason-text + * set to "handover canceled". + * + * @hide + */ + @SystemApi + public void notifySrvccCanceled() { + // Base Implementation - Should be overridden by IMS service + } + private void setSmsListener(IImsSmsListener listener) { - getSmsImplementation().registerSmsListener(listener); + getImsSmsImpl().registerSmsListener(listener); } private void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu) { - getSmsImplementation().sendSms(token, messageRef, format, smsc, isRetry, pdu); + getImsSmsImpl().sendSms(token, messageRef, format, smsc, isRetry, pdu); + } + + private void onMemoryAvailable(int token) { + getImsSmsImpl().onMemoryAvailable(token); } private void acknowledgeSms(int token, int messageRef, @ImsSmsImplBase.DeliverStatusResult int result) { - getSmsImplementation().acknowledgeSms(token, messageRef, result); + getImsSmsImpl().acknowledgeSms(token, messageRef, result); + } + + private void acknowledgeSms(int token, int messageRef, + @ImsSmsImplBase.DeliverStatusResult int result, byte[] pdu) { + getImsSmsImpl().acknowledgeSms(token, messageRef, result, pdu); } private void acknowledgeSmsReport(int token, int messageRef, @ImsSmsImplBase.StatusReportResult int result) { - getSmsImplementation().acknowledgeSmsReport(token, messageRef, result); + getImsSmsImpl().acknowledgeSmsReport(token, messageRef, result); } private void onSmsReady() { - getSmsImplementation().onReady(); + getImsSmsImpl().onReady(); } /** @@ -974,7 +1845,7 @@ public class MmTelFeature extends ImsFeature { } private String getSmsFormat() { - return getSmsImplementation().getSmsFormat(); + return getImsSmsImpl().getSmsFormat(); } /** diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java index 7a1a2af060d2..28c2d59e2d68 100644 --- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java +++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java @@ -23,6 +23,7 @@ import android.net.Uri; import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.RcsFeature; @@ -108,12 +109,35 @@ public interface CapabilityExchangeEventListener { * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare * cases when the Telephony stack has crashed. * + * @deprecated Replaced sip information with the newly added + * {@link #onPublishUpdated(SipDetails)}. */ + @Deprecated default void onPublishUpdated(int reasonCode, @NonNull String reasonPhrase, int reasonHeaderCause, @NonNull String reasonHeaderText) throws ImsException { + onPublishUpdated(new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setSipResponseCode(reasonCode, reasonPhrase) + .setSipResponseReasonHeader(reasonHeaderCause, reasonHeaderText) + .build()); } /** + * Notify the framework that the ImsService has refreshed the PUBLISH + * internally, which has resulted in a new PUBLISH result. + * <p> + * This method must be called to notify the framework of SUCCESS (200 OK) and FAILURE (300+) + * codes in order to keep the AOSP stack up to date. + * @param details The SIP information received in response to a publish operation. + * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not + * currently connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received + * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare + * cases when the Telephony stack has crashed. + */ + default void onPublishUpdated(@NonNull SipDetails details) + throws ImsException { + } + /** * Inform the framework of an OPTIONS query from a remote device for this device's UCE * capabilities. * <p> diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java index 25bf7d6af9ca..30a0684af101 100644 --- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java @@ -16,8 +16,11 @@ package android.telephony.ims.stub; +import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.os.Bundle; import android.os.Message; import android.os.RemoteException; import android.telephony.ims.ImsCallProfile; @@ -36,6 +39,8 @@ import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsVideoCallProvider; import com.android.internal.telephony.util.TelephonyUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Set; import java.util.concurrent.CancellationException; @@ -67,6 +72,48 @@ public class ImsCallSessionImplBase implements AutoCloseable { */ public static final int USSD_MODE_REQUEST = 1; + /** @hide */ + @IntDef( + prefix = "MEDIA_STREAM_TYPE_", + value = { + MEDIA_STREAM_TYPE_AUDIO, + MEDIA_STREAM_TYPE_VIDEO + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MediaStreamType {} + + /** + * Media Stream Type - Audio + * @hide + */ + public static final int MEDIA_STREAM_TYPE_AUDIO = 1; + /** + * Media Stream Type - Video + * @hide + */ + public static final int MEDIA_STREAM_TYPE_VIDEO = 2; + + /** @hide */ + @IntDef( + prefix = "MEDIA_STREAM_DIRECTION_", + value = { + MEDIA_STREAM_DIRECTION_UPLINK, + MEDIA_STREAM_DIRECTION_DOWNLINK + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MediaStreamDirection {} + + /** + * Media Stream Direction - Uplink + * @hide + */ + public static final int MEDIA_STREAM_DIRECTION_UPLINK = 1; + /** + * Media Stream Direction - Downlink + * @hide + */ + public static final int MEDIA_STREAM_DIRECTION_DOWNLINK = 2; + /** * Defines IMS call session state. */ @@ -327,6 +374,12 @@ public class ImsCallSessionImplBase implements AutoCloseable { new ArraySet<RtpHeaderExtension>(extensions)), "sendRtpHeaderExtensions"); } + @Override + public void callSessionNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { + executeMethodAsync(() -> ImsCallSessionImplBase.this.callSessionNotifyAnbr( + mediaType, direction, bitsPerSecond), "callSessionNotifyAnbr"); + } + // Call the methods with a clean calling identity on the executor and wait indefinitely for // the future to return. private void executeMethodAsync(Runnable r, String errorLogName) { @@ -367,7 +420,11 @@ public class ImsCallSessionImplBase implements AutoCloseable { * * @param listener {@link ImsCallSessionListener} used to notify the framework of updates * to the ImsCallSession + + * @deprecated use {@link android.telephony.ims.feature.MmTelFeature#notifyIncomingCall( + * ImsCallSessionImplBase, String, Bundle)} to get the listener instead */ + @Deprecated public void setListener(ImsCallSessionListener listener) { } @@ -726,6 +783,22 @@ public class ImsCallSessionImplBase implements AutoCloseable { public void sendRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) { } + /** + * Deliver the bitrate for the indicated media type, direction and bitrate to the upper layer. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate received from the NW through the Recommended + * bitrate MAC Control Element message and ImsStack converts this value from MAC bitrate + * to audio/video codec bitrate (defined in TS26.114). + * @hide + */ + public void callSessionNotifyAnbr(@MediaStreamType int mediaType, + @MediaStreamDirection int direction, @IntRange(from = 0) int bitsPerSecond) { + // Base Implementation - Should be overridden by IMS service + Log.i(LOG_TAG, "ImsCallSessionImplBase callSessionNotifyAnbr - mediaType: " + mediaType); + } + /** @hide */ public IImsCallSession getServiceImpl() { return mServiceImpl; diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index f371ec3a28a7..ad8a936c3c27 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -22,6 +22,7 @@ import android.annotation.SystemApi; import android.content.Context; import android.os.PersistableBundle; import android.os.RemoteException; +import android.telephony.ims.ImsService; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RcsClientConfiguration; import android.telephony.ims.RcsConfig; @@ -481,6 +482,17 @@ public class ImsConfigImplBase { } } + /** + * Clear cached configuration value. + */ + public void clearCachedValue() { + Log.i(TAG, "clearCachedValue"); + synchronized (mLock) { + mProvisionedIntValue.clear(); + mProvisionedStringValue.clear(); + } + } + // Call the methods with a clean calling identity on the executor and wait indefinitely for // the future to return. private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { @@ -538,10 +550,11 @@ public class ImsConfigImplBase { private final RemoteCallbackListExt<IRcsConfigCallback> mRcsCallbacks = new RemoteCallbackListExt<>(); private byte[] mRcsConfigData; + private final Object mRcsConfigDataLock = new Object(); ImsConfigStub mImsConfigStub; /** - * Create a ImsConfig using the Executor specified for methods being called by the + * Create an ImsConfig using the Executor specified for methods being called by the * framework. * @param executor The executor for the framework to use when executing the methods overridden * by the implementation of ImsConfig. @@ -557,6 +570,9 @@ public class ImsConfigImplBase { mImsConfigStub = new ImsConfigStub(this, null); } + /** + * Create an ImsConfig using the Executor defined in {@link ImsService#getExecutor} + */ public ImsConfigImplBase() { mImsConfigStub = new ImsConfigStub(this, null); } @@ -616,12 +632,20 @@ public class ImsConfigImplBase { private void addRcsConfigCallback(IRcsConfigCallback c) { mRcsCallbacks.register(c); - if (mRcsConfigData != null) { - try { - c.onConfigurationChanged(mRcsConfigData); - } catch (RemoteException e) { - Log.w(TAG, "dead binder to call onConfigurationChanged, skipping."); + + // This is used to avoid calling the binder out of the synchronized scope. + byte[] cloneRcsConfigData; + synchronized (mRcsConfigDataLock) { + if (mRcsConfigData == null) { + return; } + cloneRcsConfigData = mRcsConfigData.clone(); + } + + try { + c.onConfigurationChanged(cloneRcsConfigData); + } catch (RemoteException e) { + Log.w(TAG, "dead binder to call onConfigurationChanged, skipping."); } } @@ -631,18 +655,23 @@ public class ImsConfigImplBase { private void onNotifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) { // cache uncompressed config - config = isCompressed ? RcsConfig.decompressGzip(config) : config; - if (Arrays.equals(mRcsConfigData, config)) { - return; + final byte[] rcsConfigData = isCompressed ? RcsConfig.decompressGzip(config) : config; + + synchronized (mRcsConfigDataLock) { + if (Arrays.equals(mRcsConfigData, config)) { + return; + } + mRcsConfigData = rcsConfigData; } - mRcsConfigData = config; // can be null in testing if (mRcsCallbacks != null) { synchronized (mRcsCallbacks) { mRcsCallbacks.broadcastAction(c -> { try { - c.onConfigurationChanged(mRcsConfigData); + // config is cloned here so modifications to the config passed to the + // vendor do not accidentally modify the cache. + c.onConfigurationChanged(rcsConfigData.clone()); } catch (RemoteException e) { Log.w(TAG, "dead binder in notifyRcsAutoConfigurationReceived, skipping."); } @@ -653,7 +682,9 @@ public class ImsConfigImplBase { } private void onNotifyRcsAutoConfigurationRemoved() { - mRcsConfigData = null; + synchronized (mRcsConfigDataLock) { + mRcsConfigData = null; + } if (mRcsCallbacks != null) { synchronized (mRcsCallbacks) { mRcsCallbacks.broadcastAction(c -> { @@ -857,4 +888,17 @@ public class ImsConfigImplBase { mImsConfigStub.mExecutor = executor; } } + + /** + * Clear all cached config data. This will be called when the config data is no longer valid + * such as when the SIM was removed. + * @hide + */ + public final void clearConfigurationCache() { + mImsConfigStub.clearCachedValue(); + + synchronized (mRcsConfigDataLock) { + mRcsConfigData = null; + } + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java index 593f0807ef27..ff378ba02856 100644 --- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IImsRegistration; import android.telephony.ims.aidl.IImsRegistrationCallback; import android.util.Log; @@ -42,6 +43,7 @@ import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.function.Supplier; /** @@ -64,7 +66,8 @@ public class ImsRegistrationImplBase { REGISTRATION_TECH_LTE, REGISTRATION_TECH_IWLAN, REGISTRATION_TECH_CROSS_SIM, - REGISTRATION_TECH_NR + REGISTRATION_TECH_NR, + REGISTRATION_TECH_3G }) @Retention(RetentionPolicy.SOURCE) public @interface ImsRegistrationTech {} @@ -92,10 +95,15 @@ public class ImsRegistrationImplBase { public static final int REGISTRATION_TECH_NR = 3; /** + * This ImsService is registered to IMS via 3G. + */ + public static final int REGISTRATION_TECH_3G = 4; + + /** * This is used to check the upper range of registration tech * @hide */ - public static final int REGISTRATION_TECH_MAX = REGISTRATION_TECH_NR + 1; + public static final int REGISTRATION_TECH_MAX = REGISTRATION_TECH_3G + 1; // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current // state. @@ -104,6 +112,73 @@ public class ImsRegistrationImplBase { // yet. private static final int REGISTRATION_STATE_UNKNOWN = -1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"REASON_"}, + value = { + REASON_UNKNOWN, + REASON_SIM_REMOVED, + REASON_SIM_REFRESH, + REASON_ALLOWED_NETWORK_TYPES_CHANGED, + REASON_NON_IMS_CAPABLE_NETWORK, + REASON_RADIO_POWER_OFF, + REASON_HANDOVER_FAILED, + REASON_VOPS_NOT_SUPPORTED, + }) + public @interface ImsDeregistrationReason{} + + /** + * Unspecified reason. + * @hide + */ + public static final int REASON_UNKNOWN = 0; + + /** + * Since SIM is removed, the credentials for IMS service is also removed. + * @hide + */ + public static final int REASON_SIM_REMOVED = 1; + + /** + * Detach from the network shall be performed due to the SIM refresh. IMS service should be + * deregistered before that procedure. + * @hide + */ + public static final int REASON_SIM_REFRESH = 2; + + /** + * The allowed network types have changed, resulting in a network type + * that does not support IMS. + * @hide + */ + public static final int REASON_ALLOWED_NETWORK_TYPES_CHANGED = 3; + + /** + * The device camped on a network that does not support IMS. + * @hide + */ + public static final int REASON_NON_IMS_CAPABLE_NETWORK = 4; + + /** + * IMS service should be deregistered from the network before turning off the radio. + * @hide + */ + public static final int REASON_RADIO_POWER_OFF = 5; + + /** + * Since the handover is failed or not allowed, the data service for IMS shall be + * disconnected. + * @hide + */ + public static final int REASON_HANDOVER_FAILED = 6; + + /** + * The network is changed to a network that does not support voice over IMS. + * @hide + */ + public static final int REASON_VOPS_NOT_SUPPORTED = 7; + private Executor mExecutor; /** @@ -182,6 +257,12 @@ public class ImsRegistrationImplBase { .triggerSipDelegateDeregistration(), "triggerSipDelegateDeregistration"); } + @Override + public void triggerDeregistration(@ImsDeregistrationReason int reason) { + executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this + .triggerDeregistration(reason), "triggerDeregistration"); + } + // Call the methods with a clean calling identity on the executor and wait indefinitely for // the future to return. private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { @@ -228,6 +309,9 @@ public class ImsRegistrationImplBase { private int mRegistrationState = REGISTRATION_STATE_UNKNOWN; // Locked on mLock, create unspecified disconnect cause. private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo(); + // Locked on mLock + private int mLastDisconnectSuggestedAction = RegistrationManager.SUGGESTED_ACTION_NONE; + private int mLastDisconnectRadioTech = REGISTRATION_TECH_NONE; // We hold onto the uris each time they change so that we can send it to a callback when its // first added. @@ -242,11 +326,19 @@ public class ImsRegistrationImplBase { } private void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { + // This is purposefully not synchronized with broadcastToCallbacksLocked because the + // list of callbacks to notify is copied over from the original list modified here. I also + // do not want to risk introducing a deadlock by using the same mCallbacks Object to + // synchronize on outgoing and incoming operations. mCallbacks.register(c); updateNewCallbackWithState(c); } private void removeRegistrationCallback(IImsRegistrationCallback c) { + // This is purposefully not synchronized with broadcastToCallbacksLocked because the + // list of callbacks to notify is copied over from the original list modified here. I also + // do not want to risk introducing a deadlock by using the same mCallbacks Object to + // synchronize on outgoing and incoming operations. mCallbacks.unregister(c); } @@ -303,6 +395,19 @@ public class ImsRegistrationImplBase { // Stub implementation, ImsService should implement this } + /** + * Requests IMS stack to perform graceful IMS deregistration before radio performing + * network detach in the events of SIM remove, refresh or and so on. The radio waits for + * the IMS deregistration, which will be notified by telephony via + * {@link android.hardware.radio.ims.IRadioIms#updateImsRegistrationInfo()}, + * or a certain timeout interval to start the network detach procedure. + * + * @param reason the reason why the deregistration is triggered. + * @hide + */ + public void triggerDeregistration(@ImsDeregistrationReason int reason) { + // Stub Implementation, can be overridden by ImsService + } /** * Notify the framework that the device is connected to the IMS network. @@ -324,7 +429,7 @@ public class ImsRegistrationImplBase { @SystemApi public final void onRegistered(@NonNull ImsRegistrationAttributes attributes) { updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERED); - mCallbacks.broadcastAction((c) -> { + broadcastToCallbacksLocked((c) -> { try { c.onRegistered(attributes); } catch (RemoteException e) { @@ -353,7 +458,7 @@ public class ImsRegistrationImplBase { @SystemApi public final void onRegistering(@NonNull ImsRegistrationAttributes attributes) { updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERING); - mCallbacks.broadcastAction((c) -> { + broadcastToCallbacksLocked((c) -> { try { c.onRegistering(attributes); } catch (RemoteException e) { @@ -381,12 +486,101 @@ public class ImsRegistrationImplBase { */ @SystemApi public final void onDeregistered(ImsReasonInfo info) { - updateToDisconnectedState(info); + // Default impl to keep backwards compatibility with old implementations + onDeregistered(info, RegistrationManager.SUGGESTED_ACTION_NONE, REGISTRATION_TECH_NONE); + } + + /** + * Notify the framework that the device is disconnected from the IMS network. + * <p> + * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo,int)}, you should ensure that any + * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent + * to the framework. For example, + * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO} + * and + * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE} + * may be set to unavailable to ensure the framework knows these services are no longer + * available due to de-registration. If you do not report capability changes impacted by + * de-registration, the framework will not know which features are no longer available as a + * result. + * + * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + * @param suggestedAction the expected behavior of radio protocol stack. + * @param imsRadioTech the network type on which IMS registration has failed. + * @hide This API is not part of the Android public SDK API + */ + @SystemApi + public final void onDeregistered(@Nullable ImsReasonInfo info, + @RegistrationManager.SuggestedAction int suggestedAction, + @ImsRegistrationTech int imsRadioTech) { + updateToDisconnectedState(info, suggestedAction, imsRadioTech); + // ImsReasonInfo should never be null. + final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo(); + broadcastToCallbacksLocked((c) -> { + try { + c.onDeregistered(reasonInfo, suggestedAction, imsRadioTech); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback."); + } + }); + } + + /** + * Notify the framework that the device is disconnected from the IMS network. + * <p> + * Note: Before calling {@link #onDeregistered(ImsReasonInfo, SipDetails)}, ImsService should + * ensure that any changes to {@link android.telephony.ims.feature.ImsFeature} capability + * availability is sent to the framework. + * For example, + * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO} + * and + * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE} + * may be set to unavailable to ensure the framework knows these services are no longer + * available due to de-registration. If ImsService do not report capability changes impacted + * by de-registration, the framework will not know which features are no longer available as a + * result. + * + * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + * @param details the {@link SipDetails} related to disconnected Ims registration + * @hide This API is not part of the Android public SDK API + */ + @SystemApi + public final void onDeregistered(@Nullable ImsReasonInfo info, + @NonNull SipDetails details) { + onDeregistered(info, RegistrationManager.SUGGESTED_ACTION_NONE, REGISTRATION_TECH_NONE, + details); + } + + /** + * Notify the framework that the device is disconnected from the IMS network. + * <p> + * Note: Before calling {@link #onDeregistered(ImsReasonInfo, SipDetails)}, ImsService should + * ensure that any changes to {@link android.telephony.ims.feature.ImsFeature} capability + * availability is sent to the framework. + * For example, + * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO} + * and + * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE} + * may be set to unavailable to ensure the framework knows these services are no longer + * available due to de-registration. If ImsService do not report capability changes impacted + * by de-registration, the framework will not know which features are no longer available as a + * result. + * + * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + * @param suggestedAction the expected behavior of radio protocol stack. + * @param details the {@link SipDetails} related to disconnected Ims registration + * @hide This API is not part of the Android public SDK API + */ + @SystemApi + public final void onDeregistered(@Nullable ImsReasonInfo info, + @RegistrationManager.SuggestedAction int suggestedAction, + @ImsRegistrationTech int imsRadioTech, @NonNull SipDetails details) { + updateToDisconnectedState(info, suggestedAction, imsRadioTech); // ImsReasonInfo should never be null. final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo(); - mCallbacks.broadcastAction((c) -> { + broadcastToCallbacksLocked((c) -> { try { - c.onDeregistered(reasonInfo); + c.onDeregisteredWithDetails(reasonInfo, suggestedAction, imsRadioTech, details); } catch (RemoteException e) { Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback."); } @@ -406,7 +600,7 @@ public class ImsRegistrationImplBase { public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, ImsReasonInfo info) { final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo(); - mCallbacks.broadcastAction((c) -> { + broadcastToCallbacksLocked((c) -> { try { c.onTechnologyChangeFailed(imsRadioTech, reasonInfo); } catch (RemoteException e) { @@ -429,7 +623,20 @@ public class ImsRegistrationImplBase { mUris = ArrayUtils.cloneOrNull(uris); mUrisSet = true; } - mCallbacks.broadcastAction((c) -> onSubscriberAssociatedUriChanged(c, uris)); + broadcastToCallbacksLocked((c) -> onSubscriberAssociatedUriChanged(c, uris)); + } + + /** + * Broadcast the specified operation in a synchronized manner so that multiple threads do not + * try to call broadcast at the same time, which will generate an error. + * @param c The Consumer lambda method containing the callback to call. + */ + private void broadcastToCallbacksLocked(Consumer<IImsRegistrationCallback> c) { + // One broadcast can happen at a time, so synchronize threads so only one + // beginBroadcast/endBroadcast happens at a time. + synchronized (mCallbacks) { + mCallbacks.broadcastAction(c); + } } private void onSubscriberAssociatedUriChanged(IImsRegistrationCallback callback, Uri[] uris) { @@ -445,10 +652,14 @@ public class ImsRegistrationImplBase { mRegistrationAttributes = attributes; mRegistrationState = newState; mLastDisconnectCause = null; + mLastDisconnectSuggestedAction = RegistrationManager.SUGGESTED_ACTION_NONE; + mLastDisconnectRadioTech = REGISTRATION_TECH_NONE; } } - private void updateToDisconnectedState(ImsReasonInfo info) { + private void updateToDisconnectedState(ImsReasonInfo info, + @RegistrationManager.SuggestedAction int suggestedAction, + @ImsRegistrationTech int imsRadioTech) { synchronized (mLock) { //We don't want to send this info over if we are disconnected mUrisSet = false; @@ -458,6 +669,8 @@ public class ImsRegistrationImplBase { RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED); if (info != null) { mLastDisconnectCause = info; + mLastDisconnectSuggestedAction = suggestedAction; + mLastDisconnectRadioTech = imsRadioTech; } else { Log.w(LOG_TAG, "updateToDisconnectedState: no ImsReasonInfo provided."); mLastDisconnectCause = new ImsReasonInfo(); @@ -474,18 +687,22 @@ public class ImsRegistrationImplBase { int state; ImsRegistrationAttributes attributes; ImsReasonInfo disconnectInfo; + int suggestedAction; + int imsDisconnectRadioTech; boolean urisSet; Uri[] uris; synchronized (mLock) { state = mRegistrationState; attributes = mRegistrationAttributes; disconnectInfo = mLastDisconnectCause; + suggestedAction = mLastDisconnectSuggestedAction; + imsDisconnectRadioTech = mLastDisconnectRadioTech; urisSet = mUrisSet; uris = mUris; } switch (state) { case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: { - c.onDeregistered(disconnectInfo); + c.onDeregistered(disconnectInfo, suggestedAction, imsDisconnectRadioTech); break; } case RegistrationManager.REGISTRATION_STATE_REGISTERING: { @@ -517,4 +734,16 @@ public class ImsRegistrationImplBase { mExecutor = executor; } } + + /** + * Clear the cached data when the subscription is no longer valid + * such as when a sim is removed. + * @hide + */ + public final void clearRegistrationCache() { + synchronized (mLock) { + mUris = null; + mUrisSet = false; + } + } } diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java index fb997d118419..e7e0ec212839 100644 --- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java @@ -18,6 +18,7 @@ package android.telephony.ims.stub; import android.annotation.IntDef; import android.annotation.IntRange; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.RemoteException; import android.telephony.SmsManager; @@ -27,6 +28,7 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * Base implementation for SMS over IMS. @@ -128,6 +130,22 @@ public class ImsSmsImplBase { // Lock for feature synchronization private final Object mLock = new Object(); private IImsSmsListener mListener; + private Executor mExecutor; + + /** + * Create a new ImsSmsImplBase using the Executor set in MmTelFeature + */ + public ImsSmsImplBase() { + } + + /** + * Create a new ImsSmsImplBase with specified executor. + * <p> + * @param executor Default executor for ImsSmsImplBase + */ + public ImsSmsImplBase(@NonNull Executor executor) { + mExecutor = executor; + } /** * Registers a listener responsible for handling tasks like delivering messages. @@ -170,10 +188,29 @@ public class ImsSmsImplBase { } /** + * This method will be triggered by the platform when memory becomes available to receive SMS + * after a memory full event. This method should be implemented by IMS providers to + * send RP-SMMA notification from SMS Relay Layer to server over IMS as per section 7.3.2 of + * TS 124.11. Once the RP-SMMA Notification is sent to the network. The network will deliver all + * the pending messages which failed due to Unavailability of Memory. + * + * @param token unique token generated in {@link ImsSmsDispatcher#onMemoryAvailable(void)} that + * should be used when triggering callbacks for this specific message. + * + * @hide + */ + public void onMemoryAvailable(int token) { + // Base Implementation - Should be overridden + } + + /** * This method will be triggered by the platform after * {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS * provider. * + * If the framework needs to provide the PDU used to acknowledge the SMS, + * {@link #acknowledgeSms(int, int, int, byte[])} will be called. + * * @param token token provided in {@link #onSmsReceived(int, String, byte[])} * @param messageRef the message reference, which may be 1 byte if it is in * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in @@ -186,6 +223,27 @@ public class ImsSmsImplBase { } /** + * This method will be called by the platform after + * {@link #onSmsReceived(int, String, byte[])} has been called to acknowledge an incoming SMS. + * + * This method is only called in cases where the framework needs to provide the PDU such as the + * case where we provide the Short Message Transfer Layer PDU (see 3GPP TS 23.040). Otherwise, + * {@link #acknowledgeSms(int, int, int)} will be used. + * + * @param token token provided in {@link #onSmsReceived(int, String, byte[])} + * @param messageRef the message reference, which may be 1 byte if it is in + * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in + * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). + * @param result result of delivering the message. + * @param pdu PDU representing the contents of the message. + */ + public void acknowledgeSms(int token, @IntRange(from = 0, to = 65535) int messageRef, + @DeliverStatusResult int result, @NonNull byte[] pdu) { + Log.e(LOG_TAG, "acknowledgeSms() not implemented. acknowledgeSms(int, int, int) called."); + acknowledgeSms(token, messageRef, result); + } + + /** * This method will be triggered by the platform after * {@link #onSmsStatusReportReceived(int, int, String, byte[])} or * {@link #onSmsStatusReportReceived(int, String, byte[])} has been called to provide the @@ -347,6 +405,38 @@ public class ImsSmsImplBase { } /** + * This API is used to report the result of sending + * RP-SMMA to framework based on received network responses(RP-ACK, + * RP-ERROR or SIP error). + * + * @param token provided in {@link #onMemoryAvailable()}. + * @param result based on RP-ACK or RP_ERROR + * @param networkErrorCode the error code reported by the carrier + * network if sending this SMS has resulted in an error or + * {@link #RESULT_NO_NETWORK_ERROR} if no network error was generated. See + * 3GPP TS 24.011 Section 7.3.4 for valid error codes and more + * information. + * + * @hide + */ + public final void onMemoryAvailableResult(int token, @SendStatusResult int result, + int networkErrorCode) throws RuntimeException { + IImsSmsListener listener = null; + synchronized (mLock) { + listener = mListener; + } + + if (listener == null) { + throw new RuntimeException("Feature not ready."); + } + try { + listener.onMemoryAvailableResult(token, result, networkErrorCode); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** * This method should be triggered by the IMS providers when the status report of the sent * message is received. The platform will handle the report and notify the IMS provider of the * result by calling {@link #acknowledgeSmsReport(int, int, int)}. @@ -443,4 +533,29 @@ public class ImsSmsImplBase { public void onReady() { // Base Implementation - Should be overridden } + + /** + * Set default Executor for ImsSmsImplBase. + * + * @param executor The default executor for the framework to use when executing the methods + * overridden by the implementation of ImsSms. + * @hide + */ + public final void setDefaultExecutor(@NonNull Executor executor) { + if (mExecutor == null) { + mExecutor = executor; + } + } + + /** + * Get Executor from ImsSmsImplBase. + * If there is no settings for the executor, all ImsSmsImplBase method calls will use + * Runnable::run as default + * + * @return an Executor used to execute methods in ImsSms called remotely by the framework. + * @hide + */ + public @NonNull Executor getExecutor() { + return mExecutor != null ? mExecutor : Runnable::run; + } } diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java index 474eb05ca19c..66442a6adb54 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java @@ -24,8 +24,10 @@ import android.annotation.SystemApi; import android.net.Uri; import android.telephony.ims.ImsException; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.RcsFeature; +import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -155,7 +157,11 @@ public class RcsCapabilityExchangeImplBase { * is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases * when the Telephony stack has crashed. + * + * @deprecated Replaced sip information with the newly added + * {@link #onNetworkResponse(SipDetails)}. */ + @Deprecated void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, @NonNull String reason) throws ImsException; @@ -178,11 +184,35 @@ public class RcsCapabilityExchangeImplBase { * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in * rare cases when the Telephony stack has crashed. + * + * @deprecated Replaced sip information with the newly added + * {@link #onNetworkResponse(SipDetails)}. */ + @Deprecated void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, @NonNull String reasonPhrase, @IntRange(from = 100, to = 699) int reasonHeaderCause, @NonNull String reasonHeaderText) throws ImsException; + + /** + * Provide the framework with a subsequent network response update to + * {@link #publishCapabilities(String, PublishResponseCallback)}. + * + * @param details The SIP information received in response to a publish operation. + * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is + * not currently connected to the framework. This can happen if the {@link RcsFeature} + * is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received + * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases + * when the Telephony stack has crashed. + */ + default void onNetworkResponse(@NonNull SipDetails details) throws ImsException { + if (TextUtils.isEmpty(details.getReasonHeaderText())) { + onNetworkResponse(details.getResponseCode(), details.getResponsePhrase()); + } else { + onNetworkResponse(details.getResponseCode(), details.getResponsePhrase(), + details.getReasonHeaderCause(), details.getReasonHeaderText()); + } + } } /** @@ -262,7 +292,11 @@ public class RcsCapabilityExchangeImplBase { * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the * {@link RcsFeature} has not received the {@link ImsFeature#onFeatureReady()} callback. * This may also happen in rare cases when the Telephony stack has crashed. + * + * @deprecated Replaced sip information with the newly added + * {@link #onNetworkResponse(SipDetails)}. */ + @Deprecated void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, @NonNull String reason) throws ImsException; @@ -285,13 +319,42 @@ public class RcsCapabilityExchangeImplBase { * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in * rare cases when the Telephony stack has crashed. + * + * @deprecated Replaced sip information with the newly added + * {@link #onNetworkResponse(SipDetails)}. */ + @Deprecated void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, @NonNull String reasonPhrase, @IntRange(from = 100, to = 699) int reasonHeaderCause, @NonNull String reasonHeaderText) throws ImsException; /** + * Notify the framework of the response to the SUBSCRIBE request from + * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)}. + * <p> + * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the + * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate}, + * {@link #onResourceTerminated}, and {@link #onTerminated} as required for the + * subsequent NOTIFY responses to the subscription. + * + * @param details The SIP information related to this request. + * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is + * not currently connected to the framework. This can happen if the + * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the + * {@link RcsFeature} has not received the {@link ImsFeature#onFeatureReady()} callback. + * This may also happen in rare cases when the Telephony stack has crashed. + */ + default void onNetworkResponse(@NonNull SipDetails details) throws ImsException { + if (TextUtils.isEmpty(details.getReasonHeaderText())) { + onNetworkResponse(details.getResponseCode(), details.getResponsePhrase()); + } else { + onNetworkResponse(details.getResponseCode(), details.getResponsePhrase(), + details.getReasonHeaderCause(), details.getReasonHeaderText()); + } + }; + + /** * Notify the framework of the latest XML PIDF documents included in the network response * for the requested contacts' capabilities requested by the Framework using * {@link RcsUceAdapter#requestCapabilities(List, Executor, diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java index dd1061f3bd46..556d6f4565d4 100644 --- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java +++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java @@ -195,7 +195,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { return false; } DownloadRequest request = intent.getParcelableExtra( - MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST); + MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, android.telephony.mbms.DownloadRequest.class); String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX; File expectedTokenFile = new File( MbmsUtils.getEmbmsTempFileDirForService(context, request.getFileServiceId()), @@ -236,7 +236,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private void moveDownloadedFile(Context context, Intent intent) { DownloadRequest request = intent.getParcelableExtra( - MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST); + MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, android.telephony.mbms.DownloadRequest.class); Intent intentForApp = request.getIntentForApp(); if (intentForApp == null) { Log.i(LOG_TAG, "Malformed app notification intent"); @@ -256,7 +256,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { return; } - Uri finalTempFile = intent.getParcelableExtra(VendorUtils.EXTRA_FINAL_URI); + Uri finalTempFile = intent.getParcelableExtra(VendorUtils.EXTRA_FINAL_URI, android.net.Uri.class); if (!verifyTempFilePath(context, request.getFileServiceId(), finalTempFile)) { Log.w(LOG_TAG, "Download result specified an invalid temp file " + finalTempFile); setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR); @@ -264,7 +264,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } FileInfo completedFileInfo = - (FileInfo) intent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO); + (FileInfo) intent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO, android.telephony.mbms.FileInfo.class); Path appSpecifiedDestination = FileSystems.getDefault().getPath( request.getDestinationUri().getPath()); @@ -288,13 +288,13 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private void cleanupPostMove(Context context, Intent intent) { DownloadRequest request = intent.getParcelableExtra( - MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST); + MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, android.telephony.mbms.DownloadRequest.class); if (request == null) { Log.w(LOG_TAG, "Intent does not include a DownloadRequest. Ignoring."); return; } - List<Uri> tempFiles = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_LIST); + List<Uri> tempFiles = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_LIST, android.net.Uri.class); if (tempFiles == null) { return; } @@ -318,7 +318,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { return; } int fdCount = intent.getIntExtra(VendorUtils.EXTRA_FD_COUNT, 0); - List<Uri> pausedList = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_PAUSED_LIST); + List<Uri> pausedList = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_PAUSED_LIST, android.net.Uri.class); if (fdCount == 0 && (pausedList == null || pausedList.size() == 0)) { Log.i(LOG_TAG, "No temp files actually requested. Ending."); @@ -417,7 +417,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { String serviceId = intent.getStringExtra(VendorUtils.EXTRA_SERVICE_ID); File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context, serviceId); final List<Uri> filesInUse = - intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_FILES_IN_USE); + intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_FILES_IN_USE, android.net.Uri.class); File[] filesToDelete = tempFileDir.listFiles(new FileFilter() { @Override public boolean accept(File file) { diff --git a/telephony/java/android/telephony/satellite/AntennaDirection.aidl b/telephony/java/android/telephony/satellite/AntennaDirection.aidl new file mode 100644 index 000000000000..c838f6fbb8ac --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaDirection.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2023, 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 android.telephony.satellite; + +parcelable AntennaDirection; diff --git a/telephony/java/android/telephony/satellite/AntennaDirection.java b/telephony/java/android/telephony/satellite/AntennaDirection.java new file mode 100644 index 000000000000..02b0bc7364a2 --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaDirection.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Antenna direction is provided as X/Y/Z values corresponding to the direction of the antenna + * main lobe as a unit vector in CTIA coordinate system (as specified in Appendix A of Wireless + * device CTIA OTAn test plan). CTIA coordinate system is defined relative to device’s screen + * when the device is held in default portrait mode with screen facing the user: + * + * Z axis is vertical along the plane of the device with positive Z pointing up and negative z + * pointing towards bottom of the device + * Y axis is horizontal along the plane of the device with positive Y pointing towards right of + * the phone screen and negative Y pointing towards left + * X axis is orthogonal to the Y-Z plane (phone screen), pointing away from the phone screen for + * positive X and pointing away from back of the phone for negative X. + * @hide + */ +public final class AntennaDirection implements Parcelable { + /** Antenna x axis direction. */ + private float mX; + + /** Antenna y axis direction. */ + private float mY; + + /** Antenna z axis direction. */ + private float mZ; + + /** + * @hide + */ + @UnsupportedAppUsage + public AntennaDirection(float x, float y, float z) { + mX = x; + mY = y; + mZ = z; + } + + private AntennaDirection(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeFloat(mX); + out.writeFloat(mY); + out.writeFloat(mZ); + } + + @NonNull + public static final Creator<AntennaDirection> CREATOR = + new Creator<>() { + @Override + public AntennaDirection createFromParcel(Parcel in) { + return new AntennaDirection(in); + } + + @Override + public AntennaDirection[] newArray(int size) { + return new AntennaDirection[size]; + } + }; + + @Override + @NonNull public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("X:"); + sb.append(mX); + sb.append(","); + + sb.append("Y:"); + sb.append(mY); + sb.append(","); + + sb.append("Z:"); + sb.append(mZ); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AntennaDirection that = (AntennaDirection) o; + return mX == that.mX + && mY == that.mY + && mZ == that.mZ; + } + + @Override + public int hashCode() { + return Objects.hash(mX, mY, mZ); + } + + public float getX() { + return mX; + } + + public float getY() { + return mY; + } + + public float getZ() { + return mZ; + } + + private void readFromParcel(Parcel in) { + mX = in.readFloat(); + mY = in.readFloat(); + mZ = in.readFloat(); + } +} diff --git a/telephony/java/android/telephony/satellite/AntennaPosition.aidl b/telephony/java/android/telephony/satellite/AntennaPosition.aidl new file mode 100644 index 000000000000..00525624329c --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaPosition.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2023, 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 android.telephony.satellite; + +parcelable AntennaPosition; diff --git a/telephony/java/android/telephony/satellite/AntennaPosition.java b/telephony/java/android/telephony/satellite/AntennaPosition.java new file mode 100644 index 000000000000..eefc8b00f8e8 --- /dev/null +++ b/telephony/java/android/telephony/satellite/AntennaPosition.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Antenna Position received from satellite modem which gives information about antenna + * direction to be used with satellite communication and suggested device hold positions. + * @hide + */ +public final class AntennaPosition implements Parcelable { + /** Antenna direction used for satellite communication. */ + @NonNull AntennaDirection mAntennaDirection; + + /** Enum corresponding to device hold position to be used by the end user. */ + @SatelliteManager.DeviceHoldPosition int mSuggestedHoldPosition; + + /** + * @hide + */ + @UnsupportedAppUsage + public AntennaPosition(@NonNull AntennaDirection antennaDirection, int suggestedHoldPosition) { + mAntennaDirection = antennaDirection; + mSuggestedHoldPosition = suggestedHoldPosition; + } + + private AntennaPosition(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeParcelable(mAntennaDirection, flags); + out.writeInt(mSuggestedHoldPosition); + } + + @NonNull + public static final Creator<AntennaPosition> CREATOR = + new Creator<>() { + @Override + public AntennaPosition createFromParcel(Parcel in) { + return new AntennaPosition(in); + } + + @Override + public AntennaPosition[] newArray(int size) { + return new AntennaPosition[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AntennaPosition that = (AntennaPosition) o; + return Objects.equals(mAntennaDirection, that.mAntennaDirection) + && mSuggestedHoldPosition == that.mSuggestedHoldPosition; + } + + @Override + public int hashCode() { + return Objects.hash(mAntennaDirection, mSuggestedHoldPosition); + } + + @Override + @NonNull public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("antennaDirection:"); + sb.append(mAntennaDirection); + sb.append(","); + + sb.append("suggestedHoldPosition:"); + sb.append(mSuggestedHoldPosition); + return sb.toString(); + } + + @NonNull + public AntennaDirection getAntennaDirection() { + return mAntennaDirection; + } + + @SatelliteManager.DeviceHoldPosition + public int getSuggestedHoldPosition() { + return mSuggestedHoldPosition; + } + + private void readFromParcel(Parcel in) { + mAntennaDirection = in.readParcelable(AntennaDirection.class.getClassLoader(), + AntennaDirection.class); + mSuggestedHoldPosition = in.readInt(); + } +} diff --git a/telephony/java/android/telephony/satellite/ISatelliteDatagramCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteDatagramCallback.aidl new file mode 100644 index 000000000000..e229f05b1ad3 --- /dev/null +++ b/telephony/java/android/telephony/satellite/ISatelliteDatagramCallback.aidl @@ -0,0 +1,40 @@ +/* + * Copyright 2023 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 android.telephony.satellite; + +import android.telephony.satellite.SatelliteDatagram; + +import com.android.internal.telephony.IVoidConsumer; + +/** + * Interface for satellite datagrams callback. + * @hide + */ +oneway interface ISatelliteDatagramCallback { + /** + * Called when there is an incoming datagram to be received from satellite. + * + * @param datagramId An id that uniquely identifies incoming datagram. + * @param datagram Datagram received from satellite. + * @param pendingCount Number of datagrams yet to be received from satellite. + * @param callback This callback will be used by datagram receiver app to to inform + * Telephony that datagram is received. If the callback is not received + * within five minutes, Telephony will resend the datagram. + */ + void onSatelliteDatagramReceived(long datagramId, in SatelliteDatagram datagram, + int pendingCount, IVoidConsumer callback); +} diff --git a/telephony/java/android/telephony/satellite/ISatelliteProvisionStateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteProvisionStateCallback.aidl new file mode 100644 index 000000000000..f981fb1d67c7 --- /dev/null +++ b/telephony/java/android/telephony/satellite/ISatelliteProvisionStateCallback.aidl @@ -0,0 +1,30 @@ +/* + * Copyright 2023 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 android.telephony.satellite; + +/** + * Interface for satellite provision state callback. + * @hide + */ +oneway interface ISatelliteProvisionStateCallback { + /** + * Indicates that the satellite provision state has changed. + * + * @param provisioned True means the service is provisioned and false means it is not. + */ + void onSatelliteProvisionStateChanged(in boolean provisioned); +} diff --git a/telephony/java/android/telephony/satellite/ISatelliteStateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteStateCallback.aidl new file mode 100644 index 000000000000..cd9d81e1ee9b --- /dev/null +++ b/telephony/java/android/telephony/satellite/ISatelliteStateCallback.aidl @@ -0,0 +1,30 @@ +/* + * Copyright 2023 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 android.telephony.satellite; + +/** + * Interface for satellite state change callback. + * @hide + */ +oneway interface ISatelliteStateCallback { + /** + * Indicates that the satellite modem state has changed. + * + * @param state The current satellite modem state. + */ + void onSatelliteModemStateChanged(in int state); +} diff --git a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl new file mode 100644 index 000000000000..a81444d51374 --- /dev/null +++ b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl @@ -0,0 +1,50 @@ +/* + * Copyright 2023 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 android.telephony.satellite; + +import android.telephony.satellite.PointingInfo; + +/** + * Interface for position update and datagram transfer state change callback. + * @hide + */ +oneway interface ISatelliteTransmissionUpdateCallback { + /** + * Called when satellite datagram send state changed. + * + * @param state The new send datagram transfer state. + * @param sendPendingCount The number of datagrams that are currently being sent. + * @param errorCode If datagram transfer failed, the reason for failure. + */ + void onSendDatagramStateChanged(in int state, in int sendPendingCount, in int errorCode); + + /** + * Called when satellite datagram receive state changed. + * + * @param state The new receive datagram transfer state. + * @param receivePendingCount The number of datagrams that are currently pending to be received. + * @param errorCode If datagram transfer failed, the reason for failure. + */ + void onReceiveDatagramStateChanged(in int state, in int receivePendingCount, in int errorCode); + + /** + * Called when the satellite position changed. + * + * @param pointingInfo The pointing info containing the satellite location. + */ + void onSatellitePositionChanged(in PointingInfo pointingInfo); +} diff --git a/telephony/java/android/telephony/satellite/PointingInfo.aidl b/telephony/java/android/telephony/satellite/PointingInfo.aidl new file mode 100644 index 000000000000..7ff95cdeee85 --- /dev/null +++ b/telephony/java/android/telephony/satellite/PointingInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2023, 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 android.telephony.satellite; + +parcelable PointingInfo; diff --git a/telephony/java/android/telephony/satellite/PointingInfo.java b/telephony/java/android/telephony/satellite/PointingInfo.java new file mode 100644 index 000000000000..a559b32f0021 --- /dev/null +++ b/telephony/java/android/telephony/satellite/PointingInfo.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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 android.telephony.satellite; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public final class PointingInfo implements Parcelable { + /** Satellite azimuth in degrees */ + private float mSatelliteAzimuthDegrees; + + /** Satellite elevation in degrees */ + private float mSatelliteElevationDegrees; + + /** + * @hide + */ + + public PointingInfo(float satelliteAzimuthDegrees, float satelliteElevationDegrees) { + mSatelliteAzimuthDegrees = satelliteAzimuthDegrees; + mSatelliteElevationDegrees = satelliteElevationDegrees; + } + + private PointingInfo(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeFloat(mSatelliteAzimuthDegrees); + out.writeFloat(mSatelliteElevationDegrees); + } + + public static final @android.annotation.NonNull Creator<PointingInfo> CREATOR = + new Creator<PointingInfo>() { + @Override + public PointingInfo createFromParcel(Parcel in) { + return new PointingInfo(in); + } + + @Override + public PointingInfo[] newArray(int size) { + return new PointingInfo[size]; + } + }; + + @NonNull + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("SatelliteAzimuthDegrees:"); + sb.append(mSatelliteAzimuthDegrees); + sb.append(","); + + sb.append("SatelliteElevationDegrees:"); + sb.append(mSatelliteElevationDegrees); + return sb.toString(); + } + + public float getSatelliteAzimuthDegrees() { + return mSatelliteAzimuthDegrees; + } + + public float getSatelliteElevationDegrees() { + return mSatelliteElevationDegrees; + } + + private void readFromParcel(Parcel in) { + mSatelliteAzimuthDegrees = in.readFloat(); + mSatelliteElevationDegrees = in.readFloat(); + } +} diff --git a/telephony/java/android/telephony/satellite/SatelliteCapabilities.aidl b/telephony/java/android/telephony/satellite/SatelliteCapabilities.aidl new file mode 100644 index 000000000000..a09306b07208 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteCapabilities.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2023, 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 android.telephony.satellite; + +parcelable SatelliteCapabilities; diff --git a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java new file mode 100644 index 000000000000..6856cc0c5df2 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2022 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 android.telephony.satellite; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * @hide + */ +public final class SatelliteCapabilities implements Parcelable { + /** + * List of technologies supported by the satellite modem. + */ + @NonNull @SatelliteManager.NTRadioTechnology private Set<Integer> mSupportedRadioTechnologies; + + /** + * Whether UE needs to point to a satellite to send and receive data. + */ + private boolean mIsPointingRequired; + + /** + * The maximum number of bytes per datagram that can be sent over satellite. + */ + private int mMaxBytesPerOutgoingDatagram; + + /** + * Antenna Position received from satellite modem which gives information about antenna + * direction to be used with satellite communication and suggested device hold positions. + * Map key: {@link SatelliteManager.DeviceHoldPosition} value: AntennaPosition + */ + @NonNull + private Map<Integer, AntennaPosition> mAntennaPositionMap; + + /** + * @hide + */ + public SatelliteCapabilities(Set<Integer> supportedRadioTechnologies, + boolean isPointingRequired, int maxBytesPerOutgoingDatagram, + @NonNull Map<Integer, AntennaPosition> antennaPositionMap) { + mSupportedRadioTechnologies = supportedRadioTechnologies == null + ? new HashSet<>() : supportedRadioTechnologies; + mIsPointingRequired = isPointingRequired; + mMaxBytesPerOutgoingDatagram = maxBytesPerOutgoingDatagram; + mAntennaPositionMap = antennaPositionMap; + } + + private SatelliteCapabilities(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + if (mSupportedRadioTechnologies != null && !mSupportedRadioTechnologies.isEmpty()) { + out.writeInt(mSupportedRadioTechnologies.size()); + for (int technology : mSupportedRadioTechnologies) { + out.writeInt(technology); + } + } else { + out.writeInt(0); + } + + out.writeBoolean(mIsPointingRequired); + out.writeInt(mMaxBytesPerOutgoingDatagram); + + if (mAntennaPositionMap != null && !mAntennaPositionMap.isEmpty()) { + int size = mAntennaPositionMap.size(); + out.writeInt(size); + for (Map.Entry<Integer, AntennaPosition> entry : mAntennaPositionMap.entrySet()) { + out.writeInt(entry.getKey()); + out.writeParcelable(entry.getValue(), flags); + } + } else { + out.writeInt(0); + } + } + + @NonNull public static final Creator<SatelliteCapabilities> CREATOR = new Creator<>() { + @Override + public SatelliteCapabilities createFromParcel(Parcel in) { + return new SatelliteCapabilities(in); + } + + @Override + public SatelliteCapabilities[] newArray(int size) { + return new SatelliteCapabilities[size]; + } + }; + + @Override + @NonNull public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("SupportedRadioTechnology:"); + if (mSupportedRadioTechnologies != null && !mSupportedRadioTechnologies.isEmpty()) { + for (int technology : mSupportedRadioTechnologies) { + sb.append(technology); + sb.append(","); + } + } else { + sb.append("none,"); + } + + sb.append("isPointingRequired:"); + sb.append(mIsPointingRequired); + sb.append(","); + + sb.append("maxBytesPerOutgoingDatagram:"); + sb.append(mMaxBytesPerOutgoingDatagram); + sb.append(","); + + sb.append("antennaPositionMap:"); + sb.append(mAntennaPositionMap); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SatelliteCapabilities that = (SatelliteCapabilities) o; + return Objects.equals(mSupportedRadioTechnologies, that.mSupportedRadioTechnologies) + && mIsPointingRequired == that.mIsPointingRequired + && mMaxBytesPerOutgoingDatagram == that.mMaxBytesPerOutgoingDatagram + && Objects.equals(mAntennaPositionMap, that.mAntennaPositionMap); + } + + @Override + public int hashCode() { + return Objects.hash(mSupportedRadioTechnologies, mIsPointingRequired, + mMaxBytesPerOutgoingDatagram, mAntennaPositionMap); + } + + /** + * @return The list of technologies supported by the satellite modem. + */ + @NonNull @SatelliteManager.NTRadioTechnology public Set<Integer> + getSupportedRadioTechnologies() { + return mSupportedRadioTechnologies; + } + + /** + * Get whether UE needs to point to a satellite to send and receive data. + * + * @return {@code true} if UE needs to point to a satellite to send and receive data and + * {@code false} otherwise. + */ + public boolean isPointingRequired() { + return mIsPointingRequired; + } + + /** + * The maximum number of bytes per datagram that can be sent over satellite. + * + * @return The maximum number of bytes per datagram that can be sent over satellite. + */ + public int getMaxBytesPerOutgoingDatagram() { + return mMaxBytesPerOutgoingDatagram; + } + + /** + * Antenna Position received from satellite modem which gives information about antenna + * direction to be used with satellite communication and suggested device hold positions. + * @return Map key: {@link SatelliteManager.DeviceHoldPosition} value: AntennaPosition + */ + @NonNull + public Map<Integer, AntennaPosition> getAntennaPositionMap() { + return mAntennaPositionMap; + } + + private void readFromParcel(Parcel in) { + mSupportedRadioTechnologies = new HashSet<>(); + int numSupportedRadioTechnologies = in.readInt(); + if (numSupportedRadioTechnologies > 0) { + for (int i = 0; i < numSupportedRadioTechnologies; i++) { + mSupportedRadioTechnologies.add(in.readInt()); + } + } + + mIsPointingRequired = in.readBoolean(); + mMaxBytesPerOutgoingDatagram = in.readInt(); + + mAntennaPositionMap = new HashMap<>(); + int antennaPositionMapSize = in.readInt(); + for (int i = 0; i < antennaPositionMapSize; i++) { + int key = in.readInt(); + AntennaPosition antennaPosition = in.readParcelable( + AntennaPosition.class.getClassLoader(), AntennaPosition.class); + mAntennaPositionMap.put(key, antennaPosition); + } + } +} diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagram.aidl b/telephony/java/android/telephony/satellite/SatelliteDatagram.aidl new file mode 100644 index 000000000000..993aacf80bd1 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteDatagram.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2023, 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 android.telephony.satellite; + +parcelable SatelliteDatagram; diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagram.java b/telephony/java/android/telephony/satellite/SatelliteDatagram.java new file mode 100644 index 000000000000..d3cb8a07e4ba --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteDatagram.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public final class SatelliteDatagram implements Parcelable { + /** + * Datagram to be sent or received over satellite. + */ + @NonNull private byte[] mData; + + /** + * @hide + */ + public SatelliteDatagram(@NonNull byte[] data) { + mData = data; + } + + private SatelliteDatagram(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeByteArray(mData); + } + + @NonNull public static final Creator<SatelliteDatagram> CREATOR = + new Creator<>() { + @Override + public SatelliteDatagram createFromParcel(Parcel in) { + return new SatelliteDatagram(in); + } + + @Override + public SatelliteDatagram[] newArray(int size) { + return new SatelliteDatagram[size]; + } + }; + + @NonNull public byte[] getSatelliteDatagram() { + return mData; + } + + private void readFromParcel(Parcel in) { + mData = in.createByteArray(); + } +} diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java new file mode 100644 index 000000000000..b2dec71ecb32 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +import android.annotation.NonNull; + +import java.util.function.Consumer; + +/** + * A callback class for listening to satellite datagrams. + * + * @hide + */ +public interface SatelliteDatagramCallback { + /** + * Called when there is an incoming datagram to be received. + * + * @param datagramId An id that uniquely identifies incoming datagram. + * @param datagram Datagram to be received over satellite. + * @param pendingCount Number of datagrams yet to be received by the app. + * @param callback This callback will be used by datagram receiver app to inform Telephony + * that they received the datagram. If the callback is not received within + * five minutes, Telephony will resend the datagram. + */ + void onSatelliteDatagramReceived(long datagramId, @NonNull SatelliteDatagram datagram, + int pendingCount, @NonNull Consumer<Void> callback); +} diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java new file mode 100644 index 000000000000..2021ac7c4cd5 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -0,0 +1,1561 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +import android.Manifest; +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresFeature; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.ICancellationSignal; +import android.os.OutcomeReceiver; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyFrameworkInitializer; + +import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.IVoidConsumer; +import com.android.telephony.Rlog; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.time.Duration; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * Manages satellite operations such as provisioning, pointing, messaging, location sharing, etc. + * To get the object, call {@link Context#getSystemService(String)}. + * + * @hide + */ +@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SATELLITE) +public class SatelliteManager { + private static final String TAG = "SatelliteManager"; + + private static final ConcurrentHashMap<SatelliteDatagramCallback, ISatelliteDatagramCallback> + sSatelliteDatagramCallbackMap = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap<SatelliteProvisionStateCallback, + ISatelliteProvisionStateCallback> sSatelliteProvisionStateCallbackMap = + new ConcurrentHashMap<>(); + private static final ConcurrentHashMap<SatelliteStateCallback, ISatelliteStateCallback> + sSatelliteStateCallbackMap = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap<SatelliteTransmissionUpdateCallback, + ISatelliteTransmissionUpdateCallback> sSatelliteTransmissionUpdateCallbackMap = + new ConcurrentHashMap<>(); + + private final int mSubId; + + /** + * Context this SatelliteManager is for. + */ + @Nullable private final Context mContext; + + /** + * Create an instance of the SatelliteManager. + * + * @param context The context the SatelliteManager belongs to. + * @hide + */ + + public SatelliteManager(@Nullable Context context) { + this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); + } + + /** + * Create an instance of the SatelliteManager associated with a particular subscription. + * + * @param context The context the SatelliteManager belongs to. + * @param subId The subscription ID associated with the SatelliteManager. + */ + private SatelliteManager(@Nullable Context context, int subId) { + mContext = context; + mSubId = subId; + } + + /** + * Exception from the satellite service containing the {@link SatelliteError} error code. + */ + public static class SatelliteException extends Exception { + @SatelliteError private final int mErrorCode; + + /** + * Create a SatelliteException with a given error code. + * + * @param errorCode The {@link SatelliteError}. + */ + public SatelliteException(@SatelliteError int errorCode) { + mErrorCode = errorCode; + } + + /** + * Get the error code returned from the satellite service. + * + * @return The {@link SatelliteError}. + */ + @SatelliteError public int getErrorCode() { + return mErrorCode; + } + } + + /** + * Bundle key to get the response from + * {@link #requestIsSatelliteEnabled(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_SATELLITE_ENABLED = "satellite_enabled"; + + /** + * Bundle key to get the response from + * {@link #requestIsDemoModeEnabled(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_DEMO_MODE_ENABLED = "demo_mode_enabled"; + + /** + * Bundle key to get the response from + * {@link #requestIsSatelliteSupported(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_SATELLITE_SUPPORTED = "satellite_supported"; + + /** + * Bundle key to get the response from + * {@link #requestSatelliteCapabilities(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_SATELLITE_CAPABILITIES = "satellite_capabilities"; + + /** + * Bundle key to get the response from + * {@link #requestIsSatelliteProvisioned(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned"; + + /** + * Bundle key to get the response from + * {@link #requestIsSatelliteCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_SATELLITE_COMMUNICATION_ALLOWED = + "satellite_communication_allowed"; + + /** + * Bundle key to get the response from + * {@link #requestTimeForNextSatelliteVisibility(Executor, OutcomeReceiver)}. + * @hide + */ + + public static final String KEY_SATELLITE_NEXT_VISIBILITY = "satellite_next_visibility"; + + /** + * The request was successfully processed. + */ + public static final int SATELLITE_ERROR_NONE = 0; + /** + * A generic error which should be used only when other specific errors cannot be used. + */ + public static final int SATELLITE_ERROR = 1; + /** + * Error received from the satellite server. + */ + public static final int SATELLITE_SERVER_ERROR = 2; + /** + * Error received from the vendor service. This generic error code should be used + * only when the error cannot be mapped to other specific service error codes. + */ + public static final int SATELLITE_SERVICE_ERROR = 3; + /** + * Error received from satellite modem. This generic error code should be used only when + * the error cannot be mapped to other specific modem error codes. + */ + public static final int SATELLITE_MODEM_ERROR = 4; + /** + * Error received from the satellite network. This generic error code should be used only when + * the error cannot be mapped to other specific network error codes. + */ + public static final int SATELLITE_NETWORK_ERROR = 5; + /** + * Telephony is not in a valid state to receive requests from clients. + */ + public static final int SATELLITE_INVALID_TELEPHONY_STATE = 6; + /** + * Satellite modem is not in a valid state to receive requests from clients. + */ + public static final int SATELLITE_INVALID_MODEM_STATE = 7; + /** + * Either vendor service, or modem, or Telephony framework has received a request with + * invalid arguments from its clients. + */ + public static final int SATELLITE_INVALID_ARGUMENTS = 8; + /** + * Telephony framework failed to send a request or receive a response from the vendor service + * or satellite modem due to internal error. + */ + public static final int SATELLITE_REQUEST_FAILED = 9; + /** + * Radio did not start or is resetting. + */ + public static final int SATELLITE_RADIO_NOT_AVAILABLE = 10; + /** + * The request is not supported by either the satellite modem or the network. + */ + public static final int SATELLITE_REQUEST_NOT_SUPPORTED = 11; + /** + * Satellite modem or network has no resources available to handle requests from clients. + */ + public static final int SATELLITE_NO_RESOURCES = 12; + /** + * Satellite service is not provisioned yet. + */ + public static final int SATELLITE_SERVICE_NOT_PROVISIONED = 13; + /** + * Satellite service provision is already in progress. + */ + public static final int SATELLITE_SERVICE_PROVISION_IN_PROGRESS = 14; + /** + * The ongoing request was aborted by either the satellite modem or the network. + * This error is also returned when framework decides to abort current send request as one + * of the previous send request failed. + */ + public static final int SATELLITE_REQUEST_ABORTED = 15; + /** + * The device/subscriber is barred from accessing the satellite service. + */ + public static final int SATELLITE_ACCESS_BARRED = 16; + /** + * Satellite modem timeout to receive ACK or response from the satellite network after + * sending a request to the network. + */ + public static final int SATELLITE_NETWORK_TIMEOUT = 17; + /** + * Satellite network is not reachable from the modem. + */ + public static final int SATELLITE_NOT_REACHABLE = 18; + /** + * The device/subscriber is not authorized to register with the satellite service provider. + */ + public static final int SATELLITE_NOT_AUTHORIZED = 19; + /** + * The device does not support satellite. + */ + public static final int SATELLITE_NOT_SUPPORTED = 20; + + /** + * The current request is already in-progress. + */ + public static final int SATELLITE_REQUEST_IN_PROGRESS = 21; + + /** + * Satellite modem is currently busy due to which current request cannot be processed. + */ + public static final int SATELLITE_MODEM_BUSY = 22; + + /** @hide */ + @IntDef(prefix = {"SATELLITE_"}, value = { + SATELLITE_ERROR_NONE, + SATELLITE_ERROR, + SATELLITE_SERVER_ERROR, + SATELLITE_SERVICE_ERROR, + SATELLITE_MODEM_ERROR, + SATELLITE_NETWORK_ERROR, + SATELLITE_INVALID_TELEPHONY_STATE, + SATELLITE_INVALID_MODEM_STATE, + SATELLITE_INVALID_ARGUMENTS, + SATELLITE_REQUEST_FAILED, + SATELLITE_RADIO_NOT_AVAILABLE, + SATELLITE_REQUEST_NOT_SUPPORTED, + SATELLITE_NO_RESOURCES, + SATELLITE_SERVICE_NOT_PROVISIONED, + SATELLITE_SERVICE_PROVISION_IN_PROGRESS, + SATELLITE_REQUEST_ABORTED, + SATELLITE_ACCESS_BARRED, + SATELLITE_NETWORK_TIMEOUT, + SATELLITE_NOT_REACHABLE, + SATELLITE_NOT_AUTHORIZED, + SATELLITE_NOT_SUPPORTED, + SATELLITE_REQUEST_IN_PROGRESS, + SATELLITE_MODEM_BUSY + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SatelliteError {} + + /** + * Unknown Non-Terrestrial radio technology. This generic radio technology should be used + * only when the radio technology cannot be mapped to other specific radio technologies. + */ + public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; + /** + * 3GPP NB-IoT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology. + */ + public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1; + /** + * 3GPP 5G NR over Non-Terrestrial-Networks technology. + */ + public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2; + /** + * 3GPP eMTC (enhanced Machine-Type Communication) over Non-Terrestrial-Networks technology. + */ + public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3; + /** + * Proprietary technology. + */ + public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4; + + /** @hide */ + @IntDef(prefix = "NT_RADIO_TECHNOLOGY_", value = { + NT_RADIO_TECHNOLOGY_UNKNOWN, + NT_RADIO_TECHNOLOGY_NB_IOT_NTN, + NT_RADIO_TECHNOLOGY_NR_NTN, + NT_RADIO_TECHNOLOGY_EMTC_NTN, + NT_RADIO_TECHNOLOGY_PROPRIETARY + }) + @Retention(RetentionPolicy.SOURCE) + public @interface NTRadioTechnology {} + + /** Suggested device hold position is unknown. */ + public static final int DEVICE_HOLD_POSITION_UNKNOWN = 0; + /** User is suggested to hold the device in portrait mode. */ + public static final int DEVICE_HOLD_POSITION_PORTRAIT = 1; + /** User is suggested to hold the device in landscape mode with left hand. */ + public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2; + /** User is suggested to hold the device in landscape mode with right hand. */ + public static final int DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT = 3; + + /** @hide */ + @IntDef(prefix = {"DEVICE_HOLD_POSITION_"}, value = { + DEVICE_HOLD_POSITION_UNKNOWN, + DEVICE_HOLD_POSITION_PORTRAIT, + DEVICE_HOLD_POSITION_LANDSCAPE_LEFT, + DEVICE_HOLD_POSITION_LANDSCAPE_RIGHT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DeviceHoldPosition {} + + /** Display mode is unknown. */ + public static final int DISPLAY_MODE_UNKNOWN = 0; + /** Display mode of the device used for satellite communication for non-foldable phones. */ + public static final int DISPLAY_MODE_FIXED = 1; + /** Display mode of the device used for satellite communication for foldabale phones when the + * device is opened. */ + public static final int DISPLAY_MODE_OPENED = 2; + /** Display mode of the device used for satellite communication for foldabable phones when the + * device is closed. */ + public static final int DISPLAY_MODE_CLOSED = 3; + + /** @hide */ + @IntDef(prefix = {"ANTENNA_POSITION_"}, value = { + DISPLAY_MODE_UNKNOWN, + DISPLAY_MODE_FIXED, + DISPLAY_MODE_OPENED, + DISPLAY_MODE_CLOSED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisplayMode {} + + /** + * Request to enable or disable the satellite modem and demo mode. If the satellite modem is + * enabled, this may also disable the cellular modem, and if the satellite modem is disabled, + * this may also re-enable the cellular modem. + * + * @param enableSatellite {@code true} to enable the satellite modem and + * {@code false} to disable. + * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable. + * @param executor The executor on which the error code listener will be called. + * @param resultListener Listener for the {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, + @NonNull @CallbackExecutor Executor executor, + @SatelliteError @NonNull Consumer<Integer> resultListener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + telephony.requestSatelliteEnabled(mSubId, enableSatellite, enableDemoMode, + errorCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "requestSatelliteEnabled() RemoteException: ", ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Request to get whether the satellite modem is enabled. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return a {@code boolean} with value {@code true} if the satellite modem + * is enabled and {@code false} otherwise. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteError}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void requestIsSatelliteEnabled(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_ENABLED)) { + boolean isSatelliteEnabled = + resultData.getBoolean(KEY_SATELLITE_ENABLED); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(isSatelliteEnabled))); + } else { + loge("KEY_SATELLITE_ENABLED does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError( + new SatelliteException(SATELLITE_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestIsSatelliteEnabled(mSubId, receiver); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("requestIsSatelliteEnabled() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Request to get whether the satellite service demo mode is enabled. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return a {@code boolean} with value {@code true} if demo mode is enabled + * and {@code false} otherwise. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteError}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void requestIsDemoModeEnabled(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) { + boolean isDemoModeEnabled = + resultData.getBoolean(KEY_DEMO_MODE_ENABLED); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(isDemoModeEnabled))); + } else { + loge("KEY_DEMO_MODE_ENABLED does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError( + new SatelliteException(SATELLITE_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestIsDemoModeEnabled(mSubId, receiver); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("requestIsDemoModeEnabled() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Request to get whether the satellite service is supported on the device. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return a {@code boolean} with value {@code true} if the satellite + * service is supported on the device and {@code false} otherwise. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteError}. + * + * @throws IllegalStateException if the Telephony process is not currently available. + */ + + public void requestIsSatelliteSupported(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) { + boolean isSatelliteSupported = + resultData.getBoolean(KEY_SATELLITE_SUPPORTED); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(isSatelliteSupported))); + } else { + loge("KEY_SATELLITE_SUPPORTED does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError( + new SatelliteException(SATELLITE_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestIsSatelliteSupported(mSubId, receiver); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("requestIsSatelliteSupported() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Request to get the {@link SatelliteCapabilities} of the satellite service. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return the {@link SatelliteCapabilities} of the satellite service. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteError}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void requestSatelliteCapabilities(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) { + SatelliteCapabilities capabilities = + resultData.getParcelable(KEY_SATELLITE_CAPABILITIES, + SatelliteCapabilities.class); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(capabilities))); + } else { + loge("KEY_SATELLITE_CAPABILITIES does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError( + new SatelliteException(SATELLITE_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestSatelliteCapabilities(mSubId, receiver); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("requestSatelliteCapabilities() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * The default state indicating that datagram transfer is idle. + * This should be sent if there are no message transfer activity happening. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; + /** + * A transition state indicating that a datagram is being sent. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING = 1; + /** + * An end state indicating that datagram sending completed successfully. + * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE} + * will be sent if no more messages are pending. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2; + /** + * An end state indicating that datagram sending completed with a failure. + * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE} + * must be sent before reporting any additional datagram transfer state changes. All pending + * messages will be reported as failed, to the corresponding applications. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3; + /** + * A transition state indicating that a datagram is being received. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING = 4; + /** + * An end state indicating that datagram receiving completed successfully. + * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE} + * will be sent if no more messages are pending. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS = 5; + /** + * An end state indicating that datagram receive operation found that there are no + * messages to be retrieved from the satellite. + * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE} + * will be sent if no more messages are pending. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; + /** + * An end state indicating that datagram receive completed with a failure. + * After datagram transfer completes, {@link #SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE} + * will be sent if no more messages are pending. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; + /** + * The datagram transfer state is unknown. This generic datagram transfer state should be used + * only when the datagram transfer state cannot be mapped to other specific datagram transfer + * states. + */ + public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1; + + /** @hide */ + @IntDef(prefix = {"SATELLITE_DATAGRAM_TRANSFER_STATE_"}, value = { + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, + SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, + SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SatelliteDatagramTransferState {} + // TODO: Split into two enums for sending and receiving states + + /** + * Satellite modem is in idle state. + */ + public static final int SATELLITE_MODEM_STATE_IDLE = 0; + /** + * Satellite modem is listening for incoming datagrams. + */ + public static final int SATELLITE_MODEM_STATE_LISTENING = 1; + /** + * Satellite modem is sending and/or receiving datagrams. + */ + public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; + /** + * Satellite modem is retrying to send and/or receive datagrams. + */ + public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; + /** + * Satellite modem is powered off. + */ + public static final int SATELLITE_MODEM_STATE_OFF = 4; + /** + * Satellite modem is unavailable. + */ + public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5; + /** + * Satellite modem state is unknown. This generic modem state should be used only when the + * modem state cannot be mapped to other specific modem states. + */ + public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1; + + /** @hide */ + @IntDef(prefix = {"SATELLITE_MODEM_STATE_"}, value = { + SATELLITE_MODEM_STATE_IDLE, + SATELLITE_MODEM_STATE_LISTENING, + SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING, + SATELLITE_MODEM_STATE_DATAGRAM_RETRYING, + SATELLITE_MODEM_STATE_OFF, + SATELLITE_MODEM_STATE_UNAVAILABLE, + SATELLITE_MODEM_STATE_UNKNOWN + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SatelliteModemState {} + + /** + * Datagram type is unknown. This generic datagram type should be used only when the + * datagram type cannot be mapped to other specific datagram types. + */ + public static final int DATAGRAM_TYPE_UNKNOWN = 0; + /** + * Datagram type indicating that the datagram to be sent or received is of type SOS message. + */ + public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; + /** + * Datagram type indicating that the datagram to be sent or received is of type + * location sharing. + */ + public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; + + /** @hide */ + @IntDef(prefix = "DATAGRAM_TYPE_", value = { + DATAGRAM_TYPE_UNKNOWN, + DATAGRAM_TYPE_SOS_MESSAGE, + DATAGRAM_TYPE_LOCATION_SHARING + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DatagramType {} + + /** + * Start receiving satellite transmission updates. + * This can be called by the pointing UI when the user starts pointing to the satellite. + * Modem should continue to report the pointing input as the device or satellite moves. + * Satellite transmission updates are started only on {@link #SATELLITE_ERROR_NONE}. + * All other results indicate that this operation failed. + * Once satellite transmission updates begin, position and datagram transfer state updates + * will be sent through {@link SatelliteTransmissionUpdateCallback}. + * + * @param executor The executor on which the callback and error code listener will be called. + * @param resultListener Listener for the {@link SatelliteError} result of the operation. + * @param callback The callback to notify of satellite transmission updates. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor, + @SatelliteError @NonNull Consumer<Integer> resultListener, + @NonNull SatelliteTransmissionUpdateCallback callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + ISatelliteTransmissionUpdateCallback internalCallback = + new ISatelliteTransmissionUpdateCallback.Stub() { + + @Override + public void onSatellitePositionChanged(PointingInfo pointingInfo) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> callback.onSatellitePositionChanged(pointingInfo))); + } + + @Override + public void onSendDatagramStateChanged(int state, int sendPendingCount, + int errorCode) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> callback.onSendDatagramStateChanged( + state, sendPendingCount, errorCode))); + } + + @Override + public void onReceiveDatagramStateChanged(int state, + int receivePendingCount, int errorCode) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> callback.onReceiveDatagramStateChanged( + state, receivePendingCount, errorCode))); + } + }; + sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback); + telephony.startSatelliteTransmissionUpdates(mSubId, errorCallback, + internalCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("startSatelliteTransmissionUpdates() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Stop receiving satellite transmission updates. + * This can be called by the pointing UI when the user stops pointing to the satellite. + * Satellite transmission updates are stopped and the callback is unregistered only on + * {@link #SATELLITE_ERROR_NONE}. All other results that this operation failed. + * + * @param callback The callback that was passed to {@link + * #startSatelliteTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}. + * @param executor The executor on which the error code listener will be called. + * @param resultListener Listener for the {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void stopSatelliteTransmissionUpdates( + @NonNull SatelliteTransmissionUpdateCallback callback, + @NonNull @CallbackExecutor Executor executor, + @SatelliteError @NonNull Consumer<Integer> resultListener) { + Objects.requireNonNull(callback); + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + ISatelliteTransmissionUpdateCallback internalCallback = + sSatelliteTransmissionUpdateCallbackMap.remove(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + if (internalCallback != null) { + IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + telephony.stopSatelliteTransmissionUpdates(mSubId, errorCallback, + internalCallback); + // TODO: Notify SmsHandler that pointing UI stopped + } else { + loge("stopSatelliteTransmissionUpdates: No internal callback."); + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(SATELLITE_INVALID_ARGUMENTS))); + } + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("stopSatelliteTransmissionUpdates() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Provision the device with a satellite provider. + * This is needed if the provider allows dynamic registration. + * + * @param token The token to be used as a unique identifier for provisioning with satellite + * gateway. + * @param provisionData Data from the provisioning app that can be used by provisioning server + * @param cancellationSignal The optional signal used by the caller to cancel the provision + * request. Even when the cancellation is signaled, Telephony will + * still trigger the callback to return the result of this request. + * @param executor The executor on which the error code listener will be called. + * @param resultListener Listener for the {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData, + @Nullable CancellationSignal cancellationSignal, + @NonNull @CallbackExecutor Executor executor, + @SatelliteError @NonNull Consumer<Integer> resultListener) { + Objects.requireNonNull(token); + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + Objects.requireNonNull(provisionData); + + ICancellationSignal cancelRemote = null; + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + cancelRemote = telephony.provisionSatelliteService(mSubId, token, provisionData, + errorCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("provisionSatelliteService() RemoteException=" + ex); + ex.rethrowFromSystemServer(); + } + if (cancellationSignal != null) { + cancellationSignal.setRemote(cancelRemote); + } + } + + /** + * Deprovision the device with the satellite provider. + * This is needed if the provider allows dynamic registration. Once deprovisioned, + * {@link SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean)} + * should report as deprovisioned. + * For provisioning satellite service, refer to + * {@link #provisionSatelliteService(String, String, CancellationSignal, Executor, Consumer)} + * + * @param token The token of the device/subscription to be deprovisioned. + * @param resultListener Listener for the {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void deprovisionSatelliteService(@NonNull String token, + @NonNull @CallbackExecutor Executor executor, + @SatelliteError @NonNull Consumer<Integer> resultListener) { + Objects.requireNonNull(token); + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + telephony.deprovisionSatelliteService(mSubId, token, errorCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("deprovisionSatelliteService() RemoteException=" + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Registers for the satellite provision state changed. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback to handle the satellite provision state changed event. + * + * @return The {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + @SatelliteError public int registerForSatelliteProvisionStateChanged( + @NonNull @CallbackExecutor Executor executor, + @NonNull SatelliteProvisionStateCallback callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ISatelliteProvisionStateCallback internalCallback = + new ISatelliteProvisionStateCallback.Stub() { + @Override + public void onSatelliteProvisionStateChanged(boolean provisioned) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> callback.onSatelliteProvisionStateChanged( + provisioned))); + } + }; + sSatelliteProvisionStateCallbackMap.put(callback, internalCallback); + return telephony.registerForSatelliteProvisionStateChanged( + mSubId, internalCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("registerForSatelliteProvisionStateChanged() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + return SATELLITE_REQUEST_FAILED; + } + + /** + * Unregisters for the satellite provision state changed. + * If callback was not registered before, the request will be ignored. + * + * @param callback The callback that was passed to + * {@link #registerForSatelliteProvisionStateChanged(Executor, SatelliteProvisionStateCallback)} + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void unregisterForSatelliteProvisionStateChanged( + @NonNull SatelliteProvisionStateCallback callback) { + Objects.requireNonNull(callback); + ISatelliteProvisionStateCallback internalCallback = + sSatelliteProvisionStateCallbackMap.remove(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + if (internalCallback != null) { + telephony.unregisterForSatelliteProvisionStateChanged(mSubId, internalCallback); + } else { + loge("unregisterForSatelliteProvisionStateChanged: No internal callback."); + } + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("unregisterForSatelliteProvisionStateChanged() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Request to get whether this device is provisioned with a satellite provider. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return a {@code boolean} with value {@code true} if the device is + * provisioned with a satellite provider and {@code false} otherwise. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteError}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void requestIsSatelliteProvisioned(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) { + boolean isSatelliteProvisioned = + resultData.getBoolean(KEY_SATELLITE_PROVISIONED); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(isSatelliteProvisioned))); + } else { + loge("KEY_SATELLITE_PROVISIONED does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError( + new SatelliteException(SATELLITE_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestIsSatelliteProvisioned(mSubId, receiver); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("requestIsSatelliteProvisioned() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Registers for modem state changed from satellite modem. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback to handle the satellite modem state changed event. + * + * @return The {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + @SatelliteError public int registerForSatelliteModemStateChanged( + @NonNull @CallbackExecutor Executor executor, + @NonNull SatelliteStateCallback callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ISatelliteStateCallback internalCallback = new ISatelliteStateCallback.Stub() { + @Override + public void onSatelliteModemStateChanged(int state) { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onSatelliteModemStateChanged(state))); + } + }; + sSatelliteStateCallbackMap.put(callback, internalCallback); + return telephony.registerForSatelliteModemStateChanged(mSubId, internalCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("registerForSatelliteModemStateChanged() RemoteException:" + ex); + ex.rethrowFromSystemServer(); + } + return SATELLITE_REQUEST_FAILED; + } + + /** + * Unregisters for modem state changed from satellite modem. + * If callback was not registered before, the request will be ignored. + * + * @param callback The callback that was passed to + * {@link #registerForSatelliteModemStateChanged(Executor, SatelliteStateCallback)}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void unregisterForSatelliteModemStateChanged(@NonNull SatelliteStateCallback callback) { + Objects.requireNonNull(callback); + ISatelliteStateCallback internalCallback = sSatelliteStateCallbackMap.remove(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + if (internalCallback != null) { + telephony.unregisterForSatelliteModemStateChanged(mSubId, internalCallback); + } else { + loge("unregisterForSatelliteModemStateChanged: No internal callback."); + } + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("unregisterForSatelliteModemStateChanged() RemoteException:" + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Register to receive incoming datagrams over satellite. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback to handle incoming datagrams over satellite. + * This callback with be invoked when a new datagram is received from satellite. + * + * @return The {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + @SatelliteError public int registerForSatelliteDatagram( + @NonNull @CallbackExecutor Executor executor, + @NonNull SatelliteDatagramCallback callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ISatelliteDatagramCallback internalCallback = + new ISatelliteDatagramCallback.Stub() { + @Override + public void onSatelliteDatagramReceived(long datagramId, + @NonNull SatelliteDatagram datagram, int pendingCount, + @NonNull IVoidConsumer internalAck) { + Consumer<Void> externalAck = new Consumer<Void>() { + @Override + public void accept(Void result) { + try { + internalAck.accept(); + } catch (RemoteException e) { + logd("onSatelliteDatagramReceived " + + "RemoteException: " + e); + } + } + }; + + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> callback.onSatelliteDatagramReceived( + datagramId, datagram, pendingCount, externalAck))); + } + }; + sSatelliteDatagramCallbackMap.put(callback, internalCallback); + return telephony.registerForSatelliteDatagram(mSubId, internalCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("registerForSatelliteDatagram() RemoteException:" + ex); + ex.rethrowFromSystemServer(); + } + return SATELLITE_REQUEST_FAILED; + } + + /** + * Unregister to stop receiving incoming datagrams over satellite. + * If callback was not registered before, the request will be ignored. + * + * @param callback The callback that was passed to + * {@link #registerForSatelliteDatagram(Executor, SatelliteDatagramCallback)}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void unregisterForSatelliteDatagram(@NonNull SatelliteDatagramCallback callback) { + Objects.requireNonNull(callback); + ISatelliteDatagramCallback internalCallback = + sSatelliteDatagramCallbackMap.remove(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + if (internalCallback != null) { + telephony.unregisterForSatelliteDatagram(mSubId, internalCallback); + } else { + loge("unregisterForSatelliteDatagram: No internal callback."); + } + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("unregisterForSatelliteDatagram() RemoteException:" + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Poll pending satellite datagrams over satellite. + * + * This method requests modem to check if there are any pending datagrams to be received over + * satellite. If there are any incoming datagrams, they will be received via + * {@link SatelliteDatagramCallback#onSatelliteDatagramReceived(long, SatelliteDatagram, int, + * Consumer)} )} + * + * @param executor The executor on which the result listener will be called. + * @param resultListener Listener for the {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor, + @SatelliteError @NonNull Consumer<Integer> resultListener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + telephony.pollPendingSatelliteDatagrams(mSubId, internalCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("pollPendingSatelliteDatagrams() RemoteException:" + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Send datagram over satellite. + * + * Gateway encodes SOS message or location sharing message into a datagram and passes it as + * input to this method. Datagram received here will be passed down to modem without any + * encoding or encryption. + * + * @param datagramType datagram type indicating whether the datagram is of type + * SOS_SMS or LOCATION_SHARING. + * @param datagram encoded gateway datagram which is encrypted by the caller. + * Datagram will be passed down to modem without any encoding or encryption. + * @param needFullScreenPointingUI If set to true, this indicates pointingUI app to open in full + * screen mode if satellite communication needs pointingUI. + * If this is set to false, pointingUI may be presented to the + * user in collapsed view. Application may decide to mark this + * flag as true when the user is sending data for the first time + * or whenever there is a considerable idle time between + * satellite activity. This decision should be done based upon + * user activity and the application's ability to determine the + * best possible UX experience for the user. + * @param executor The executor on which the result listener will be called. + * @param resultListener Listener for the {@link SatelliteError} result of the operation. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void sendSatelliteDatagram(@DatagramType int datagramType, + @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, + @NonNull @CallbackExecutor Executor executor, + @SatelliteError @NonNull Consumer<Integer> resultListener) { + Objects.requireNonNull(datagram); + Objects.requireNonNull(executor); + Objects.requireNonNull(resultListener); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> resultListener.accept(result))); + } + }; + telephony.sendSatelliteDatagram(mSubId, datagramType, datagram, + needFullScreenPointingUI, internalCallback); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("sendSatelliteDatagram() RemoteException:" + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Request to get whether satellite communication is allowed for the current location. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return a {@code boolean} with value {@code true} if satellite + * communication is allowed for the current location and + * {@code false} otherwise. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteError}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void requestIsSatelliteCommunicationAllowedForCurrentLocation( + @NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) { + boolean isSatelliteCommunicationAllowed = + resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(isSatelliteCommunicationAllowed))); + } else { + loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError( + new SatelliteException(SATELLITE_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestIsSatelliteCommunicationAllowedForCurrentLocation(mSubId, + receiver); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("requestIsSatelliteCommunicationAllowedForCurrentLocation() RemoteException: " + + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Request to get the duration in seconds after which the satellite will be visible. + * This will be {@link Duration#ZERO} if the satellite is currently visible. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return the time after which the satellite will be visible. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteError}. + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Duration, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) { + int nextVisibilityDuration = + resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult( + Duration.ofSeconds(nextVisibilityDuration)))); + } else { + loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist."); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError( + new SatelliteException(SATELLITE_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestTimeForNextSatelliteVisibility(mSubId, receiver); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("requestTimeForNextSatelliteVisibility() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Inform whether the device is aligned with the satellite for demo mode. + * + * @param isAligned {@true} Device is aligned with the satellite for demo mode + * {@false} Device is not aligned with the satellite for demo mode + * + * @throws SecurityException if the caller doesn't have required permission. + * @throws IllegalStateException if the Telephony process is not currently available. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + + public void onDeviceAlignedWithSatellite(boolean isAligned) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.onDeviceAlignedWithSatellite(mSubId, isAligned); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + loge("informDeviceAlignedToSatellite() RemoteException:" + ex); + ex.rethrowFromSystemServer(); + } + } + + private static ITelephony getITelephony() { + ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getTelephonyServiceRegisterer() + .get()); + if (binder == null) { + throw new RuntimeException("Could not find Telephony Service."); + } + return binder; + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} diff --git a/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java new file mode 100644 index 000000000000..a62eb8b8a5fb --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteProvisionStateCallback.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +/** + * A callback class for monitoring satellite provision state change events. + * + * @hide + */ +public interface SatelliteProvisionStateCallback { + /** + * Called when satellite provision state changes. + * + * @param provisioned The new provision state. {@code true} means satellite is provisioned + * {@code false} means satellite is not provisioned. + */ + void onSatelliteProvisionStateChanged(boolean provisioned); +} diff --git a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteStateCallback.java new file mode 100644 index 000000000000..d9ecaa3467e3 --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteStateCallback.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +/** + * A callback class for monitoring satellite modem state change events. + * + * @hide + */ +public interface SatelliteStateCallback { + /** + * Called when satellite modem state changes. + * @param state The new satellite modem state. + */ + void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state); +} diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java new file mode 100644 index 000000000000..d4fe57a0be2e --- /dev/null +++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite; + +import android.annotation.NonNull; + +/** + * A callback class for monitoring satellite position update and datagram transfer state change + * events. + * + * @hide + */ +public interface SatelliteTransmissionUpdateCallback { + /** + * Called when the satellite position changed. + * + * @param pointingInfo The pointing info containing the satellite location. + */ + void onSatellitePositionChanged(@NonNull PointingInfo pointingInfo); + + /** + * Called when satellite datagram send state changed. + * + * @param state The new send datagram transfer state. + * @param sendPendingCount The number of datagrams that are currently being sent. + * @param errorCode If datagram transfer failed, the reason for failure. + */ + void onSendDatagramStateChanged( + @SatelliteManager.SatelliteDatagramTransferState int state, int sendPendingCount, + @SatelliteManager.SatelliteError int errorCode); + + /** + * Called when satellite datagram receive state changed. + * + * @param state The new receive datagram transfer state. + * @param receivePendingCount The number of datagrams that are currently pending to be received. + * @param errorCode If datagram transfer failed, the reason for failure. + */ + void onReceiveDatagramStateChanged( + @SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount, + @SatelliteManager.SatelliteError int errorCode); +} diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl new file mode 100644 index 000000000000..ea4e2e2ef1b9 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer; +import android.telephony.satellite.stub.ISatelliteListener; +import android.telephony.satellite.stub.SatelliteDatagram; + +import com.android.internal.telephony.IBooleanConsumer; +import com.android.internal.telephony.IIntegerConsumer; + +/** + * {@hide} + */ +oneway interface ISatellite { + /** + * Register the callback interface with satellite service. + * + * @param listener The callback interface to handle satellite service indications. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void setSatelliteListener(in ISatelliteListener listener); + + /** + * Request to enable or disable the satellite service listening mode. + * Listening mode allows the satellite service to listen for incoming pages. + * + * @param enable True to enable satellite listening mode and false to disable. + * @param timeout How long the satellite modem should wait for the next incoming page before + * disabling listening mode. + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestSatelliteListeningEnabled(in boolean enable, in int timeout, + in IIntegerConsumer resultCallback); + + /** + * Allow cellular modem scanning while satellite mode is on. + * @param enabled {@code true} to enable cellular modem while satellite mode is on + * and {@code false} to disable + * @param errorCallback The callback to receive the error code result of the operation. + */ + void enableCellularModemWhileSatelliteModeIsOn(in boolean enabled, + in IIntegerConsumer errorCallback); + + /** + * Request to enable or disable the satellite modem and demo mode. If the satellite modem + * is enabled, this may also disable the cellular modem, and if the satellite modem is disabled, + * this may also re-enable the cellular modem. + * + * @param enableSatellite True to enable the satellite modem and false to disable. + * @param enableDemoMode True to enable demo mode and false to disable. + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestSatelliteEnabled(in boolean enableSatellite, in boolean enableDemoMode, + in IIntegerConsumer resultCallback); + + /** + * Request to get whether the satellite modem is enabled. + * + * @param resultCallback The callback to receive the error code result of the operation. + * This must only be sent when the error is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether the satellite modem is enabled. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestIsSatelliteEnabled(in IIntegerConsumer resultCallback, in IBooleanConsumer callback); + + /** + * Request to get whether the satellite service is supported on the device. + * + * @param resultCallback The callback to receive the error code result of the operation. + * This must only be sent when the error is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether the satellite service is supported on the device. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestIsSatelliteSupported(in IIntegerConsumer resultCallback, + in IBooleanConsumer callback); + + /** + * Request to get the SatelliteCapabilities of the satellite service. + * + * @param resultCallback The callback to receive the error code result of the operation. + * This must only be sent when the error is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * the SatelliteCapabilities of the satellite service. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestSatelliteCapabilities(in IIntegerConsumer resultCallback, + in ISatelliteCapabilitiesConsumer callback); + + /** + * User started pointing to the satellite. + * The satellite service should report the satellite pointing info via + * ISatelliteListener#onSatellitePositionChanged as the user device/satellite moves. + * + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void startSendingSatellitePointingInfo(in IIntegerConsumer resultCallback); + + /** + * User stopped pointing to the satellite. + * The satellite service should stop reporting satellite pointing info to the framework. + * + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void stopSendingSatellitePointingInfo(in IIntegerConsumer resultCallback); + + /** + * Provision the device with a satellite provider. + * This is needed if the provider allows dynamic registration. + * Once provisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report true. + * + * @param token The token to be used as a unique identifier for provisioning with satellite + * gateway. + * @param provisionData Data from the provisioning app that can be used by provisioning server + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:REQUEST_ABORTED + * SatelliteError:NETWORK_TIMEOUT + */ + void provisionSatelliteService(in String token, in byte[] provisionData, + in IIntegerConsumer resultCallback); + + /** + * Deprovision the device with the satellite provider. + * This is needed if the provider allows dynamic registration. + * Once deprovisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report false. + * + * @param token The token of the device/subscription to be deprovisioned. + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:REQUEST_ABORTED + * SatelliteError:NETWORK_TIMEOUT + */ + void deprovisionSatelliteService(in String token, in IIntegerConsumer resultCallback); + + /** + * Request to get whether this device is provisioned with a satellite provider. + * + * @param resultCallback The callback to receive the error code result of the operation. + * This must only be sent when the error is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether this device is provisioned with a satellite provider. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestIsSatelliteProvisioned(in IIntegerConsumer resultCallback, + in IBooleanConsumer callback); + + /** + * Poll the pending datagrams to be received over satellite. + * The satellite service should check if there are any pending datagrams to be received over + * satellite and report them via ISatelliteListener#onSatelliteDatagramsReceived. + * + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:SATELLITE_ACCESS_BARRED + * SatelliteError:NETWORK_TIMEOUT + * SatelliteError:SATELLITE_NOT_REACHABLE + * SatelliteError:NOT_AUTHORIZED + */ + void pollPendingSatelliteDatagrams(in IIntegerConsumer resultCallback); + + /** + * Send datagram over satellite. + * + * @param datagram Datagram to send in byte format. + * @param isEmergency Whether this is an emergency datagram. + * @param resultCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:REQUEST_ABORTED + * SatelliteError:SATELLITE_ACCESS_BARRED + * SatelliteError:NETWORK_TIMEOUT + * SatelliteError:SATELLITE_NOT_REACHABLE + * SatelliteError:NOT_AUTHORIZED + */ + void sendSatelliteDatagram(in SatelliteDatagram datagram, in boolean isEmergency, + in IIntegerConsumer resultCallback); + + /** + * Request the current satellite modem state. + * The satellite service should report the current satellite modem state via + * ISatelliteListener#onSatelliteModemStateChanged. + * + * @param resultCallback The callback to receive the error code result of the operation. + * This must only be sent when the error is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * the current satellite modem state. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestSatelliteModemState(in IIntegerConsumer resultCallback, + in IIntegerConsumer callback); + + /** + * Request to get whether satellite communication is allowed for the current location. + * + * @param resultCallback The callback to receive the error code result of the operation. + * This must only be sent when the error is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether satellite communication is allowed for the current location. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestIsSatelliteCommunicationAllowedForCurrentLocation( + in IIntegerConsumer resultCallback, in IBooleanConsumer callback); + + /** + * Request to get the time after which the satellite will be visible. This is an int + * representing the duration in seconds after which the satellite will be visible. + * This will return 0 if the satellite is currently visible. + * + * @param resultCallback The callback to receive the error code result of the operation. + * This must only be sent when the error is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * the time after which the satellite will be visible. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + void requestTimeForNextSatelliteVisibility(in IIntegerConsumer resultCallback, + in IIntegerConsumer callback); +} diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteCapabilitiesConsumer.aidl b/telephony/java/android/telephony/satellite/stub/ISatelliteCapabilitiesConsumer.aidl new file mode 100644 index 000000000000..e87c6da80518 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/ISatelliteCapabilitiesConsumer.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +import android.telephony.satellite.stub.SatelliteCapabilities; + +/** + * Consumer pattern for a request that receives a SatelliteCapabilities from the SatelliteService. + * @hide + */ +oneway interface ISatelliteCapabilitiesConsumer { + void accept(in SatelliteCapabilities result); +} diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteGateway.aidl b/telephony/java/android/telephony/satellite/stub/ISatelliteGateway.aidl new file mode 100644 index 000000000000..4f1a13623c3b --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/ISatelliteGateway.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +/** + * {@hide} + */ +oneway interface ISatelliteGateway { + // An empty service because Telephony does not need to use any APIs from this service. + // Once satellite modem is enabled, Telephony will bind to the ISatelliteGateway service; and + // when satellite modem is disabled, Telephony will unbind to the service. +} diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl new file mode 100644 index 000000000000..5e692151c604 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +import android.telephony.satellite.stub.NTRadioTechnology; +import android.telephony.satellite.stub.PointingInfo; +import android.telephony.satellite.stub.SatelliteDatagram; +import android.telephony.satellite.stub.SatelliteError; +import android.telephony.satellite.stub.SatelliteModemState; + +/** + * {@hide} + */ +oneway interface ISatelliteListener { + /** + * Indicates that the satellite provision state has changed. + * + * @param provisioned True means the service is provisioned and false means it is not. + */ + void onSatelliteProvisionStateChanged(in boolean provisioned); + + /** + * Indicates that new datagrams have been received on the device. + * + * @param datagram New datagram that was received. + * @param pendingCount Number of additional datagrams yet to be received. + */ + void onSatelliteDatagramReceived(in SatelliteDatagram datagram, in int pendingCount); + + /** + * Indicates that the satellite has pending datagrams for the device to be pulled. + */ + void onPendingDatagrams(); + + /** + * Indicates that the satellite pointing input has changed. + * + * @param pointingInfo The current pointing info. + */ + void onSatellitePositionChanged(in PointingInfo pointingInfo); + + /** + * Indicates that the satellite modem state has changed. + * + * @param state The current satellite modem state. + */ + void onSatelliteModemStateChanged(in SatelliteModemState state); +} diff --git a/telephony/java/android/telephony/satellite/stub/NTRadioTechnology.aidl b/telephony/java/android/telephony/satellite/stub/NTRadioTechnology.aidl new file mode 100644 index 000000000000..33164084ea40 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/NTRadioTechnology.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +/** + * {@hide} + */ +@Backing(type="int") +enum NTRadioTechnology { + /** + * 3GPP NB-IoT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology. + */ + NB_IOT_NTN = 0, + /* + * 3GPP 5G NR over Non-Terrestrial-Networks technology. + */ + NR_NTN = 1, + /** + * 3GPP eMTC (enhanced Machine-Type Communication) over Non-Terrestrial-Networks technology. + */ + EMTC_NTN = 2, + /** + * Proprietary technology. + */ + PROPRIETARY = 3, + /** + * Unknown Non-Terrestrial radio technology. This generic radio technology should be used + * only when the radio technology cannot be mapped to other specific radio technologies. + */ + UNKNOWN = -1, +} diff --git a/telephony/java/android/telephony/satellite/stub/PointingInfo.aidl b/telephony/java/android/telephony/satellite/stub/PointingInfo.aidl new file mode 100644 index 000000000000..52a36d8b29a3 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/PointingInfo.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +/** + * @hide + */ +parcelable PointingInfo { + /** + * Satellite azimuth in degrees. + */ + float satelliteAzimuth; + + /** + * Satellite elevation in degrees. + */ + float satelliteElevation; +} diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteCapabilities.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteCapabilities.aidl new file mode 100644 index 000000000000..eaf96abeb80a --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/SatelliteCapabilities.aidl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +import android.telephony.satellite.stub.NTRadioTechnology; +import android.telephony.satellite.AntennaPosition; +/** + * {@hide} + */ +parcelable SatelliteCapabilities { + /** + * List of technologies supported by the satellite modem. + */ + NTRadioTechnology[] supportedRadioTechnologies; + + /** + * Whether UE needs to point to a satellite to send and receive data. + */ + boolean isPointingRequired; + + /** + * The maximum number of bytes per datagram that can be sent over satellite. + */ + int maxBytesPerOutgoingDatagram; + + /** + * Keys which are used to fill mAntennaPositionMap. + */ + int[] antennaPositionKeys; + + /** + * Antenna Position for different display modes received from satellite modem. + */ + AntennaPosition[] antennaPositionValues; +} diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteDatagram.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteDatagram.aidl new file mode 100644 index 000000000000..f92cf0e1f06a --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/SatelliteDatagram.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +/** + * @hide + */ +parcelable SatelliteDatagram { + /** + * The contents of this datagram as a byte array. + */ + byte[] data; +} diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl new file mode 100644 index 000000000000..6a110a90276f --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +/** + * {@hide} + */ +@Backing(type="int") +enum SatelliteError { + /** + * The request was successfully processed. + */ + ERROR_NONE = 0, + /** + * A generic error which should be used only when other specific errors cannot be used. + */ + SATELLITE_ERROR = 1, + /** + * Error received from the satellite server. + */ + SERVER_ERROR = 2, + /** + * Error received from the vendor service. This generic error code should be used + * only when the error cannot be mapped to other specific service error codes. + */ + SERVICE_ERROR = 3, + /** + * Error received from satellite modem. This generic error code should be used only when + * the error cannot be mapped to other specific modem error codes. + */ + MODEM_ERROR = 4, + /** + * Error received from the satellite network. This generic error code should be used only when + * the error cannot be mapped to other specific network error codes. + */ + NETWORK_ERROR = 5, + /** + * Telephony is not in a valid state to receive requests from clients. + */ + INVALID_TELEPHONY_STATE = 6, + /** + * Satellite modem is not in a valid state to receive requests from clients. + */ + INVALID_MODEM_STATE = 7, + /** + * Either vendor service, or modem, or Telephony framework has received a request with + * invalid arguments from its clients. + */ + INVALID_ARGUMENTS = 8, + /** + * Telephony framework failed to send a request or receive a response from the vendor service + * or satellite modem due to internal error. + */ + REQUEST_FAILED = 9, + /** + * Radio did not start or is resetting. + */ + RADIO_NOT_AVAILABLE = 10, + /** + * The request is not supported by either the satellite modem or the network. + */ + REQUEST_NOT_SUPPORTED = 11, + /** + * Satellite modem or network has no resources available to handle requests from clients. + */ + NO_RESOURCES = 12, + /** + * Satellite service is not provisioned yet. + */ + SERVICE_NOT_PROVISIONED = 13, + /** + * Satellite service provision is already in progress. + */ + SERVICE_PROVISION_IN_PROGRESS = 14, + /** + * The ongoing request was aborted by either the satellite modem or the network. + */ + REQUEST_ABORTED = 15, + /** + * The device/subscriber is barred from accessing the satellite service. + */ + SATELLITE_ACCESS_BARRED = 16, + /** + * Satellite modem timeout to receive ACK or response from the satellite network after + * sending a request to the network. + */ + NETWORK_TIMEOUT = 17, + /** + * Satellite network is not reachable from the modem. + */ + SATELLITE_NOT_REACHABLE = 18, + /** + * The device/subscriber is not authorized to register with the satellite service provider. + */ + NOT_AUTHORIZED = 19 +} diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteGatewayService.java b/telephony/java/android/telephony/satellite/stub/SatelliteGatewayService.java new file mode 100644 index 000000000000..f4514a6de413 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/SatelliteGatewayService.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +import android.annotation.SdkConstant; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import com.android.telephony.Rlog; + +/** + * Main SatelliteGatewayService implementation, which binds via the Telephony SatelliteController. + * Services that extend SatelliteGatewayService must register the service in their AndroidManifest + * to be detected by the framework. The application must declare that they require the + * "android.permission.BIND_SATELLITE_GATEWAY_SERVICE" permission to ensure that nothing else can + * bind to their service except the Telephony framework. The SatelliteGatewayService definition in + * the manifest must follow the following format: + * + * ... + * <service android:name=".EgSatelliteGatewayService" + * android:permission="android.permission.BIND_SATELLITE_GATEWAY_SERVICE" > + * ... + * <intent-filter> + * <action android:name="android.telephony.satellite.SatelliteGatewayService" /> + * </intent-filter> + * </service> + * ... + * + * The telephony framework will then bind to the SatelliteGatewayService defined in the manifest if + * it is the default SatelliteGatewayService defined in the device overlay + * "config_satellite_gateway_service_package". + * @hide + */ +public abstract class SatelliteGatewayService extends Service { + private static final String TAG = "SatelliteGatewayService"; + + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.telephony.satellite.SatelliteGatewayService"; + + private final IBinder mBinder = new ISatelliteGateway.Stub() {}; + + /** + * @hide + */ + @Override + public final IBinder onBind(Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + Rlog.d(TAG, "SatelliteGatewayService bound"); + return mBinder; + } + return null; + } + + /** + * @return The binder for the ISatelliteGateway. + * @hide + */ + public final IBinder getBinder() { + return mBinder; + } +} diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java new file mode 100644 index 000000000000..d606f874e422 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java @@ -0,0 +1,621 @@ +/* + * Copyright (C) 2022 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 android.telephony.satellite.stub; + +import android.annotation.NonNull; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.telephony.IBooleanConsumer; +import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.util.TelephonyUtils; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; + +/** + * Base implementation of satellite service. + * Any service wishing to provide satellite services should extend this class and implement all + * methods that the service supports. + * @hide + */ +public class SatelliteImplBase extends SatelliteService { + private static final String TAG = "SatelliteImplBase"; + + protected final Executor mExecutor; + + /** + * Create SatelliteImplBase using the Executor specified for methods being called from the + * framework. + * @param executor The executor for the framework to use when executing the methods overridden + * by the implementation of Satellite. + * @hide + */ + public SatelliteImplBase(@NonNull Executor executor) { + super(); + mExecutor = executor; + } + + /** + * @return The binder for the Satellite implementation. + * @hide + */ + public final IBinder getBinder() { + return mBinder; + } + + private final IBinder mBinder = new ISatellite.Stub() { + @Override + public void setSatelliteListener(ISatelliteListener listener) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this.setSatelliteListener(listener), + "setSatelliteListener"); + } + + @Override + public void requestSatelliteListeningEnabled(boolean enable, int timeout, + IIntegerConsumer errorCallback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestSatelliteListeningEnabled(enable, timeout, errorCallback), + "requestSatelliteListeningEnabled"); + } + + @Override + public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled, + IIntegerConsumer errorCallback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .enableCellularModemWhileSatelliteModeIsOn(enabled, errorCallback), + "enableCellularModemWhileSatelliteModeIsOn"); + } + + @Override + public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, + IIntegerConsumer errorCallback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestSatelliteEnabled( + enableSatellite, enableDemoMode, errorCallback), + "requestSatelliteEnabled"); + } + + @Override + public void requestIsSatelliteEnabled(IIntegerConsumer errorCallback, + IBooleanConsumer callback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestIsSatelliteEnabled(errorCallback, callback), + "requestIsSatelliteEnabled"); + } + + @Override + public void requestIsSatelliteSupported(IIntegerConsumer errorCallback, + IBooleanConsumer callback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestIsSatelliteSupported(errorCallback, callback), + "requestIsSatelliteSupported"); + } + + @Override + public void requestSatelliteCapabilities(IIntegerConsumer errorCallback, + ISatelliteCapabilitiesConsumer callback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestSatelliteCapabilities(errorCallback, callback), + "requestSatelliteCapabilities"); + } + + @Override + public void startSendingSatellitePointingInfo(IIntegerConsumer errorCallback) + throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this.startSendingSatellitePointingInfo(errorCallback), + "startSendingSatellitePointingInfo"); + } + + @Override + public void stopSendingSatellitePointingInfo(IIntegerConsumer errorCallback) + throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this.stopSendingSatellitePointingInfo(errorCallback), + "stopSendingSatellitePointingInfo"); + } + + @Override + public void provisionSatelliteService(String token, byte[] provisionData, + IIntegerConsumer errorCallback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .provisionSatelliteService(token, provisionData, errorCallback), + "provisionSatelliteService"); + } + + @Override + public void deprovisionSatelliteService(String token, IIntegerConsumer errorCallback) + throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this.deprovisionSatelliteService(token, errorCallback), + "deprovisionSatelliteService"); + } + + @Override + public void requestIsSatelliteProvisioned(IIntegerConsumer errorCallback, + IBooleanConsumer callback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestIsSatelliteProvisioned(errorCallback, callback), + "requestIsSatelliteProvisioned"); + } + + @Override + public void pollPendingSatelliteDatagrams(IIntegerConsumer errorCallback) + throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this.pollPendingSatelliteDatagrams(errorCallback), + "pollPendingSatelliteDatagrams"); + } + + @Override + public void sendSatelliteDatagram(SatelliteDatagram datagram, boolean isEmergency, + IIntegerConsumer errorCallback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .sendSatelliteDatagram(datagram, isEmergency, errorCallback), + "sendSatelliteDatagram"); + } + + @Override + public void requestSatelliteModemState(IIntegerConsumer errorCallback, + IIntegerConsumer callback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestSatelliteModemState(errorCallback, callback), + "requestSatelliteModemState"); + } + + @Override + public void requestIsSatelliteCommunicationAllowedForCurrentLocation( + IIntegerConsumer errorCallback, IBooleanConsumer callback) + throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestIsSatelliteCommunicationAllowedForCurrentLocation( + errorCallback, callback), + "requestIsSatelliteCommunicationAllowedForCurrentLocation"); + } + + @Override + public void requestTimeForNextSatelliteVisibility(IIntegerConsumer errorCallback, + IIntegerConsumer callback) throws RemoteException { + executeMethodAsync( + () -> SatelliteImplBase.this + .requestTimeForNextSatelliteVisibility(errorCallback, callback), + "requestTimeForNextSatelliteVisibility"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException { + try { + CompletableFuture.runAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(TAG, "SatelliteImplBase Binder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + }; + + /** + * Register the callback interface with satellite service. + * + * @param listener The callback interface to handle satellite service indications. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void setSatelliteListener(@NonNull ISatelliteListener listener) { + // stub implementation + } + + /** + * Request to enable or disable the satellite service listening mode. + * Listening mode allows the satellite service to listen for incoming pages. + * + * @param enable True to enable satellite listening mode and false to disable. + * @param timeout How long the satellite modem should wait for the next incoming page before + * disabling listening mode. + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestSatelliteListeningEnabled(boolean enable, int timeout, + @NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Allow cellular modem scanning while satellite mode is on. + * @param enabled {@code true} to enable cellular modem while satellite mode is on + * and {@code false} to disable + * @param errorCallback The callback to receive the error code result of the operation. + */ + public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled, + @NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Request to enable or disable the satellite modem and demo mode. If the satellite modem is + * enabled, this may also disable the cellular modem, and if the satellite modem is disabled, + * this may also re-enable the cellular modem. + * + * @param enableSatellite True to enable the satellite modem and false to disable. + * @param enableDemoMode True to enable demo mode and false to disable. + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, + @NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Request to get whether the satellite modem is enabled. + * + * @param errorCallback The callback to receive the error code result of the operation. + * This must only be sent when the result is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether the satellite modem is enabled. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestIsSatelliteEnabled(@NonNull IIntegerConsumer errorCallback, + @NonNull IBooleanConsumer callback) { + // stub implementation + } + + /** + * Request to get whether the satellite service is supported on the device. + * + * @param errorCallback The callback to receive the error code result of the operation. + * This must only be sent when the result is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether the satellite service is supported on the device. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestIsSatelliteSupported(@NonNull IIntegerConsumer errorCallback, + @NonNull IBooleanConsumer callback) { + // stub implementation + } + + /** + * Request to get the SatelliteCapabilities of the satellite service. + * + * @param errorCallback The callback to receive the error code result of the operation. + * This must only be sent when the result is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * the SatelliteCapabilities of the satellite service. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestSatelliteCapabilities(@NonNull IIntegerConsumer errorCallback, + @NonNull ISatelliteCapabilitiesConsumer callback) { + // stub implementation + } + + /** + * User started pointing to the satellite. + * The satellite service should report the satellite pointing info via + * ISatelliteListener#onSatellitePositionChanged as the user device/satellite moves. + * + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void startSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * User stopped pointing to the satellite. + * The satellite service should stop reporting satellite pointing info to the framework. + * + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void stopSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Provision the device with a satellite provider. + * This is needed if the provider allows dynamic registration. + * Once provisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report true. + * + * @param token The token to be used as a unique identifier for provisioning with satellite + * gateway. + * @param provisionData Data from the provisioning app that can be used by provisioning + * server + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:REQUEST_ABORTED + * SatelliteError:NETWORK_TIMEOUT + */ + public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData, + @NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Deprovision the device with the satellite provider. + * This is needed if the provider allows dynamic registration. + * Once deprovisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report false. + * + * @param token The token of the device/subscription to be deprovisioned. + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:REQUEST_ABORTED + * SatelliteError:NETWORK_TIMEOUT + */ + public void deprovisionSatelliteService(@NonNull String token, + @NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Request to get whether this device is provisioned with a satellite provider. + * + * @param errorCallback The callback to receive the error code result of the operation. + * This must only be sent when the result is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether this device is provisioned with a satellite provider. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestIsSatelliteProvisioned(@NonNull IIntegerConsumer errorCallback, + @NonNull IBooleanConsumer callback) { + // stub implementation + } + + /** + * Poll the pending datagrams to be received over satellite. + * The satellite service should check if there are any pending datagrams to be received over + * satellite and report them via ISatelliteListener#onSatelliteDatagramsReceived. + * + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:SATELLITE_ACCESS_BARRED + * SatelliteError:NETWORK_TIMEOUT + * SatelliteError:SATELLITE_NOT_REACHABLE + * SatelliteError:NOT_AUTHORIZED + */ + public void pollPendingSatelliteDatagrams(@NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Send datagram over satellite. + * + * @param datagram Datagram to send in byte format. + * @param isEmergency Whether this is an emergency datagram. + * @param errorCallback The callback to receive the error code result of the operation. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:NETWORK_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + * SatelliteError:REQUEST_ABORTED + * SatelliteError:SATELLITE_ACCESS_BARRED + * SatelliteError:NETWORK_TIMEOUT + * SatelliteError:SATELLITE_NOT_REACHABLE + * SatelliteError:NOT_AUTHORIZED + */ + public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency, + @NonNull IIntegerConsumer errorCallback) { + // stub implementation + } + + /** + * Request the current satellite modem state. + * The satellite service should report the current satellite modem state via + * ISatelliteListener#onSatelliteModemStateChanged. + * + * @param errorCallback The callback to receive the error code result of the operation. + * This must only be sent when the result is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * the current satellite modem state. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestSatelliteModemState(@NonNull IIntegerConsumer errorCallback, + @NonNull IIntegerConsumer callback) { + // stub implementation + } + + /** + * Request to get whether satellite communication is allowed for the current location. + * + * @param errorCallback The callback to receive the error code result of the operation. + * This must only be sent when the result is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * whether satellite communication is allowed for the current location. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestIsSatelliteCommunicationAllowedForCurrentLocation( + @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) { + // stub implementation + } + + /** + * Request to get the time after which the satellite will be visible. This is an int + * representing the duration in seconds after which the satellite will be visible. + * This will return 0 if the satellite is currently visible. + * + * @param errorCallback The callback to receive the error code result of the operation. + * This must only be sent when the result is not SatelliteError#ERROR_NONE. + * @param callback If the result is SatelliteError#ERROR_NONE, the callback to receive + * the time after which the satellite will be visible. + * + * Valid error codes returned: + * SatelliteError:ERROR_NONE + * SatelliteError:SERVICE_ERROR + * SatelliteError:MODEM_ERROR + * SatelliteError:INVALID_MODEM_STATE + * SatelliteError:INVALID_ARGUMENTS + * SatelliteError:RADIO_NOT_AVAILABLE + * SatelliteError:REQUEST_NOT_SUPPORTED + * SatelliteError:NO_RESOURCES + */ + public void requestTimeForNextSatelliteVisibility(@NonNull IIntegerConsumer errorCallback, + @NonNull IIntegerConsumer callback) { + // stub implementation + } +} diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteModemState.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteModemState.aidl new file mode 100644 index 000000000000..e4f94134caa1 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/SatelliteModemState.aidl @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +/** + * {@hide} + */ +@Backing(type="int") +enum SatelliteModemState { + /** + * Satellite modem is in idle state. + */ + SATELLITE_MODEM_STATE_IDLE = 0, + /** + * Satellite modem is listening for incoming datagrams. + */ + SATELLITE_MODEM_STATE_LISTENING = 1, + /** + * Satellite modem is sending and/or receiving datagrams. + */ + SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2, + /** + * Satellite modem is retrying to send and/or receive datagrams. + */ + SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3, + /** + * Satellite modem is powered off. + */ + SATELLITE_MODEM_STATE_OFF = 4, + /** + * Satellite modem is unavailable. + */ + SATELLITE_MODEM_STATE_UNAVAILABLE = 5, + /** + * Satellite modem state is unknown. This generic modem state should be used only when the + * modem state cannot be mapped to other specific modem states. + */ + SATELLITE_MODEM_STATE_UNKNOWN = -1, +} diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteService.java b/telephony/java/android/telephony/satellite/stub/SatelliteService.java new file mode 100644 index 000000000000..5b96e34186e9 --- /dev/null +++ b/telephony/java/android/telephony/satellite/stub/SatelliteService.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 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 android.telephony.satellite.stub; + +import android.annotation.SdkConstant; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import com.android.telephony.Rlog; + +/** + * Main SatelliteService implementation, which binds via the Telephony SatelliteServiceController. + * Services that extend SatelliteService must register the service in their AndroidManifest to be + * detected by the framework. First, the application must declare that they use the + * "android.permission.BIND_SATELLITE_SERVICE" permission. Then, the SatelliteService definition in + * the manifest must follow the following format: + * + * ... + * <service android:name=".EgSatelliteService" + * android:permission="android.permission.BIND_SATELLITE_SERVICE" > + * ... + * <intent-filter> + * <action android:name="android.telephony.satellite.SatelliteService" /> + * </intent-filter> + * </service> + * ... + * + * The telephony framework will then bind to the SatelliteService defined in the manifest if it is + * the default SatelliteService defined in the device overlay "config_satellite_service_package". + * @hide + */ +public class SatelliteService extends Service { + private static final String TAG = "SatelliteService"; + + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = "android.telephony.satellite.SatelliteService"; + + /** + * @hide + */ + @Override + public IBinder onBind(Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + Rlog.d(TAG, "SatelliteService bound"); + return new SatelliteImplBase(Runnable::run).getBinder(); + } + return null; + } +} diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl index e3a8aeed7ad5..60a74788b709 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl @@ -91,6 +91,8 @@ interface IImsCallSession { * override the previous listener. * * @param listener to listen to the session events of this object + * + * @deprecated This is depreacated. */ void setListener(in IImsCallSessionListener listener); @@ -305,4 +307,15 @@ interface IImsCallSession { * @param extensions the header extensions to be sent */ void sendRtpHeaderExtensions(in List<RtpHeaderExtension> extensions); + + /* + * Deliver the bitrate for the indicated media type, direction and bitrate to the upper layer. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate received from the NW through the Recommended + * bitrate MAC Control Element message and ImsStack converts this value from MAC bitrate + * to audio/video codec bitrate (defined in TS26.114). + */ + void callSessionNotifyAnbr(int mediaType, int direction, int bitsPerSecond); } diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl index 8afd85633322..9395fbd6a85e 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl @@ -194,4 +194,17 @@ oneway interface IImsCallSessionListener { * @param callQuality then updated call quality */ void callQualityChanged(in CallQuality callQuality); + + /** + * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114. + * This API triggers radio to send ANBRQ message to the access network to query the desired + * bitrate. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate requested by the other party UE through + * RTP CMR, RTCPAPP or TMMBR, and ImsStack converts this value to the MAC bitrate + * (defined in TS36.321, range: 0 ~ 8000 kbit/s). + */ + void callSessionSendAnbrQuery(int mediaType, int direction, int bitsPerSecond); } diff --git a/telephony/java/com/android/internal/telephony/IDomainSelectionServiceController.aidl b/telephony/java/com/android/internal/telephony/IDomainSelectionServiceController.aidl new file mode 100644 index 000000000000..8ad79ed3430e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IDomainSelectionServiceController.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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.internal.telephony; + +import android.telephony.BarringInfo; +import android.telephony.DomainSelectionService.SelectionAttributes; +import android.telephony.ServiceState; + +import com.android.internal.telephony.ITransportSelectorCallback; + +oneway interface IDomainSelectionServiceController { + void selectDomain(in SelectionAttributes attr, in ITransportSelectorCallback callback); + void updateServiceState(int slotId, int subId, in ServiceState serviceState); + void updateBarringInfo(int slotId, int subId, in BarringInfo info); +} diff --git a/telephony/java/com/android/internal/telephony/IDomainSelector.aidl b/telephony/java/com/android/internal/telephony/IDomainSelector.aidl new file mode 100644 index 000000000000..d94840b112ee --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IDomainSelector.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 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.internal.telephony; + +import android.telephony.DomainSelectionService.SelectionAttributes; + +oneway interface IDomainSelector { + void cancelSelection(); + void reselectDomain(in SelectionAttributes attr); + void finishSelection(); +} diff --git a/telephony/java/com/android/internal/telephony/ILongConsumer.aidl b/telephony/java/com/android/internal/telephony/ILongConsumer.aidl new file mode 100644 index 000000000000..2f0d4a00e405 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ILongConsumer.aidl @@ -0,0 +1,25 @@ +/* + * Copyright 2023 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.internal.telephony; + + /** + * Copies consumer pattern for an operation that requires long result from another process to + * finish. + */ + oneway interface ILongConsumer { + void accept(long result); + } diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index ce2017bb9a35..b4d93fddd7aa 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.telephony.ImsiEncryptionInfo; +import android.net.Uri; /** * Interface used to retrieve various phone-related subscriber information. @@ -179,6 +180,19 @@ interface IPhoneSubInfo { String getIsimImpi(int subId); /** + * Fetches the ISIM PrivateUserIdentity (EF_IMPI) based on subId + * + * @param subId subscriptionId + * @return IMPI (IMS private user identity) of type string or null if EF_IMPI is not available. + * @throws IllegalArgumentException if the subscriptionId is not valid + * @throws IllegalStateException in case the ISIM hasn’t been loaded. + * @throws SecurityException if the caller does not have the required permission + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER)") + String getImsPrivateUserIdentity(int subId, String callingPackage, String callingFeatureId); + + /** * Returns the IMS home network domain name that was loaded from the ISIM. * @return the IMS domain name, or null if not present or not loaded */ @@ -192,6 +206,14 @@ interface IPhoneSubInfo { String[] getIsimImpu(int subId); /** + * Fetches the ISIM public user identities (EF_IMPU) from UICC based on subId + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "anyOf={android.Manifest.permission.READ_PHONE_NUMBERS, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})") + List<Uri> getImsPublicUserIdentities(int subId, String callingPackage, + String callingFeatureId); + + /** * Returns the IMS Service Table (IST) that was loaded from the ISIM. * @return IMS Service Table or null if not present or not loaded */ @@ -218,4 +240,39 @@ interface IPhoneSubInfo { */ String getIccSimChallengeResponse(int subId, int appType, int authType, String data, String callingPackage, String callingFeatureId); + + /** + * Fetches the EF_PSISMSC value from the UICC that contains the Public Service Identity of + * the SM-SC (either a SIP URI or tel URI). The EF_PSISMSC of ISIM and USIM can be found in + * DF_TELECOM. + * The EF_PSISMSC value is used by the ME to submit SMS over IP as defined in 24.341 [55]. + * + * @return Uri : Public Service Identity of SM-SC + * @throws SecurityException if the caller does not have the required permission/privileges + * @hide + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)") + Uri getSmscIdentity(int subId, int appType); + + /** + * Fetches the sim service table from the EFUST/EFIST based on the application type + * {@link #APPTYPE_USIM} or {@link #APPTYPE_ISIM}. The return value is hexaString format + * representing X bytes (x >= 1). Each bit of every byte indicates which optional services + * are available for the given application type. + * The USIM service table EF is described in as per Section 4.2.8 of 3GPP TS 31.102. + * The ISIM service table EF is described in as per Section 4.2.7 of 3GPP TS 31.103. + * The list of services mapped to the exact nth byte of response as mentioned in Section 4.2 + * .7 of 3GPP TS 31.103. Eg. Service n°1: Local Phone Book, Service n°2: Fixed Dialling + * Numbers (FDN) - Bit 1 and 2 of the 1st Byte represent service Local Phone Book and Fixed + * Dialling Numbers (FDN)respectively. The coding format for each service type should be + * interpreted as bit = 1: service available;bit = 0:service not available. + * + * @param appType of type int of either {@link #APPTYPE_USIM} or {@link #APPTYPE_ISIM}. + * @return HexString represents sim service table else null. + * @throws SecurityException if the caller does not have the required permission/privileges + * @throws IllegalStateException in case if phone or UiccApplication is not available. + * @hide + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)") + String getSimServiceTable(int subId, int appType); } diff --git a/telephony/java/com/android/internal/telephony/ISipDialogStateCallback.aidl b/telephony/java/com/android/internal/telephony/ISipDialogStateCallback.aidl new file mode 100644 index 000000000000..6847eb4d92a3 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ISipDialogStateCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 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.internal.telephony; + +import android.telephony.ims.SipDialogState; + +/** + * Provides callback interface for SipDialogState when a state is changed. + * + */ +oneway interface ISipDialogStateCallback { + void onActiveSipDialogsChanged(in List<SipDialogState> dialogs); +} diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 9ec3c6716a29..0e23f364134c 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -530,6 +530,25 @@ interface ISms { int subId, String callingPkg, String prefixes, in PendingIntent intent); /** + * set Memory Status in SmsStorageMonitor + * + * @param subId the subscription Id. + * @param callingPackage the package name of the calling app. + * @param isStorageAvailable sets StorageAvailable to false or true + * for testing behaviour of SmsStorageMonitor + */ + void setStorageMonitorMemoryStatusOverride(int subId, boolean isStorageAvailable); + + /** + * reset Memory Status change made by TestApi setStorageMonitorMemoryStatusOverride + * in SmsStorageMonitor + * + * @param subId the subscription Id. + * @param callingPackage the package name of the calling app. + */ + void clearStorageMonitorMemoryStatusOverride(int subId); + + /** * Check if the destination is a possible premium short code. * * @param destAddress the destination address to test for possible short code diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java index c361d5bec097..686455688203 100644 --- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java +++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java @@ -192,6 +192,16 @@ public class ISmsImplBase extends ISms.Stub { } @Override + public void setStorageMonitorMemoryStatusOverride(int subId, boolean storageAvailable) { + throw new UnsupportedOperationException(); + } + + @Override + public void clearStorageMonitorMemoryStatusOverride(int subId) { + throw new UnsupportedOperationException(); + } + + @Override public int checkSmsShortCodeDestination(int subid, String callingPackage, String callingFeatureId, String destAddress, String countryIso) { throw new UnsupportedOperationException(); diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 6a5380ddb36e..21a6b447d6a4 100644 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -129,9 +129,9 @@ interface ISub { * @param uniqueId This is the unique identifier for the subscription within the specific * subscription type. * @param subscriptionType the type of subscription to be removed - * @return 0 if success, < 0 on error. + * @return true if success, false on error. */ - int removeSubInfo(String uniqueId, int subscriptionType); + boolean removeSubInfo(String uniqueId, int subscriptionType); /** * Set SIM icon tint color by simInfo index @@ -260,7 +260,7 @@ interface ISub { int[] getActiveSubIdList(boolean visibleOnly); - int setSubscriptionProperty(int subId, String propKey, String propValue); + void setSubscriptionProperty(int subId, String propKey, String propValue); String getSubscriptionProperty(int subId, String propKey, String callingPackage, String callingFeatureId); @@ -353,13 +353,6 @@ interface ISub { */ List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(in UserHandle userHandle); - /** - * @return {@code true} if using SubscriptionManagerService instead of - * SubscriptionController. - */ - //TODO: Removed before U AOSP public release. - boolean isSubscriptionManagerServiceEnabled(); - /** * Called during setup wizard restore flow to attempt to restore the backed up sim-specific * configs to device for all existing SIMs in the subscription database diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 9d05517050e2..23f4217caf9d 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -17,9 +17,11 @@ package com.android.internal.telephony; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; import android.os.Bundle; +import android.os.ICancellationSignal; import android.os.IBinder; import android.os.Messenger; import android.os.ParcelFileDescriptor; @@ -34,6 +36,7 @@ import android.telephony.CallForwardingInfo; import android.telephony.CarrierRestrictionRules; import android.telephony.CellIdentity; import android.telephony.CellInfo; +import android.telephony.CellBroadcastIdRange; import android.telephony.ClientRequestStats; import android.telephony.ThermalMitigationRequest; import android.telephony.gba.UaSecurityProtocolIdentifier; @@ -64,6 +67,12 @@ import android.telephony.ims.aidl.IImsRcsFeature; import android.telephony.ims.aidl.IImsRegistration; import android.telephony.ims.aidl.IImsRegistrationCallback; import android.telephony.ims.aidl.IRcsConfigCallback; +import android.telephony.satellite.ISatelliteDatagramCallback; +import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; +import android.telephony.satellite.ISatelliteProvisionStateCallback; +import android.telephony.satellite.ISatelliteStateCallback; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteDatagram; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.telephony.CellNetworkScanResult; import com.android.internal.telephony.IBooleanConsumer; @@ -244,6 +253,44 @@ interface ITelephony { boolean setRadioPower(boolean turnOn); /** + * Vote on powering off the radio for a reason. The radio will be turned on only when there is + * no reason to power it off. When any of the voters want to power it off, it will be turned + * off. In case of emergency, the radio will be turned on even if there are some reasons for + * powering it off, and these radio off votes will be cleared. + * Multiple apps can vote for the same reason and the last vote will take effect. Each app is + * responsible for its vote. A powering-off vote of a reason will be maintained until it is + * cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call + * is made, or the device is rebooted. When an app comes backup from a crash, it needs to make + * sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to + * check its vote. + * + * @param subId The subscription ID. + * @param reason The reason for powering off radio. + * @return true on success and false on failure. + */ + boolean requestRadioPowerOffForReason(int subId, int reason); + + /** + * Remove the vote on powering off the radio for a reasonas, requested by + * {@link requestRadioPowerOffForReason}. + * + * @param subId The subscription ID. + * @param reason The reason for powering off radio. + * @return true on success and false on failure. + */ + boolean clearRadioPowerOffForReason(int subId, int reason); + + /** + * Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}. + * + * @param subId The subscription ID. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * @return List of reasons for powering off radio. + */ + List getRadioPowerOffReasons(int subId, String callingPackage, String callingFeatureId); + + /** * This method has been removed due to security and stability issues. */ @UnsupportedAppUsage @@ -583,7 +630,7 @@ interface ITelephony { /** * Sets minimum time in milli-seconds between onCellInfoChanged */ - void setCellInfoListRate(int rateInMillis); + void setCellInfoListRate(int rateInMillis, int subId); /** * Opens a logical channel to the ICC card. @@ -1281,6 +1328,16 @@ interface ITelephony { String getImeiForSlot(int slotIndex, String callingPackage, String callingFeatureId); /** + * Returns the primary IMEI of the device + * + * @param callingPackage The package name of the caller + * @param callingFeatureId The feature Id of the calling package + * @throws UnsupportedOperationException if the radio doesn't support this feature. + * @throws SecurityException if the caller does not have the required permission/privileges + */ + String getPrimaryImei(String callingPackage, String callingFeatureId); + + /** * Returns the Type Allocation Code from the IMEI for the given slot. * * @param slotIndex - Which slot to retrieve the Type Allocation Code from. @@ -1483,7 +1540,7 @@ interface ITelephony { */ CarrierRestrictionRules getAllowedCarriers(); - /** + /** * Returns carrier id of the given subscription. * <p>To recognize carrier as a first class identity, assign each carrier with a canonical * integer a.k.a carrier id. @@ -2137,6 +2194,12 @@ interface ITelephony { int getRadioHalVersion(); /** + * Get the HAL Version of a specific service + * encoded as 100 * MAJOR_VERSION + MINOR_VERSION or -1 if unknown + */ + int getHalVersion(int service); + + /** * Get the current calling package name. */ String getCurrentPackageName(); @@ -2169,6 +2232,11 @@ interface ITelephony { IIntegerConsumer subIdResult); /** + * Show error dialog to switch to managed profile. + */ + oneway void showSwitchToManagedProfileDialog(); + + /** * Returns the MMS user agent. */ String getMmsUserAgent(int subId); @@ -2507,6 +2575,16 @@ interface ITelephony { void getSlicingConfig(in ResultReceiver callback); /** + * Check whether the given premium capability is available for purchase from the carrier. + */ + boolean isPremiumCapabilityAvailableForPurchase(int capability, int subId); + + /** + * Purchase the given premium capability from the carrier. + */ + void purchasePremiumCapability(int capability, IIntegerConsumer callback, int subId); + + /** * Register an IMS connection state callback */ void registerImsStateCallback(int subId, int feature, in IImsStateCallback cb, @@ -2582,9 +2660,388 @@ interface ITelephony { boolean isRemovableEsimDefaultEuicc(String callingPackage); /** + * Get the component name of the default app to direct respond-via-message intent for the + * user associated with this subscription, update the cache if there is no respond-via-message + * application currently configured for this user. + * @return component name of the app and class to direct Respond Via Message intent to, or + * {@code null} if the functionality is not supported. + * @hide + */ + ComponentName getDefaultRespondViaMessageApplication(int subId, boolean updateIfNeeded); + + /** * Get the SIM state for the logical SIM slot index. * * @param slotIndex Logical SIM slot index. */ int getSimStateForSlotIndex(int slotIndex); + + /** + * Request telephony to persist state for debugging emergency call failures. + * + * @param dropBoxTag Tag to use when persisting data to dropbox service. + * @param enableLogcat whether to collect logcat output + * @param logcatStartTimestampMillis timestamp from when logcat buffers would be persisted + * @param enableTelecomDump whether to collect telecom dumpsys + * @param enableTelephonyDump whether to collect telephony dumpsys + * + * @hide + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.DUMP)") + void persistEmergencyCallDiagnosticData(String dropboxTag, boolean enableLogcat, + long logcatStartTimestampMillis, boolean enableTelecomDump, boolean enableTelephonyDump); + /** + * Set whether the radio is able to connect with null ciphering or integrity + * algorithms. This is a global setting and will apply to all active subscriptions + * and all new subscriptions after this. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * + * @param enabled when true, null cipher and integrity algorithms are allowed. + * @hide + */ + void setNullCipherAndIntegrityEnabled(boolean enabled); + + /** + * Get whether the radio is able to connect with null ciphering or integrity + * algorithms. Note that this retrieves the phone-global preference and not + * the state of the radio. + * + * @hide + */ + boolean isNullCipherAndIntegrityPreferenceEnabled(); + + /** + * Get current broadcast ranges. + */ + List<CellBroadcastIdRange> getCellBroadcastIdRanges(int subId); + + /** + * Set reception of cell broadcast messages with the list of the given ranges + */ + void setCellBroadcastIdRanges(int subId, in List<CellBroadcastIdRange> ranges, + IIntegerConsumer callback); + + /** + * Returns whether the domain selection service is supported. + * + * @return {@code true} if the domain selection service is supported. + */ + boolean isDomainSelectionSupported(); + + /** + * Get the carrier restriction status of the device. + */ + void getCarrierRestrictionStatus(IIntegerConsumer internalCallback, String packageName); + + /** + * Request to enable or disable the satellite modem. + * + * @param subId The subId of the subscription to enable or disable the satellite modem for. + * @param enable True to enable the satellite modem and false to disable. + * @param isDemoModeEnabled True if demo mode is enabled and false otherwise. + * @param callback The callback to get the result of the request. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestSatelliteEnabled(int subId, boolean enable, boolean isDemoModeEnabled, + in IIntegerConsumer callback); + + /** + * Request to get whether the satellite modem is enabled. + * + * @param subId The subId of the subscription to request whether satellite is enabled for. + * @param receiver Result receiver to get the error code of the request and whether the + * satellite modem is enabled. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestIsSatelliteEnabled(int subId, in ResultReceiver receiver); + + /** + * Request to get whether the satellite service demo mode is enabled. + * + * @param subId The subId of the subscription to request whether the satellite demo mode is + * enabled for. + * @param receiver Result receiver to get the error code of the request and whether the + * satellite demo mode is enabled. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestIsDemoModeEnabled(int subId, in ResultReceiver receiver); + + /** + * Request to get whether the satellite service is supported on the device. + * + * @param subId The subId of the subscription to check whether satellite is supported for. + * @param receiver Result receiver to get the error code of the request and whether the + * satellite service is supported on the device. + */ + void requestIsSatelliteSupported(int subId, in ResultReceiver receiver); + + /** + * Request to get the capabilities of the satellite service. + * + * @param subId The subId of the subscription to get the capabilities for. + * @param receiver Result receiver to get the error code of the request and the requested + * capabilities of the satellite service. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestSatelliteCapabilities(int subId, in ResultReceiver receiver); + + /** + * Start receiving satellite transmission updates. + * + * @param subId The subId of the subscription to stop satellite transmission updates for. + * @param resultCallback The callback to get the result of the request. + * @param callback The callback to handle transmission updates. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void startSatelliteTransmissionUpdates(int subId, in IIntegerConsumer resultCallback, + in ISatelliteTransmissionUpdateCallback callback); + + /** + * Stop receiving satellite transmission updates. + * + * @param subId The subId of the subscritpion to stop satellite transmission updates for. + * @param resultCallback The callback to get the result of the request. + * @param callback The callback that was passed to startSatelliteTransmissionUpdates. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void stopSatelliteTransmissionUpdates(int subId, in IIntegerConsumer resultCallback, + in ISatelliteTransmissionUpdateCallback callback); + + /** + * Register the subscription with a satellite provider. + * This is needed to register the subscription if the provider allows dynamic registration. + * + * @param subId The subId of the subscription to be provisioned. + * @param token The token to be used as a unique identifier for provisioning with satellite + * gateway. + * @provisionData Data from the provisioning app that can be used by provisioning server + * @param callback The callback to get the result of the request. + * + * @return The signal transport used by callers to cancel the provision request. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + ICancellationSignal provisionSatelliteService(int subId, in String token, + in byte[] provisionData, in IIntegerConsumer callback); + + /** + * Unregister the subscription with the satellite provider. + * This is needed to unregister the subscription if the provider allows dynamic registration. + * Once deprovisioned, + * {@link SatelliteCallback.SatelliteProvisionStateListener#onSatelliteProvisionStateChanged} + * should report as deprovisioned. + * + * @param subId The subId of the subscription to be deprovisioned. + * @param token The token of the device/subscription to be deprovisioned. + * @param callback The callback to get the result of the request. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void deprovisionSatelliteService(int subId, in String token, in IIntegerConsumer callback); + + + /** + * Registers for provision state changed from satellite modem. + * + * @param subId The subId of the subscription to register for provision state changed. + * @param callback The callback to handle the satellite provision state changed event. + * + * @return The {@link SatelliteError} result of the operation. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + int registerForSatelliteProvisionStateChanged(int subId, + in ISatelliteProvisionStateCallback callback); + + /** + * Unregisters for provision state changed from satellite modem. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for provision state changed. + * @param callback The callback that was passed to registerForSatelliteProvisionStateChanged. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void unregisterForSatelliteProvisionStateChanged(int subId, + in ISatelliteProvisionStateCallback callback); + + /** + * Request to get whether the device is provisioned with a satellite provider. + * + * @param subId The subId of the subscription to get whether the device is provisioned for. + * @param receiver Result receiver to get the error code of the request and whether the + * device is provisioned with a satellite provider. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestIsSatelliteProvisioned(int subId, in ResultReceiver receiver); + + /** + * Registers for modem state changed from satellite modem. + * + * @param subId The subId of the subscription to register for satellite modem state changed. + * @param callback The callback to handle the satellite modem state changed event. + * + * @return The {@link SatelliteError} result of the operation. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + int registerForSatelliteModemStateChanged(int subId, ISatelliteStateCallback callback); + + /** + * Unregisters for modem state changed from satellite modem. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for satellite modem state changed. + * @param callback The callback that was passed to registerForSatelliteStateChanged. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void unregisterForSatelliteModemStateChanged(int subId, ISatelliteStateCallback callback); + + /** + * Register to receive incoming datagrams over satellite. + * + * @param subId The subId of the subscription to register for incoming satellite datagrams. + * @param callback The callback to handle the incoming datagrams. + * + * @return The {@link SatelliteError} result of the operation. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + int registerForSatelliteDatagram(int subId, ISatelliteDatagramCallback callback); + + /** + * Unregister to stop receiving incoming datagrams over satellite. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for incoming satellite datagrams. + * @param callback The callback that was passed to registerForSatelliteDatagram. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void unregisterForSatelliteDatagram(int subId, ISatelliteDatagramCallback callback); + + /** + * Poll pending satellite datagrams over satellite. + * + * @param subId The subId of the subscription used for receiving datagrams. + * @param callback The callback to get the result of the request. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void pollPendingSatelliteDatagrams(int subId, IIntegerConsumer callback); + + /** + * Send datagram over satellite. + * + * @param subId The subId of the subscription to send satellite datagrams for. + * @param datagramType Type of datagram. + * @param datagram Datagram to send over satellite. + * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in + * full screen mode. + * @param callback The callback to get the result of the request. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void sendSatelliteDatagram(int subId, int datagramType, + in SatelliteDatagram datagram, in boolean needFullScreenPointingUI, + IIntegerConsumer callback); + + /** + * Request to get whether satellite communication is allowed for the current location. + * + * @param subId The subId of the subscription to get whether satellite communication is allowed + * for the current location for. + * @param receiver Result receiver to get the error code of the request and whether satellite + * communication is allowed for the current location. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, + in ResultReceiver receiver); + + /** + * Request to get the time after which the satellite will be visible. + * + * @param subId The subId to get the time after which the satellite will be visible for. + * @param receiver Result receiver to get the error code of the request and the requested + * time after which the satellite will be visible. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestTimeForNextSatelliteVisibility(int subId, in ResultReceiver receiver); + + /** + * Inform whether the device is aligned with the satellite within in margin for demo mode. + * + * @param isAligned {@true} Device is aligned with the satellite for demo mode + * {@false} Device is not aligned with the satellite for demo mode + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void onDeviceAlignedWithSatellite(int subId, in boolean isAligned); + + /** + * This API can be used by only CTS to update satellite vendor service package name. + * + * @param servicePackageName The package name of the satellite vendor service. + * @return {@code true} if the satellite vendor service is set successfully, + * {@code false} otherwise. + */ + boolean setSatelliteServicePackageName(in String servicePackageName); + + /** + * This API can be used by only CTS to update satellite gateway service package name. + * + * @param servicePackageName The package name of the satellite gateway service. + * @return {@code true} if the satellite gateway service is set successfully, + * {@code false} otherwise. + */ + boolean setSatelliteGatewayServicePackageName(in String servicePackageName); + + /** + * This API can be used by only CTS to update the timeout duration in milliseconds that + * satellite should stay at listening mode to wait for the next incoming page before disabling + * listening mode. + * + * @param timeoutMillis The timeout duration in millisecond. + * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. + */ + boolean setSatelliteListeningTimeoutDuration(in long timeoutMillis); + + /** + * This API can be used by only CTS to update satellite pointing UI app package and class names. + * + * @param packageName The package name of the satellite pointing UI app. + * @param className The class name of the satellite pointing UI app. + * @return {@code true} if the satellite pointing UI app package and class is set successfully, + * {@code false} otherwise. + */ + boolean setSatellitePointingUiClassName(in String packageName, in String className); + + /** + * This API can be used by only CTS to update the timeout duration in milliseconds whether + * the device is aligned with the satellite for demo mode + * + * @param timeoutMillis The timeout duration in millisecond. + * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. + */ + boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis); + + /** + * Test method to confirm the file contents are not altered. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)") + List<String> getShaIdFromAllowList(String pkgName, int carrierId); } diff --git a/telephony/java/com/android/internal/telephony/ITransportSelectorCallback.aidl b/telephony/java/com/android/internal/telephony/ITransportSelectorCallback.aidl new file mode 100644 index 000000000000..6777256d171e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ITransportSelectorCallback.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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.internal.telephony; + +import com.android.internal.telephony.IDomainSelector; +import com.android.internal.telephony.ITransportSelectorResultCallback; +import com.android.internal.telephony.IWwanSelectorCallback; + +interface ITransportSelectorCallback { + oneway void onCreated(in IDomainSelector selector); + oneway void onWlanSelected(boolean useEmergencyPdn); + IWwanSelectorCallback onWwanSelected(); + oneway void onWwanSelectedAsync(in ITransportSelectorResultCallback cb); + oneway void onSelectionTerminated(int cause); +} diff --git a/telephony/java/com/android/internal/telephony/ITransportSelectorResultCallback.aidl b/telephony/java/com/android/internal/telephony/ITransportSelectorResultCallback.aidl new file mode 100644 index 000000000000..1460b45acac5 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ITransportSelectorResultCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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.internal.telephony; + +import com.android.internal.telephony.IWwanSelectorCallback; + +oneway interface ITransportSelectorResultCallback { + void onCompleted(in IWwanSelectorCallback cb); +} diff --git a/telephony/java/com/android/internal/telephony/IVoidConsumer.aidl b/telephony/java/com/android/internal/telephony/IVoidConsumer.aidl new file mode 100644 index 000000000000..b5557fde2a02 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IVoidConsumer.aidl @@ -0,0 +1,25 @@ +/* + * Copyright 2023 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.internal.telephony; + + /** + * Copies consumer pattern for an operation that requires void result from another process to + * finish. + */ + oneway interface IVoidConsumer { + void accept(); + }
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/IWwanSelectorCallback.aidl b/telephony/java/com/android/internal/telephony/IWwanSelectorCallback.aidl new file mode 100644 index 000000000000..94e7c871066e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IWwanSelectorCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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.internal.telephony; + +import com.android.internal.telephony.IWwanSelectorResultCallback; + +oneway interface IWwanSelectorCallback { + void onRequestEmergencyNetworkScan(in int[] preferredNetworks, + int scanType, in IWwanSelectorResultCallback cb); + void onDomainSelected(int domain, boolean useEmergencyPdn); + void onCancel(); +} diff --git a/telephony/java/com/android/internal/telephony/IWwanSelectorResultCallback.aidl b/telephony/java/com/android/internal/telephony/IWwanSelectorResultCallback.aidl new file mode 100644 index 000000000000..0d61fcbb266e --- /dev/null +++ b/telephony/java/com/android/internal/telephony/IWwanSelectorResultCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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.internal.telephony; + +import android.telephony.EmergencyRegResult; + +oneway interface IWwanSelectorResultCallback { + void onComplete(in EmergencyRegResult result); +} diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 813e80e6f355..07f2916838e8 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -226,6 +226,8 @@ public class PhoneConstants { // per 3GPP TS 31.102 (Section 7.1.2) public static final int AUTH_CONTEXT_EAP_SIM = 128; public static final int AUTH_CONTEXT_EAP_AKA = 129; + public static final int AUTH_CONTEXT_GBA_BOOTSTRAP = 132; + public static final int AUTHTYPE_GBA_NAF_KEY_EXTERNAL = 133; public static final int AUTH_CONTEXT_UNDEFINED = -1; /** @@ -237,4 +239,20 @@ public class PhoneConstants { public static final int CELL_OFF_FLAG = 0; public static final int CELL_ON_FLAG = 1; public static final int CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG = 2; + + /** The key to specify the selected domain for dialing calls. */ + public static final String EXTRA_DIAL_DOMAIN = "dial_domain"; + + /** + * Indicates that this call should be routed over Wi-Fi. + * An internal extension of NetworkRegistrationInfo's DOMAIN_* constants + * to also include NON_3GPP_PS routing for the domain selection service. + */ + public static final int DOMAIN_NON_3GPP_PS = 4; + + /** Key to enable comparison of domain selection results from legacy and new code. */ + public static final String EXTRA_COMPARE_DOMAIN = "compare_domain"; + + /** The key to specify the emergency service category */ + public static final String EXTRA_EMERGENCY_SERVICE_CATEGORY = "emergency_service_category"; } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 39ab7eb0973c..b273ba2e9f11 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -120,6 +120,31 @@ public interface RILConstants { int BLOCKED_DUE_TO_CALL = 69; /* SMS is blocked due to call control */ int RF_HARDWARE_ISSUE = 70; /* RF HW issue is detected */ int NO_RF_CALIBRATION_INFO = 71; /* No RF calibration in device */ + int ENCODING_NOT_SUPPORTED = 72; /* The encoding scheme is not supported by + either the network or the MS. */ + int FEATURE_NOT_SUPPORTED = 73; /* The requesting feature is not supported by + the service provider. */ + int INVALID_CONTACT = 74; /* The contact to be added is either not + existing or not valid. */ + int MODEM_INCOMPATIBLE = 75; /* The modem of the MS is not compatible with + the service provider. */ + int NETWORK_TIMEOUT = 76; /* Modem timeout to receive ACK or response from + network after sending a request to it. */ + int NO_SATELLITE_SIGNAL = 77; /* Modem fails to communicate with the satellite + network since there is no satellite signal.*/ + int NOT_SUFFICIENT_ACCOUNT_BALANCE = 78; /* The request cannot be performed since the + subscriber's account balance is not + sufficient. */ + int RADIO_TECHNOLOGY_NOT_SUPPORTED = 79; /* The radio technology is not supported by the + service provider. */ + int SUBSCRIBER_NOT_AUTHORIZED = 80; /* The subscription is not authorized to + register with the service provider. */ + int SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL = 81; /* While processing a request from the + Framework the satellite modem detects + terrestrial signal, aborts the request, and + switches to the terrestrial network. */ + int UNIDENTIFIED_SUBSCRIBER = 82; /* The subscriber is not registered with the + service provider */ // Below is list of OEM specific error codes which can by used by OEMs in case they don't want to // reveal particular replacement for Generic failure @@ -500,7 +525,7 @@ public interface RILConstants { int RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY = 149; int RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS = 150; int RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD = 151; - + int RIL_REQUEST_DEVICE_IMEI = 152; /* The following requests are not defined in RIL.h */ int RIL_REQUEST_HAL_NON_RIL_BASE = 200; int RIL_REQUEST_GET_SLOT_STATUS = 200; @@ -532,6 +557,21 @@ public interface RILConstants { int RIL_REQUEST_IS_VONR_ENABLED = 226; int RIL_REQUEST_SET_USAGE_SETTING = 227; int RIL_REQUEST_GET_USAGE_SETTING = 228; + int RIL_REQUEST_SET_EMERGENCY_MODE = 229; + int RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN = 230; + int RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN = 231; + int RIL_REQUEST_EXIT_EMERGENCY_MODE = 232; + int RIL_REQUEST_SET_SRVCC_CALL_INFO = 233; + int RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO = 234; + int RIL_REQUEST_START_IMS_TRAFFIC = 235; + int RIL_REQUEST_STOP_IMS_TRAFFIC = 236; + int RIL_REQUEST_SEND_ANBR_QUERY = 237; + int RIL_REQUEST_TRIGGER_EPS_FALLBACK = 238; + int RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED = 239; + int RIL_REQUEST_UPDATE_IMS_CALL_STATUS = 240; + int RIL_REQUEST_SET_N1_MODE_ENABLED = 241; + int RIL_REQUEST_IS_N1_MODE_ENABLED = 242; + int RIL_REQUEST_IS_NULL_CIPHER_AND_INTEGRITY_ENABLED = 259; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; @@ -602,4 +642,8 @@ public interface RILConstants { int RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED = 1103; int RIL_UNSOL_REGISTRATION_FAILED = 1104; int RIL_UNSOL_BARRING_INFO_CHANGED = 1105; + int RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT = 1106; + int RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION = 1107; + int RIL_UNSOL_CONNECTION_SETUP_FAILURE = 1108; + int RIL_UNSOL_NOTIFY_ANBR = 1109; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index b905212a9100..09101d88130c 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -212,23 +212,6 @@ public class TelephonyIntents { public static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE"; /** - * <p>Broadcast Action: It indicates one column of a subinfo record has been changed - * <p class="note">This is a protected intent that can only be sent - * by the system. - */ - public static final String ACTION_SUBINFO_CONTENT_CHANGE - = "android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE"; - - /** - * <p>Broadcast Action: It indicates subinfo record update is completed - * when SIM inserted state change - * <p class="note">This is a protected intent that can only be sent - * by the system. - */ - public static final String ACTION_SUBINFO_RECORD_UPDATED - = "android.intent.action.ACTION_SUBINFO_RECORD_UPDATED"; - - /** * Broadcast Action: The default subscription has changed. This has the following * extra values:</p> * <ul> diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java b/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java index f4f40361fb69..b70d548df969 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.gsm; +import java.util.Objects; + /** * SmsBroadcastConfigInfo defines one configuration of Cell Broadcast * Message (CBM) to be received by the ME @@ -130,4 +132,24 @@ public final class SmsBroadcastConfigInfo { mFromCodeScheme + ',' + mToCodeScheme + "] " + (mSelected ? "ENABLED" : "DISABLED"); } + + @Override + public int hashCode() { + return Objects.hash(mFromServiceId, mToServiceId, + mFromCodeScheme, mToCodeScheme, mSelected); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SmsBroadcastConfigInfo)) { + return false; + } + + SmsBroadcastConfigInfo other = (SmsBroadcastConfigInfo) obj; + + return mFromServiceId == other.mFromServiceId + && mToServiceId == other.mToServiceId + && mFromCodeScheme == other.mFromCodeScheme + && mToCodeScheme == other.mToCodeScheme && mSelected == other.mSelected; + } } |