Merge "Add feature flag to clears cached IMS phone number when device lost IMS registration." into main
diff --git a/flags/data.aconfig b/flags/data.aconfig
index 0bcd4bd..8d05a51 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -20,3 +20,10 @@
   description: "Allow bring up MMTEL in nonVops area specified by carrier config."
   bug: "241198464"
 }
+
+flag {
+  name: "metered_embb_urlcc"
+  namespace: "telephony"
+  description: "Force networks that have PRIORITIZE_BANDWIDTH or PRIORITIZE_LATENCY to be metered."
+  bug: "301310451"
+}
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 950ac10..39e7325 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -598,10 +598,20 @@
      */
     public @NonNull @NetCapability Set<Integer> getMeteredNetworkCapabilities(boolean isRoaming) {
         Set<Integer> meteredApnTypes = isRoaming ? mRoamingMeteredApnTypes : mMeteredApnTypes;
-        return meteredApnTypes.stream()
+        Set<Integer> meteredCapabilities = meteredApnTypes.stream()
                 .map(DataUtils::apnTypeToNetworkCapability)
                 .filter(cap -> cap >= 0)
-                .collect(Collectors.toUnmodifiableSet());
+                .collect(Collectors.toSet());
+
+        // Consumer slices are the slices that are allowed to be accessed by regular application to
+        // get better performance. They should be metered. This can be turned into configurations in
+        // the future.
+        if (mFeatureFlags.meteredEmbbUrlcc()) {
+            meteredCapabilities.add(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH);
+            meteredCapabilities.add(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY);
+        }
+
+        return Collections.unmodifiableSet(meteredCapabilities);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 23473d2..6773dca 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -130,6 +130,7 @@
     private boolean mIsInEcm;
     private boolean mIsTestEmergencyNumber;
     private Runnable mOnEcmExitCompleteRunnable;
+    private int mOngoingCallProperties;
 
     /** For emergency SMS */
     private final Set<String> mOngoingEmergencySmsIds = new ArraySet<>();
@@ -447,6 +448,7 @@
             return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED);
         }
 
+        mOngoingCallProperties = 0;
         mCallEmergencyModeFuture = new CompletableFuture<>();
 
         if (mSmsPhone != null) {
@@ -487,6 +489,7 @@
 
         if (Objects.equals(mOngoingCallId, callId)) {
             mOngoingCallId = null;
+            mOngoingCallProperties = 0;
         }
 
         if (wasActive && mActiveEmergencyCalls.isEmpty()
@@ -520,6 +523,7 @@
         mIsEmergencyCallStartedDuringEmergencySms = false;
         mCallEmergencyModeFuture = null;
         mOngoingCallId = null;
+        mOngoingCallProperties = 0;
         mPhone = null;
     }
 
@@ -757,10 +761,36 @@
     public void onEmergencyCallStateChanged(Call.State state, String callId) {
         if (state == Call.State.ACTIVE) {
             mActiveEmergencyCalls.add(callId);
+            if (Objects.equals(mOngoingCallId, callId)) {
+                Rlog.i(TAG, "call connected " + callId);
+                if (mPhone != null
+                        && isVoWiFi(mOngoingCallProperties)
+                        && mEmergencyMode == EmergencyConstants.MODE_EMERGENCY_WLAN) {
+                    // Recover normal service in cellular when VoWiFi is connected
+                    mPhone.cancelEmergencyNetworkScan(true, null);
+                }
+            }
         }
     }
 
     /**
+     * Handles the change of emergency call properties.
+     *
+     * @param properties the new call properties.
+     * @param callId the callId whose state has changed.
+     */
+    public void onEmergencyCallPropertiesChanged(int properties, String callId) {
+        if (Objects.equals(mOngoingCallId, callId)) {
+            mOngoingCallProperties = properties;
+        }
+    }
+
+    private static boolean isVoWiFi(int properties) {
+        return (properties & android.telecom.Connection.PROPERTY_WIFI) > 0
+                || (properties & android.telecom.Connection.PROPERTY_CROSS_SIM) > 0;
+    }
+
+    /**
      * Returns {@code true} if device and carrier support emergency callback mode.
      */
     @VisibleForTesting
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 896063f..5148ecb 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -794,7 +794,7 @@
                     }
                     SessionMetricsStats.getInstance()
                             .setInitializationResult(error)
-                            .setRadioTechnology(SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY)
+                            .setRadioTechnology(getSupportedNtnRadioTechnology())
                             .reportSessionMetrics();
                 } else {
                     mControllerMetricsStats.onSatelliteDisabled();
@@ -1195,14 +1195,15 @@
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
         int error = evaluateOemSatelliteRequestAllowed(true);
         if (error != SATELLITE_RESULT_SUCCESS) {
-            result.accept(error);
+            sendErrorAndReportSessionMetrics(error, result);
             return;
         }
 
         if (enableSatellite) {
             if (!mIsRadioOn) {
                 loge("Radio is not on, can not enable satellite");
-                result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE);
+                sendErrorAndReportSessionMetrics(
+                        SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE, result);
                 return;
             }
         } else {
@@ -1216,12 +1217,14 @@
                     if (enableDemoMode != mIsDemoModeEnabled) {
                         loge("Received invalid demo mode while satellite session is enabled"
                                 + " enableDemoMode = " + enableDemoMode);
-                        result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS);
+                        sendErrorAndReportSessionMetrics(
+                                SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS, result);
                         return;
                     } else {
                         logd("Enable request matches with current state"
                                 + " enableSatellite = " + enableSatellite);
-                        result.accept(SATELLITE_RESULT_SUCCESS);
+                        sendErrorAndReportSessionMetrics(
+                                SatelliteManager.SATELLITE_RESULT_SUCCESS, result);
                         return;
                     }
                 }
@@ -1246,13 +1249,15 @@
             } else if (mSatelliteEnabledRequest.enableSatellite == request.enableSatellite) {
                 logd("requestSatelliteEnabled enableSatellite: " + enableSatellite
                         + " is already in progress.");
-                result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS);
+                sendErrorAndReportSessionMetrics(
+                        SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS, result);
                 return;
             } else if (mSatelliteEnabledRequest.enableSatellite == false
                     && request.enableSatellite == true) {
                 logd("requestSatelliteEnabled enableSatellite: " + enableSatellite + " cannot be "
                         + "processed. Disable satellite is already in progress.");
-                result.accept(SatelliteManager.SATELLITE_RESULT_ERROR);
+                sendErrorAndReportSessionMetrics(
+                        SatelliteManager.SATELLITE_RESULT_ERROR, result);
                 return;
             }
         }
@@ -1295,6 +1300,7 @@
      */
     public boolean isSatelliteEnabled() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("isSatelliteEnabled: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         if (mIsSatelliteEnabled == null) return false;
@@ -1328,6 +1334,7 @@
      */
     public boolean isDemoModeEnabled() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("isDemoModeEnabled: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         return mIsDemoModeEnabled;
@@ -1342,6 +1349,7 @@
      */
     public void requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("requestIsSatelliteSupported: oemEnabledSatelliteFlag is disabled");
             result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
             return;
         }
@@ -1553,6 +1561,8 @@
     public void unregisterForSatelliteProvisionStateChanged(
             int subId, @NonNull ISatelliteProvisionStateCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("unregisterForSatelliteProvisionStateChanged: "
+                    + "oemEnabledSatelliteFlag is disabled");
             return;
         }
         mSatelliteProvisionStateChangedListeners.remove(callback.asBinder());
@@ -1597,6 +1607,7 @@
     @SatelliteManager.SatelliteResult public int registerForSatelliteModemStateChanged(int subId,
             @NonNull ISatelliteStateCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("registerForSatelliteModemStateChanged: oemEnabledSatelliteFlag is disabled");
             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
         }
         if (mSatelliteSessionController != null) {
@@ -1620,6 +1631,7 @@
     public void unregisterForSatelliteModemStateChanged(int subId,
             @NonNull ISatelliteStateCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("unregisterForSatelliteModemStateChanged: oemEnabledSatelliteFlag is disabled");
             return;
         }
         if (mSatelliteSessionController != null) {
@@ -1641,6 +1653,7 @@
     @SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId,
             @NonNull ISatelliteDatagramCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("registerForSatelliteDatagram: oemEnabledSatelliteFlag is disabled");
             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
         }
         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
@@ -1660,6 +1673,7 @@
     public void unregisterForSatelliteDatagram(int subId,
             @NonNull ISatelliteDatagramCallback callback) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("unregisterForSatelliteDatagram: oemEnabledSatelliteFlag is disabled");
             return;
         }
         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
@@ -1774,6 +1788,7 @@
      */
     public void setDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setDeviceAlignedWithSatellite: oemEnabledSatelliteFlag is disabled");
             return;
         }
         mDatagramController.setDeviceAlignedWithSatellite(isAligned);
@@ -1866,6 +1881,8 @@
      */
     @NonNull public Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier(int subId) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("getSatelliteAttachRestrictionReasonsForCarrier: carrierEnabledSatelliteFlag is "
+                    + "disabled");
             return new HashSet<>();
         }
         synchronized (mIsSatelliteEnabledLock) {
@@ -1956,9 +1973,13 @@
      */
     public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteServicePackageName: oemEnabledSatelliteFlag is disabled");
             return false;
         }
-        if (!isMockModemAllowed()) return false;
+        if (!isMockModemAllowed()) {
+            logd("setSatelliteServicePackageName: mock modem not allowed");
+            return false;
+        }
 
         // Cached states need to be cleared whenever switching satellite vendor services.
         logd("setSatelliteServicePackageName: Resetting cached states");
@@ -1988,6 +2009,7 @@
      */
     public boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteListeningTimeoutDuration: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         if (mSatelliteSessionController == null) {
@@ -2006,6 +2028,7 @@
      */
     public boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteDeviceAlignedTimeoutDuration: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         return mDatagramController.setSatelliteDeviceAlignedTimeoutDuration(timeoutMillis);
@@ -2020,6 +2043,7 @@
      */
     public boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatelliteGatewayServicePackageName: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         if (mSatelliteSessionController == null) {
@@ -2041,6 +2065,7 @@
     public boolean setSatellitePointingUiClassName(
             @Nullable String packageName, @Nullable String className) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setSatellitePointingUiClassName: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         return mPointingAppController.setSatellitePointingUiClassName(packageName, className);
@@ -2060,6 +2085,7 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public void onSatelliteServiceConnected() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("onSatelliteServiceConnected: oemEnabledSatelliteFlag is disabled");
             return;
         }
         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
@@ -2110,6 +2136,7 @@
      */
     public boolean isSatelliteSupported() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("isSatelliteSupported: oemEnabledSatelliteFlag is disabled");
             return false;
         }
         Boolean supported = isSatelliteSupportedInternal();
@@ -2123,6 +2150,7 @@
     @NonNull
     public List<String> getSatellitePlmnList(int subId) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("getSatellitePlmnList: carrierEnabledSatelliteFlag is disabled");
             return new ArrayList<>();
         }
         synchronized (mSupportedSatelliteServicesLock) {
@@ -2143,6 +2171,7 @@
     @NonNull
     public List<Integer> getSupportedSatelliteServices(int subId, String plmn) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("getSupportedSatelliteServices: carrierEnabledSatelliteFlag is disabled");
             return new ArrayList<>();
         }
         synchronized (mSupportedSatelliteServicesLock) {
@@ -2983,6 +3012,30 @@
         return SATELLITE_RESULT_SUCCESS;
     }
 
+    /**
+     * Returns the non-terrestrial network radio technology that the satellite modem currently
+     * supports. If multiple technologies are available, returns the first supported technology.
+     */
+    @VisibleForTesting
+    protected @SatelliteManager.NTRadioTechnology int getSupportedNtnRadioTechnology() {
+        synchronized (mSatelliteCapabilitiesLock) {
+            if (mSatelliteCapabilities != null) {
+                return mSatelliteCapabilities.getSupportedRadioTechnologies()
+                        .stream().findFirst().orElse(SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN);
+            }
+            return SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN;
+        }
+    }
+
+    private void sendErrorAndReportSessionMetrics(@SatelliteManager.SatelliteResult int error,
+            Consumer<Integer> result) {
+        result.accept(error);
+        SessionMetricsStats.getInstance()
+                .setInitializationResult(error)
+                .setRadioTechnology(getSupportedNtnRadioTechnology())
+                .reportSessionMetrics();
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index 62f7371..dc6ea13 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -30,6 +30,8 @@
 import android.os.Message;
 import android.os.RegistrantList;
 import android.os.RemoteException;
+import android.telephony.IBooleanConsumer;
+import android.telephony.IIntegerConsumer;
 import android.telephony.Rlog;
 import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
@@ -47,8 +49,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.ExponentialBackoff;
-import com.android.internal.telephony.IBooleanConsumer;
-import com.android.internal.telephony.IIntegerConsumer;
 
 import java.util.Arrays;
 import java.util.List;
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index a952197..8146983 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.compat.CompatChanges;
@@ -44,9 +45,11 @@
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.TelephonyServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Telephony.SimInfo;
 import android.service.carrier.CarrierIdentifier;
@@ -124,6 +127,7 @@
 import java.util.concurrent.Executor;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
+import java.util.stream.Stream;
 
 /**
  * The subscription manager service is the backend service of {@link SubscriptionManager}.
@@ -131,6 +135,8 @@
  */
 public class SubscriptionManagerService extends ISub.Stub {
     private static final String LOG_TAG = "SMSVC";
+    private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
+    private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem";
 
     /** Whether enabling verbose debugging message or not. */
     private static final boolean VDBG = false;
@@ -189,6 +195,18 @@
     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
     public static final long REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L;
 
+    /**
+     * Apps targeting on Android V and beyond can only see subscriptions accessible by them
+     * according to its user Id.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    public static final long FILTER_ACCESSIBLE_SUBS_BY_USER = 296076674L;
+
+    /** Wrap Binder methods for testing. */
+    @NonNull
+    private static final BinderWrapper BINDER_WRAPPER = new BinderWrapper();
+
     /** Instance of subscription manager service. */
     @NonNull
     private static SubscriptionManagerService sInstance;
@@ -285,6 +303,12 @@
     private final int[] mSimState;
 
     /**
+     * {@code true} if a user profile can only see the SIMs associated with it, unless it possesses
+     * no SIMs on the device.
+     */
+    private Map<Integer, List<Integer>> mUserIdToAvailableSubs = new ConcurrentHashMap<>();
+
+    /**
      * Slot index/subscription map that automatically invalidate cache in
      * {@link SubscriptionManager}.
      *
@@ -357,6 +381,14 @@
         }
     }
 
+    /** Binder Wrapper for test mocking. */
+    @VisibleForTesting
+    public static class BinderWrapper {
+        @NonNull public UserHandle getCallingUserHandle() {
+            return Binder.getCallingUserHandle();
+        }
+    }
+
     /**
      * This is the callback used for listening events from {@link SubscriptionManagerService}.
      */
@@ -511,6 +543,8 @@
                      */
                     @Override
                     public void onSubscriptionChanged(int subId) {
+                        updateUserIdToAvailableSubs();
+
                         mSubscriptionManagerServiceCallbacks.forEach(
                                 callback -> callback.invokeFromExecutor(
                                         () -> callback.onSubscriptionChanged(subId)));
@@ -1146,6 +1180,8 @@
                         if (mFeatureFlags.oemEnabledSatelliteFlag()) {
                             builder.setOnlyNonTerrestrialNetwork(
                                     isSatellitePlmn(mcc + mnc) ? 1 : 0);
+                        } else {
+                            log("updateEmbeddedSubscriptions: oemEnabledSatelliteFlag is disabled");
                         }
                     }
                     // If cardId = unsupported or un-initialized, we have no reason to update DB.
@@ -1658,7 +1694,8 @@
     }
 
     /**
-     * Get all subscription info records from SIMs that are inserted now or previously inserted.
+     * Get all subscription info records from SIMs visible to the calling user that are inserted now
+     * or previously inserted.
      *
      * <p>
      * If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission,
@@ -1698,8 +1735,7 @@
             throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or "
                     + "carrier privilege");
         }
-
-        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+        return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle())
                 // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full
                 // list. Carrier apps can only get the subscriptions they have privileged.
                 .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow(
@@ -1828,8 +1864,8 @@
     }
 
     /**
-     * Get the SubscriptionInfo(s) of the active subscriptions. The records will be sorted
-     * by {@link SubscriptionInfo#getSimSlotIndex} then by
+     * Get the SubscriptionInfo(s) of the active subscriptions for calling user. The records will be
+     * sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
      * {@link SubscriptionInfo#getSubscriptionId}.
      *
      * @param callingPackage The package making the call.
@@ -1852,7 +1888,7 @@
         // on the subs it has carrier privilege.
         if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext,
                 Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId,
-                "getAllSubInfoList")) {
+                "getActiveSubscriptionInfoList")) {
             // Ideally we should avoid silent failure, but since this API has already been used by
             // many apps and they do not expect the security exception, we return an empty list
             // here so it's consistent with pre-U behavior.
@@ -1860,14 +1896,13 @@
                     + "permission. Returning empty list here.");
             return Collections.emptyList();
         }
-
-        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+        return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle())
                 .filter(SubscriptionInfoInternal::isActive)
                 // Remove the identifier if the caller does not have sufficient permission.
                 // carrier apps will get full subscription info on the subscriptions associated
                 // to them.
                 .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(),
-                        callingPackage, callingFeatureId, "getAllSubInfoList"))
+                        callingPackage, callingFeatureId, "getActiveSubscriptionInfoList"))
                 .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex)
                         .thenComparing(SubscriptionInfo::getSubscriptionId))
                 .collect(Collectors.toList());
@@ -1897,13 +1932,7 @@
             throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or "
                     + "carrier privilege");
         }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            return getActiveSubIdList(false).length;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        return getActiveSubIdListAsUser(false, BINDER_WRAPPER.getCallingUserHandle()).length;
     }
 
     /**
@@ -1934,27 +1963,42 @@
             @Nullable String callingFeatureId) {
         enforcePermissions("getAvailableSubscriptionInfoList",
                 Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        return getAvailableSubscriptionsInternalStream()
+                .sorted(Comparator.comparing(SubscriptionInfoInternal::getSimSlotIndex)
+                        .thenComparing(SubscriptionInfoInternal::getSubscriptionId))
+                .map(SubscriptionInfoInternal::toSubscriptionInfo)
+                .collect(Collectors.toList());
 
-        // Now that all security checks pass, perform the operation as ourselves.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if
-            // they are in inactive slot or programmatically disabled, they are still considered
-            // available. In this case we get their iccid from slot info and include their
-            // subscriptionInfos.
-            List<String> iccIds = getIccIdsOfInsertedPhysicalSims();
+    }
 
-            return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
-                    .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId())
-                            || (mEuiccManager != null && mEuiccManager.isEnabled()
-                            && subInfo.isEmbedded()))
-                    .map(SubscriptionInfoInternal::toSubscriptionInfo)
-                    .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex)
-                            .thenComparing(SubscriptionInfo::getSubscriptionId))
-                    .collect(Collectors.toList());
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+    /**
+     * @return all the subscriptions visible to user on the device.
+     */
+    private Stream<SubscriptionInfoInternal> getAvailableSubscriptionsInternalStream() {
+        // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if
+        // they are in inactive slot or programmatically disabled, they are still considered
+        // available. In this case we get their iccid from slot info and include their
+        // subscriptionInfos.
+        List<String> iccIds = getIccIdsOfInsertedPhysicalSims();
+
+        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+                .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId())
+                        || (mEuiccManager != null && mEuiccManager.isEnabled()
+                        && subInfo.isEmbedded()));
+    }
+
+    /**
+     * Tracks for each user Id, a list of subscriptions associated with it.
+     * A profile is barred from seeing unassociated subscriptions if it has its own subscription
+     * which is available to choose from the device.
+     */
+    private void updateUserIdToAvailableSubs() {
+        mUserIdToAvailableSubs = getAvailableSubscriptionsInternalStream()
+                .collect(Collectors.groupingBy(
+                        SubscriptionInfoInternal::getUserId,
+                        Collectors.mapping(SubscriptionInfoInternal::getSubscriptionId,
+                                Collectors.toList())));
+        log("updateUserIdToAvailableSubs: " + mUserIdToAvailableSubs);
     }
 
     /**
@@ -1989,8 +2033,7 @@
 
         // Verify that the callingPackage belongs to the calling UID
         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
-
-        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+        return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle())
                 .map(SubscriptionInfoInternal::toSubscriptionInfo)
                 .filter(subInfo -> subInfo.isEmbedded()
                         && mSubscriptionManager.canManageSubscription(subInfo, callingPackage))
@@ -2781,10 +2824,37 @@
 
     /**
      * @return The default subscription id.
+     * @deprecated Use {@link #getDefaultSubIdAsUser}.
      */
     @Override
     public int getDefaultSubId() {
-        return mDefaultSubId.get();
+        return getDefaultSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier());
+    }
+
+    /**
+     * @param userId The given user Id to check.
+     * @return The default subscription id.
+     */
+    @Override
+    public int getDefaultSubIdAsUser(@UserIdInt int userId) {
+        return getDefaultAsUser(userId, mDefaultSubId.get());
+    }
+
+    /**
+     * Get the default subscription visible to the caller.
+     * @param userId The calling user Id.
+     * @param defaultValue Useful if the user owns more than one subscription.
+     * @return The subscription Id default to use.
+     */
+    private int getDefaultAsUser(@UserIdInt int userId, int defaultValue) {
+        List<SubscriptionInfoInternal> subInfos =
+                getSubscriptionInfoStreamAsUser(UserHandle.of(userId))
+                        .filter(SubscriptionInfoInternal::isActive)
+                        .toList();
+        if (subInfos.size() == 1) {
+            return subInfos.get(0).getSubscriptionId();
+        }
+        return defaultValue;
     }
 
     /**
@@ -2876,10 +2946,20 @@
 
     /**
      * @return The default subscription id for voice.
+     * @deprecated Use {@link #getDefaultVoiceSubIdAsUser}.
      */
     @Override
     public int getDefaultVoiceSubId() {
-        return mDefaultVoiceSubId.get();
+        return getDefaultVoiceSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier());
+    }
+
+    /**
+     * @param userId The calling user Id.
+     * @return The default voice subscription id.
+     */
+    @Override
+    public int getDefaultVoiceSubIdAsUser(@UserIdInt int userId) {
+        return getDefaultAsUser(userId, mDefaultVoiceSubId.get());
     }
 
     /**
@@ -2922,10 +3002,24 @@
 
     /**
      * @return The default subscription id for SMS.
+     * @deprecated Use {@link #getDefaultSmsSubIdAsUser}.
      */
     @Override
     public int getDefaultSmsSubId() {
-        return mDefaultSmsSubId.get();
+        return getDefaultSmsSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier());
+    }
+
+    /**
+     * Get the default sms subscription id associated with the user. When a subscription is
+     * associated with personal profile or work profile, the default sms subscription id will be
+     * always the subscription it is associated with.
+     *
+     * @param userId The given user Id to check.
+     * @return The default voice id.
+     */
+    @Override
+    public int getDefaultSmsSubIdAsUser(@UserIdInt int userId) {
+        return getDefaultAsUser(userId, mDefaultSmsSubId.get());
     }
 
     /**
@@ -2982,19 +3076,30 @@
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public int[] getActiveSubIdList(boolean visibleOnly) {
         enforcePermissions("getActiveSubIdList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        // UserHandle.ALL because this API is exposed as system API.
+        return getActiveSubIdListAsUser(visibleOnly, UserHandle.ALL);
+    }
 
-        final long token = Binder.clearCallingIdentity();
-        try {
-            return mSlotIndexToSubId.values().stream()
-                    .filter(subId -> {
-                        SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
-                                .getSubscriptionInfoInternal(subId);
-                        return subInfo != null && (!visibleOnly || subInfo.isVisible()); })
-                    .mapToInt(x -> x)
-                    .toArray();
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+    /**
+     * Get the active subscription id list as user.
+     * Must be used before clear Binder identity.
+     *
+     * @param visibleOnly {@code true} if only includes user visible subscription's sub id.
+     * @param user If {@code null}, uses the calling user handle to judge which subscriptions are
+     *             accessible to the caller.
+     * @return List of the active subscription id.
+     */
+    private int[] getActiveSubIdListAsUser(boolean visibleOnly, @NonNull final UserHandle user) {
+        return mSlotIndexToSubId.values().stream()
+                .filter(subId -> {
+                    SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
+                            .getSubscriptionInfoInternal(subId);
+                    return subInfo != null && (!visibleOnly || subInfo.isVisible())
+                            && isSubscriptionAssociatedWithUserInternal(
+                                    subInfo, user.getIdentifier());
+                })
+                .mapToInt(x -> x)
+                .toArray();
     }
 
     /**
@@ -3658,26 +3763,28 @@
             @NonNull UserHandle userHandle) {
         enforcePermissions("isSubscriptionAssociatedWithUser",
                 Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        SubscriptionInfoInternal subInfoInternal = mSubscriptionDatabaseManager
+                .getSubscriptionInfoInternal(subscriptionId);
+        // Throw IAE if no record of the sub's association state.
+        if (subInfoInternal == null) {
+            throw new IllegalArgumentException(
+                    "[isSubscriptionAssociatedWithUser]: Subscription doesn't exist: "
+                            + subscriptionId);
+        }
+
+        if (mFeatureFlags.workProfileApiSplit()) {
+            return isSubscriptionAssociatedWithUserInternal(
+                    subInfoInternal, userHandle.getIdentifier());
+        }
 
         long token = Binder.clearCallingIdentity();
         try {
-            // Throw IAE if no record of the sub's association state.
-            if (mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subscriptionId) == null) {
-                throw new IllegalArgumentException(
-                        "[isSubscriptionAssociatedWithUser]: Subscription doesn't exist: "
-                                + subscriptionId);
-            }
-
             // Get list of subscriptions associated with this user.
             List<SubscriptionInfo> associatedSubscriptionsList =
                     getSubscriptionInfoListAssociatedWithUser(userHandle);
-            if (associatedSubscriptionsList.isEmpty()) {
-                return false;
-            }
-
             // Return true if required subscription is present in associated subscriptions list.
             for (SubscriptionInfo subInfo: associatedSubscriptionsList) {
-                if (subInfo.getSubscriptionId() == subscriptionId){
+                if (subInfo.getSubscriptionId() == subscriptionId) {
                     return true;
                 }
             }
@@ -3688,6 +3795,25 @@
     }
 
     /**
+     * @param subInfo The subscription info to check.
+     * @param userId The caller user Id.
+     * @return {@code true} if the given user Id is allowed to access to the given subscription.
+     */
+    private boolean isSubscriptionAssociatedWithUserInternal(
+            @NonNull SubscriptionInfoInternal subInfo, @UserIdInt int userId) {
+        if (!mFeatureFlags.workProfileApiSplit()
+                || !CompatChanges.isChangeEnabled(FILTER_ACCESSIBLE_SUBS_BY_USER,
+                Binder.getCallingUid())) {
+            return true;
+        }
+        return subInfo.getUserId() == userId
+                // Can access the unassociated sub if the user doesn't have its own.
+                || (subInfo.getUserId() == UserHandle.USER_NULL
+                && mUserIdToAvailableSubs.get(userId) == null)
+                || userId == UserHandle.USER_ALL;
+    }
+
+    /**
      * Get list of subscriptions associated with user.
      *
      * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser
@@ -3700,11 +3826,18 @@
      *
      */
     @Override
-    public @NonNull List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(
+    @NonNull
+    public List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(
             @NonNull UserHandle userHandle) {
         enforcePermissions("getSubscriptionInfoListAssociatedWithUser",
                 Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
 
+        if (mFeatureFlags.workProfileApiSplit()) {
+            return getSubscriptionInfoStreamAsUser(userHandle)
+                    .map(SubscriptionInfoInternal::toSubscriptionInfo)
+                    .collect(Collectors.toList());
+        }
+
         long token = Binder.clearCallingIdentity();
         try {
             List<SubscriptionInfoInternal> subInfoList =  mSubscriptionDatabaseManager
@@ -3728,20 +3861,45 @@
             UserManager userManager = mContext.getSystemService(UserManager.class);
             if ((userManager != null)
                     && (userManager.isManagedProfile(userHandle.getIdentifier()))) {
-                // For work profile, return subscriptions associated only with work profile
+                // For work profile, return subscriptions associated only with work profile even
+                // if it's empty.
                 return subscriptionsAssociatedWithUser;
             }
 
-            // For all other profiles, if subscriptionsAssociatedWithUser is empty return all the
-            // subscriptionsWithNoAssociation.
-            return subscriptionsAssociatedWithUser.isEmpty() ?
-                    subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser;
+            // For all other profiles, if subscriptionsAssociatedWithUser is empty return all
+            // the subscriptionsWithNoAssociation.
+            return subscriptionsAssociatedWithUser.isEmpty()
+                    ? subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser;
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
     /**
+     * @return All active subscriptions.
+     */
+    @NonNull
+    private List<SubscriptionInfoInternal> getActiveSubscriptionInfoListAllUser() {
+        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+                .filter(SubscriptionInfoInternal::isActive)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Get subscriptions accessible to the caller user.
+     *
+     * @param user The user to check.
+     * @return a stream of accessible internal subscriptions.
+     */
+    @NonNull
+    private Stream<SubscriptionInfoInternal> getSubscriptionInfoStreamAsUser(
+            @NonNull final UserHandle user) {
+        return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
+                .filter(info -> isSubscriptionAssociatedWithUserInternal(
+                        info, user.getIdentifier()));
+    }
+
+    /**
      * 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 {@link SimInfo}.
      * Internally, it will store the backup data in an internal file. This file will persist on
@@ -3808,14 +3966,26 @@
      * @throws SecurityException if the caller does not have any permissions.
      */
     private void enforcePermissions(@Nullable String message, @NonNull String ...permissions) {
+        if (!hasPermissions(permissions)) {
+            throw new SecurityException(
+                    message + ". Does not have any of the following permissions. "
+                            + Arrays.toString(permissions));
+        }
+    }
+
+    /**
+     * Check have any of the permissions
+     * @param permissions The permissions to check.
+     * @return {@code true} if the caller has one of the given permissions.
+     */
+    private boolean hasPermissions(@NonNull String ...permissions) {
         for (String permission : permissions) {
             if (mContext.checkCallingOrSelfPermission(permission)
                     == PackageManager.PERMISSION_GRANTED) {
-                return;
+                return true;
             }
         }
-        throw new SecurityException(message + ". Does not have any of the following permissions. "
-                + Arrays.toString(permissions));
+        return false;
     }
 
     /**
@@ -3839,9 +4009,8 @@
      */
     @Nullable
     public SubscriptionInfo getSubscriptionInfo(int subId) {
-        SubscriptionInfoInternal subscriptionInfoInternal = getSubscriptionInfoInternal(subId);
-        return subscriptionInfoInternal != null
-                ? subscriptionInfoInternal.toSubscriptionInfo() : null;
+        SubscriptionInfoInternal infoInternal = getSubscriptionInfoInternal(subId);
+        return infoInternal != null ? infoInternal.toSubscriptionInfo() : null;
     }
 
     /**
@@ -3958,8 +4127,7 @@
      */
     @VisibleForTesting
     public void updateGroupDisabled() {
-        List<SubscriptionInfo> activeSubscriptions = getActiveSubscriptionInfoList(
-                mContext.getOpPackageName(), mContext.getFeatureId());
+        List<SubscriptionInfoInternal> activeSubscriptions = getActiveSubscriptionInfoListAllUser();
         for (SubscriptionInfo oppSubInfo : getOpportunisticSubscriptions(
                 mContext.getOpPackageName(), mContext.getFeatureId())) {
             boolean groupDisabled = activeSubscriptions.stream()
@@ -3987,6 +4155,7 @@
      */
     private boolean isSatellitePlmn(@NonNull String mccMnc) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            log("isSatellitePlmn: oemEnabledSatelliteFlag is disabled");
             return false;
         }
 
@@ -3997,11 +4166,19 @@
         } catch (Resources.NotFoundException ex) {
             loge("isSatellitePlmn: id= " + id + ", ex=" + ex);
         }
-        if (overlayMccMnc == null) {
-            return false;
-        } else {
-            return mccMnc.equals(overlayMccMnc);
+        if (TextUtils.isEmpty(overlayMccMnc) && isMockModemAllowed()) {
+            log("isSatellitePlmn: Read config_satellite_sim_identifier from device config");
+            overlayMccMnc = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY,
+                    "config_satellite_sim_identifier", "");
         }
+        log("isSatellitePlmn: overlayMccMnc=" + overlayMccMnc + ", mccMnc=" + mccMnc);
+        return TextUtils.equals(mccMnc, overlayMccMnc);
+    }
+
+    private boolean isMockModemAllowed() {
+        boolean isAllowed = SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false);
+        return (SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)
+                || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false));
     }
 
     /**
@@ -4066,6 +4243,7 @@
             pw.println("activeDataSubId=" + getActiveDataSubscriptionId());
             pw.println("defaultSmsSubId=" + getDefaultSmsSubId());
             pw.println("areAllSubscriptionsLoaded=" + areAllSubscriptionsLoaded());
+            pw.println("mUserIdToAvailableSubs=" + mUserIdToAvailableSubs);
             pw.println();
             for (int i = 0; i < mSimState.length; i++) {
                 pw.println("mSimState[" + i + "]="
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index a7382ef..0459bf6 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -597,8 +597,6 @@
                         log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "
                                 + "getIccCardStatus");
                     }
-                    mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
-                            phoneId));
                     // slot status should be the same on all RILs; request it only for phoneId 0
                     if (phoneId == 0) {
                         if (DBG) {
@@ -608,6 +606,8 @@
                         mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,
                                 phoneId));
                     }
+                    mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
+                            phoneId));
                     break;
                 case EVENT_GET_ICC_STATUS_DONE:
                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
index 4fcf620..005b312 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
@@ -18,18 +18,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
+import android.net.NetworkCapabilities;
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -51,7 +50,6 @@
         logd("DataConfigManagerTest +Setup!");
         super.setUp(getClass().getSimpleName());
         mBundle = mContextFixture.getCarrierConfigBundle();
-        when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle);
         mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper(), mFeatureFlags);
         logd("DataConfigManagerTest -Setup!");
     }
@@ -145,4 +143,24 @@
                 signalStrength))
                 .isEqualTo(0/*OUT_OF_SERVICE_AUTO_DATA_SWITCH_SCORE*/);
     }
+
+    @Test
+    public void testMeteredNetworkCapabilities() {
+        doReturn(true).when(mFeatureFlags).meteredEmbbUrlcc();
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[] {ApnSetting.TYPE_MMS_STRING, ApnSetting.TYPE_DEFAULT_STRING});
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
+                new String[] {ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_MCX_STRING});
+        mDataConfigManagerUT.sendEmptyMessage(1/*EVENT_CARRIER_CONFIG_CHANGED*/);
+        processAllMessages();
+
+        assertThat(mDataConfigManagerUT.getMeteredNetworkCapabilities(false)).containsExactly(
+                NetworkCapabilities.NET_CAPABILITY_MMS, NetworkCapabilities.NET_CAPABILITY_INTERNET,
+                NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH,
+                NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY);
+        assertThat(mDataConfigManagerUT.getMeteredNetworkCapabilities(true)).containsExactly(
+                NetworkCapabilities.NET_CAPABILITY_SUPL, NetworkCapabilities.NET_CAPABILITY_MCX,
+                NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH,
+                NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
index 0be1927..7da79a6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -830,6 +830,34 @@
 
     @Test
     @SmallTest
+    public void testRecoverNormalInCellularWhenVoWiFiConnected() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        // Create test Phones
+        Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        // Call startEmergencyCall() to set testPhone
+        CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone,
+                TEST_CALL_ID, false);
+
+        // Set emergency transport
+        emergencyStateTracker.onEmergencyTransportChanged(
+                EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WLAN);
+
+        // Set call properties
+        emergencyStateTracker.onEmergencyCallPropertiesChanged(
+                android.telecom.Connection.PROPERTY_WIFI, TEST_CALL_ID);
+
+        verify(testPhone, times(0)).cancelEmergencyNetworkScan(anyBoolean(), any());
+
+        // Set call to ACTIVE
+        emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID);
+
+        verify(testPhone, times(1)).cancelEmergencyNetworkScan(eq(true), any());
+    }
+
+    @Test
+    @SmallTest
     public void testStartEmergencySms() {
         EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
                 /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 2feb34d..221aa0e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -764,9 +764,9 @@
         verify(mMockDatagramController, times(4)).setDemoMode(eq(false));
         verify(mMockControllerMetricsStats, times(2)).onSatelliteEnabled();
         verify(mMockControllerMetricsStats, times(2)).reportServiceEnablementSuccessCount();
-        verify(mMockSessionMetricsStats, times(3)).setInitializationResult(anyInt());
-        verify(mMockSessionMetricsStats, times(3)).setRadioTechnology(anyInt());
-        verify(mMockSessionMetricsStats, times(3)).reportSessionMetrics();
+        verify(mMockSessionMetricsStats, times(7)).setInitializationResult(anyInt());
+        verify(mMockSessionMetricsStats, times(7)).setRadioTechnology(anyInt());
+        verify(mMockSessionMetricsStats, times(7)).reportSessionMetrics();
 
         // Successfully enable satellite when it is already enabled.
         mIIntegerConsumerResults.clear();
@@ -921,6 +921,9 @@
         assertTrue(waitForRequestSatelliteCapabilitiesResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteCapabilitiesResultCode);
         assertEquals(mSatelliteCapabilities, mQueriedSatelliteCapabilities);
+        assertTrue(
+                mQueriedSatelliteCapabilities.getSupportedRadioTechnologies().contains(
+                        mSatelliteControllerUT.getSupportedNtnRadioTechnology()));
 
         resetSatelliteControllerUT();
         setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
@@ -1992,6 +1995,9 @@
         assertTrue(waitForRequestSatelliteCapabilitiesResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteCapabilitiesResultCode);
         assertEquals(mEmptySatelliteCapabilities, mQueriedSatelliteCapabilities);
+        assertEquals(SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN,
+                mSatelliteControllerUT.getSupportedNtnRadioTechnology());
+
         assertFalse(satelliteController.isSatelliteAttachRequired());
 
         setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
@@ -2007,6 +2013,9 @@
         assertTrue(waitForRequestSatelliteCapabilitiesResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteCapabilitiesResultCode);
         assertEquals(mSatelliteCapabilities, mQueriedSatelliteCapabilities);
+        assertTrue(
+                mQueriedSatelliteCapabilities.getSupportedRadioTechnologies().contains(
+                        satelliteController.getSupportedNtnRadioTechnology()));
         assertTrue(satelliteController.isSatelliteAttachRequired());
 
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
@@ -3023,5 +3032,12 @@
         protected boolean areAllRadiosDisabled() {
             return allRadiosDisabled;
         }
+
+        @Override
+        protected int getSupportedNtnRadioTechnology() {
+            int ntRadioTechnology = super.getSupportedNtnRadioTechnology();
+            logd("getCurrentNtnRadioTechnology: val=" + ntRadioTechnology);
+            return ntRadioTechnology;
+        }
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index 05489dc..e4e2434 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -105,7 +105,9 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.euicc.EuiccController;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback;
 import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider;
+import com.android.internal.telephony.subscription.SubscriptionManagerService.BinderWrapper;
 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback;
 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionMap;
 import com.android.internal.telephony.uicc.IccCardStatus;
@@ -155,6 +157,7 @@
     private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback;
     private EuiccController mEuiccController;
     private FeatureFlags mFlags;
+    private BinderWrapper mBinder;
     private Set<Integer> mActiveSubs = new ArraySet<>();
 
     @Rule
@@ -195,6 +198,10 @@
         doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1));
         doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2));
 
+        mBinder = Mockito.mock(BinderWrapper.class);
+        doReturn(FAKE_USER_HANDLE).when(mBinder).getCallingUserHandle();
+        replaceInstance(SubscriptionManagerService.class, "BINDER_WRAPPER", null, mBinder);
+
         doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList();
 
         ((MockContentResolver) mContext.getContentResolver()).addProvider(
@@ -256,6 +263,12 @@
         return (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT);
     }
 
+    private SubscriptionDatabaseManagerCallback getSubscriptionDatabaseCallback() throws Exception {
+        Field field = SubscriptionDatabaseManager.class.getDeclaredField("mCallback");
+        field.setAccessible(true);
+        return (SubscriptionDatabaseManagerCallback) field.get(getSubscriptionDatabaseManager());
+    }
+
     /**
      * Insert the subscription info to the database. This is an instant insertion method. For real
      * insertion sequence please use {@link #testInsertNewSim()}.
@@ -265,7 +278,6 @@
      */
     private int insertSubscription(@NonNull SubscriptionInfoInternal subInfo) {
         try {
-            mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
             subInfo = new SubscriptionInfoInternal.Builder(subInfo)
                     .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build();
             int subId = getSubscriptionDatabaseManager().insertSubscriptionInfo(subInfo);
@@ -277,17 +289,12 @@
             field.setAccessible(true);
             SubscriptionMap<Integer, Integer> map = (SubscriptionMap<Integer, Integer>)
                     field.get(mSubscriptionManagerServiceUT);
-            Class[] cArgs = new Class[2];
-            cArgs[0] = Object.class;
-            cArgs[1] = Object.class;
 
             if (subInfo.getSimSlotIndex() >= 0) {
                 // Change the slot -> subId mapping
                 map.put(subInfo.getSimSlotIndex(), subId);
             }
 
-            mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
-            processAllMessages();
             verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId));
             Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback);
 
@@ -964,7 +971,7 @@
     }
 
     @Test
-    public void testSetIconTint() throws Exception {
+    public void testSetIconTint() {
         insertSubscription(FAKE_SUBSCRIPTION_INFO1);
 
         // Should fail without MODIFY_PHONE_STATE
@@ -1150,6 +1157,299 @@
     }
 
     @Test
+    @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID,
+            SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER})
+    public void testIsSubscriptionAssociatedWithUserMultiSubs() {
+        doReturn(true).when(mFlags).workProfileApiSplit();
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                UserHandle.of(UserHandle.USER_NULL), 1);
+
+        // Verify sub 1 unassociated is visible to all profiles
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+
+        // Assign sub 2 to work profile
+        insertSubscription(FAKE_SUBSCRIPTION_INFO2);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                FAKE_MANAGED_PROFILE_USER_HANDLE, 2);
+        processAllMessages();
+        // Verify work profile can only see its dedicated sub 2
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(false);
+        // Verify personal profile can only see the unassigned sub 1
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_USER_HANDLE)).isEqualTo(false);
+
+        // Sub 2 is deactivated, but still on device, verify visibility doesn't change.
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        mSubscriptionManagerServiceUT.updateSimState(
+                1, TelephonyManager.SIM_STATE_NOT_READY, null, null);
+        processAllMessages();
+        // Verify work profile can only see its dedicated sub 2
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(false);
+        // Verify personal profile can only see the unassigned sub 1
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2,
+                FAKE_USER_HANDLE)).isEqualTo(false);
+
+        // Sub 2 is removed from the device.
+        mSubscriptionManagerServiceUT.updateSimState(
+                1, TelephonyManager.SIM_STATE_ABSENT, null, null);
+        processAllMessages();
+        // Verify the visibility of the unassigned sub 1 is restored to both profiles.
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_USER_HANDLE)).isEqualTo(true);
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1,
+                FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true);
+    }
+
+    @Test
+    @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID,
+            SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER})
+    public void testSubscriptionAssociationWorkProfileCallerVisibility() {
+        // Split mode is defined as when a profile owns a dedicated sub, it loses the visibility to
+        // the unassociated sub.
+        doReturn(true).when(mFlags).workProfileApiSplit();
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        // Sub 1 is associated with work profile; Sub 2 is unassociated.
+        int subId1 = insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                FAKE_MANAGED_PROFILE_USER_HANDLE, subId1);
+        int subId2 = insertSubscription(FAKE_SUBSCRIPTION_INFO2);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                UserHandle.of(UserHandle.USER_NULL), subId2);
+        // Set Sub 1 default data sub
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        mSubscriptionManagerServiceUT.setDefaultDataSubId(subId1);
+        processAllMessages();
+
+        // Calling from work profile
+        doReturn(FAKE_MANAGED_PROFILE_USER_HANDLE).when(mBinder).getCallingUserHandle();
+
+        // Test getAccessibleSubscriptionInfoList
+        doReturn(true).when(mEuiccManager).isEnabled();
+        doReturn(true).when(mSubscriptionManager).canManageSubscription(
+                any(SubscriptionInfo.class), eq(CALLING_PACKAGE));
+        assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList(
+                CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()));
+        // Test getActiveSubIdList, System
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false/*visible only*/))
+                .isEqualTo(new int[]{subId1, subId2});
+        // Test get getActiveSubInfoCount
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount(
+                CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(1);
+        // Test getActiveSubscriptionInfo
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForIccId
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForSimSlotIndex
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                0, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
+                CALLING_PACKAGE, CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getAllSubInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test getAvailableSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getDefaultDataSubId
+        assertThat(mSubscriptionManagerServiceUT.getDefaultDataSubId()).isEqualTo(subId1);
+        // Test getDefault<Sms/Voice>SubIdAsUser
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSmsSubIdAsUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSubIdAsUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultVoiceSubIdAsUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        // Test getEnabledSubscriptionId
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(
+                subId1);
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo(
+                subId2);
+        // Test getOpportunisticSubscriptions
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId1, CALLING_PACKAGE);
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId2, CALLING_PACKAGE);
+        processAllMessages();
+        assertThat(mSubscriptionManagerServiceUT.getOpportunisticSubscriptions(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getSubscriptionInfo - can get both as it's an internal getter
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId1).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId2).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getSubscriptionInfoListAssociatedWithUser
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoListAssociatedWithUser(
+                FAKE_MANAGED_PROFILE_USER_HANDLE).stream().map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getSubscriptionsInGroup
+        setCarrierPrivilegesForSubId(true, subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionsInGroup(
+                ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE)
+                .stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test isActiveSubId
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId1, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId2, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        // Test isSubscriptionEnabled
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId1)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId2)).isTrue();
+    }
+
+    @Test
+    @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID,
+            SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER})
+    public void testSubscriptionAssociationPersonalCallerVisibility() {
+        // Split mode is defined as when a profile owns a dedicated sub, it loses the visibility to
+        // the unassociated sub.
+        doReturn(true).when(mFlags).workProfileApiSplit();
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        // Sub 1 is unassociated; Sub 2 is associated with work profile.
+        int subId1 = insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                UserHandle.of(UserHandle.USER_NULL), subId1);
+        int subId2 = insertSubscription(FAKE_SUBSCRIPTION_INFO2);
+        mSubscriptionManagerServiceUT.setSubscriptionUserHandle(
+                FAKE_MANAGED_PROFILE_USER_HANDLE, subId2);
+        // Set Sub 1 default data sub
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        mSubscriptionManagerServiceUT.setDefaultDataSubId(subId1);
+        processAllMessages();
+
+        // Calling from a profile that owns no dedicated subs.
+        doReturn(FAKE_USER_HANDLE).when(mBinder).getCallingUserHandle();
+
+        // Test getAccessibleSubscriptionInfoList
+        doReturn(true).when(mEuiccManager).isEnabled();
+        doReturn(true).when(mSubscriptionManager).canManageSubscription(
+                any(SubscriptionInfo.class), eq(CALLING_PACKAGE));
+        assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList(
+                CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()));
+        // Test getActiveSubIdList, System
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false/*visible only*/))
+                .isEqualTo(new int[]{subId1, subId2});
+        // Test get getActiveSubInfoCount
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount(
+                CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(1);
+        // Test getActiveSubscriptionInfo
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
+                subId2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForIccId
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId(
+                FAKE_ICCID2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoForSimSlotIndex
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                0, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex(
+                1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getActiveSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
+                        CALLING_PACKAGE, CALLING_FEATURE).stream()
+                .map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getAllSubInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test getAvailableSubscriptionInfoList
+        assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getDefaultDataSubId
+        assertThat(mSubscriptionManagerServiceUT.getDefaultDataSubId()).isEqualTo(subId1);
+        // Test getDefault<Sms/Voice>SubIdAsUser
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSmsSubIdAsUser(
+                FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultSubIdAsUser(
+                FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getDefaultVoiceSubIdAsUser(
+                FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1);
+        // Test getEnabledSubscriptionId
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(
+                subId1);
+        assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo(
+                subId2);
+        // Test getOpportunisticSubscriptions
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId1, CALLING_PACKAGE);
+        mSubscriptionManagerServiceUT.setOpportunistic(true, subId2, CALLING_PACKAGE);
+        processAllMessages();
+        assertThat(mSubscriptionManagerServiceUT.getOpportunisticSubscriptions(CALLING_PACKAGE,
+                CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1, subId2));
+        // Test getSubscriptionInfo - can get both as it's an internal getter
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId1).getSubscriptionId())
+                .isEqualTo(subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId2).getSubscriptionId())
+                .isEqualTo(subId2);
+        // Test getSubscriptionInfoListAssociatedWithUser
+        mContextFixture.addCallingOrSelfPermission(
+                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoListAssociatedWithUser(
+                        FAKE_USER_HANDLE).stream().map(SubscriptionInfo::getSubscriptionId)
+                .toList()).isEqualTo(List.of(subId1));
+        // Test getSubscriptionsInGroup
+        setCarrierPrivilegesForSubId(true, subId1);
+        assertThat(mSubscriptionManagerServiceUT.getSubscriptionsInGroup(
+                        ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE)
+                .stream().map(SubscriptionInfo::getSubscriptionId).toList())
+                .isEqualTo(List.of(subId1));
+        // Test isActiveSubId
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId1, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId2, CALLING_PACKAGE,
+                CALLING_FEATURE)).isTrue();
+        // Test isSubscriptionEnabled
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId1)).isTrue();
+        assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId2)).isTrue();
+    }
+
+    @Test
     public void testSetUsageSetting() {
         insertSubscription(FAKE_SUBSCRIPTION_INFO1);