Adding render stats APIs to UiAutomation (CTS).
bug:12927198
Change-Id: Ic9b3aeed6d75e8ceaeda84ec962cd3caa0ed7bbe
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 0daf064..52456e7 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -115,6 +115,7 @@
CtsTextTestCases \
CtsTextureViewTestCases \
CtsThemeTestCases \
+ CtsUiAutomationTestCases \
CtsUtilTestCases \
CtsViewTestCases \
CtsWebkitTestCases \
diff --git a/tests/tests/uiautomation/Android.mk b/tests/tests/uiautomation/Android.mk
new file mode 100644
index 0000000..bb0fc19
--- /dev/null
+++ b/tests/tests/uiautomation/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ub-uiautomator
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsUiAutomationTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
diff --git a/tests/tests/uiautomation/AndroidManifest.xml b/tests/tests/uiautomation/AndroidManifest.xml
new file mode 100644
index 0000000..06b31c8
--- /dev/null
+++ b/tests/tests/uiautomation/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.app.cts.uiautomation">
+
+ <application android:theme="@android:style/Theme.Holo.NoActionBar" >
+
+ <uses-library android:name="android.test.runner"/>
+
+ <activity
+ android:name="android.app.uiautomation.cts.UiAutomationTestFirstActivity"
+ android:exported="true">
+ </activity>
+
+ <activity
+ android:name="android.app.uiautomation.cts.UiAutomationTestSecondActivity"
+ android:exported="true">
+ </activity>
+
+ </application>
+
+ <instrumentation android:name="android.support.test.uiautomator.UiAutomatorInstrumentationTestRunner"
+ android:targetPackage="android.app.cts.uiautomation">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
diff --git a/tests/tests/uiautomation/res/layout/ui_automation_test.xml b/tests/tests/uiautomation/res/layout/ui_automation_test.xml
new file mode 100644
index 0000000..fb9621d
--- /dev/null
+++ b/tests/tests/uiautomation/res/layout/ui_automation_test.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+</ListView>
diff --git a/tests/tests/uiautomation/res/values/strings.xml b/tests/tests/uiautomation/res/values/strings.xml
new file mode 100644
index 0000000..7e4e4e4
--- /dev/null
+++ b/tests/tests/uiautomation/res/values/strings.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <string name="uiautomation_test_activity">Cheeses</string>
+
+ <string-array name="some_cheeses">
+ <item>Abbaye de Belloc</item>
+ <item>Abbaye de Belval</item>
+ <item>Abbaye de Citeaux</item>
+ <item>Abbaye du Mont des Cats</item>
+ <item>Abbot’s Gold</item>
+ <item>Acapella</item>
+ <item>Acorn</item>
+ <item>Adelost</item>
+ <item>Affidelice au Chablis</item>
+ <item>Afuega\'l Pitu</item>
+ <item>Aged Gouda</item>
+ <item>Airag</item>
+ <item>Airedale</item>
+ <item>Aisy Cendre</item>
+ <item>Allgauer Emmentaler</item>
+ <item>Babybel</item>
+ <item>Baby Swiss</item>
+ <item>Baguette Laonnaise</item>
+ <item>Bakers</item>
+ <item>Balaton</item>
+ <item>Bandal</item>
+ <item>Banon</item>
+ <item>Barry\'s Bay Cheddar</item>
+ <item>Basing</item>
+ <item>Basket Cheese</item>
+ <item>Bath Cheese</item>
+ <item>Bavarian Bergkase</item>
+ <item>Baylough</item>
+ <item>Beauvoorde</item>
+ <item>Beemster 2% Milk</item>
+ </string-array>
+
+</resources>
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
new file mode 100644
index 0000000..6d80819
--- /dev/null
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.uiautomation.cts;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.Activity;
+import android.app.UiAutomation;
+import android.content.Intent;
+import android.view.FrameStats;
+import android.view.WindowAnimationFrameStats;
+import android.view.WindowContentFrameStats;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.UiAutomatorTestCase;
+
+import java.util.List;
+
+/**
+ * Tests for the UiAutomation APIs.
+ */
+public class UiAutomationTest extends UiAutomatorTestCase {
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
+ info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+ getInstrumentation().getUiAutomation().setServiceInfo(info);
+ }
+
+ public void testWindowContentFrameStats() throws Exception {
+ Activity activity = null;
+ try {
+ UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+ // Start an activity.
+ Intent intent = new Intent(getInstrumentation().getContext(),
+ UiAutomationTestFirstActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ activity = getInstrumentation().startActivitySync(intent);
+
+ // Wait for things to settle.
+ getUiDevice().waitForIdle();
+
+ // Find the application window.
+ final int windowId = findAppWindowId(uiAutomation.getWindows());
+ assertTrue(windowId >= 0);
+
+ // Clear stats to be with a clean slate.
+ assertTrue(uiAutomation.clearWindowContentFrameStats(windowId));
+
+ // Find the list to scroll around.
+ UiScrollable listView = new UiScrollable(new UiSelector().resourceId(
+ "android.app.cts.uiautomation:id/list_view"));
+
+ // Scoll a bit.
+ listView.scrollToEnd(Integer.MAX_VALUE);
+ listView.scrollToBeginning(Integer.MAX_VALUE);
+
+ // Get the frame stats.
+ WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId);
+
+ // Check the frame stats...
+
+ // We should have somethong.
+ assertNotNull(stats);
+
+ // The refresh presiod is always positive.
+ assertTrue(stats.getRefreshPeriodNano() > 0);
+
+ // There is some frame data.
+ final int frameCount = stats.getFrameCount();
+ assertTrue(frameCount > 0);
+
+ // The frames are ordered in ascending order.
+ assertWindowContentTimestampsInAscendingOrder(stats);
+
+ // The start and end times are based on first and last frame.
+ assertEquals(stats.getStartTimeNano(), stats.getFramePresentedTimeNano(0));
+ assertEquals(stats.getEndTimeNano(), stats.getFramePresentedTimeNano(frameCount - 1));
+ } finally {
+ // Clean up.
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+ }
+
+ public void testWindowContentFrameStatsNoAnimation() throws Exception {
+ Activity activity = null;
+ try {
+ UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+ // Start an activity.
+ Intent intent = new Intent(getInstrumentation().getContext(),
+ UiAutomationTestFirstActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ activity = getInstrumentation().startActivitySync(intent);
+
+ // Wait for things to settle.
+ getUiDevice().waitForIdle();
+
+ // Find the application window.
+ final int windowId = findAppWindowId(uiAutomation.getWindows());
+ assertTrue(windowId >= 0);
+
+ // Clear stats to be with a clean slate.
+ assertTrue(uiAutomation.clearWindowContentFrameStats(windowId));
+
+ // Get the frame stats.
+ WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId);
+
+ // Check the frame stats...
+
+ // We should have somethong.
+ assertNotNull(stats);
+
+ // The refresh presiod is always positive.
+ assertTrue(stats.getRefreshPeriodNano() > 0);
+
+ // There is no data.
+ assertTrue(stats.getFrameCount() == 0);
+
+ // The start and end times are undefibed as we have no data.
+ assertEquals(stats.getStartTimeNano(), FrameStats.UNDEFINED_TIME_NANO);
+ assertEquals(stats.getEndTimeNano(), FrameStats.UNDEFINED_TIME_NANO);
+ } finally {
+ // Clean up.
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+ }
+
+ public void testWindowAnimationFrameStats() throws Exception {
+ Activity firstActivity = null;
+ Activity secondActivity = null;
+ try {
+ UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+ // Start the frist activity.
+ Intent firstIntent = new Intent(getInstrumentation().getContext(),
+ UiAutomationTestFirstActivity.class);
+ firstIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ firstActivity = getInstrumentation().startActivitySync(firstIntent);
+
+ // Wait for things to settle.
+ getUiDevice().waitForIdle();
+
+ // Clear the window animation stats to be with a clean slate.
+ uiAutomation.clearWindowAnimationFrameStats();
+
+ // Start the second activity
+ Intent secondIntent = new Intent(getInstrumentation().getContext(),
+ UiAutomationTestSecondActivity.class);
+ secondIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ secondActivity = getInstrumentation().startActivitySync(secondIntent);
+
+ // Wait for things to settle.
+ getUiDevice().waitForIdle();
+
+ // Get the frame stats.
+ WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
+
+ // Check the frame stats...
+
+ // We should have somethong.
+ assertNotNull(stats);
+
+ // The refresh presiod is always positive.
+ assertTrue(stats.getRefreshPeriodNano() > 0);
+
+ // There is some frame data.
+ final int frameCount = stats.getFrameCount();
+ assertTrue(frameCount > 0);
+
+ // The frames are ordered in ascending order.
+ assertWindowAnimationTimestampsInAscendingOrder(stats);
+
+ // The start and end times are based on first and last frame.
+ assertEquals(stats.getStartTimeNano(), stats.getFramePresentedTimeNano(0));
+ assertEquals(stats.getEndTimeNano(), stats.getFramePresentedTimeNano(frameCount - 1));
+ } finally {
+ // Clean up.
+ if (firstActivity != null) {
+ firstActivity.finish();
+ }
+ if (secondActivity != null) {
+ secondActivity.finish();
+ }
+ }
+ }
+
+ public void testWindowAnimationFrameStatsNoAnimation() throws Exception {
+ UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+
+ // Wait for things to settle.
+ getUiDevice().waitForIdle();
+
+ // Clear the window animation stats to be with a clean slate.
+ uiAutomation.clearWindowAnimationFrameStats();
+
+ // Get the frame stats.
+ WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
+
+ // Check the frame stats...
+
+ // We should have somethong.
+ assertNotNull(stats);
+
+ // The refresh presiod is always positive.
+ assertTrue(stats.getRefreshPeriodNano() > 0);
+
+ // There is no data.
+ assertTrue(stats.getFrameCount() == 0);
+
+ // The start and end times are undefibed as we have no data.
+ assertEquals(stats.getStartTimeNano(), FrameStats.UNDEFINED_TIME_NANO);
+ assertEquals(stats.getEndTimeNano(), FrameStats.UNDEFINED_TIME_NANO);
+ }
+
+ private void assertWindowContentTimestampsInAscendingOrder(WindowContentFrameStats stats) {
+ long lastExpectedTimeNano = 0;
+ long lastPresentedTimeNano = 0;
+ long lastPreparedTimeNano = 0;
+
+ final int frameCount = stats.getFrameCount();
+ for (int i = 0; i < frameCount; i++) {
+ final long expectedTimeNano = stats.getFramePostedTimeNano(i);
+ assertTrue(expectedTimeNano > lastExpectedTimeNano);
+ lastExpectedTimeNano = expectedTimeNano;
+
+ final long presentedTimeNano = stats.getFramePresentedTimeNano(i);
+ if (lastPresentedTimeNano == FrameStats.UNDEFINED_TIME_NANO) {
+ assertTrue(presentedTimeNano == FrameStats.UNDEFINED_TIME_NANO);
+ } else if (presentedTimeNano != FrameStats.UNDEFINED_TIME_NANO) {
+ assertTrue(presentedTimeNano > lastPresentedTimeNano);
+ }
+ lastPresentedTimeNano = presentedTimeNano;
+
+ final long preparedTimeNano = stats.getFrameReadyTimeNano(i);
+ if (lastPreparedTimeNano == FrameStats.UNDEFINED_TIME_NANO) {
+ assertTrue(preparedTimeNano == FrameStats.UNDEFINED_TIME_NANO);
+ } else if (preparedTimeNano != FrameStats.UNDEFINED_TIME_NANO) {
+ assertTrue(preparedTimeNano > lastPreparedTimeNano);
+ }
+ lastPreparedTimeNano = preparedTimeNano;
+ }
+ }
+
+ private void assertWindowAnimationTimestampsInAscendingOrder(WindowAnimationFrameStats stats) {
+ long lastPresentedTimeNano = 0;
+
+ final int frameCount = stats.getFrameCount();
+ for (int i = 0; i < frameCount; i++) {
+ final long presentedTimeNano = stats.getFramePresentedTimeNano(i);
+ if (lastPresentedTimeNano == FrameStats.UNDEFINED_TIME_NANO) {
+ assertTrue(presentedTimeNano == FrameStats.UNDEFINED_TIME_NANO);
+ } else if (presentedTimeNano != FrameStats.UNDEFINED_TIME_NANO) {
+ assertTrue(presentedTimeNano > lastPresentedTimeNano);
+ }
+ lastPresentedTimeNano = presentedTimeNano;
+ }
+ }
+
+ private int findAppWindowId(List<AccessibilityWindowInfo> windows) {
+ final int windowCount = windows.size();
+ for (int i = 0; i < windowCount; i++) {
+ AccessibilityWindowInfo window = windows.get(i);
+ if (window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) {
+ return window.getId();
+ }
+ }
+ return -1;
+ }
+}
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java
new file mode 100644
index 0000000..49791ab
--- /dev/null
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestFirstActivity.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.app.uiautomation.cts;
+
+import android.app.cts.uiautomation.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+* Activity for testing the UiAutomatoin APIs.
+*/
+public class UiAutomationTestFirstActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.ui_automation_test);
+
+ String[] cheeses = getResources().getStringArray(R.array.some_cheeses);
+ ArrayAdapter<String> cheeseAdapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, cheeses);
+
+ ListView listView = (ListView) findViewById(R.id.list_view);
+ listView.setAdapter(cheeseAdapter);
+ }
+}
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java
new file mode 100644
index 0000000..7def379
--- /dev/null
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTestSecondActivity.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.app.uiautomation.cts;
+
+import android.app.Activity;
+import android.app.cts.uiautomation.R;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+* Activity for testing the UiAutomatoin APIs.
+*/
+public class UiAutomationTestSecondActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.ui_automation_test);
+
+ String[] cheeses = getResources().getStringArray(R.array.some_cheeses);
+ ArrayAdapter<String> cheeseAdapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, cheeses);
+
+ ListView listView = (ListView) findViewById(R.id.list_view);
+ listView.setAdapter(cheeseAdapter);
+ }
+}