Merge "Increase FILTER_COMPLETE_TIMEOUT_MS." into main
diff --git a/Android.bp b/Android.bp
index 66cca32..b56ee2a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -108,6 +108,7 @@
         "telephony-protos",
         "modules-utils-build_system",
         "modules-utils-statemachine",
+        "telephony_flags-lib",
     ],
 
     optimize: {
diff --git a/flags/Android.bp b/flags/Android.bp
new file mode 100644
index 0000000..184f716
--- /dev/null
+++ b/flags/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aconfig_declarations {
+    name: "telephony_flags",
+    package: "com.android.internal.telephony.flags",
+    srcs: [
+      "data.aconfig",
+      "ims.aconfig",
+      "messaging.aconfig",
+      "misc.aconfig",
+      "subscription.aconfig",
+      "uicc.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "telephony_flags-lib",
+    aconfig_declarations: "telephony_flags"
+}
diff --git a/flags/data.aconfig b/flags/data.aconfig
new file mode 100644
index 0000000..9a5b506
--- /dev/null
+++ b/flags/data.aconfig
@@ -0,0 +1 @@
+package: "com.android.internal.telephony.flags"
diff --git a/flags/ims.aconfig b/flags/ims.aconfig
new file mode 100644
index 0000000..84e491e
--- /dev/null
+++ b/flags/ims.aconfig
@@ -0,0 +1 @@
+package: "com.android.internal.telephony.flags"
\ No newline at end of file
diff --git a/flags/messaging.aconfig b/flags/messaging.aconfig
new file mode 100644
index 0000000..84e491e
--- /dev/null
+++ b/flags/messaging.aconfig
@@ -0,0 +1 @@
+package: "com.android.internal.telephony.flags"
\ No newline at end of file
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
new file mode 100644
index 0000000..84e491e
--- /dev/null
+++ b/flags/misc.aconfig
@@ -0,0 +1 @@
+package: "com.android.internal.telephony.flags"
\ No newline at end of file
diff --git a/flags/subscription.aconfig b/flags/subscription.aconfig
new file mode 100644
index 0000000..0521cb9
--- /dev/null
+++ b/flags/subscription.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.internal.telephony.flags"
+
+flag {
+  name: "work_profile_api_split"
+  namespace: "telephony"
+  description: "To support separation between personal and work from TelephonyManager and SubscriptionManager API perspective."
+  bug: "296076674"
+}
\ No newline at end of file
diff --git a/flags/uicc.aconfig b/flags/uicc.aconfig
new file mode 100644
index 0000000..84e491e
--- /dev/null
+++ b/flags/uicc.aconfig
@@ -0,0 +1 @@
+package: "com.android.internal.telephony.flags"
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java
index a60179b..73874e8 100644
--- a/src/java/com/android/internal/telephony/NetworkTypeController.java
+++ b/src/java/com/android/internal/telephony/NetworkTypeController.java
@@ -1365,7 +1365,7 @@
         // Check if meeting minimum bandwidth requirement. For most carriers, there is no minimum
         // bandwidth requirement and mNrAdvancedThresholdBandwidth is 0.
         if (mNrAdvancedThresholdBandwidth > 0
-                && mRatchetedNrBandwidths <= mNrAdvancedThresholdBandwidth) {
+                && mRatchetedNrBandwidths < mNrAdvancedThresholdBandwidth) {
             if (DBG) {
                 log("isNrAdvanced: false because bandwidths=" + mRatchetedNrBandwidths
                         + " does not meet the threshold=" + mNrAdvancedThresholdBandwidth);
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index 57a375b..1b05ffd 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -23,6 +23,7 @@
 
 import static java.util.Arrays.copyOf;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
@@ -47,6 +48,7 @@
 import com.android.internal.telephony.data.TelephonyNetworkFactory;
 import com.android.internal.telephony.euicc.EuiccCardController;
 import com.android.internal.telephony.euicc.EuiccController;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneFactory;
 import com.android.internal.telephony.metrics.MetricsCollector;
@@ -105,8 +107,12 @@
 
     //***** Class Methods
 
-    public static void makeDefaultPhones(Context context) {
-        makeDefaultPhone(context);
+    /**
+     * @param context The context.
+     * @param featureFlags The feature flag.
+     */
+    public static void makeDefaultPhones(Context context, @NonNull FeatureFlags featureFlags) {
+        makeDefaultPhone(context, featureFlags);
     }
 
     /**
@@ -114,7 +120,7 @@
      * instances
      */
     @UnsupportedAppUsage
-    public static void makeDefaultPhone(Context context) {
+    public static void makeDefaultPhone(Context context, @NonNull FeatureFlags featureFlags) {
         synchronized (sLockProxyPhones) {
             if (!sMadeDefaults) {
                 sContext = context;
@@ -198,7 +204,7 @@
 
                 Rlog.i(LOG_TAG, "Creating SubscriptionManagerService");
                 sSubscriptionManagerService = new SubscriptionManagerService(context,
-                        Looper.myLooper());
+                        Looper.myLooper(), featureFlags);
 
                 TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class.
                         getName()).initMultiSimSettingController(context);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index c5b6383..a5127f2 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -2722,9 +2722,13 @@
             @RegistrationManager.SuggestedAction int suggestedAction) {
 
         if (regState == mImsRegistrationState) {
+            // In NOT_REGISTERED state, the current PLMN can be blocked with a suggested action.
+            // But in this case, the same behavior is able to occur in different PLMNs with
+            // same radio tech and suggested action.
             if ((regState == REGISTRATION_STATE_REGISTERED && imsRadioTech == mImsRegistrationTech)
                     || (regState == REGISTRATION_STATE_NOT_REGISTERED
-                            && suggestedAction == mImsRegistrationSuggestedAction
+                            && suggestedAction == SUGGESTED_ACTION_NONE
+                            && mImsRegistrationSuggestedAction == SUGGESTED_ACTION_NONE
                             && imsRadioTech == mImsDeregistrationTech)) {
                 // Filter duplicate notification.
                 return;
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 11a7e15..0e32aee 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -95,6 +95,7 @@
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.internal.telephony.data.PhoneSwitcher;
 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.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccUtils;
@@ -194,6 +195,10 @@
     @NonNull
     private final Context mContext;
 
+    /** Feature flags */
+    @NonNull
+    private final FeatureFlags mFeatureFlags;
+
     /** App Ops manager instance. */
     @NonNull
     private final AppOpsManager mAppOpsManager;
@@ -406,10 +411,12 @@
      * @param context The context
      * @param looper The looper for the handler.
      */
-    public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) {
+    public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper,
+            @NonNull FeatureFlags featureFlags) {
         logl("Created SubscriptionManagerService");
         sInstance = this;
         mContext = context;
+        mFeatureFlags = featureFlags;
         mTelephonyManager = context.getSystemService(TelephonyManager.class);
         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
         mEuiccManager = context.getSystemService(EuiccManager.class);
@@ -488,7 +495,7 @@
                     @Override
                     public void onInitialized() {
                         log("Subscription database has been initialized.");
-                        for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount()
+                        for (int phoneId = 0; phoneId < mTelephonyManager.getSupportedModemCount()
                                 ; phoneId++) {
                             markSubscriptionsInactive(phoneId);
                         }
@@ -1119,6 +1126,7 @@
                     // CARD_ID field should not contain the EID
                     if (cardId >= 0 && mUiccController.getCardIdForDefaultEuicc()
                             != TelephonyManager.UNSUPPORTED_CARD_ID) {
+                        builder.setCardId(cardId);
                         builder.setCardString(mUiccController.convertToCardString(cardId));
                     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
index e0ecca2..fbf169c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
@@ -578,7 +578,7 @@
                 .setNetworkType(TelephonyManager.NETWORK_TYPE_NR)
                 .setPhysicalCellId(1)
                 .setCellConnectionStatus(CellInfo.CONNECTION_PRIMARY_SERVING)
-                .setCellBandwidthDownlinkKhz(20000)
+                .setCellBandwidthDownlinkKhz(19999)
                 .build();
         // Secondary serving NR PCC with cell ID = 2, band = 41, bandwidth = 10000
         PhysicalChannelConfig pcc2 = new PhysicalChannelConfig.Builder()
@@ -1376,7 +1376,7 @@
                 .setNetworkType(TelephonyManager.NETWORK_TYPE_NR)
                 .setCellConnectionStatus(CellInfo.CONNECTION_PRIMARY_SERVING)
                 .setPhysicalCellId(1)
-                .setCellBandwidthDownlinkKhz(20000)
+                .setCellBandwidthDownlinkKhz(19999)
                 .build());
         lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder()
                 .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE)
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index a62fa49..9eafa09 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -1394,13 +1394,14 @@
 
         assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
 
-        // duplicated notification with the same suggested action
+        // verifies that duplicated notification with the same suggested action is invoked
         registrationCallback.onUnregistered(reasonInfo,
                 SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, REGISTRATION_TECH_LTE);
         regInfo = mSimulatedCommands.getImsRegistrationInfo();
 
-        // verify that there is no update in the SimulatedCommands
-        assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
+        assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED
+                && regInfo[1] == REGISTRATION_TECH_LTE
+                && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK);
 
         // unregistered with repeated error
         registrationCallback.onUnregistered(reasonInfo,
@@ -1418,14 +1419,15 @@
 
         assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
 
-        // duplicated notification with the same suggested action
+        // verfies that duplicated notification with the same suggested action is invoked
         registrationCallback.onUnregistered(reasonInfo,
                 SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT,
                 REGISTRATION_TECH_LTE);
         regInfo = mSimulatedCommands.getImsRegistrationInfo();
 
-        // verify that there is no update in the SimulatedCommands
-        assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
+        assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED
+                && regInfo[1] == REGISTRATION_TECH_LTE
+                && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT);
 
         // unregistered with temporary error
         registrationCallback.onUnregistered(reasonInfo,
@@ -1436,6 +1438,19 @@
                 && regInfo[1] == REGISTRATION_TECH_LTE
                 && regInfo[2] == SUGGESTED_ACTION_NONE);
 
+        // reset the registration info saved in the SimulatedCommands
+        mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
+
+        // verfies that duplicated notification with temporary error is discarded
+        registrationCallback.onUnregistered(reasonInfo,
+                SUGGESTED_ACTION_NONE, REGISTRATION_TECH_LTE);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
+
         // verifies that reason codes except ImsReasonInfo.CODE_REGISTRATION_ERROR are discarded.
         reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_SERVICE,
                 ImsReasonInfo.CODE_UNSPECIFIED, "");
@@ -1453,7 +1468,7 @@
 
         assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1);
 
-        // duplicated notification with the same suggested action
+        // verifies that duplicated notification with temporary error is discarded
         registrationCallback.onUnregistered(reasonInfo,
                 SUGGESTED_ACTION_NONE, REGISTRATION_TECH_NR);
         regInfo = mSimulatedCommands.getImsRegistrationInfo();
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 0dcdece..ab531a6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -104,6 +104,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 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.SubscriptionDatabaseManagerTest.SubscriptionProvider;
 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback;
 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionMap;
@@ -153,7 +154,7 @@
     // mocked
     private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback;
     private EuiccController mEuiccController;
-
+    private FeatureFlags mFlags;
     private Set<Integer> mActiveSubs = new ArraySet<>();
 
     @Rule
@@ -199,7 +200,9 @@
         ((MockContentResolver) mContext.getContentResolver()).addProvider(
                 Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider);
 
-        mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper());
+        mFlags = Mockito.mock(FeatureFlags.class);
+        mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper(),
+                mFlags);
 
         monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper()));
         monitorTestableLooper(new TestableLooper(getSubscriptionDatabaseManager().getLooper()));
@@ -833,6 +836,8 @@
         doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(2));
         doReturn(TelephonyManager.INVALID_PORT_INDEX).when(mUiccSlot)
                 .getPortIndexFromIccId(anyString());
+        doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1));
+        doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2));
 
         mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1, 2), null);
         processAllMessages();
@@ -853,6 +858,9 @@
         assertThat(subInfo.isEmbedded()).isTrue();
         assertThat(subInfo.isRemovableEmbedded()).isFalse();
         assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES1);
+        // Downloaded esim profile should contain proper cardId
+        assertThat(subInfo.getCardId()).isEqualTo(1);
+        assertThat(subInfo.getCardString()).isEqualTo(FAKE_ICCID1);
 
         subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2);
         assertThat(subInfo.getSubscriptionId()).isEqualTo(2);
@@ -869,6 +877,9 @@
         assertThat(subInfo.isEmbedded()).isTrue();
         assertThat(subInfo.isRemovableEmbedded()).isFalse();
         assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES2);
+        // Downloaded esim profile should contain proper cardId
+        assertThat(subInfo.getCardId()).isEqualTo(2);
+        assertThat(subInfo.getCardString()).isEqualTo(FAKE_ICCID2);
     }
 
     @Test