Merge "Change app name to carrier name"
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index ede0015..58b8299 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -65,6 +65,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SubscriptionInfoUpdater;
 import com.android.internal.telephony.TelephonyPermissions;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.telephony.Rlog;
@@ -309,7 +310,7 @@
                             // smoothly.
                             mConfigFromDefaultApp[phoneId] = new PersistableBundle();
                             // Send broadcast if bind fails.
-                            notifySubscriptionInfoUpdater(phoneId);
+                            updateSubscriptionDatabase(phoneId);
                             // TODO: We *must* call unbindService even if bindService returns false.
                             // (And possibly if SecurityException was thrown.)
                             loge("binding to default app: "
@@ -344,7 +345,7 @@
                                     if (resultCode == RESULT_ERROR || resultData == null) {
                                         // On error, abort config fetching.
                                         loge("Failed to get carrier config");
-                                        notifySubscriptionInfoUpdater(phoneId);
+                                        updateSubscriptionDatabase(phoneId);
                                         return;
                                     }
                                     PersistableBundle config =
@@ -393,7 +394,7 @@
                     }
                     // Put a stub bundle in place so that the rest of the logic continues smoothly.
                     mConfigFromDefaultApp[phoneId] = new PersistableBundle();
-                    notifySubscriptionInfoUpdater(phoneId);
+                    updateSubscriptionDatabase(phoneId);
                     break;
                 }
 
@@ -409,7 +410,7 @@
                         logd("Found carrier config app: " + carrierPackageName);
                         sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1));
                     } else {
-                        notifySubscriptionInfoUpdater(phoneId);
+                        updateSubscriptionDatabase(phoneId);
                     }
                     break;
                 }
@@ -443,7 +444,7 @@
                             // Send broadcast if bind fails.
                             broadcastConfigChangedIntent(phoneId);
                             loge("Bind to carrier app: " + carrierPackageName + " fails");
-                            notifySubscriptionInfoUpdater(phoneId);
+                            updateSubscriptionDatabase(phoneId);
                         }
                     }
                     break;
@@ -476,7 +477,7 @@
                                         loge("Failed to get carrier config from carrier app: "
                                                 + getCarrierPackageForPhoneId(phoneId));
                                         broadcastConfigChangedIntent(phoneId);
-                                        notifySubscriptionInfoUpdater(phoneId);
+                                        updateSubscriptionDatabase(phoneId);
                                         return;
                                     }
                                     PersistableBundle config =
@@ -533,7 +534,7 @@
                     }
                     // Put a stub bundle in place so that the rest of the logic continues smoothly.
                     mConfigFromCarrierApp[phoneId] = new PersistableBundle();
-                    notifySubscriptionInfoUpdater(phoneId);
+                    updateSubscriptionDatabase(phoneId);
                     break;
                 }
                 case EVENT_FETCH_CARRIER_DONE: {
@@ -543,7 +544,7 @@
                             && mServiceConnection[phoneId] == null) {
                         break;
                     }
-                    notifySubscriptionInfoUpdater(phoneId);
+                    updateSubscriptionDatabase(phoneId);
                     break;
                 }
 
@@ -696,7 +697,8 @@
      */
     @VisibleForTesting
     /* package */ CarrierConfigLoader(@NonNull Context context,
-            @NonNull SubscriptionInfoUpdater subscriptionInfoUpdater, @NonNull Looper looper) {
+            //TODO: Remove SubscriptionInfoUpdater.
+            @Nullable SubscriptionInfoUpdater subscriptionInfoUpdater, @NonNull Looper looper) {
         mContext = context;
         mPlatformCarrierConfigPackage =
                 mContext.getString(R.string.platform_carrier_config_package);
@@ -774,17 +776,17 @@
         }
     }
 
-    private void notifySubscriptionInfoUpdater(int phoneId) {
-        String configPackagename;
+    private void updateSubscriptionDatabase(int phoneId) {
+        String configPackageName;
         PersistableBundle configToSend;
         int carrierId = getSpecificCarrierIdForPhoneId(phoneId);
         // Prefer the carrier privileged carrier app, but if there is not one, use the platform
         // default carrier app.
         if (mConfigFromCarrierApp[phoneId] != null) {
-            configPackagename = getCarrierPackageForPhoneId(phoneId);
+            configPackageName = getCarrierPackageForPhoneId(phoneId);
             configToSend = mConfigFromCarrierApp[phoneId];
         } else {
-            configPackagename = mPlatformCarrierConfigPackage;
+            configPackageName = mPlatformCarrierConfigPackage;
             configToSend = mConfigFromDefaultApp[phoneId];
         }
 
@@ -799,9 +801,16 @@
             configToSend.putAll(config);
         }
 
-        mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
-                phoneId, configPackagename, configToSend,
-                mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
+        if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+            SubscriptionManagerService.getInstance().updateSubscriptionByCarrierConfig(
+                    phoneId, configPackageName, configToSend,
+                    () -> mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1)
+                            .sendToTarget());
+        } else {
+            mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
+                    phoneId, configPackageName, configToSend,
+                    mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
+        }
     }
 
     private void broadcastConfigChangedIntent(int phoneId) {
@@ -1434,7 +1443,7 @@
                     fileToDelete.delete();
                 }
             }
-            notifySubscriptionInfoUpdater(phoneId);
+            updateSubscriptionDatabase(phoneId);
         });
     }
 
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 194b8f7..d6eb4aa 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -395,7 +395,7 @@
     private AppOpsManager mAppOps;
     private PackageManager mPm;
     private MainThreadHandler mMainThreadHandler;
-    private SubscriptionController mSubscriptionController;
+    private final SubscriptionController mSubscriptionController;
     private SharedPreferences mTelephonySharedPreferences;
     private PhoneConfigurationManager mPhoneConfigurationManager;
     private final RadioInterfaceCapabilityController mRadioInterfaceCapabilities;
@@ -437,6 +437,8 @@
 
     private static final int SET_NETWORK_SELECTION_MODE_AUTOMATIC_TIMEOUT_MS = 2000; // 2 seconds
 
+    private static final int MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS = 50;
+
     /**
      * With support for MEP(multiple enabled profile) in Android T, a SIM card can have more than
      * one ICCID active at the same time.
@@ -1466,6 +1468,8 @@
                         ModemActivityInfo info = (ModemActivityInfo) ar.result;
                         if (isModemActivityInfoValid(info)) {
                             mergeModemActivityInfo(info);
+                        } else {
+                            loge("queryModemActivityInfo: invalid response");
                         }
                         // This is needed to decouple ret from mLastModemActivityInfo
                         // We don't want to return mLastModemActivityInfo which is updated
@@ -2409,7 +2413,11 @@
         mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
         mPm = app.getSystemService(PackageManager.class);
         mMainThreadHandler = new MainThreadHandler();
-        mSubscriptionController = SubscriptionController.getInstance();
+        if (!PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+            mSubscriptionController = SubscriptionController.getInstance();
+        } else {
+            mSubscriptionController = null;
+        }
         mTelephonySharedPreferences =
                 PreferenceManager.getDefaultSharedPreferences(mApp);
         mNetworkScanRequestTracker = new NetworkScanRequestTracker();
@@ -6733,11 +6741,15 @@
             return false;
         }
 
-        log("setAllowedNetworkTypesForReason: " + reason + " value: "
+        log("setAllowedNetworkTypesForReason: subId=" + subId + ", reason=" + reason + " value: "
                 + TelephonyManager.convertNetworkTypeBitmaskToString(allowedNetworkTypes));
 
+        Phone phone = getPhone(subId);
+        if (phone == null) {
+            return false;
+        }
 
-        if (allowedNetworkTypes == getPhoneFromSubId(subId).getAllowedNetworkTypes(reason)) {
+        if (allowedNetworkTypes == phone.getAllowedNetworkTypes(reason)) {
             log("setAllowedNetworkTypesForReason: " + reason + "does not change value");
             return true;
         }
@@ -8014,7 +8026,7 @@
         }
     }
 
-    // Checks that ModemActivityInfo is valid. Sleep time, Idle time, Rx time and Tx time should be
+    // Checks that ModemActivityInfo is valid. Sleep time and Idle time should be
     // less than total activity duration.
     private boolean isModemActivityInfoValid(ModemActivityInfo info) {
         if (info == null) {
@@ -8022,13 +8034,13 @@
         }
         int activityDurationMs =
                 (int) (info.getTimestampMillis() - mLastModemActivityInfo.getTimestampMillis());
+        activityDurationMs += MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS;
+
         int totalTxTimeMs = Arrays.stream(info.getTransmitTimeMillis()).sum();
 
         return (info.isValid()
             && (info.getSleepTimeMillis() <= activityDurationMs)
-            && (info.getIdleTimeMillis() <= activityDurationMs)
-            && (info.getReceiveTimeMillis() <= activityDurationMs)
-            && (totalTxTimeMs <= activityDurationMs));
+            && (info.getIdleTimeMillis() <= activityDurationMs));
     }
 
     private void updateLastModemActivityInfo(ModemActivityInfo info, int rat, int freq) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 0b71feb..7d7d949 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -590,36 +590,41 @@
             new DomainSelectionConnection.DomainSelectionConnectionCallback() {
                 @Override
                 public void onSelectionTerminated(@DisconnectCauses int cause) {
-                    Log.v(this, "Call domain selection terminated.");
-                    if (mDomainSelectionConnection != null) {
-                        mDomainSelectionConnection = null;
-                    }
-
-                    if (mNormalCallConnection != null) {
-                        // TODO: To support ShowPreciseFailedCause,
-                        //  TelephonyConnection.getShowPreciseFailedCause API should be added.
-
-                        // If cause is NOT_VALID then, it's a redial cancellation and use cause
-                        // code from original connection.
-                        com.android.internal.telephony.Connection connection =
-                                mNormalCallConnection.getOriginalConnection();
-                        if (connection != null) {
-                            if (cause == android.telephony.DisconnectCause.NOT_VALID) {
-                                cause = connection.getDisconnectCause();
+                    mDomainSelectionMainExecutor.execute(new Runnable() {
+                        int mCause = cause;
+                        @Override
+                        public void run() {
+                            Log.v(this, "Call domain selection terminated.");
+                            if (mDomainSelectionConnection != null) {
+                                mDomainSelectionConnection = null;
                             }
 
-                            String reason = connection.getVendorDisconnectCause();
+                            if (mNormalCallConnection != null) {
+                                // TODO: To support ShowPreciseFailedCause, TelephonyConnection
+                                //  .getShowPreciseFailedCause API should be added.
 
-                            mNormalCallConnection.setTelephonyConnectionDisconnected(
-                                    mDisconnectCauseFactory.toTelecomDisconnectCause(
-                                            cause, reason));
-                            Log.d(this, "Call connection closed. Cause: " + cause
-                                    + " Reason: " + reason);
+                                // If cause is NOT_VALID then, it's a redial cancellation and
+                                // use cause code from original connection.
+                                com.android.internal.telephony.Connection connection =
+                                        mNormalCallConnection.getOriginalConnection();
+                                if (connection != null) {
+                                    if (mCause == android.telephony.DisconnectCause.NOT_VALID) {
+                                        mCause = connection.getDisconnectCause();
+                                    }
+
+                                    String reason = connection.getVendorDisconnectCause();
+                                    int phoneId = mNormalCallConnection.getPhone().getPhoneId();
+                                    mNormalCallConnection.setTelephonyConnectionDisconnected(
+                                            mDisconnectCauseFactory.toTelecomDisconnectCause(
+                                                    mCause, reason, phoneId));
+                                    Log.d(this, "Call connection closed. Cause: " + mCause
+                                            + " Reason: " + reason);
+                                }
+                                mNormalCallConnection.close();
+                                mNormalCallConnection = null;
+                            }
                         }
-                        mNormalCallConnection.close();
-                        mNormalCallConnection = null;
-                    }
-
+                    });
                 }
             };
 
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 9aaf6da..dcb1de7 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -221,8 +221,14 @@
 
     @Override
     public void reselectDomain(SelectionAttributes attr) {
-        logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails + ", attr=" + attr);
+        logi("reselectDomain attr=" + attr);
         mSelectionAttributes = attr;
+        post(() -> { reselectDomain(); });
+    }
+
+    private void reselectDomain() {
+        logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
+
         if (mTryCsWhenPsFails) {
             mTryCsWhenPsFails = false;
             mCsNetworkType = getSelectableCsNetworkType();
@@ -241,10 +247,7 @@
 
         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
             // Dialing over Wi-Fi failed. Try scanning cellular networks.
-            onWwanSelected(() -> {
-                requestScan(true, false, true);
-                mDomainSelected = false;
-            });
+            onWwanSelected(this::reselectDomainInternal);
             return;
         }
 
@@ -252,6 +255,13 @@
         mDomainSelected = false;
     }
 
+    private void reselectDomainInternal() {
+        post(() -> {
+            requestScan(true, false, true);
+            mDomainSelected = false;
+        });
+    }
+
     @Override
     public void finishSelection() {
         logi("finishSelection");
@@ -422,6 +432,10 @@
     }
 
     private void selectDomainInternal() {
+        post(this::selectDomainFromInitialState);
+    }
+
+    private void selectDomainFromInitialState() {
         if (getImsNetworkTypeConfiguration().isEmpty()
                 || (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled())) {
             // Emergency call over IMS is not supported.
@@ -896,6 +910,12 @@
 
     private void onWlanSelected() {
         logi("onWlanSelected");
+        if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
+            logi("onWlanSelected ignore duplicated callback");
+            return;
+        }
+
+        mDomainSelected = true;
         mLastTransportType = TRANSPORT_TYPE_WLAN;
         mVoWifiTrialCount++;
         mTransportSelectorCallback.onWlanSelected();
@@ -904,10 +924,8 @@
 
     private void onWwanSelected(Runnable runnable) {
         logi("onWwanSelected");
-        if (mLastTransportType == TRANSPORT_TYPE_WWAN
-                && mWwanSelectorCallback != null) {
-            logi("onWwanSelected already notified");
-            runnable.run();
+        if (mLastTransportType == TRANSPORT_TYPE_WWAN) {
+            logi("onWwanSelected ignore duplicated callback");
             return;
         }
 
diff --git a/src/com/android/services/telephony/domainselection/ImsStateTracker.java b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
index e1d0d31..95c81a0 100644
--- a/src/com/android/services/telephony/domainselection/ImsStateTracker.java
+++ b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
@@ -773,6 +773,7 @@
             case ImsRegistrationImplBase.REGISTRATION_TECH_NR:
                 return AccessNetworkType.NGRAN;
             case ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN:
+            case ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM:
                 return AccessNetworkType.IWLAN;
             default:
                 return AccessNetworkType.UNKNOWN;
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index e1de0ab..3f6ce98 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -903,6 +903,39 @@
         verify(mTransportSelectorCallback, times(1)).onWlanSelected();
     }
 
+    @Test
+    public void testIgnoreDuplicatedCallbacks() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsService(true);
+
+        verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+        // duplicated event
+        unsolBarringInfoChanged(true);
+
+        // ignore duplicated callback, no change in interaction
+        verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+
+        // duplicated event
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // ignore duplicated callback, no change in interaction
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
     private void createSelector(int subId) throws Exception {
         mDomainSelector = new EmergencyCallDomainSelector(
                 mContext, SLOT_0, subId, mHandlerThread.getLooper(),
@@ -913,10 +946,12 @@
     }
 
     private void verifyCsDialed() {
+        processAllMessages();
         verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_CS));
     }
 
     private void verifyPsDialed() {
+        processAllMessages();
         verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS));
     }
 
@@ -929,6 +964,7 @@
     }
 
     private void verifyScanPreferred(int scanType, int expectedPreferredAccessNetwork) {
+        processAllMessages();
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
                 any(), eq(scanType), any(), any());
         assertEquals(expectedPreferredAccessNetwork, (int) mAccessNetwork.get(0));
diff --git a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
index b00926f..3551593 100644
--- a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
@@ -528,6 +528,14 @@
         assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
+                ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).build());
+
+        assertFalse(mImsStateTracker.isImsStateReady());
+        assertTrue(mImsStateTracker.isImsRegistered());
+        assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+        assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
+
+        callback.onRegistered(new ImsRegistrationAttributes.Builder(
                 ImsRegistrationImplBase.REGISTRATION_TECH_NONE).build());
 
         assertFalse(mImsStateTracker.isImsStateReady());
@@ -535,7 +543,7 @@
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
         assertEquals(AccessNetworkType.UNKNOWN, mImsStateTracker.getImsAccessNetworkType());
 
-        verify(mImsStateListener, times(4)).onImsRegistrationStateChanged();
+        verify(mImsStateListener, times(5)).onImsRegistrationStateChanged();
     }
 
     @Test