Merge "Adding debug message when updateing eSIM profiles."
diff --git a/src/java/com/android/internal/telephony/CarrierResolver.java b/src/java/com/android/internal/telephony/CarrierResolver.java
index 0c7950f..14d093f 100644
--- a/src/java/com/android/internal/telephony/CarrierResolver.java
+++ b/src/java/com/android/internal/telephony/CarrierResolver.java
@@ -375,7 +375,6 @@
                     .ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
             intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, mCarrierId);
             intent.putExtra(TelephonyManager.EXTRA_CARRIER_NAME, mCarrierName);
-            intent.putExtra(TelephonyManager.EXTRA_MNO_CARRIER_ID, mMnoCarrierId);
             intent.putExtra(TelephonyManager.EXTRA_SUBSCRIPTION_ID, mPhone.getSubId());
             mContext.sendBroadcast(intent);
 
@@ -383,10 +382,8 @@
             ContentValues cv = new ContentValues();
             cv.put(CarrierId.CARRIER_ID, mCarrierId);
             cv.put(CarrierId.CARRIER_NAME, mCarrierName);
-            cv.put(CarrierId.MNO_CARRIER_ID, mMnoCarrierId);
             mContext.getContentResolver().update(
-                    Uri.withAppendedPath(CarrierId.CONTENT_URI,
-                            Integer.toString(mPhone.getSubId())), cv, null, null);
+                    Telephony.CarrierId.getUriForSubscriptionId(mPhone.getSubId()), cv, null, null);
         }
 
         update = false;
diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index edbbcda..a8dcee7 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.CallSuper;
 import android.hardware.radio.V1_0.CellInfoType;
 import android.hardware.radio.V1_0.RegState;
 import android.os.AsyncResult;
@@ -277,7 +276,6 @@
                         accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
                         cellIdentity, maxDataCalls, false /* isDcNrRestricted */,
                         false /* isNrAvailable */, false /* isEnDcAvailable */);
-
             } else if (result instanceof android.hardware.radio.V1_2.DataRegStateResult) {
                 android.hardware.radio.V1_2.DataRegStateResult dataRegState =
                         (android.hardware.radio.V1_2.DataRegStateResult) result;
@@ -506,10 +504,8 @@
             }
         }
 
-        @CallSuper
-        protected void onDestroy() {
-            super.onDestroy();
-
+        @Override
+        public void close() {
             mCallbackMap.clear();
             mHandlerThread.quit();
             mPhone.mCi.unregisterForNetworkStateChanged(mHandler);
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index cd1f44a..3a5e9ad 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -34,6 +34,7 @@
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.hardware.radio.V1_0.CellInfoType;
+import android.net.NetworkCapabilities;
 import android.os.AsyncResult;
 import android.os.BaseBundle;
 import android.os.Build;
@@ -50,6 +51,7 @@
 import android.provider.Settings;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityCdma;
@@ -82,6 +84,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriInfo;
+import com.android.internal.telephony.dataconnection.DataConnection;
+import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
@@ -1439,9 +1443,16 @@
                     }
                     mPhone.notifyPhysicalChannelConfiguration(list);
                     mLastPhysicalChannelConfigList = list;
+                    boolean hasChanged =
+                            updateNrFrequencyRangeFromPhysicalChannelConfigs(list, mSS);
+                    hasChanged |= updateNrStatusFromPhysicalChannelConfigs(
+                            list,
+                            mSS.getNetworkRegistrationState(
+                                    NetworkRegistrationState.DOMAIN_PS, AccessNetworkType.EUTRAN));
 
-                    // only notify if bandwidths changed
-                    if (RatRatcheter.updateBandwidths(getBandwidthsFromConfigs(list), mSS)) {
+                    // Notify NR frequency, NR connection status or bandwidths changed.
+                    if (hasChanged
+                            || RatRatcheter.updateBandwidths(getBandwidthsFromConfigs(list), mSS)) {
                         mPhone.notifyServiceStateChanged(mSS);
                     }
                 }
@@ -1813,6 +1824,78 @@
         return cdmaRoaming && !isSameOperatorNameFromSimAndSS(s);
     }
 
+    private boolean isNrStatusChanged(
+            NetworkRegistrationState oldRegState, NetworkRegistrationState newRegState) {
+        if (oldRegState == null || newRegState == null) {
+            return oldRegState != newRegState;
+        }
+
+        return oldRegState.getNrStatus() != newRegState.getNrStatus();
+    }
+
+    private boolean updateNrFrequencyRangeFromPhysicalChannelConfigs(
+            List<PhysicalChannelConfig> physicalChannelConfigs, ServiceState ss) {
+        int newFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+
+        if (physicalChannelConfigs != null) {
+            DcTracker dcTracker = mPhone.getDcTracker(TransportType.WWAN);
+            for (PhysicalChannelConfig config : physicalChannelConfigs) {
+                if (isNrPhysicalChannelConfig(config)) {
+                    // Update the frequency range of the NR parameters if there is an internet data
+                    // connection associate to this NR physical channel channel config.
+                    int[] contextIds = config.getContextIds();
+                    for (int cid : contextIds) {
+                        DataConnection dc = dcTracker.getDataConnectionByContextId(cid);
+                        if (dc != null && dc.getNetworkCapabilities().hasCapability(
+                                NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                            newFrequencyRange = ServiceState.getBetterNRFrequencyRange(
+                                    newFrequencyRange, config.getFrequencyRange());
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        boolean hasChanged = newFrequencyRange != ss.getNrFrequencyRange();
+        ss.setNrFrequencyRange(newFrequencyRange);
+        return hasChanged;
+    }
+
+    private boolean updateNrStatusFromPhysicalChannelConfigs(
+            List<PhysicalChannelConfig> configs, NetworkRegistrationState regState) {
+
+        if (regState == null || configs == null) return false;
+
+        boolean hasNrSecondaryServingCell = false;
+        for (PhysicalChannelConfig config : configs) {
+            if (isNrPhysicalChannelConfig(config) && config.getConnectionStatus()
+                    == PhysicalChannelConfig.CONNECTION_SECONDARY_SERVING) {
+                hasNrSecondaryServingCell = true;
+                break;
+            }
+        }
+
+        int newNrStatus = regState.getNrStatus();
+        if (hasNrSecondaryServingCell) {
+            if (regState.getNrStatus() == NetworkRegistrationState.NR_STATUS_NOT_RESTRICTED) {
+                newNrStatus = NetworkRegistrationState.NR_STATUS_CONNECTED;
+            }
+        } else {
+            if (regState.getNrStatus() == NetworkRegistrationState.NR_STATUS_CONNECTED) {
+                newNrStatus = NetworkRegistrationState.NR_STATUS_NOT_RESTRICTED;
+            }
+        }
+
+        boolean hasChanged = newNrStatus != regState.getNrStatus();
+        regState.setNrStatus(newNrStatus);
+        return hasChanged;
+    }
+
+    private boolean isNrPhysicalChannelConfig(PhysicalChannelConfig config) {
+        return config.getRat() == TelephonyManager.NETWORK_TYPE_NR;
+    }
+
     void handlePollStateResultMessage(int what, AsyncResult ar) {
         int ints[];
         switch (what) {
@@ -1905,14 +1988,17 @@
                         networkRegState.getAccessNetworkTechnology());
                 mNewSS.setDataRegState(serviceState);
                 mNewSS.setRilDataRadioTechnology(newDataRat);
-                mNewSS.addNetworkRegistrationState(networkRegState);
 
                 // When we receive OOS reset the PhyChanConfig list so that non-return-to-idle
                 // implementers of PhyChanConfig unsol will not carry forward a CA report
                 // (2 or more cells) to a new cell if they camp for emergency service only.
                 if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
                     mLastPhysicalChannelConfigList = null;
+                    updateNrFrequencyRangeFromPhysicalChannelConfigs(null, mNewSS);
                 }
+                updateNrStatusFromPhysicalChannelConfigs(
+                        mLastPhysicalChannelConfigList, networkRegState);
+                mNewSS.addNetworkRegistrationState(networkRegState);
                 setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity());
 
                 if (mPhone.isPhoneTypeGsm()) {
@@ -2851,6 +2937,15 @@
         boolean hasVoiceRegStateChanged =
                 mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
 
+        boolean hasNrFrequencyRangeChanged =
+                mSS.getNrFrequencyRange() != mNewSS.getNrFrequencyRange();
+
+        boolean hasNrStatusChanged = isNrStatusChanged(
+                mSS.getNetworkRegistrationState(
+                        NetworkRegistrationState.DOMAIN_PS, AccessNetworkType.EUTRAN),
+                mNewSS.getNetworkRegistrationState(
+                        NetworkRegistrationState.DOMAIN_PS, AccessNetworkType.EUTRAN));
+
         // TODO: loosen this restriction to exempt fields that are provided through system
         // information; otherwise, we will get false positives when things like the operator
         // alphas are provided later - that's better than missing location changes, but
@@ -2914,23 +3009,25 @@
 
         if (DBG) {
             log("pollStateDone:"
-                    + " hasRegistered=" + hasRegistered
-                    + " hasDeregistered=" + hasDeregistered
-                    + " hasDataAttached=" + hasDataAttached
-                    + " hasDataDetached=" + hasDataDetached
-                    + " hasDataRegStateChanged=" + hasDataRegStateChanged
-                    + " hasRilVoiceRadioTechnologyChanged= " + hasRilVoiceRadioTechnologyChanged
-                    + " hasRilDataRadioTechnologyChanged=" + hasRilDataRadioTechnologyChanged
-                    + " hasChanged=" + hasChanged
-                    + " hasVoiceRoamingOn=" + hasVoiceRoamingOn
-                    + " hasVoiceRoamingOff=" + hasVoiceRoamingOff
-                    + " hasDataRoamingOn=" + hasDataRoamingOn
-                    + " hasDataRoamingOff=" + hasDataRoamingOff
-                    + " hasLocationChanged=" + hasLocationChanged
+                    + " hasRegistered = " + hasRegistered
+                    + " hasDeregistered = " + hasDeregistered
+                    + " hasDataAttached = " + hasDataAttached
+                    + " hasDataDetached = " + hasDataDetached
+                    + " hasDataRegStateChanged = " + hasDataRegStateChanged
+                    + " hasRilVoiceRadioTechnologyChanged = " + hasRilVoiceRadioTechnologyChanged
+                    + " hasRilDataRadioTechnologyChanged = " + hasRilDataRadioTechnologyChanged
+                    + " hasChanged = " + hasChanged
+                    + " hasVoiceRoamingOn = " + hasVoiceRoamingOn
+                    + " hasVoiceRoamingOff = " + hasVoiceRoamingOff
+                    + " hasDataRoamingOn =" + hasDataRoamingOn
+                    + " hasDataRoamingOff = " + hasDataRoamingOff
+                    + " hasLocationChanged = " + hasLocationChanged
                     + " has4gHandoff = " + has4gHandoff
-                    + " hasMultiApnSupport=" + hasMultiApnSupport
-                    + " hasLostMultiApnSupport=" + hasLostMultiApnSupport
-                    + " hasCssIndicatorChanged=" + hasCssIndicatorChanged);
+                    + " hasMultiApnSupport = " + hasMultiApnSupport
+                    + " hasLostMultiApnSupport = " + hasLostMultiApnSupport
+                    + " hasCssIndicatorChanged = " + hasCssIndicatorChanged
+                    + " hasNrFrequencyRangeChanged = " + hasNrFrequencyRangeChanged
+                    + " hasNrStatusChanged = " + hasNrStatusChanged);
         }
 
         // Add an event log when connection state changes
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 09fcc93..5d45177 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -1917,20 +1918,14 @@
      * @return the list of subId's that are active, is never null but the length maybe 0.
      */
     @Override
-    public int[] getActiveSubIdList() {
-        Set<Entry<Integer, Integer>> simInfoSet = new HashSet<>(sSlotIndexToSubId.entrySet());
-
-        int[] subIdArr = new int[simInfoSet.size()];
-        int i = 0;
-        for (Entry<Integer, Integer> entry: simInfoSet) {
-            int sub = entry.getValue();
-            subIdArr[i] = sub;
-            i++;
-        }
+    public @NonNull int[] getActiveSubIdList() {
+        int[] subIdArr = sSlotIndexToSubId.keySet().stream()
+                .sorted()
+                .mapToInt(slotId -> sSlotIndexToSubId.get(slotId))
+                .toArray();
 
         if (VDBG) {
-            logdl("[getActiveSubIdList] simInfoSet=" + simInfoSet + " subIdArr.length="
-                    + subIdArr.length);
+            logdl("[getActiveSubIdList] subIdArr=" + Arrays.toString(subIdArr));
         }
         return subIdArr;
     }
diff --git a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
index cbc3efe..555b6e9 100644
--- a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
@@ -69,6 +69,8 @@
 
         private final Handler mHandler;
 
+        private final HandlerThread mHandlerThread;
+
         private final Phone mPhone;
 
         private CellularDataServiceProvider(int slotId) {
@@ -76,9 +78,9 @@
 
             mPhone = PhoneFactory.getPhone(getSlotId());
 
-            HandlerThread thread = new HandlerThread(CellularDataService.class.getSimpleName());
-            thread.start();
-            mLooper = thread.getLooper();
+            mHandlerThread = new HandlerThread(CellularDataService.class.getSimpleName());
+            mHandlerThread.start();
+            mLooper = mHandlerThread.getLooper();
             mHandler = new Handler(mLooper) {
                 @Override
                 public void handleMessage(Message message) {
@@ -219,6 +221,12 @@
             }
             mPhone.mCi.getDataCallList(message);
         }
+
+        @Override
+        public void close() {
+            mPhone.mCi.unregisterForDataCallListChanged(mHandler);
+            mHandlerThread.quit();
+        }
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 0de4a53..216ebb6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -982,7 +982,10 @@
         return true;
     }
 
-    NetworkCapabilities getNetworkCapabilities() {
+    /**
+     * @return the {@link NetworkCapabilities} of this data connection.
+     */
+    public NetworkCapabilities getNetworkCapabilities() {
         NetworkCapabilities result = new NetworkCapabilities();
         result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 2efc095..f22acc0 100755
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -1764,6 +1764,13 @@
     }
 
     /**
+     * @return the {@link DataConnection} with the given context id {@code cid}.
+     */
+    public DataConnection getDataConnectionByContextId(int cid) {
+        return mDcc.getActiveDcByCid(cid);
+    }
+
+    /**
      * Determine if DUN connection is special and we need to teardown on start/stop
      */
     private boolean teardownForDun() {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index 61b0077..2d1b5c2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -45,6 +45,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 
+import java.util.Arrays;
 import java.util.List;
 
 public class SubscriptionControllerTest extends TelephonyTest {
@@ -522,4 +523,15 @@
         doReturn(mTelephonyRegisteryMock).when(mTelephonyRegisteryMock)
                 .queryLocalInterface(anyString());
     }
+
+    @Test
+    @SmallTest
+    public void testGetActiveSubIdList() throws Exception {
+        mSubscriptionControllerUT.addSubInfoRecord("123", 1);   // sub 1
+        mSubscriptionControllerUT.addSubInfoRecord("456", 0);   // sub 2
+
+        // Make sure the return sub ids are sorted by slot index
+        assertTrue("active sub ids = " + mSubscriptionControllerUT.getActiveSubIdList(),
+                Arrays.equals(mSubscriptionControllerUT.getActiveSubIdList(), new int[]{2, 1}));
+    }
 }