diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 9000e0703e85..03c8f8fc6891 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -189,6 +189,7 @@ package android { field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER"; field public static final String MANAGE_SPEECH_RECOGNITION = "android.permission.MANAGE_SPEECH_RECOGNITION"; field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS"; + field public static final String MANAGE_SUBSCRIPTION_USER_ASSOCIATION = "android.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION"; field public static final String MANAGE_TEST_NETWORKS = "android.permission.MANAGE_TEST_NETWORKS"; field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION"; field public static final String MANAGE_UI_TRANSLATION = "android.permission.MANAGE_UI_TRANSLATION"; @@ -13282,6 +13283,7 @@ package android.telephony { method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getCompleteActiveSubscriptionIdList(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int); method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public android.os.UserHandle getUserHandle(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int); method public void requestEmbeddedSubscriptionInfoListRefresh(); method public void requestEmbeddedSubscriptionInfoListRefresh(int); @@ -13292,6 +13294,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(int, boolean); + method @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public void setUserHandle(int, @Nullable android.os.UserHandle); field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED"; field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; field @NonNull public static final android.net.Uri CROSS_SIM_ENABLED_CONTENT_URI; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7002a524a6b9..a5e96176ec4c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3041,6 +3041,12 @@ + + + + diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index abb3cb3d0e14..a523d18377c7 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -54,6 +54,7 @@ import android.os.Looper; import android.os.ParcelUuid; import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.provider.Telephony.SimInfo; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; @@ -4201,5 +4202,80 @@ public class SubscriptionManager { return "UNKNOWN(" + usageSetting + ")"; } } + + /** + * Set userHandle for a subscription. + * + * Used to set an association between a subscription and a user on the device so that voice + * calling and SMS from that subscription can be associated with that user. + * Data services are always shared between users on the device. + * + * @param subscriptionId the subId of the subscription. + * @param userHandle the userHandle associated with the subscription. + * Pass {@code null} user handle to clear the association. + * + * @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 void setUserHandle(int subscriptionId, @Nullable UserHandle userHandle) { + if (!isValidSubscriptionId(subscriptionId)) { + throw new IllegalArgumentException("[setUserHandle]: Invalid subscriptionId: " + + subscriptionId); + } + + try { + ISub iSub = TelephonyManager.getSubscriptionService(); + if (iSub != null) { + iSub.setUserHandle(userHandle, subscriptionId, mContext.getOpPackageName()); + } else { + throw new IllegalStateException("[setUserHandle]: " + + "subscription service unavailable"); + } + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + } + + /** + * Get UserHandle of this subscription. + * + * Used to get user handle associated with this subscription. + * + * @param subscriptionId the subId of the subscription. + * @return userHandle associated with this subscription + * or {@code null} if subscription is not associated with any user. + * + * @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 getUserHandle(int subscriptionId) { + if (!isValidSubscriptionId(subscriptionId)) { + throw new IllegalArgumentException("[getUserHandle]: Invalid subscriptionId: " + + subscriptionId); + } + + try { + ISub iSub = TelephonyManager.getSubscriptionService(); + if (iSub != null) { + return iSub.getUserHandle(subscriptionId, mContext.getOpPackageName()); + } else { + throw new IllegalStateException("[getUserHandle]: " + + "subscription service unavailable"); + } + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + return null; + } } diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 1e38b9215d76..01a90b382626 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.telephony.SubscriptionInfo; import android.os.ParcelUuid; +import android.os.UserHandle; import com.android.internal.telephony.ISetOpportunisticDataCallback; interface ISub { @@ -324,4 +325,28 @@ interface ISub { * @throws SecurityException if doesn't have MODIFY_PHONE_STATE or Carrier Privileges */ int setUsageSetting(int usageSetting, int subId, String callingPackage); + + /** + * Set userHandle for this subscription. + * + * @param userHandle the user handle for this subscription + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage The package making the IPC. + * + * @throws SecurityException if doesn't have MANAGE_SUBSCRIPTION_USER_ASSOCIATION + * @throws IllegalArgumentException if subId is invalid. + */ + int setUserHandle(in UserHandle userHandle, int subId, String callingPackage); + + /** + * Get UserHandle for this subscription + * + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage the package making the IPC + * @return userHandle associated with this subscription. + * + * @throws SecurityException if doesn't have SMANAGE_SUBSCRIPTION_USER_ASSOCIATION + * @throws IllegalArgumentException if subId is invalid. + */ + UserHandle getUserHandle(int subId, String callingPackage); }