Adding dialogs to warn users about the potential eSIM erase failure

eUICC card could potential in the card error state and all the eSIM
operations will fail which could be fixed by a reboot. Thus, we need to
pop up a dialog to inform users that their eSIM profiles cannot be
erased successfully.

Bug: 163078560
Test: Manually tested by mocking the eUICC card error state.
Mock: https://docs.google.com/presentation/d/1AVNXxPbieTX1KmoewG4mo3xWPnEZyba_h9rPcwHHcr8/edit#slide=id.p

Change-Id: I102fb2de889e08554f525f2cbe1528bb9a37afd7
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5829cc9..4f0ea10 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4319,6 +4319,20 @@
         result from their use.
     </string>
 
+    <!-- eSIM erase warning dialog. -->
+    <!-- Factory data reset erase eSIM failure title [CHAR LIMIT=50] -->
+    <string name="fdr_esim_failure_title" >There is an issue erasing the downloaded SIMs</string>
+    <!-- Factory data reset erase eSIM failure text [CHAR LIMIT=none] -->
+    <string name="fdr_esim_failure_text">Please reboot the device and try again. If you continue factory reset, the downloaded SIMs may remain on the device.</string>
+    <!-- Factory data reset erase eSIM failure reboot button text [CHAR LIMIT=none] -->
+    <string name="fdr_esim_failure_reboot_btn">Reboot</string>
+    <!-- Factory data reset continue factory data reset title [CHAR LIMIT=35] -->
+    <string name="fdr_continue_title" >Continue factory reset?</string>
+    <!-- Factory data reset continue factory data reset text [CHAR LIMIT=none] -->
+    <string name="fdr_continue_text">Downloaded SIMs will remain on device.</string>
+    <!-- Factory data reset continue factory data reset button text [CHAR LIMIT=none] -->
+    <string name="fdr_continue_btn">Factory reset</string>
+
     <!-- Warning that appears below the unknown sources switch in settings -->
     <string name="install_all_warning" product="device">
         Your device and personal data are more vulnerable
diff --git a/src/com/android/settings/MasterClearConfirm.java b/src/com/android/settings/MasterClearConfirm.java
index 3ace436..676789e 100644
--- a/src/com/android/settings/MasterClearConfirm.java
+++ b/src/com/android/settings/MasterClearConfirm.java
@@ -21,20 +21,26 @@
 
 import android.app.ActionBar;
 import android.app.Activity;
+import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.FactoryResetProtectionPolicy;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.graphics.Color;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.PowerManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.oemlock.OemLockManager;
 import android.service.persistentdata.PersistentDataBlockManager;
+import android.telephony.TelephonyManager;
+import android.telephony.UiccSlotInfo;
+import android.telephony.euicc.EuiccManager;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -54,6 +60,8 @@
 import com.google.android.setupcompat.util.WizardManagerHelper;
 import com.google.android.setupdesign.GlifLayout;
 
+import java.util.Arrays;
+
 /**
  * Confirm and execute a reset of the device to a clean "just out of the box"
  * state.  Multiple confirmations are required: first, a general "are you sure
@@ -83,6 +91,89 @@
                 return;
             }
 
+            // If the eSIM slot is in an error state, display a dialog to warn users that their eSIM
+            // profiles may not be fully deleted during FDR.
+            if (shouldShowEsimEraseFailureDialog()) {
+                Log.e(TAG, "eUICC card is in an error state. Display a dialog to warn the user.");
+                showEsimErrorDialog();
+                return;
+            }
+
+            performFactoryReset();
+        }
+
+        /**
+         * Returns true if the user choose to erase eSIM profile but the eUICC card is in an error
+         * state.
+         */
+        private boolean shouldShowEsimEraseFailureDialog() {
+            EuiccManager euiccManager = getActivity().getSystemService(EuiccManager.class);
+            TelephonyManager telephonyManager =
+                    getActivity().getSystemService(TelephonyManager.class);
+
+            if (euiccManager == null || !euiccManager.isEnabled()) {
+                Log.i(
+                        TAG,
+                        "eSIM manager is disabled. No need to check eSIM slot before FDR.");
+                return false;
+            }
+            if (!mEraseEsims) {
+                Log.i(
+                        TAG,
+                        "eSIM does not need to be reset. No need to check eSIM slot before FDR.");
+                return false;
+            }
+            UiccSlotInfo[] slotInfos = telephonyManager.getUiccSlotsInfo();
+            if (slotInfos == null) {
+                Log.i(TAG, "Unable to get UICC slots.");
+                return false;
+            }
+            // If getIsEuicc() returns false for an eSIM slot, it means the eSIM is in the error
+            // state.
+            return Arrays.stream(slotInfos).anyMatch(
+                    slot -> slot != null && !slot.isRemovable() && !slot.getIsEuicc());
+        }
+
+        private void showEsimErrorDialog() {
+            new AlertDialog.Builder(getActivity())
+                    .setTitle(R.string.fdr_esim_failure_title)
+                    .setMessage(R.string.fdr_esim_failure_text)
+                    .setNeutralButton(R.string.dlg_cancel,
+                            (DialogInterface.OnClickListener) (dialog, which) -> {
+                                dialog.dismiss();
+                            })
+                    .setNegativeButton(R.string.fdr_esim_failure_reboot_btn,
+                            (DialogInterface.OnClickListener) (dialog, which) -> {
+                                dialog.dismiss();
+                                PowerManager pm = (PowerManager) getActivity()
+                                        .getSystemService(Context.POWER_SERVICE);
+                                pm.reboot(null);
+                            })
+                    .setPositiveButton(R.string.lockpassword_continue_label,
+                            (DialogInterface.OnClickListener) (dialog, which) -> {
+                                dialog.dismiss();
+                                showContinueFdrDialog();
+                            })
+                    .show();
+        }
+
+        private void showContinueFdrDialog() {
+            new AlertDialog.Builder(getActivity())
+                    .setTitle(R.string.fdr_continue_title)
+                    .setMessage(R.string.fdr_continue_text)
+                    .setNegativeButton(R.string.dlg_cancel,
+                            (DialogInterface.OnClickListener) (dialog, which) -> {
+                                dialog.dismiss();
+                            })
+                    .setPositiveButton(R.string.fdr_continue_btn,
+                            (DialogInterface.OnClickListener) (dialog, which) -> {
+                                dialog.dismiss();
+                                performFactoryReset();
+                            })
+                    .show();
+        }
+
+        private void performFactoryReset() {
             final PersistentDataBlockManager pdbManager = (PersistentDataBlockManager)
                     getActivity().getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);