Merge "CTS tests for tooltip a11y support"
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index eb3578b..e9902f8 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -36,7 +36,7 @@
 public class AccessibilityNodeInfoTest extends AndroidTestCase {
 
     /** The number of properties of the {@link AccessibilityNodeInfo} class that are marshalled. */
-    private static final int NUM_MARSHALLED_PROPERTIES = 34;
+    private static final int NUM_MARSHALLED_PROPERTIES = 35;
 
     /**
      * The number of properties that are purposely not marshalled
@@ -205,6 +205,7 @@
         info.setBoundsInScreen(new Rect(2,2,2,2));
         info.setClassName("foo.bar.baz.Class");
         info.setContentDescription("content description");
+        info.setTooltipText("tooltip");
         info.setPackageName("foo.bar.baz");
         info.setText("text");
         info.setHintText("hint");
@@ -255,6 +256,8 @@
                 receivedInfo.getClassName());
         assertEquals("contentDescription has incorrect value", expectedInfo.getContentDescription(),
                 receivedInfo.getContentDescription());
+        assertEquals("tooltip text has incorrect value", expectedInfo.getTooltipText(),
+                receivedInfo.getTooltipText());
         assertEquals("packageName has incorrect value", expectedInfo.getPackageName(),
                 receivedInfo.getPackageName());
         assertEquals("text has incorrect value", expectedInfo.getText(), receivedInfo.getText());
@@ -324,6 +327,7 @@
         assertTrue("boundsInScreen not properly recycled", bounds.isEmpty());
         assertNull("className not properly recycled", info.getClassName());
         assertNull("contentDescription not properly recycled", info.getContentDescription());
+        assertNull("tooltiptext not properly recycled", info.getTooltipText());
         assertNull("packageName not properly recycled", info.getPackageName());
         assertNull("text not properly recycled", info.getText());
         assertNull("Hint text not properly recycled", info.getHintText());
diff --git a/tests/accessibilityservice/res/layout/end_to_end_test.xml b/tests/accessibilityservice/res/layout/end_to_end_test.xml
index cba3a15..fdc3998 100644
--- a/tests/accessibilityservice/res/layout/end_to_end_test.xml
+++ b/tests/accessibilityservice/res/layout/end_to_end_test.xml
@@ -39,6 +39,7 @@
         <Button android:id="@+id/button"
                 android:text="@string/button_title"
                 android:accessibilityPaneTitle="@string/paneTitle"
+                android:tooltipText="@string/button_tooltip"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:bufferType="normal">
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index 0e8d78a..454102a 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -34,6 +34,8 @@
     <!-- String title of the button -->
     <string name="button_title">Click me</string>
 
+    <string name="button_tooltip">Never press this button</string>
+
     <!-- String value of the first list item -->
     <string name="first_list_item">First list item</string>
 
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index 7052fc3..8202399 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -18,6 +18,12 @@
 
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventType;
 import static android.accessibilityservice.cts.utils.RunOnMainUtils.getOnMain;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP;
+
+import static org.hamcrest.Matchers.in;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertThat;
 
 import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
 import android.app.Activity;
@@ -41,6 +47,7 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -51,6 +58,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * This class performs end-to-end testing of the accessibility feature by
@@ -581,6 +589,42 @@
                 editTextNode.isHeading());
     }
 
+    @MediumTest
+    public void testTooltipTextReportedToAccessibility() {
+        final Instrumentation instrumentation = getInstrumentation();
+        final UiAutomation uiAutomation = instrumentation.getUiAutomation();
+        final AccessibilityNodeInfo buttonNode = uiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByViewId(
+                        "android.accessibilityservice.cts:id/button")
+                .get(0);
+        assertEquals("Tooltip text not reported to accessibility",
+                instrumentation.getContext().getString(R.string.button_tooltip),
+                buttonNode.getTooltipText());
+    }
+
+    @MediumTest
+    public void testTooltipTextActionsReportedToAccessibility() throws Exception {
+        final Instrumentation instrumentation = getInstrumentation();
+        final UiAutomation uiAutomation = instrumentation.getUiAutomation();
+        final AccessibilityNodeInfo buttonNode = uiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByViewId(
+                        "android.accessibilityservice.cts:id/button")
+                .get(0);
+        assertFalse(hasTooltip(R.id.button));
+        assertThat(ACTION_SHOW_TOOLTIP, in(buttonNode.getActionList()));
+        assertThat(ACTION_HIDE_TOOLTIP, not(in(buttonNode.getActionList())));
+        uiAutomation.executeAndWaitForEvent(() -> buttonNode.performAction(
+                ACTION_SHOW_TOOLTIP.getId()),
+                filterForEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED),
+                TIMEOUT_ASYNC_PROCESSING);
+
+        // The button should now be showing the tooltip, so it should have the option to hide it.
+        buttonNode.refresh();
+        assertThat(ACTION_HIDE_TOOLTIP, in(buttonNode.getActionList()));
+        assertThat(ACTION_SHOW_TOOLTIP, not(in(buttonNode.getActionList())));
+        assertTrue(hasTooltip(R.id.button));
+    }
+
     private static void assertPackageName(AccessibilityNodeInfo node, String packageName) {
         if (node == null) {
             return;
@@ -690,4 +734,15 @@
         }
         return true;
     }
+
+    private boolean hasTooltip(int id) {
+        return getOnMain(getInstrumentation(), () -> {
+            final View viewWithTooltip = getActivity().findViewById(id);
+            if (viewWithTooltip == null) {
+                return false;
+            }
+            final View tooltipView = viewWithTooltip.getTooltipView();
+            return (tooltipView != null) && (tooltipView.getParent() != null);
+        });
+    }
 }