Resolve CTS race condition

Test: atest android.appwidget.cts.UpdateProviderInfoTest
Bug: 143356447
Change-Id: Idedf2ad835f52b0d817154dbc431cc900f1d25f6
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/UpdateProviderInfoTest.java b/tests/tests/appwidget/src/android/appwidget/cts/UpdateProviderInfoTest.java
index 3d7f779..5f1320a 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/UpdateProviderInfoTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/UpdateProviderInfoTest.java
@@ -17,8 +17,7 @@
 package android.appwidget.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
@@ -35,9 +34,11 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.time.Instant;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
 
 @AppModeFull(reason = "Instant apps cannot provide or host app widgets")
 public class UpdateProviderInfoTest extends AppWidgetTestCase {
@@ -55,6 +56,10 @@
     private static final int HOST_ID = 42;
 
     private static final int RETRY_COUNT = 3;
+    private static final int WAIT_FOR_STATE_CHANGE_TIMEOUT_MS = 1000;
+
+    private static final Predicate<ComponentName> NULL_CN_PREDICATE = (cn) -> cn == null;
+    private static final Predicate<ComponentName> NOT_NULL_CN_PREDICATE = (cn) -> cn != null;
 
     private CountDownLatch mProviderChangeNotifier;
     AppWidgetHost mHost;
@@ -78,48 +83,48 @@
     public void testInfoOverrides() throws Throwable {
         // On first install the provider does not have any config activity.
         installApk(APK_V1);
-        assertNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NULL_CN_PREDICATE);
 
         // The provider info is updated
         updateInfo(EXTRA_CUSTOM_INFO);
-        assertNotNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NOT_NULL_CN_PREDICATE);
 
         // The provider info is updated
         updateInfo(null);
-        assertNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NULL_CN_PREDICATE);
     }
 
     @Test
     public void testOverridesPersistedOnUpdate() throws Exception {
         installApk(APK_V1);
-        assertNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NULL_CN_PREDICATE);
 
         updateInfo(EXTRA_CUSTOM_INFO);
-        assertNotNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NOT_NULL_CN_PREDICATE);
         assertEquals((AppWidgetProviderInfo.RESIZE_BOTH & getProviderInfo().resizeMode),
                 AppWidgetProviderInfo.RESIZE_BOTH);
 
         // Apk updated, the info is also updated
         installApk(APK_V2);
-        assertNotNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NOT_NULL_CN_PREDICATE);
         assertEquals((AppWidgetProviderInfo.RESIZE_BOTH & getProviderInfo().resizeMode), 0);
 
         // The provider info is reverted
         updateInfo(null);
-        assertNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NULL_CN_PREDICATE);
     }
 
     @Test
     public void testOverrideClearedWhenMissingInfo() throws Exception {
         installApk(APK_V1);
-        assertNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NULL_CN_PREDICATE);
 
         updateInfo(EXTRA_CUSTOM_INFO);
-        assertNotNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NOT_NULL_CN_PREDICATE);
 
         // V3 does not have the custom info definition
         installApk(APK_V3);
-        assertNull(getProviderInfo().configure);
+        waitAndConfirmComponentName(NULL_CN_PREDICATE);
     }
 
     private void createHost() throws Exception {
@@ -143,6 +148,18 @@
         }
     }
 
+    private void waitAndConfirmComponentName(Predicate<ComponentName> condition) throws Exception {
+        long deadline = Instant.now().plusMillis(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS).toEpochMilli();
+        boolean passesTest = condition.test(getProviderInfo().configure);
+        while (!passesTest && Instant.now().toEpochMilli() < deadline) {
+            long timeout = deadline - Instant.now().toEpochMilli();
+            mProviderChangeNotifier = new CountDownLatch(1);
+            mProviderChangeNotifier.await(timeout, TimeUnit.MILLISECONDS);
+            passesTest = condition.test(getProviderInfo().configure);
+        }
+        assertTrue(passesTest);
+    }
+
     private void updateInfo(String key) throws Exception {
         mProviderChangeNotifier = new CountDownLatch(1);
         Intent intent = new Intent(Constants.ACTION_APPLY_OVERRIDE)
@@ -170,8 +187,8 @@
     private AppWidgetProviderInfo getProviderInfo() throws Exception {
         for (int i = 0; i < RETRY_COUNT; i++) {
             mProviderChangeNotifier = new CountDownLatch(1);
-            List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(getInstrumentation()
-                    .getTargetContext()).getInstalledProvidersForPackage(
+            List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(
+                    getInstrumentation().getTargetContext()).getInstalledProvidersForPackage(
                     PROVIDER_PACKAGE, Process.myUserHandle());
 
             if (providers != null && !providers.isEmpty()) {