Merge "Wait for rotation to complete after changing orientation" into androidx-main
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiDeviceTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiDeviceTest.java
index 693d7bf..7d956be 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiDeviceTest.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiDeviceTest.java
@@ -24,7 +24,6 @@
 
 import android.app.UiAutomation;
 import android.graphics.Point;
-import android.os.SystemClock;
 import android.view.KeyEvent;
 import android.widget.TextView;
 
@@ -363,13 +362,12 @@
         try {
             assertTrue(mDevice.isNaturalOrientation());
             assertEquals(UiAutomation.ROTATION_FREEZE_0, mDevice.getDisplayRotation());
+
             mDevice.setOrientationLeft();
-            // Make the device wait for 1 sec for the rotation animation to finish.
-            SystemClock.sleep(1_000);
             assertFalse(mDevice.isNaturalOrientation());
             assertEquals(UiAutomation.ROTATION_FREEZE_90, mDevice.getDisplayRotation());
+
             mDevice.setOrientationNatural();
-            SystemClock.sleep(1_000);
             assertTrue(mDevice.isNaturalOrientation());
         } finally {
             mDevice.unfreezeRotation();
@@ -382,12 +380,12 @@
         try {
             assertTrue(mDevice.isNaturalOrientation());
             assertEquals(UiAutomation.ROTATION_FREEZE_0, mDevice.getDisplayRotation());
+
             mDevice.setOrientationRight();
-            SystemClock.sleep(1_000);
             assertFalse(mDevice.isNaturalOrientation());
             assertEquals(UiAutomation.ROTATION_FREEZE_270, mDevice.getDisplayRotation());
+
             mDevice.setOrientationNatural();
-            SystemClock.sleep(1_000);
             assertTrue(mDevice.isNaturalOrientation());
         } finally {
             mDevice.unfreezeRotation();
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/InteractionController.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/InteractionController.java
index 3d6eee1..379d940 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/InteractionController.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/InteractionController.java
@@ -480,60 +480,6 @@
     }
 
     /**
-     * Rotates right and also freezes rotation in that position by
-     * disabling the sensors. If you want to un-freeze the rotation
-     * and re-enable the sensors see {@link #unfreezeRotation()}. Note
-     * that doing so may cause the screen contents to rotate
-     * depending on the current physical position of the test device.
-     * @throws RemoteException
-     */
-    public void setRotationRight() {
-        getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_270);
-    }
-
-    /**
-     * Rotates left and also freezes rotation in that position by
-     * disabling the sensors. If you want to un-freeze the rotation
-     * and re-enable the sensors see {@link #unfreezeRotation()}. Note
-     * that doing so may cause the screen contents to rotate
-     * depending on the current physical position of the test device.
-     * @throws RemoteException
-     */
-    public void setRotationLeft() {
-        getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90);
-    }
-
-    /**
-     * Rotates up and also freezes rotation in that position by
-     * disabling the sensors. If you want to un-freeze the rotation
-     * and re-enable the sensors see {@link #unfreezeRotation()}. Note
-     * that doing so may cause the screen contents to rotate
-     * depending on the current physical position of the test device.
-     * @throws RemoteException
-     */
-    public void setRotationNatural() {
-        getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
-    }
-
-    /**
-     * Disables the sensors and freezes the device rotation at its
-     * current rotation state.
-     * @throws RemoteException
-     */
-    public void freezeRotation() {
-        getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_CURRENT);
-    }
-
-    /**
-     * Re-enables the sensors and un-freezes the device rotation
-     * allowing its contents to rotate with the device physical rotation.
-     * @throws RemoteException
-     */
-    public void unfreezeRotation() {
-        getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
-    }
-
-    /**
      * This method simply presses the power button if the screen is OFF else
      * it does nothing if the screen is already ON.
      * On API 20 or later devices, this will press the wakeup button instead.
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java
index a15835f..a39869e 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/UiDevice.java
@@ -76,6 +76,7 @@
     // Use a short timeout after HOME or BACK key presses, as no events might be generated if
     // already on the home page or if there is nothing to go back to.
     private static final long KEY_PRESS_EVENT_TIMEOUT = 1_000; // ms
+    private static final long ROTATION_TIMEOUT = 1_000; // ms
 
     // Singleton instance.
     private static UiDevice sInstance;
@@ -751,19 +752,16 @@
     }
 
     /**
-     * Check if the device is in its natural orientation. This is determined by checking if the
-     * orientation is at 0 or 180 degrees.
-     * @return true if it is in natural orientation
+     * @return true if device is in its natural orientation (0 or 180 degrees)
      */
     public boolean isNaturalOrientation() {
-        waitForIdle();
         int ret = getDisplayRotation();
         return ret == UiAutomation.ROTATION_FREEZE_0 ||
                 ret == UiAutomation.ROTATION_FREEZE_180;
     }
 
     /**
-     * Returns the current rotation of the display, as defined in {@link Surface}
+     * @return the current rotation of the display, as defined in {@link Surface}
      */
     public int getDisplayRotation() {
         waitForIdle();
@@ -771,66 +769,72 @@
     }
 
     /**
-     * Disables the sensors and freezes the device rotation at its
-     * current rotation state.
-     * @throws RemoteException
+     * Freezes the device rotation at its current state.
+     * @throws RemoteException never
      */
     public void freezeRotation() throws RemoteException {
         Log.d(TAG, "Freezing rotation.");
-        getInteractionController().freezeRotation();
+        getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_CURRENT);
     }
 
     /**
-     * Re-enables the sensors and un-freezes the device rotation allowing its contents
-     * to rotate with the device physical rotation. During a test execution, it is best to
-     * keep the device frozen in a specific orientation until the test case execution has completed.
-     * @throws RemoteException
+     * Un-freezes the device rotation allowing its contents to rotate with the device physical
+     * rotation. During testing, it is best to keep the device frozen in a specific orientation.
+     * @throws RemoteException never
      */
     public void unfreezeRotation() throws RemoteException {
         Log.d(TAG, "Unfreezing rotation.");
-        getInteractionController().unfreezeRotation();
+        getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
     }
 
     /**
-     * Simulates orienting the device to the left and also freezes rotation
-     * by disabling the sensors.
-     *
-     * If you want to un-freeze the rotation and re-enable the sensors
-     * see {@link #unfreezeRotation()}.
-     * @throws RemoteException
+     * Orients the device to the left and freezes rotation. Use {@link #unfreezeRotation()} to
+     * un-freeze the rotation.
+     * @throws RemoteException never
      */
     public void setOrientationLeft() throws RemoteException {
         Log.d(TAG, "Setting orientation to left.");
-        getInteractionController().setRotationLeft();
-        waitForIdle(); // we don't need to check for idle on entry for this. We'll sync on exit
+        rotate(UiAutomation.ROTATION_FREEZE_90);
     }
 
     /**
-     * Simulates orienting the device to the right and also freezes rotation
-     * by disabling the sensors.
-     *
-     * If you want to un-freeze the rotation and re-enable the sensors
-     * see {@link #unfreezeRotation()}.
-     * @throws RemoteException
+     * Orients the device to the right and freezes rotation. Use {@link #unfreezeRotation()} to
+     * un-freeze the rotation.
+     * @throws RemoteException never
      */
     public void setOrientationRight() throws RemoteException {
         Log.d(TAG, "Setting orientation to right.");
-        getInteractionController().setRotationRight();
-        waitForIdle(); // we don't need to check for idle on entry for this. We'll sync on exit
+        rotate(UiAutomation.ROTATION_FREEZE_270);
     }
 
     /**
-     * Simulates orienting the device into its natural orientation and also freezes rotation
-     * by disabling the sensors.
-     *
-     * If you want to un-freeze the rotation and re-enable the sensors
-     * see {@link #unfreezeRotation()}.
-     * @throws RemoteException
+     * Orients the device to its natural orientation (0 or 180 degrees) and freezes rotation. Use
+     * {@link #unfreezeRotation()} to un-freeze the rotation.
+     * @throws RemoteException never
      */
     public void setOrientationNatural() throws RemoteException {
         Log.d(TAG, "Setting orientation to natural.");
-        getInteractionController().setRotationNatural();
-        waitForIdle(); // we don't need to check for idle on entry for this. We'll sync on exit
+        rotate(UiAutomation.ROTATION_FREEZE_0);
+    }
+
+    // Rotates the device and waits for the rotation to be detected.
+    private void rotate(int rotation) {
+        getUiAutomation().setRotation(rotation);
+        Condition<UiDevice, Boolean> rotationCondition = new Condition<UiDevice, Boolean>() {
+            @Override
+            public Boolean apply(UiDevice device) {
+                return device.getDisplayRotation() == rotation;
+            }
+
+            @NonNull
+            @Override
+            public String toString() {
+                return String.format("Condition[displayRotation=%d]", rotation);
+            }
+        };
+        if (!wait(rotationCondition, ROTATION_TIMEOUT)) {
+            Log.w(TAG, String.format("Didn't detect rotation within %dms.", ROTATION_TIMEOUT));
+        }
     }
 
     /**