Add Robustness in dissming setup wizard

Bug: 309008042
Test: Presubmit
Change-Id: I63fd7f6fb2bd33ed60eff1d6daaa2fd152216343
diff --git a/javatests/com/android/tradefed/targetprep/DeviceSetupTest.java b/javatests/com/android/tradefed/targetprep/DeviceSetupTest.java
index e4da38e..4051c2d 100644
--- a/javatests/com/android/tradefed/targetprep/DeviceSetupTest.java
+++ b/javatests/com/android/tradefed/targetprep/DeviceSetupTest.java
@@ -43,6 +43,8 @@
 import com.android.tradefed.invoker.TestInformation;
 import com.android.tradefed.result.error.InfraErrorIdentifier;
 import com.android.tradefed.util.BinaryState;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.FileUtil;
 
 import org.junit.After;
@@ -1547,6 +1549,16 @@
         when(mMockDevice.getProperty("ro.audio.silent")).thenReturn("1");
         when(mMockDevice.getProperty("ro.test_harness")).thenReturn("1");
         when(mMockDevice.getProperty("ro.monkey")).thenReturn("1");
+        CommandResult successResult = new CommandResult();
+        successResult.setStatus(CommandStatus.SUCCESS);
+        successResult.setStdout("");
+        when(mMockDevice.executeShellV2Command(
+                        "am start -a com.android.setupwizard.FOUR_CORNER_EXIT"))
+                .thenReturn(successResult);
+        when(mMockDevice.executeShellV2Command("am start -a com.android.setupwizard.EXIT"))
+                .thenReturn(successResult);
+        when(mMockDevice.executeShellV2Command("dumpsys window displays | grep mCurrentFocus"))
+                .thenReturn(successResult);
     }
 
     /** Perform common EasyMock expect operations for a setUp call which syncs local data */
diff --git a/src/com/android/tradefed/targetprep/DeviceSetup.java b/src/com/android/tradefed/targetprep/DeviceSetup.java
index 0838f4e..e1a8194 100644
--- a/src/com/android/tradefed/targetprep/DeviceSetup.java
+++ b/src/com/android/tradefed/targetprep/DeviceSetup.java
@@ -43,6 +43,7 @@
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.MultiMap;
+import com.android.tradefed.util.RunUtil;
 import com.android.tradefed.util.executor.ParallelDeviceExecutor;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -410,6 +411,16 @@
             description = "Attempt to dismiss the setup wizard if present.")
     private boolean mDismissSetupWizard = true;
 
+    @Option(
+            name = "dismiss-setup-wizard-timeout",
+            description = "Set the timeout for dismissing setup wizard in milli seconds.")
+    private Long mDismissSetupWizardTimeout = 60 * 1000L;
+
+    @Option(
+            name = "dismiss-setup-wizard-retry-count",
+            description = "Number of times to retry to dismiss setup wizard.")
+    private int mDismissSetupWizardRetry = 2;
+
     private Map<String, String> mPreviousSystemSettings = new HashMap<>();
     private Map<String, String> mPreviousSecureSettings = new HashMap<>();
     private Map<String, String> mPreviousGlobalSettings = new HashMap<>();
@@ -565,7 +576,7 @@
         if (mDismissSetupWizard) {
             callableTasks.add(
                     () -> {
-                        dismissSetupWiward(device);
+                        dismissSetupWizard(device);
                         return true;
                     });
         }
@@ -601,7 +612,7 @@
             // Throw an error if there is not enough storage space
             checkExternalStoreSpace(device);
             if (mDismissSetupWizard) {
-                dismissSetupWiward(device);
+                dismissSetupWizard(device);
             }
         }
         // Run commands designated to be run after changing settings
@@ -1262,11 +1273,42 @@
         }
     }
 
-    private void dismissSetupWiward(ITestDevice device) throws DeviceNotAvailableException {
-        device.executeShellCommand(
-                "am start -a com.android.setupwizard.FOUR_CORNER_EXIT"); // Android
-        // UDC+
-        device.executeShellCommand("am start -a com.android.setupwizard.EXIT"); // Android L - T
+    private void dismissSetupWizard(ITestDevice device) throws DeviceNotAvailableException {
+        for (int i = 0; i < mDismissSetupWizardRetry; i++) {
+            CommandResult cmd1 =
+                    device.executeShellV2Command(
+                            "am start -a com.android.setupwizard.FOUR_CORNER_EXIT"); // Android
+            // UDC+
+            CommandResult cmd2 =
+                    device.executeShellV2Command(
+                            "am start -a com.android.setupwizard.EXIT"); // Android L - T
+            // if either of the command is successful, count it as success. Otherwise, retry.
+            if (CommandStatus.SUCCESS.equals(cmd1.getStatus())
+                    || CommandStatus.SUCCESS.equals(cmd2.getStatus())) {
+                break;
+            }
+        }
+        // verify setup wizard is dismissed
+        CLog.d("Waiting %d ms for setup wizard to be dismissed.", mDismissSetupWizardTimeout);
+        boolean dismissed = false;
+        long startTime = System.currentTimeMillis();
+        while (System.currentTimeMillis() - startTime < mDismissSetupWizardTimeout) {
+            CommandResult cmdOut =
+                    device.executeShellV2Command("dumpsys window displays | grep mCurrentFocus");
+            if (CommandStatus.SUCCESS.equals(cmdOut.getStatus())
+                    && !cmdOut.getStdout().contains("setupwizard")) {
+                CLog.d("Setup wizard is dismissed.");
+                dismissed = true;
+                break;
+            } else {
+                RunUtil.getDefault().sleep(2 * 1000);
+            }
+        }
+        if (!dismissed) {
+            CLog.w(
+                    "Setup wizard was not dismissed within the timeout limit: %d ms.",
+                    mDismissSetupWizardTimeout);
+        }
     }
 
     /**