Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index abffe11..f2e28a3 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -23,7 +23,6 @@
 import android.content.Intent;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.euicc.EuiccManager;
 
@@ -36,8 +35,9 @@
 import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.network.helper.SelectableSubscriptions;
+import com.android.settings.network.helper.SubscriptionAnnotation;
 import com.android.settings.network.telephony.MobileNetworkActivity;
-import com.android.settings.network.telephony.MobileNetworkUtils;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.widget.AddPreference;
 import com.android.settingslib.Utils;
@@ -61,6 +61,8 @@
     private SubscriptionsChangeListener mChangeListener;
     private AddPreference mPreference;
 
+    private MobileNetworkSummaryStatus mStatusCache = new MobileNetworkSummaryStatus();
+
     /**
      * This controls the summary text and click behavior of the "Mobile network" item on the
      * Network & internet page. There are 3 separate cases depending on the number of mobile network
@@ -82,8 +84,8 @@
         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
         mUserManager = context.getSystemService(UserManager.class);
         if (lifecycle != null) {
-          mChangeListener = new SubscriptionsChangeListener(context, this);
-          lifecycle.addObserver(this);
+            mChangeListener = new SubscriptionsChangeListener(context, this);
+            lifecycle.addObserver(this);
         }
     }
 
@@ -106,25 +108,24 @@
 
     @Override
     public CharSequence getSummary() {
-        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
-                mContext);
+        mStatusCache.update(mContext, null);
+        List<SubscriptionAnnotation> subs = mStatusCache.getSubscriptionList();
+
         if (subs.isEmpty()) {
-            if (MobileNetworkUtils.showEuiccSettings(mContext)) {
+            if (mStatusCache.isEuiccConfigSupport()) {
                 return mContext.getResources().getString(
                         R.string.mobile_network_summary_add_a_network);
             }
-            return null;
+            // set empty string to override previous text for carrier when SIM available
+            return "";
         } else if (subs.size() == 1) {
-            final SubscriptionInfo info = subs.get(0);
-            final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
-                    info, mContext);
-            final int subId = info.getSubscriptionId();
-            if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)
-                    && !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
-                return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
-            } else {
+            SubscriptionAnnotation info = subs.get(0);
+            CharSequence displayName = mStatusCache.getDisplayName(info.getSubscriptionId());
+            if (info.getSubInfo().isEmbedded() || info.isActive()
+                    || mStatusCache.isPhysicalSimDisableSupport()) {
                 return displayName;
             }
+            return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
         } else {
             if (com.android.settings.Utils.isProviderModelEnabled(mContext)) {
                 return getSummaryForProviderModel(subs);
@@ -135,10 +136,16 @@
         }
     }
 
-    private CharSequence getSummaryForProviderModel(List<SubscriptionInfo> subs) {
-        return String.join(", ", subs.stream().map(subInfo -> {
-            return SubscriptionUtil.getUniqueSubscriptionDisplayName(subInfo, mContext);
-        }).collect(Collectors.toList()));
+    private CharSequence getSummaryForProviderModel(List<SubscriptionAnnotation> subs) {
+        return subs.stream()
+                .mapToInt(SubscriptionAnnotation::getSubscriptionId)
+                .mapToObj(subId -> mStatusCache.getDisplayName(subId))
+                .collect(Collectors.joining(", "));
+    }
+
+    private void logPreferenceClick(Preference preference) {
+        mMetricsFeatureProvider.logClickedPreference(preference,
+                preference.getExtras().getInt(DashboardFragment.CATEGORY));
     }
 
     private void startAddSimFlow() {
@@ -147,62 +154,64 @@
         mContext.startActivity(intent);
     }
 
-    private void update() {
-        if (mPreference == null || mPreference.isDisabledByAdmin()) {
-            return;
-        }
+    private void initPreference() {
         refreshSummary(mPreference);
         mPreference.setOnPreferenceClickListener(null);
         mPreference.setOnAddClickListener(null);
         mPreference.setFragment(null);
         mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
+    }
 
-        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
-                mContext);
+    private void update() {
+        if (mPreference == null || mPreference.isDisabledByAdmin()) {
+            return;
+        }
 
+        mStatusCache.update(mContext, statusCache -> initPreference());
+
+        List<SubscriptionAnnotation> subs = mStatusCache.getSubscriptionList();
         if (subs.isEmpty()) {
-            if (MobileNetworkUtils.showEuiccSettings(mContext)) {
+            if (mStatusCache.isEuiccConfigSupport()) {
                 mPreference.setOnPreferenceClickListener((Preference pref) -> {
-                    mMetricsFeatureProvider.logClickedPreference(pref,
-                            pref.getExtras().getInt(DashboardFragment.CATEGORY));
+                    logPreferenceClick(pref);
                     startAddSimFlow();
                     return true;
                 });
             } else {
                 mPreference.setEnabled(false);
             }
-        } else {
-            // We have one or more existing subscriptions, so we want the plus button if eSIM is
-            // supported.
-            if (MobileNetworkUtils.showEuiccSettings(mContext)) {
-                mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
-                mPreference.setOnAddClickListener(p -> {
-                    mMetricsFeatureProvider.logClickedPreference(p,
-                            p.getExtras().getInt(DashboardFragment.CATEGORY));
-                    startAddSimFlow();
-                });
-            }
+            return;
+        }
 
-            if (subs.size() == 1) {
-                mPreference.setOnPreferenceClickListener((Preference pref) -> {
-                    mMetricsFeatureProvider.logClickedPreference(pref,
-                            pref.getExtras().getInt(DashboardFragment.CATEGORY));
-                    final SubscriptionInfo info = subs.get(0);
-                    final int subId = info.getSubscriptionId();
-                    if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)
-                            && !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
-                        SubscriptionUtil.startToggleSubscriptionDialogActivity(
-                                mContext, subId, true);
-                    } else {
-                        final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
-                        intent.putExtra(Settings.EXTRA_SUB_ID, subs.get(0).getSubscriptionId());
-                        mContext.startActivity(intent);
-                    }
+        // We have one or more existing subscriptions, so we want the plus button if eSIM is
+        // supported.
+        if (mStatusCache.isEuiccConfigSupport()) {
+            mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
+            mPreference.setOnAddClickListener(p -> {
+                logPreferenceClick(p);
+                startAddSimFlow();
+            });
+        }
+
+        if (subs.size() == 1) {
+            mPreference.setOnPreferenceClickListener((Preference pref) -> {
+                logPreferenceClick(pref);
+
+                SubscriptionAnnotation info = subs.get(0);
+                if (info.getSubInfo().isEmbedded() || info.isActive()
+                        || mStatusCache.isPhysicalSimDisableSupport()) {
+                    final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
+                    intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
+                    mContext.startActivity(intent);
                     return true;
-                });
-            } else {
-                mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
-            }
+                }
+
+                SubscriptionUtil.startToggleSubscriptionDialogActivity(
+                        mContext, info.getSubscriptionId(), true);
+                return true;
+            });
+        } else {
+            mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
         }
     }
 
@@ -218,12 +227,14 @@
 
     @Override
     public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
-        update();
+        mStatusCache.update(mContext, statusCache -> update());
     }
 
     @Override
     public void onSubscriptionsChanged() {
-        refreshSummary(mPreference);
-        update();
+        mStatusCache.update(mContext, statusCache -> {
+            refreshSummary(mPreference);
+            update();
+        });
     }
 }
diff --git a/src/com/android/settings/network/MobileNetworkSummaryStatus.java b/src/com/android/settings/network/MobileNetworkSummaryStatus.java
new file mode 100644
index 0000000..b22e48e
--- /dev/null
+++ b/src/com/android/settings/network/MobileNetworkSummaryStatus.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 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 com.android.settings.network;
+
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.helper.SelectableSubscriptions;
+import com.android.settings.network.helper.SubscriptionAnnotation;
+import com.android.settings.network.helper.SubscriptionGrouping;
+import com.android.settings.network.telephony.MobileNetworkUtils;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * This one keeps the information required by MobileNetworkSummaryController.
+ */
+public class MobileNetworkSummaryStatus {
+    private static final String LOG_TAG = "MobileNetworkSummaryStatus";
+
+    private Future<Map<Integer, CharSequence>> mUniqueNameMapping;
+    private Map<Integer, CharSequence> mUniqueNameMappingCache;
+
+    private Future<Boolean> mIsEuiccConfiguable;
+    private Boolean mIsEuiccConfiguableCache;
+
+    private Future<Boolean> mIsPsimDisableSupported;
+    private Boolean mIsPsimDisableSupportedCache;
+
+    private List<SubscriptionAnnotation> mSubscriptionList;
+
+    private boolean mDisableReEntranceUpdate;
+
+    // Constructor
+    public MobileNetworkSummaryStatus() {}
+
+    /**
+     * Update the status
+     * @param context
+     * @param andThen Consumer which always performed by the end of #update()
+     *                and avoid from repeated queries.
+     */
+    public void update(Context context, Consumer<MobileNetworkSummaryStatus> andThen) {
+        if (mDisableReEntranceUpdate) {
+            Log.d(LOG_TAG, "network summary query ignored");
+            if (andThen != null) {
+                andThen.accept(this);
+            }
+            return;
+        }
+        mDisableReEntranceUpdate = true;
+        Log.d(LOG_TAG, "network summary query");
+
+        // Query Euicc in background
+        mIsEuiccConfiguable = (Future<Boolean>)
+                ThreadUtils.postOnBackgroundThread(() -> isEuiccConfiguable(context));
+
+        // Query display name in background
+        mUniqueNameMapping = (Future<Map<Integer, CharSequence>>)
+                ThreadUtils.postOnBackgroundThread(() -> getUniqueNameForDisplay(context));
+
+        // Query support status of pSIM disable feature
+        mIsPsimDisableSupported = (Future<Boolean>) ThreadUtils.postOnBackgroundThread(()
+                -> isPhysicalSimDisableSupported(context));
+
+        // Query subscription
+        mSubscriptionList = getSubscriptions(context);
+
+        if (andThen != null) {
+            andThen.accept(this);
+        }
+        mDisableReEntranceUpdate = false;
+    }
+
+    /**
+     * Get the subscription information
+     * @return a list of SubscriptionAnnotation
+     */
+    public List<SubscriptionAnnotation> getSubscriptionList() {
+        return mSubscriptionList;
+    }
+
+    /**
+     * Get unique display name for a specific subscription
+     * @param subscriptionId subscription ID
+     * @return display name for that subscription
+     */
+    public CharSequence getDisplayName(int subscriptionId) {
+        if (mUniqueNameMapping != null) {
+            try {
+                mUniqueNameMappingCache = mUniqueNameMapping.get();
+            } catch (Exception exception) {
+                Log.w(LOG_TAG, "Fail to get display names", exception);
+            }
+            mUniqueNameMapping = null;
+        }
+        if (mUniqueNameMappingCache == null) {
+            return null;
+        }
+        return mUniqueNameMappingCache.get(subscriptionId);
+    }
+
+    // Check if Euicc is currently available
+    public boolean isEuiccConfigSupport() {
+        if (mIsEuiccConfiguable != null) {
+            try {
+                mIsEuiccConfiguableCache = mIsEuiccConfiguable.get();
+            } catch (Exception exception) {
+                Log.w(LOG_TAG, "Fail to get euicc config status", exception);
+            }
+            mIsEuiccConfiguable = null;
+        }
+        return (mIsEuiccConfiguableCache == null) ?
+                false : mIsEuiccConfiguableCache.booleanValue();
+    }
+
+    // Check if disable physical SIM is supported
+    public boolean isPhysicalSimDisableSupport() {
+        if (mIsPsimDisableSupported != null) {
+            try {
+                mIsPsimDisableSupportedCache = mIsPsimDisableSupported.get();
+            } catch (Exception exception) {
+                Log.w(LOG_TAG, "Fail to get pSIM disable support", exception);
+            }
+            mIsPsimDisableSupported = null;
+        }
+        return (mIsPsimDisableSupportedCache == null) ?
+                false : mIsPsimDisableSupportedCache.booleanValue();
+    }
+
+    private List<SubscriptionAnnotation> getSubscriptions(Context context) {
+        return (new SelectableSubscriptions(context, true))
+
+                // To maintain the consistency with SubscriptionUtil#getAvailableSubscriptions().
+                .addFinisher(new SubscriptionGrouping())
+
+                .call()
+                .stream()
+                .filter(SubscriptionAnnotation::isDisplayAllowed)
+                .collect(Collectors.toList());
+    }
+
+    private Map<Integer, CharSequence> getUniqueNameForDisplay(Context context) {
+        return SubscriptionUtil.getUniqueSubscriptionDisplayNames(context);
+    }
+
+    private boolean isPhysicalSimDisableSupported(Context context) {
+        SubscriptionManager subMgr = context.getSystemService(SubscriptionManager.class);
+        return SubscriptionUtil.showToggleForPhysicalSim(subMgr);
+    }
+
+    private boolean isEuiccConfiguable(Context context) {
+        return MobileNetworkUtils.showEuiccSettingsDetecting(context);
+    }
+}
diff --git a/src/com/android/settings/network/helper/QueryEsimCardId.java b/src/com/android/settings/network/helper/QueryEsimCardId.java
index dc29c47..7ac7372 100644
--- a/src/com/android/settings/network/helper/QueryEsimCardId.java
+++ b/src/com/android/settings/network/helper/QueryEsimCardId.java
@@ -50,8 +50,7 @@
         }
         return new AtomicIntegerArray(cardInfos.stream()
                 .filter(Objects::nonNull)
-                .filter(cardInfo -> (!cardInfo.isRemovable()
-                        && (cardInfo.getCardId() != TelephonyManager.UNSUPPORTED_CARD_ID)))
+                .filter(cardInfo -> (!cardInfo.isRemovable() && (cardInfo.getCardId() >= 0)))
                 .mapToInt(UiccCardInfo::getCardId)
                 .toArray());
     }
diff --git a/src/com/android/settings/network/helper/SelectableSubscriptions.java b/src/com/android/settings/network/helper/SelectableSubscriptions.java
index 436e84c..45d842b 100644
--- a/src/com/android/settings/network/helper/SelectableSubscriptions.java
+++ b/src/com/android/settings/network/helper/SelectableSubscriptions.java
@@ -71,8 +71,17 @@
         mContext = context;
         mSubscriptions = disabledSlotsIncluded ? (() -> getAvailableSubInfoList(context)) :
                 (() -> getActiveSubInfoList(context));
-        mFilter = disabledSlotsIncluded ? (subAnno -> subAnno.isExisted()) :
-                (subAnno -> subAnno.isActive());
+        if (disabledSlotsIncluded) {
+            mFilter = subAnno -> {
+                if (subAnno.isExisted()) {
+                    return true;
+                }
+                return ((subAnno.getType() == SubscriptionAnnotation.TYPE_ESIM)
+                        && (subAnno.isDisplayAllowed()));
+            };
+        } else {
+            mFilter = subAnno -> subAnno.isActive();
+        }
         mFinisher = annoList -> annoList;
     }
 
diff --git a/src/com/android/settings/network/helper/SubscriptionAnnotation.java b/src/com/android/settings/network/helper/SubscriptionAnnotation.java
index f6d3ccd..29d4fb5 100644
--- a/src/com/android/settings/network/helper/SubscriptionAnnotation.java
+++ b/src/com/android/settings/network/helper/SubscriptionAnnotation.java
@@ -93,10 +93,9 @@
         if (mType == TYPE_ESIM) {
             int cardId = mSubInfo.getCardId();
             mIsExisted = eSimCardId.contains(cardId);
-            if (mIsExisted) {
-                mIsActive = activeSimSlotIndexList.contains(mSubInfo.getSimSlotIndex());
-                mIsAllowToDisplay = isDisplayAllowed(context);
-            }
+            mIsActive = activeSimSlotIndexList.contains(mSubInfo.getSimSlotIndex());
+            mIsAllowToDisplay = (cardId < 0)    // always allow when eSIM not in slot
+                  || isDisplayAllowed(context);
             return;
         }
 
@@ -159,4 +158,11 @@
         return SubscriptionUtil.isSubscriptionVisible(
                 context.getSystemService(SubscriptionManager.class), context, mSubInfo);
     }
+
+    public String toString() {
+        return TAG + "{" + "subId=" + getSubscriptionId()
+                + ",type=" + getType() + ",exist=" + isExisted()
+                + ",active=" + isActive() + ",displayAllow=" + isDisplayAllowed()
+                + "}";
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index 78d1237..1898484 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -266,7 +266,8 @@
         return false;
     }
 
-    private static Boolean showEuiccSettingsDetecting(Context context) {
+    // The same as #showEuiccSettings(Context context)
+    public static Boolean showEuiccSettingsDetecting(Context context) {
         final EuiccManager euiccManager =
                 (EuiccManager) context.getSystemService(EuiccManager.class);
         if (!euiccManager.isEnabled()) {