Allow switchAfterDownload for org owned devices

Manual testing
Case 1:
1. No exisiting SIM on device
2. COPE PO/DO downloads managed eSIM
3. eSIM gets downloaded successfully and is in an active state.

Case 2:
1. Existing physical SIM present on device
2. COPE PO/DO downloads managed eSIM
3. eSIM gets downloaded successfully and is in active state.
4. Default for data/sms/call remains existing physical SIM and do not change to new managed eSIM.

Case 3:
1. Existing physical SIM and users personal eSIM present on device
2. COPE PO/DO downloads managed eSIM
3. eSIM downloads fails with EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR status code

Bug: 295301164
Test: atest EuiccControllerTest
Change-Id: I7e23c5c290e11fe4f532c0f5621c0099354cdb21
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java
index 18b4b14..2c39076 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java
@@ -615,25 +615,32 @@
     void downloadSubscription(int cardId, int portIndex, DownloadableSubscription subscription,
             boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
             Bundle resolvedBundle, PendingIntent callbackIntent) {
-        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
-        boolean callerCanDownloadAdminManagedSubscription =
-                Flags.esimManagementEnabled()
-                        && callerCanManageDevicePolicyManagedSubscriptions(callingPackage);
+        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
+
+        boolean callerHasAdminPrivileges = false;
         if (Flags.esimManagementEnabled()) {
-            if (mContext
-                    .getSystemService(UserManager.class)
-                    .hasUserRestriction(UserManager.DISALLOW_SIM_GLOBALLY)
-                    && !callerCanDownloadAdminManagedSubscription) {
+            callerHasAdminPrivileges = callerCanManageDevicePolicyManagedSubscriptions(
+                    callingPackage);
+            if (callerHasAdminPrivileges && (switchAfterDownload && !shouldAllowSwitchAfterDownload(
+                    callingPackage))) {
+                // Throw error if calling admin does not have privileges to enable
+                // subscription silently after download but switchAfterDownload is passed as true.
+                sendResult(callbackIntent, ERROR, null);
+                return;
+            }
+            if (mContext.getSystemService(UserManager.class).hasUserRestriction(
+                    UserManager.DISALLOW_SIM_GLOBALLY) && !callerHasAdminPrivileges) {
                 // Only admin managed subscriptions are allowed, but the caller is not authorised to
                 // download admin managed subscriptions. Abort.
-                throw new SecurityException("Caller is not authorized to download subscriptions");
+                sendResult(callbackIntent, ERROR, null);
+                return;
             }
         }
-        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
         // Don't try to resolve the port index for apps which are not targeting on T for backward
         // compatibility. instead always use default port 0.
         boolean shouldResolvePortIndex = isCompatChangeEnabled(callingPackage,
                 EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS);
+        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
 
         long token = Binder.clearCallingIdentity();
         try {
@@ -646,26 +653,19 @@
                 isConsentNeededToResolvePortIndex = (portIndex
                         == TelephonyManager.INVALID_PORT_INDEX);
             }
-            // Caller has admin privileges if they can download admin managed subscription,
-            // and are not switching the subscription after download (admins cannot silently
-            // enable the subscription).
-            boolean hasAdminPrivileges =
-                    callerCanDownloadAdminManagedSubscription && !switchAfterDownload;
             Log.d(TAG, " downloadSubscription cardId: " + cardId + " switchAfterDownload: "
-                    + switchAfterDownload + " portIndex: " + portIndex
-                    + " forceDeactivateSim: " + forceDeactivateSim + " callingPackage: "
-                    + callingPackage
+                    + switchAfterDownload + " portIndex: " + portIndex + " forceDeactivateSim: "
+                    + forceDeactivateSim + " callingPackage: " + callingPackage
                     + " isConsentNeededToResolvePortIndex: " + isConsentNeededToResolvePortIndex
                     + " shouldResolvePortIndex:" + shouldResolvePortIndex
-                    + " hasAdminPrivileges:" + hasAdminPrivileges);
-            if (!isConsentNeededToResolvePortIndex
-                    && (callerCanWriteEmbeddedSubscriptions
-                                    || hasAdminPrivileges)) {
+                    + " callerHasAdminPrivileges:" + callerHasAdminPrivileges);
+            if (!isConsentNeededToResolvePortIndex && (callerCanWriteEmbeddedSubscriptions
+                    || callerHasAdminPrivileges)) {
                 // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
                 // and move straight to the profile download.
                 downloadSubscriptionPrivileged(cardId, portIndex, token, subscription,
                         switchAfterDownload, forceDeactivateSim, callingPackage, resolvedBundle,
-                        callbackIntent, callerCanDownloadAdminManagedSubscription,
+                        callbackIntent, callerHasAdminPrivileges,
                         getCurrentEmbeddedSubscriptionIds(cardId));
                 return;
             }
@@ -862,8 +862,11 @@
                                             cardId,
                                             existingSubscriptions);
                                     return;
+                                } else if (markAsOwnedByAdmin) {
+                                    refreshSubscriptionsOwnership(true, callingPackage, cardId,
+                                            existingSubscriptions);
                                 }
-                                break;
+                            break;
                             case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
                                 resultCode = RESOLVABLE_ERROR;
                                 addResolutionIntentWithPort(extrasIntent,
@@ -1728,22 +1731,27 @@
         SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions(
                 List.of(mTelephonyManager.getCardIdForDefaultEuicc()),
                 () -> {
-                    if (Flags.esimManagementEnabled() && isCallerAdmin) {
-                        // Mark the newly downloaded subscriptions as being owned by an admin so
-                        // that actions for that subscription can be restricted,
-                        // and the admin is limited to effecting only these subscriptions.
-                        Set<Integer> subscriptionsAfter = getCurrentEmbeddedSubscriptionIds(cardId);
-                        subscriptionsAfter.removeAll(subscriptionsBefore);
-                        for (int subId: subscriptionsAfter) {
-                            SubscriptionManagerService
-                                    .getInstance().setGroupOwner(subId, callingPackage);
-                        }
-                    }
+                    refreshSubscriptionsOwnership(isCallerAdmin, callingPackage, cardId,
+                            subscriptionsBefore);
                     sendResult(callbackIntent, resultCode, extrasIntent);
                 });
 
     }
 
+    private void refreshSubscriptionsOwnership(boolean isCallerAdmin, String callingPackage,
+            int cardId, Set<Integer> subscriptionsBefore) {
+        if (Flags.esimManagementEnabled() && isCallerAdmin) {
+            // Mark the newly downloaded subscriptions as being owned by an admin so
+            // that actions for that subscription can be restricted,
+            // and the admin is limited to effecting only these subscriptions.
+            Set<Integer> subscriptionsAfter = getCurrentEmbeddedSubscriptionIds(cardId);
+            subscriptionsAfter.removeAll(subscriptionsBefore);
+            for (int subId : subscriptionsAfter) {
+                SubscriptionManagerService.getInstance().setGroupOwner(subId, callingPackage);
+            }
+        }
+    }
+
     /** Dispatch the given callback intent with the given result code and data. */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
@@ -2181,20 +2189,31 @@
     }
 
     private boolean callerCanManageDevicePolicyManagedSubscriptions(String callingPackage) {
-        // isProfileOwner/isDeviceOwner needs to callers user, so create device policy manager
-        // with the correct context associated with the caller.
+        DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
+        boolean isAdmin =
+                devicePolicyManager != null && (devicePolicyManager.isProfileOwnerApp(
+                        callingPackage)
+                        || devicePolicyManager.isDeviceOwnerApp(callingPackage));
+        return isAdmin || mContext.checkCallingOrSelfPermission(
+                Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    private boolean shouldAllowSwitchAfterDownload(String callingPackage) {
+        DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
+        return devicePolicyManager != null && (devicePolicyManager.isDeviceOwnerApp(callingPackage)
+                || (devicePolicyManager.isProfileOwnerApp(callingPackage)
+                && devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()));
+    }
+
+    private DevicePolicyManager getDevicePolicyManager() {
+        // create device policy manager with the correct context associated with the caller.
         DevicePolicyManager devicePolicyManager =
                 retrieveDevicePolicyManagerFromUserContext(Binder.getCallingUserHandle());
         if (devicePolicyManager == null) {
             Log.w(TAG, "Unable to get device policy manager");
-            return false;
         }
-        boolean isAdmin =
-                devicePolicyManager.isProfileOwnerApp(callingPackage)
-                        || devicePolicyManager.isDeviceOwnerApp(callingPackage);
-        return isAdmin || mContext.checkCallingOrSelfPermission(
-                Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS)
-                == PackageManager.PERMISSION_GRANTED;
+        return devicePolicyManager;
     }
 
     @Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 673acbc..e5e8d15 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -35,6 +35,7 @@
 import android.app.IActivityManager;
 import android.app.KeyguardManager;
 import android.app.PropertyInvalidatedCache;
+import android.app.admin.DevicePolicyManager;
 import android.app.usage.NetworkStatsManager;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -304,6 +305,7 @@
     protected AppOpsManager mAppOpsManager;
     protected CarrierConfigManager mCarrierConfigManager;
     protected UserManager mUserManager;
+    protected DevicePolicyManager mDevicePolicyManager;
     protected KeyguardManager mKeyguardManager;
     protected VcnManager mVcnManager;
     protected NetworkPolicyManager mNetworkPolicyManager;
@@ -630,6 +632,8 @@
         mCarrierConfigManager =
                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         mVcnManager = mContext.getSystemService(VcnManager.class);
         mNetworkPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
index 57ae9ed..a6e9fcb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
@@ -230,6 +230,7 @@
                 Settings.Global.EUICC_PROVISIONED, 0);
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.EUICC_PROVISIONED, 0);
+        setHasManageDevicePolicyManagedSubscriptionsPermission(false);
     }
 
     @After
@@ -894,7 +895,7 @@
 
     @Test
     @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
-    public void testDownloadSubscription_adminPermission_usingSwitchAfterDownload()
+    public void testDownloadSubscription_adminPermission_usingSwitchAfterDownload_fails()
             throws Exception {
         mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
         setHasWriteEmbeddedPermission(false);
@@ -909,18 +910,99 @@
         when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
         setCanManageSubscriptionOnTargetSim(false /* isTargetEuicc */, false /* hasPrivileges */);
 
-        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
+        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */,
+                true /* complete */,
                 12345, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
 
-        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR,
-                0 /* detailedCode */);
+        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
         verify(mMockConnector, never()).downloadSubscription(anyInt(), anyInt(),
                 any(), anyBoolean(), anyBoolean(), any(), any());
     }
 
     @Test
     @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
-    public void testDownloadSubscription_onlyAdminManagedAllowed_callerNotAdmin_throws()
+    public void testDownloadSubscription_profileOwner_usingSwitchAfterDownload_fails()
+            throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
+        setHasWriteEmbeddedPermission(false);
+        setHasManageDevicePolicyManagedSubscriptionsPermission(true);
+        setUpUiccSlotData();
+        GetDownloadableSubscriptionMetadataResult result =
+                new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
+                        SUBSCRIPTION_WITH_METADATA);
+        doReturn(true).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
+        doReturn(false).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
+        doReturn(false).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
+        prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = PACKAGE_NAME;
+        when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
+        setCanManageSubscriptionOnTargetSim(false /* isTargetEuicc */, false /* hasPrivileges */);
+
+        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */,
+                true /* complete */,
+                12345, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
+
+        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
+        verify(mMockConnector, never()).downloadSubscription(anyInt(), anyInt(), any(),
+                anyBoolean(), anyBoolean(), any(), any());
+    }
+
+    @Test
+    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
+    public void testDownloadSubscription_orgOwnedProfileOwner_usingSwitchAfterDownload_success()
+            throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
+        setHasWriteEmbeddedPermission(false);
+        setHasManageDevicePolicyManagedSubscriptionsPermission(true);
+        setUpUiccSlotData();
+        GetDownloadableSubscriptionMetadataResult result =
+                new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
+                        SUBSCRIPTION_WITH_METADATA);
+        doReturn(true).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
+        doReturn(true).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
+        doReturn(false).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
+        prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = PACKAGE_NAME;
+        when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
+
+        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
+                EuiccService.RESULT_OK, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
+
+        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0 /* detailedCode */);
+        assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
+    }
+
+    @Test
+    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
+    public void testDownloadSubscription_deviceOwner_usingSwitchAfterDownload_success()
+            throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
+        setHasWriteEmbeddedPermission(false);
+        setHasManageDevicePolicyManagedSubscriptionsPermission(true);
+        setUpUiccSlotData();
+        GetDownloadableSubscriptionMetadataResult result =
+                new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
+                        SUBSCRIPTION_WITH_METADATA);
+        doReturn(false).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
+        doReturn(false).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
+        doReturn(true).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
+        prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = PACKAGE_NAME;
+        when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
+
+        callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
+                EuiccService.RESULT_OK, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
+
+        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0 /* detailedCode */);
+        assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
+    }
+
+    @Test
+    @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
+    public void testDownloadSubscription_onlyAdminManagedAllowed_callerNotAdmin_error()
             throws Exception {
         mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
         setHasManageDevicePolicyManagedSubscriptionsPermission(false);
@@ -929,15 +1011,10 @@
                 .when(mUserManager)
                 .hasUserRestriction(UserManager.DISALLOW_SIM_GLOBALLY);
 
-        assertThrows(SecurityException.class,
-                () ->
-                        callDownloadSubscription(
-                                SUBSCRIPTION,
-                                false /* switchAfterDownload */,
-                                true /* complete */,
-                                EuiccService.RESULT_OK,
-                                0 /* resolvableError */,
-                                "whatever" /* callingPackage */));
+        callDownloadSubscription(SUBSCRIPTION, false /* switchAfterDownload */, true /* complete */,
+                12345, 0 /* resolvableError */, "whatever" /* callingPackage */);
+
+        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
         assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
     }