diff options
| -rw-r--r-- | core/tests/coretests/src/android/app/activity/ActivityThreadTest.java | 176 |
1 files changed, 106 insertions, 70 deletions
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 927c67cb1d36..be0669c42d44 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -34,9 +34,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.annotation.NonNull; @@ -67,7 +69,6 @@ import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.os.Bundle; import android.os.IBinder; -import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.util.DisplayMetrics; @@ -90,7 +91,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -123,9 +123,7 @@ public class ActivityThreadTest { @Rule(order = 1) public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); - @Mock - private BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener; - + private ActivityWindowInfoListener mActivityWindowInfoListener; private WindowTokenClientController mOriginalWindowTokenClientController; private Configuration mOriginalAppConfig; @@ -140,6 +138,7 @@ public class ActivityThreadTest { mOriginalWindowTokenClientController = WindowTokenClientController.getInstance(); mOriginalAppConfig = new Configuration(ActivityThread.currentActivityThread() .getConfiguration()); + mActivityWindowInfoListener = spy(new ActivityWindowInfoListener()); } @After @@ -808,96 +807,107 @@ public class ActivityThreadTest { @Test public void testActivityWindowInfoChanged_activityLaunch() { mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG); - ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener( mActivityWindowInfoListener); final Activity activity = mActivityTestRule.launchActivity(new Intent()); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mActivityWindowInfoListener.await(); final ActivityClientRecord activityClientRecord = getActivityClientRecord(activity); - verify(mActivityWindowInfoListener).accept(activityClientRecord.token, + // In case the system change the window after launch, there can be more than one callback. + verify(mActivityWindowInfoListener, atLeastOnce()).accept(activityClientRecord.token, activityClientRecord.getActivityWindowInfo()); } @Test - public void testActivityWindowInfoChanged_activityRelaunch() throws RemoteException { + public void testActivityWindowInfoChanged_activityRelaunch() { mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG); - ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener( mActivityWindowInfoListener); final Activity activity = mActivityTestRule.launchActivity(new Intent()); - final IApplicationThread appThread = activity.getActivityThread().getApplicationThread(); - appThread.scheduleTransaction(newRelaunchResumeTransaction(activity)); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mActivityWindowInfoListener.await(); final ActivityClientRecord activityClientRecord = getActivityClientRecord(activity); - // The same ActivityWindowInfo won't trigger duplicated callback. - verify(mActivityWindowInfoListener).accept(activityClientRecord.token, - activityClientRecord.getActivityWindowInfo()); - - final Configuration currentConfig = activity.getResources().getConfiguration(); - final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); - activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 1000, 2000), - new Rect(0, 0, 1000, 1000)); - final ActivityRelaunchItem relaunchItem = ActivityRelaunchItem.obtain( - activity.getActivityToken(), null, null, 0, - new MergedConfiguration(currentConfig, currentConfig), - false /* preserveWindow */, activityWindowInfo); - final ClientTransaction transaction = newTransaction(activity); - transaction.addTransactionItem(relaunchItem); - appThread.scheduleTransaction(transaction); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - - verify(mActivityWindowInfoListener).accept(activityClientRecord.token, - activityWindowInfo); + // Run on main thread to avoid racing from updating from window relayout. + final ActivityThread activityThread = activity.getActivityThread(); + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + // Try relaunch with the same ActivityWindowInfo + clearInvocations(mActivityWindowInfoListener); + activityThread.executeTransaction(newRelaunchResumeTransaction(activity)); + + // The same ActivityWindowInfo won't trigger duplicated callback. + verify(mActivityWindowInfoListener, never()).accept(activityClientRecord.token, + activityClientRecord.getActivityWindowInfo()); + + // Try relaunch with different ActivityWindowInfo + final Configuration currentConfig = activity.getResources().getConfiguration(); + final ActivityWindowInfo newInfo = new ActivityWindowInfo(); + newInfo.set(true /* isEmbedded */, new Rect(0, 0, 1000, 2000), + new Rect(0, 0, 1000, 1000)); + final ActivityRelaunchItem relaunchItem = ActivityRelaunchItem.obtain( + activity.getActivityToken(), null, null, 0, + new MergedConfiguration(currentConfig, currentConfig), + false /* preserveWindow */, newInfo); + final ClientTransaction transaction = newTransaction(activity); + transaction.addTransactionItem(relaunchItem); + + clearInvocations(mActivityWindowInfoListener); + activityThread.executeTransaction(transaction); + + // Trigger callback with a different ActivityWindowInfo + verify(mActivityWindowInfoListener).accept(activityClientRecord.token, newInfo); + }); } @Test - public void testActivityWindowInfoChanged_activityConfigurationChanged() - throws RemoteException { + public void testActivityWindowInfoChanged_activityConfigurationChanged() { mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG); - ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener( mActivityWindowInfoListener); final Activity activity = mActivityTestRule.launchActivity(new Intent()); - final IApplicationThread appThread = activity.getActivityThread().getApplicationThread(); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mActivityWindowInfoListener.await(); - clearInvocations(mActivityWindowInfoListener); - final Configuration config = new Configuration(activity.getResources().getConfiguration()); - config.seq++; - final Rect taskBounds = new Rect(0, 0, 1000, 2000); - final Rect taskFragmentBounds = new Rect(0, 0, 1000, 1000); - final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); - activityWindowInfo.set(true /* isEmbedded */, taskBounds, taskFragmentBounds); - final ActivityConfigurationChangeItem activityConfigurationChangeItem = - ActivityConfigurationChangeItem.obtain( - activity.getActivityToken(), config, activityWindowInfo); - final ClientTransaction transaction = newTransaction(activity); - transaction.addTransactionItem(activityConfigurationChangeItem); - appThread.scheduleTransaction(transaction); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - - verify(mActivityWindowInfoListener).accept(activity.getActivityToken(), - activityWindowInfo); - - clearInvocations(mActivityWindowInfoListener); - final ActivityWindowInfo activityWindowInfo2 = new ActivityWindowInfo(); - activityWindowInfo2.set(true /* isEmbedded */, taskBounds, taskFragmentBounds); - config.seq++; - final ActivityConfigurationChangeItem activityConfigurationChangeItem2 = - ActivityConfigurationChangeItem.obtain( - activity.getActivityToken(), config, activityWindowInfo2); - final ClientTransaction transaction2 = newTransaction(activity); - transaction2.addTransactionItem(activityConfigurationChangeItem2); - appThread.scheduleTransaction(transaction); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - - // The same ActivityWindowInfo won't trigger duplicated callback. - verify(mActivityWindowInfoListener, never()).accept(any(), any()); + final ActivityThread activityThread = activity.getActivityThread(); + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + // Trigger callback with different ActivityWindowInfo + final Configuration config = new Configuration(activity.getResources() + .getConfiguration()); + config.seq++; + final Rect taskBounds = new Rect(0, 0, 1000, 2000); + final Rect taskFragmentBounds = new Rect(0, 0, 1000, 1000); + final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); + activityWindowInfo.set(true /* isEmbedded */, taskBounds, taskFragmentBounds); + final ActivityConfigurationChangeItem activityConfigurationChangeItem = + ActivityConfigurationChangeItem.obtain( + activity.getActivityToken(), config, activityWindowInfo); + final ClientTransaction transaction = newTransaction(activity); + transaction.addTransactionItem(activityConfigurationChangeItem); + + clearInvocations(mActivityWindowInfoListener); + activityThread.executeTransaction(transaction); + + // Trigger callback with a different ActivityWindowInfo + verify(mActivityWindowInfoListener).accept(activity.getActivityToken(), + activityWindowInfo); + + // Try callback with the same ActivityWindowInfo + final ActivityWindowInfo activityWindowInfo2 = + new ActivityWindowInfo(activityWindowInfo); + config.seq++; + final ActivityConfigurationChangeItem activityConfigurationChangeItem2 = + ActivityConfigurationChangeItem.obtain( + activity.getActivityToken(), config, activityWindowInfo2); + final ClientTransaction transaction2 = newTransaction(activity); + transaction2.addTransactionItem(activityConfigurationChangeItem2); + + clearInvocations(mActivityWindowInfoListener); + activityThread.executeTransaction(transaction); + + // The same ActivityWindowInfo won't trigger duplicated callback. + verify(mActivityWindowInfoListener, never()).accept(any(), any()); + }); } /** @@ -958,10 +968,12 @@ public class ActivityThreadTest { @NonNull private static ClientTransaction newRelaunchResumeTransaction(@NonNull Activity activity) { final Configuration currentConfig = activity.getResources().getConfiguration(); + final ActivityWindowInfo activityWindowInfo = getActivityClientRecord(activity) + .getActivityWindowInfo(); final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain( activity.getActivityToken(), null, null, 0, new MergedConfiguration(currentConfig, currentConfig), - false /* preserveWindow */, new ActivityWindowInfo()); + false /* preserveWindow */, activityWindowInfo); final ResumeActivityItem resumeStateRequest = ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */, false /* shouldSendCompatFakeFocus*/); @@ -1127,4 +1139,28 @@ public class ActivityThreadTest { return mPipEnterSkipped; } } + + public static class ActivityWindowInfoListener implements + BiConsumer<IBinder, ActivityWindowInfo> { + + CountDownLatch mCallbackLatch = new CountDownLatch(1); + + @Override + public void accept(@NonNull IBinder activityToken, + @NonNull ActivityWindowInfo activityWindowInfo) { + mCallbackLatch.countDown(); + } + + /** + * When the test is expecting to receive a callback, waits until the callback is triggered. + */ + void await() { + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + try { + mCallbackLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } } |