summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2013-11-24 16:21:49 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2013-11-24 16:21:49 -0800
commita71ff4c34d708a2a130e5753e8ac966ddaa84c35 (patch)
treeb92e8d5807b79a474daa701d016fed6ec1b49e93
parent34f0bc324a145846e938b7737be0166dbf6b92fd (diff)
parent03b9a8ad5619b1fd045d6a1a1edcaed03e532a6c (diff)
downloaduiautomator-a71ff4c34d708a2a130e5753e8ac966ddaa84c35.tar.gz
Merge in Android 4.4
-rw-r--r--.classpath7
-rw-r--r--.gitignore2
-rw-r--r--.project17
-rw-r--r--Android.mk25
-rw-r--r--src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java (renamed from core/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java)0
-rw-r--r--src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java (renamed from core/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java)0
-rw-r--r--src/com/android/uiautomator/core/Configurator.java (renamed from core/com/android/uiautomator/core/Configurator.java)0
-rw-r--r--src/com/android/uiautomator/core/InstrumentationUiAutomatorBridge.java (renamed from testrunner/com/android/uiautomator/core/InstrumentationUiAutomatorBridge.java)0
-rw-r--r--src/com/android/uiautomator/core/InteractionController.java (renamed from core/com/android/uiautomator/core/InteractionController.java)0
-rw-r--r--src/com/android/uiautomator/core/QueryController.java (renamed from core/com/android/uiautomator/core/QueryController.java)18
-rw-r--r--src/com/android/uiautomator/core/Tracer.java (renamed from core/com/android/uiautomator/core/Tracer.java)0
-rw-r--r--src/com/android/uiautomator/core/UiAutomatorBridge.java (renamed from core/com/android/uiautomator/core/UiAutomatorBridge.java)0
-rw-r--r--src/com/android/uiautomator/core/UiCollection.java (renamed from core/com/android/uiautomator/core/UiCollection.java)0
-rw-r--r--src/com/android/uiautomator/core/UiDevice.java (renamed from core/com/android/uiautomator/core/UiDevice.java)0
-rw-r--r--src/com/android/uiautomator/core/UiObject.java (renamed from core/com/android/uiautomator/core/UiObject.java)2
-rw-r--r--src/com/android/uiautomator/core/UiObjectNotFoundException.java (renamed from core/com/android/uiautomator/core/UiObjectNotFoundException.java)0
-rw-r--r--src/com/android/uiautomator/core/UiScrollable.java (renamed from core/com/android/uiautomator/core/UiScrollable.java)0
-rw-r--r--src/com/android/uiautomator/core/UiSelector.java (renamed from core/com/android/uiautomator/core/UiSelector.java)2
-rw-r--r--src/com/android/uiautomator/core/UiWatcher.java (renamed from core/com/android/uiautomator/core/UiWatcher.java)0
-rw-r--r--src/com/android/uiautomator/testrunner/IAutomationSupport.java (renamed from testrunner/com/android/uiautomator/testrunner/IAutomationSupport.java)0
-rw-r--r--src/com/android/uiautomator/testrunner/InstrumentationAutomationSupport.java (renamed from testrunner/com/android/uiautomator/testrunner/InstrumentationAutomationSupport.java)0
-rw-r--r--src/com/android/uiautomator/testrunner/UiAutomatorInstrumentationTestRunner.java (renamed from testrunner/com/android/uiautomator/testrunner/UiAutomatorInstrumentationTestRunner.java)0
-rw-r--r--src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java (renamed from testrunner/com/android/uiautomator/testrunner/UiAutomatorTestCase.java)0
-rw-r--r--tests/Android.mk15
-rw-r--r--tests/CtsUiAutomatorTest/Android.mk29
-rw-r--r--tests/CtsUiAutomatorTest/AndroidManifest.xml31
-rw-r--r--tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/CtsUiAutomatorTest.java1046
-rw-r--r--tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/TimeoutTest.java144
-rw-r--r--tests/CtsUiAutomatorTest/testapp/Android.mk33
-rw-r--r--tests/CtsUiAutomatorTest/testapp/AndroidManifest.xml49
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_action_search.pngbin0 -> 3120 bytes
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_launcher.pngbin0 -> 3104 bytes
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/drawable-ldpi/ic_launcher.pngbin0 -> 1561 bytes
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_action_search.pngbin0 -> 3030 bytes
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_launcher.pngbin0 -> 1998 bytes
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_action_search.pngbin0 -> 3199 bytes
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_launcher.pngbin0 -> 4165 bytes
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/activity_main.xml31
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/launched_activity.xml7
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/list_activity.xml26
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/simple_list_item_selected.xml28
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/singlepane_activity.xml23
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test1_detail_fragment.xml61
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test2_detail_fragment.xml78
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test3_detail_fragment.xml76
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test4_detail_fragment.xml23
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test5_detail_fragment.xml109
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test6_detail_fragment.xml28
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test_results_detail_fragment.xml44
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/test_timeout_fragment.xml26
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/layout/twopane_activity.xml41
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/activity_main.xml26
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/test1_detail_activity.xml23
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/test2_detail_activity.xml32
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/test3_detail_activity.xml23
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/test4_detail_activity.xml23
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/test5_detail_activity.xml23
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/test6_detail_activity.xml23
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/menu/test_results_detail_activity.xml24
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values-large/dimens.xml24
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values-large/refs.xml20
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values-sw600dp/refs.xml20
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values-v11/styles.xml22
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values-v14/styles.xml22
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values/dimens.xml24
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values/strings.xml63
-rw-r--r--tests/CtsUiAutomatorTest/testapp/res/values/styles.xml22
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/LaunchedActivity.java31
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/MainActivity.java60
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/SinglePaneDetailActivity.java56
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test1DetailFragment.java80
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test2DetailFragment.java153
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test3DetailFragment.java134
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test4DetailFragment.java178
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test5DetailFragment.java151
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test6DetailFragment.java50
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestGenericDetailFragment.java176
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestItems.java128
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestListFragment.java105
-rw-r--r--tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestTimeoutFragment.java74
80 files changed, 3786 insertions, 25 deletions
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..c4c36bf
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="UIAUTOMATOR_ROOT/prebuilts/sdk/current/android.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..49fb040
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.class
+bin
diff --git a/.project b/.project
new file mode 100644
index 0000000..bca8b86
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>uiautomator</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/Android.mk b/Android.mk
index 7d61619..c304ebe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -16,16 +16,13 @@
LOCAL_PATH:= $(call my-dir)
-uiautomator.core_src_files := $(call all-java-files-under, testrunner) \
- $(call all-java-files-under, core)
-
-uiautomator_internal_api_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/uiautomator_api.txt
+uiautomator_internal_api_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/ub_uiautomator_api.txt
###############################################
# Build core library
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(uiautomator.core_src_files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE := ub-uiautomator
LOCAL_SDK_VERSION := current
@@ -48,7 +45,7 @@ uiautomator_library := $(LOCAL_BUILT_MODULE)
###############################################
# Generate the stub source files
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(uiautomator.core_src_files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SDK_VERSION := current
LOCAL_MODULE_CLASS := DOCS
LOCAL_DROIDDOC_HTML_DIR :=
@@ -80,7 +77,7 @@ checkapi_last_error_level_flags := \
# Check that the API we're building hasn't broken the last-released SDK version.
$(eval $(call check-api, \
- uiautomator-checkapi-last, \
+ ub-uiautomator-checkapi-last, \
$(uiautomator_api_dir)/$(last_released_sdk_version).txt, \
$(uiautomator_internal_api_file), \
$(checkapi_last_error_level_flags), \
@@ -97,7 +94,7 @@ checkapi_current_error_level_flags := \
# Check that the API we're building hasn't changed from the not-yet-released
# SDK version.
$(eval $(call check-api, \
- uiautomator-checkapi-current, \
+ ub-uiautomator-checkapi-current, \
$(uiautomator_api_dir)/current.txt, \
$(uiautomator_internal_api_file), \
$(checkapi_current_error_level_flags), \
@@ -105,19 +102,21 @@ $(eval $(call check-api, \
$(uiautomator_library), \
$(uiautomator_stubs_stamp)))
-.PHONY: update-uiautomator-api
-update-uiautomator-api: PRIVATE_API_DIR := $(uiautomator_api_dir)
-update-uiautomator-api: $(uiautomator_internal_api_file) | $(ACP)
+.PHONY: update-ub-uiautomator-api
+update-ub-uiautomator-api: PRIVATE_API_DIR := $(uiautomator_api_dir)
+update-ub-uiautomator-api: $(uiautomator_internal_api_file) | $(ACP)
@echo Copying uiautomator current.txt
$(hide) $(ACP) $< $(PRIVATE_API_DIR)/current.txt
###############################################
# clean up temp vars
-uiautomator.core_src_files :=
-uiautomator.core_java_libraries :=
uiautomator_stubs_stamp :=
uiautomator_internal_api_file :=
uiautomator_library :=
uiautomator_api_dir :=
checkapi_last_error_level_flags :=
checkapi_current_error_level_flags :=
+
+###############################################
+# Build tests
+include $(LOCAL_PATH)/tests/Android.mk
diff --git a/core/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index 1884e06..1884e06 100644
--- a/core/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
diff --git a/core/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java b/src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java
index 54835e3..54835e3 100644
--- a/core/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java
+++ b/src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java
diff --git a/core/com/android/uiautomator/core/Configurator.java b/src/com/android/uiautomator/core/Configurator.java
index 249f404..249f404 100644
--- a/core/com/android/uiautomator/core/Configurator.java
+++ b/src/com/android/uiautomator/core/Configurator.java
diff --git a/testrunner/com/android/uiautomator/core/InstrumentationUiAutomatorBridge.java b/src/com/android/uiautomator/core/InstrumentationUiAutomatorBridge.java
index 34e6d23..34e6d23 100644
--- a/testrunner/com/android/uiautomator/core/InstrumentationUiAutomatorBridge.java
+++ b/src/com/android/uiautomator/core/InstrumentationUiAutomatorBridge.java
diff --git a/core/com/android/uiautomator/core/InteractionController.java b/src/com/android/uiautomator/core/InteractionController.java
index 73e46f1..73e46f1 100644
--- a/core/com/android/uiautomator/core/InteractionController.java
+++ b/src/com/android/uiautomator/core/InteractionController.java
diff --git a/core/com/android/uiautomator/core/QueryController.java b/src/com/android/uiautomator/core/QueryController.java
index 6931528..194af4c 100644
--- a/core/com/android/uiautomator/core/QueryController.java
+++ b/src/com/android/uiautomator/core/QueryController.java
@@ -146,17 +146,15 @@ class QueryController {
if (DEBUG)
Log.d(LOG_TAG, "Searching: " + selector);
- synchronized (mLock) {
- AccessibilityNodeInfo rootNode = getRootNode();
- if (rootNode == null) {
- Log.e(LOG_TAG, "Cannot proceed when root node is null. Aborted search");
- return null;
- }
-
- // Copy so that we don't modify the original's sub selectors
- UiSelector uiSelector = new UiSelector(selector);
- return translateCompoundSelector(uiSelector, rootNode, isCounting);
+ AccessibilityNodeInfo rootNode = getRootNode();
+ if (rootNode == null) {
+ Log.e(LOG_TAG, "Cannot proceed when root node is null. Aborted search");
+ return null;
}
+
+ // Copy so that we don't modify the original's sub selectors
+ UiSelector uiSelector = new UiSelector(selector);
+ return translateCompoundSelector(uiSelector, rootNode, isCounting);
}
/**
diff --git a/core/com/android/uiautomator/core/Tracer.java b/src/com/android/uiautomator/core/Tracer.java
index d574fc0..d574fc0 100644
--- a/core/com/android/uiautomator/core/Tracer.java
+++ b/src/com/android/uiautomator/core/Tracer.java
diff --git a/core/com/android/uiautomator/core/UiAutomatorBridge.java b/src/com/android/uiautomator/core/UiAutomatorBridge.java
index bc5bc8e..bc5bc8e 100644
--- a/core/com/android/uiautomator/core/UiAutomatorBridge.java
+++ b/src/com/android/uiautomator/core/UiAutomatorBridge.java
diff --git a/core/com/android/uiautomator/core/UiCollection.java b/src/com/android/uiautomator/core/UiCollection.java
index e15beb2..e15beb2 100644
--- a/core/com/android/uiautomator/core/UiCollection.java
+++ b/src/com/android/uiautomator/core/UiCollection.java
diff --git a/core/com/android/uiautomator/core/UiDevice.java b/src/com/android/uiautomator/core/UiDevice.java
index 2a51109..2a51109 100644
--- a/core/com/android/uiautomator/core/UiDevice.java
+++ b/src/com/android/uiautomator/core/UiDevice.java
diff --git a/core/com/android/uiautomator/core/UiObject.java b/src/com/android/uiautomator/core/UiObject.java
index 4bb99cd..bd0b733 100644
--- a/core/com/android/uiautomator/core/UiObject.java
+++ b/src/com/android/uiautomator/core/UiObject.java
@@ -433,7 +433,7 @@ public class UiObject {
}
Rect rect = getVisibleBounds(node);
return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(),
- mConfig.getActionAcknowledgmentTimeout());
+ timeout);
}
/**
diff --git a/core/com/android/uiautomator/core/UiObjectNotFoundException.java b/src/com/android/uiautomator/core/UiObjectNotFoundException.java
index fc0891b..fc0891b 100644
--- a/core/com/android/uiautomator/core/UiObjectNotFoundException.java
+++ b/src/com/android/uiautomator/core/UiObjectNotFoundException.java
diff --git a/core/com/android/uiautomator/core/UiScrollable.java b/src/com/android/uiautomator/core/UiScrollable.java
index a8d20c3..a8d20c3 100644
--- a/core/com/android/uiautomator/core/UiScrollable.java
+++ b/src/com/android/uiautomator/core/UiScrollable.java
diff --git a/core/com/android/uiautomator/core/UiSelector.java b/src/com/android/uiautomator/core/UiSelector.java
index bd61bfd..482a74d 100644
--- a/core/com/android/uiautomator/core/UiSelector.java
+++ b/src/com/android/uiautomator/core/UiSelector.java
@@ -290,7 +290,7 @@ public class UiSelector {
/**
* Set the search criteria to match the resource ID
- * of the widget, using a regular expression.http://blog.bettersoftwaretesting.com/
+ * of the widget, using a regular expression.
*
* @param regex a regular expression
* @return UiSelector with the specified search criteria
diff --git a/core/com/android/uiautomator/core/UiWatcher.java b/src/com/android/uiautomator/core/UiWatcher.java
index 5403e30..5403e30 100644
--- a/core/com/android/uiautomator/core/UiWatcher.java
+++ b/src/com/android/uiautomator/core/UiWatcher.java
diff --git a/testrunner/com/android/uiautomator/testrunner/IAutomationSupport.java b/src/com/android/uiautomator/testrunner/IAutomationSupport.java
index f0c60d2..f0c60d2 100644
--- a/testrunner/com/android/uiautomator/testrunner/IAutomationSupport.java
+++ b/src/com/android/uiautomator/testrunner/IAutomationSupport.java
diff --git a/testrunner/com/android/uiautomator/testrunner/InstrumentationAutomationSupport.java b/src/com/android/uiautomator/testrunner/InstrumentationAutomationSupport.java
index a70586e..a70586e 100644
--- a/testrunner/com/android/uiautomator/testrunner/InstrumentationAutomationSupport.java
+++ b/src/com/android/uiautomator/testrunner/InstrumentationAutomationSupport.java
diff --git a/testrunner/com/android/uiautomator/testrunner/UiAutomatorInstrumentationTestRunner.java b/src/com/android/uiautomator/testrunner/UiAutomatorInstrumentationTestRunner.java
index ae763f2..ae763f2 100644
--- a/testrunner/com/android/uiautomator/testrunner/UiAutomatorInstrumentationTestRunner.java
+++ b/src/com/android/uiautomator/testrunner/UiAutomatorInstrumentationTestRunner.java
diff --git a/testrunner/com/android/uiautomator/testrunner/UiAutomatorTestCase.java b/src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
index b5f21c9..b5f21c9 100644
--- a/testrunner/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
+++ b/src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..260fae2
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,15 @@
+# Copyright (C) 2013 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.
+
+include $(call all-subdir-makefiles)
diff --git a/tests/CtsUiAutomatorTest/Android.mk b/tests/CtsUiAutomatorTest/Android.mk
new file mode 100644
index 0000000..9d06bae
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2013 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_PACKAGE_NAME := UbCtsUiAutomatorTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 18
+
+LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator
+
+include $(BUILD_PACKAGE)
+
+# Build the test APK using its own makefile, and any other CTS-related packages
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/tests/CtsUiAutomatorTest/AndroidManifest.xml b/tests/CtsUiAutomatorTest/AndroidManifest.xml
new file mode 100644
index 0000000..c8207db
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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="com.android.uiautomator.tests.cts">
+
+ <uses-sdk android:minSdkVersion="18" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="com.android.uiautomator.testrunner.UiAutomatorInstrumentationTestRunner"
+ android:targetPackage="com.android.uiautomator.tests.cts"
+ android:label="UiAutomator Tests"/>
+
+</manifest>
diff --git a/tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/CtsUiAutomatorTest.java b/tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/CtsUiAutomatorTest.java
new file mode 100644
index 0000000..65e7b9d
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/CtsUiAutomatorTest.java
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts;
+
+import android.content.Intent;
+import android.content.ComponentName;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.uiautomator.core.UiCollection;
+import com.android.uiautomator.core.UiDevice;
+import com.android.uiautomator.core.UiObject;
+import com.android.uiautomator.core.UiObjectNotFoundException;
+import com.android.uiautomator.core.UiScrollable;
+import com.android.uiautomator.core.UiSelector;
+import com.android.uiautomator.core.UiWatcher;
+import com.android.uiautomator.testrunner.UiAutomatorTestCase;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Sanity test uiautomator functionality on target device.
+ */
+public class CtsUiAutomatorTest extends UiAutomatorTestCase {
+ private static final String LOG_TAG = CtsUiAutomatorTest.class.getSimpleName();
+ private static final String[] LIST_SCROLL_TESTS = new String[] {
+ "Test 17", "Test 11", "Test 20", "Test 35"
+ };
+ private static final String PKG_NAME = "com.android.uiautomator.tests.cts.testapp";
+
+ // Maximum wait for key object to become visible
+ private static final int WAIT_EXIST_TIMEOUT = 5 * 1000;
+
+ private static final String SCREEN_SHOT_FILE_PATH_NAME = "ctsScreenShot";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // Make sure the test app is always running
+ UiDevice.getInstance().waitForIdle();
+ if (!new UiObject(new UiSelector().packageName(PKG_NAME)).exists()) {
+ Intent intent = new Intent(Intent.ACTION_MAIN)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .setComponent(new ComponentName(PKG_NAME, PKG_NAME + ".MainActivity"));
+ getInstrumentation().getContext().startActivity(intent);
+ }
+ }
+
+ /*
+ * Items in the listScrollTests array should be spread out such that a
+ * scroll is required to reach each item at each of the far ends.
+ */
+ public void testListScrollAndSelect() throws UiObjectNotFoundException {
+ UiScrollable listView = new UiScrollable(
+ new UiSelector().className(android.widget.ListView.class.getName()));
+
+ // on single fragment display
+ if (!listView.exists())
+ UiDevice.getInstance().pressBack();
+
+ for (String test : LIST_SCROLL_TESTS) {
+ openTest(test);
+ verifyTestDetailsExists(test);
+ }
+ }
+
+ /**
+ * Test erasing of multi word text in edit field and input of new text. Test
+ * verifying input text using a complex UiSelector
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testTextEraseAndInput() throws UiObjectNotFoundException {
+ String testText = "Android Ui Automator Input Text";
+ openTest("Test 1");
+
+ UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class
+ .getName()));
+ editText.setText(testText);
+
+ UiObject submitButton = new UiObject(new UiSelector()
+ .className(android.widget.Button.class.getName()).clickable(true)
+ .textStartsWith("Submit"));
+ submitButton.click();
+
+ UiObject result = new UiObject(new UiSelector().className(
+ android.widget.LinearLayout.class.getName()).childSelector(
+ (new UiSelector().className(android.widget.ScrollView.class.getName())
+ .childSelector(new UiSelector().className(android.widget.TextView.class
+ .getName())))));
+
+ if (!testText.equals(result.getText())) {
+ throw new UiObjectNotFoundException("Test text: " + testText);
+ }
+
+ getObjectByText("OK").click();
+ }
+
+ /**
+ * Select each of the buttons by using only the content description property
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectByContentDescription() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ getObjectByDescription("Button 1").click();
+ verifyDialogActionResults("Button 1");
+ getObjectByDescription("Button 2").click();
+ verifyDialogActionResults("Button 2");
+ getObjectByDescription("Button 3").click();
+ verifyDialogActionResults("Button 3");
+ }
+
+ /**
+ * Select each of the buttons by using only the text property
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectByText() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ getObjectByText("Button 1").click();
+ verifyDialogActionResults("Button 1");
+ getObjectByText("Button 2").click();
+ verifyDialogActionResults("Button 2");
+ getObjectByText("Button 3").click();
+ verifyDialogActionResults("Button 3");
+ }
+
+ /**
+ * Select each of the buttons by using only the index property
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectByIndex() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ getObjectByIndex(android.widget.Button.class.getName(), 0).click();
+ verifyDialogActionResults("Button 1");
+ getObjectByIndex(android.widget.Button.class.getName(), 1).click();
+ verifyDialogActionResults("Button 2");
+ getObjectByIndex(android.widget.Button.class.getName(), 2).click();
+ verifyDialogActionResults("Button 3");
+ }
+
+ /**
+ * Select each of the buttons by using only the instance number
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectByInstance() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ getObjectByInstance(android.widget.Button.class.getName(), 0).click();
+ verifyDialogActionResults("Button 1");
+ getObjectByInstance(android.widget.Button.class.getName(), 1).click();
+ verifyDialogActionResults("Button 2");
+ getObjectByInstance(android.widget.Button.class.getName(), 2).click();
+ verifyDialogActionResults("Button 3");
+ }
+
+ /**
+ * Test when a node's state is changed due to an action, it is updated in the accessibility
+ * hierarchy.
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectAfterContentChanged() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ UiObject dynaButton = getObjectByText("Before");
+ dynaButton.click();
+ assertTrue("Button state change is not refreshed in accessibility hierarchy",
+ getObjectByText("After").exists());
+ }
+
+ /**
+ * Test opening the options menu using the soft buttons
+ *
+ * @throws UiObjectNotFoundException
+ * @throws InterruptedException
+ * @throws IOException
+ */
+ public void testDeviceSoftKeys() throws UiObjectNotFoundException, IOException,
+ InterruptedException {
+ openTest("Test 2");
+ UiDevice device = UiDevice.getInstance();
+ device.pressMenu();
+ getObjectByText("Finish").click();
+ verifyDialogActionResults("Finish");
+
+ // Back button
+ openTest("Test 1");
+ UiObject editText = new UiObject(new UiSelector().className(android.widget.EditText.class
+ .getName()));
+ editText.setText("Android Geppetto Test Application");
+
+ UiObject submitButton = new UiObject(new UiSelector()
+ .className(android.widget.Button.class.getName()).clickable(true)
+ .textStartsWith("Submit"));
+ submitButton.click();
+
+ // Text from the popup dialog
+ UiObject result = new UiObject(new UiSelector().textContains("geppetto"));
+
+ // Back button test to dismiss the dialog
+ assertTrue("Wait for exist must return true", result.waitForExists(2000));
+ device.pressBack();
+ result.waitUntilGone(1000);
+ assertFalse("Wait for exist must return false after press back", result.exists());
+
+ // Home button test
+ openTest("Test 5");
+ String pkgName = device.getCurrentPackageName();
+ assertTrue("CTS test app must be running", pkgName.equals(PKG_NAME));
+ device.pressHome();
+ boolean gone = new UiObject(new UiSelector().packageName(PKG_NAME)).waitUntilGone(5000);
+ assertTrue("CTS test app still visble after pressing home", gone);
+ }
+
+ /**
+ * This view is in constant update generating window content changed events.
+ * The test will read the time displayed and exhaust each wait for idle
+ * timeout until it read and sets the text back into the edit field and
+ * presses submit. A dialog box should pop up with the time it took since
+ * reading the value until pressing submit.
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testWaitForIdleTimeout() throws UiObjectNotFoundException {
+ openTest("Test 3");
+ UiObject clk = new UiObject(new UiSelector().descriptionStartsWith("Performance "));
+
+ // First default wait for idle timeout assumed to be 10 seconds
+ String txtTime = clk.getText();
+ UiObject edit = new UiObject(new UiSelector().className(android.widget.EditText.class
+ .getName()));
+
+ // Second default wait for idle timeout assumed to be 10 seconds.
+ // Total ~20.
+ edit.setText(txtTime);
+
+ // Third default wait for idle timeout assumed to be 10 seconds.
+ // Total ~30.
+ getObjectByText("Submit").click();
+
+ // The value read should have value between 30 and 60 seconds indicating
+ // that the internal default timeouts for wait-for-idle is in acceptable
+ // range.
+ UiObject readTime = new UiObject(new UiSelector().className(
+ android.widget.TextView.class.getName()).instance(1));
+ String timeDiff = readTime.getText();
+ Log.i(LOG_TAG, "Sync time: " + timeDiff);
+
+ getObjectByText("OK").click();
+
+ int totalDelay = Integer.parseInt(timeDiff);
+
+ // Cumulative waits in this test should add up to at minimum 30 seconds
+ assertFalse("Timeout for wait-for-idle is too short. Expecting minimum 30 seconds",
+ totalDelay < 30 * 1000);
+
+ // allow for tolerance in time measurements due to differences between
+ // device speeds
+ assertFalse("Timeout for wait-for-idle is too long. Expecting maximum 60 seconds",
+ totalDelay > 60 * 1000);
+ }
+
+ /**
+ * This view is in constant update generating window content changed events.
+ * This test uses the soft key presses and clicks while the background
+ * screen is constantly updating causing a constant busy state.
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testVerifyMenuClicks() throws UiObjectNotFoundException {
+ openTest("Test 3");
+ UiDevice.getInstance().pressMenu();
+ new UiObject(new UiSelector().text("Submit")).click();
+ verifyDialogActionResults("Submit");
+ UiDevice.getInstance().pressMenu();
+ new UiObject(new UiSelector().text("Exit")).click();
+ verifyDialogActionResults("Exit");
+ }
+
+ /**
+ * Verifies swipeRight, swipeLeft and raw swipe APIs perform as expected.
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSwipes() throws UiObjectNotFoundException {
+ openTest("Test 4");
+ UiObject textView = new UiObject(new UiSelector().textContains("["));
+
+ textView.swipeLeft(10);
+ assertTrue("UiObject swipe left 1->2", "[ 2 ]".equals(textView.getText()));
+
+ textView.swipeLeft(10);
+ assertTrue("UiObject swipe left 2->3", "[ 3 ]".equals(textView.getText()));
+
+ textView.swipeLeft(10);
+ assertTrue("UiObject swipe left 3->4", "[ 4 ]".equals(textView.getText()));
+
+ textView.swipeRight(10);
+ assertTrue("UiObject swipe right 3<-4", "[ 3 ]".equals(textView.getText()));
+
+ textView.swipeRight(10);
+ assertTrue("UiObject swipe right 2<-3", "[ 2 ]".equals(textView.getText()));
+
+ textView.swipeRight(10);
+ assertTrue("UiObject swipe right 1<-2", "[ 1 ]".equals(textView.getText()));
+
+ Rect tb = textView.getBounds();
+ UiDevice.getInstance().swipe(tb.right - 20, tb.centerY(), tb.left + 20, tb.centerY(), 50);
+
+ SystemClock.sleep(100);
+ assertTrue("UiDevice raw swipe 1->2", "[ 2 ]".equals(textView.getText()));
+ }
+
+ /**
+ * Creates a complex selector
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testComplexSelectors() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiSelector frameLayout = new UiSelector().className(android.widget.FrameLayout.class
+ .getName());
+ UiSelector gridLayout = new UiSelector().className(android.widget.GridLayout.class
+ .getName());
+ UiSelector toggleButton = new UiSelector().className(android.widget.ToggleButton.class
+ .getName());
+ UiObject button = new UiObject(frameLayout.childSelector(gridLayout).childSelector(
+ toggleButton));
+
+ assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText()));
+ button.click();
+ assertTrue("Toggle button value should be ON", "ON".equals(button.getText()));
+ button.click();
+ assertTrue("Toggle button value should be OFF", "OFF".equals(button.getText()));
+ }
+
+ /**
+ * Test when an object does not exist, an exception is thrown
+ * @throws UiObjectNotFoundException
+ */
+ public void testExceptionObjectNotFound() throws UiObjectNotFoundException {
+ UiSelector selector = new UiSelector().text("Nothing should be found");
+ UiSelector child = new UiSelector().className("Nothing");
+ UiObject obj = new UiObject(selector.childSelector(child));
+
+ assertFalse("Object is reported as existing", obj.exists());
+
+ try {
+ obj.click();
+ } catch (UiObjectNotFoundException e) {
+ return;
+ }
+ assertTrue("Exception not thrown for Object not found", false);
+ }
+
+ /**
+ * Verifies the UiWatcher registration and trigger function
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testUiWatcher() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiDevice device = UiDevice.getInstance();
+ device.registerWatcher("Artificial crash", new UiWatcher() {
+
+ @Override
+ public boolean checkForCondition() {
+ if (new UiObject(new UiSelector().packageName("android")).exists()) {
+ try {
+ // Expecting a localized OK button
+ new UiObject(new UiSelector().className(
+ android.widget.Button.class.getName()).enabled(true)).click();
+ } catch (UiObjectNotFoundException e) {
+ }
+ return true;
+ }
+ return false;
+ }
+ });
+
+ // Causes a runtime exception to be thrown
+ getObjectByText("Button").click();
+
+ // Fake doing something while the exception is being displayed
+ SystemClock.sleep(2000);
+ device.runWatchers();
+ assertTrue("UiWatcher not triggered", device.hasAnyWatcherTriggered());
+ }
+
+ /**
+ * Verifies the 'checked' property of both UiSelector and UiObject
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectorChecked() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiObject checkboxChecked = new UiObject(new UiSelector().className(
+ android.widget.CheckBox.class.getName()).checked(true));
+ UiObject checkboxNotChecked = new UiObject(new UiSelector().className(
+ android.widget.CheckBox.class.getName()).checked(false));
+
+ checkboxNotChecked.click();
+ assertTrue("Checkbox should be checked", checkboxChecked.isChecked());
+ checkboxChecked.click();
+ assertFalse("Checkbox should be unchecked", checkboxNotChecked.isChecked());
+ }
+
+ /**
+ * Verifies the 'Clickable' property of both the UiSelector and UiObject
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectorClickable() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiSelector clickableCheckbox = new UiSelector().clickable(true).className(
+ android.widget.CheckBox.class.getName());
+ UiSelector notClickableProgress = new UiSelector().clickable(false).className(
+ android.widget.ProgressBar.class.getName());
+
+ assertTrue("Selector clickable", new UiObject(clickableCheckbox).isClickable());
+ assertFalse("Selector not clickable", new UiObject(notClickableProgress).isClickable());
+ }
+
+ /**
+ * Verifies the 'focusable' property of both UiSelector and UiObject
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectorFocusable() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiSelector mainLayout = new UiSelector().description("Widgets Collection");
+ UiSelector focusableCheckbox = mainLayout.childSelector(new UiSelector().className(
+ android.widget.CheckBox.class.getName()).focusable(true));
+ UiSelector notFocusableSpinner = mainLayout.childSelector(new UiSelector().className(
+ android.widget.Spinner.class.getName()).focusable(false));
+
+ assertTrue("Selector focusable", new UiObject(focusableCheckbox).isFocusable());
+ assertFalse("Selector not focusable", new UiObject(notFocusableSpinner).isFocusable());
+ }
+
+ /**
+ * Verifies the 'DescriptionContains' property of UiSelector
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectorDescriptionContains() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiSelector progressDescriptionContains = new UiSelector().descriptionContains("%");
+ assertTrue("Selector descriptionContains", "Progress is 50 %".equals(new UiObject(
+ progressDescriptionContains).getContentDescription()));
+ }
+
+ /**
+ * Verifies the 'DescriptionStarts' property of UiSelector
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectorDescriptionStarts() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiSelector progressDescriptionStart = new UiSelector().descriptionStartsWith("progress");
+ assertTrue("Selector descriptionStart", "Progress is 50 %".equals(new UiObject(
+ progressDescriptionStart).getContentDescription()));
+ }
+
+ /**
+ * Verifies the 'Enabled' property of both UiSelector and UiObject
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testSelectorEnabled() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiSelector mainLayout = new UiSelector().description("Widgets Collection");
+ UiSelector buttonDisabled = mainLayout.childSelector(new UiSelector().className(
+ android.widget.Button.class.getName()).enabled(false));
+ UiSelector buttonEnabled = mainLayout.childSelector(new UiSelector().className(
+ android.widget.Button.class.getName()).enabled(true));
+
+ assertFalse("Selector enabled false", new UiObject(buttonDisabled).isEnabled());
+ assertTrue("Selector enabled true", new UiObject(buttonEnabled).isEnabled());
+ }
+
+ /**
+ * Verifies the UiCollection object child counting by object pattern
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testCollectionCount() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiCollection collection = new UiCollection(
+ new UiSelector().description("Widgets Collection"));
+ assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+ assertTrue("Collection count",
+ collection.getChildCount(new UiSelector().clickable(true)) == 6);
+ }
+
+ /**
+ * Verifies the UiCollection can find an object by text and returning by
+ * pattern
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testCollectionGetChildByText() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiCollection collection = new UiCollection(
+ new UiSelector().description("Widgets Collection"));
+ assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+ UiObject item = collection.getChildByText(
+ new UiSelector().className(android.widget.Button.class.getName()), "Button");
+
+ assertTrue("Collection get child by text", "Button".equals(item.getText()));
+ }
+
+ /**
+ * Verifies the UiCollection can find an object by instance and returning by
+ * pattern
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testCollectionGetChildByInstance() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiCollection collection = new UiCollection(
+ new UiSelector().description("Widgets Collection"));
+ assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+ // find the second button
+ UiObject item = collection.getChildByInstance(
+ new UiSelector().className(android.widget.Button.class.getName()), 1);
+
+ assertTrue("Collection get child by instance", "Button".equals(item.getText()));
+ }
+
+ /**
+ * Verifies the UiCollection can find an object by description and returning
+ * by pattern
+ *
+ * @throws UiObjectNotFoundException
+ */
+ public void testCollectionGetChildByDescription() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiCollection collection = new UiCollection(
+ new UiSelector().description("Widgets Collection"));
+ assertTrue("Collection layout not found", collection.waitForExists(WAIT_EXIST_TIMEOUT));
+
+ UiObject item = collection.getChildByDescription(
+ new UiSelector().className(android.widget.Button.class.getName()),
+ "Description for Button");
+
+ assertTrue("Collection get child by description", "Button".equals(item.getText()));
+ }
+
+ /**
+ * Test Orientation APIs by causing rotations and verifying current state
+ *
+ * @throws RemoteException
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testRotation() throws RemoteException, UiObjectNotFoundException {
+ openTest("Test 5");
+ UiDevice device = UiDevice.getInstance();
+
+ device.setOrientationLeft();
+ device.waitForIdle(); // isNaturalOrientation is not waiting for idle
+ SystemClock.sleep(1000);
+ assertFalse("Device orientation should not be natural", device.isNaturalOrientation());
+
+ device.setOrientationNatural();
+ device.waitForIdle(); // isNaturalOrientation is not waiting for idle
+ SystemClock.sleep(1000);
+ assertTrue("Device orientation should be natural", device.isNaturalOrientation());
+
+ device.setOrientationRight();
+ device.waitForIdle(); // isNaturalOrientation is not waiting for idle
+ SystemClock.sleep(1000);
+ assertFalse("Device orientation should not be natural", device.isNaturalOrientation());
+
+ device.setOrientationNatural();
+ }
+
+ /**
+ * Reads the current device's product name. Since it is not possible to predetermine the
+ * would be value, the check verifies that the value is not null and not empty.
+ *
+ * @since API Level 17
+ */
+ public void testGetProductName() {
+ String name = UiDevice.getInstance().getProductName();
+ assertFalse("Product name check returned empty string", name.isEmpty());
+ }
+
+ /**
+ * Select each of the buttons by using only regex text
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testSelectByTextMatch() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ getObjectByTextMatch(".*n\\s1$").click();
+ verifyDialogActionResults("Button 1");
+ getObjectByTextMatch(".*n\\s2$").click();
+ verifyDialogActionResults("Button 2");
+ getObjectByTextMatch(".*n\\s3$").click();
+ verifyDialogActionResults("Button 3");
+ }
+
+ /**
+ * Select each of the buttons by using only regex content-description
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testSelectByDescriptionMatch() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ getObjectByDescriptionMatch(".*n\\s1$").click();
+ verifyDialogActionResults("Button 1");
+ getObjectByDescriptionMatch(".*n\\s2$").click();
+ verifyDialogActionResults("Button 2");
+ getObjectByDescriptionMatch(".*n\\s3$").click();
+ verifyDialogActionResults("Button 3");
+ }
+
+ /**
+ * Select each of the buttons by using only regex class name
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testSelectByClassMatch() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiObject tgl = getObjectByClassMatch(".*ToggleButton$", 0);
+ String tglValue = tgl.getText();
+ tgl.click();
+
+ assertFalse("Matching class by Regex failed", tglValue.equals(tgl.getText()));
+ }
+
+ /**
+ * Select each of the buttons by using only class type
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testSelectByClassType() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiObject tgl = getObjectByClass(android.widget.ToggleButton.class, 0);
+ String tglValue = tgl.getText();
+ tgl.click();
+
+ assertFalse("Matching class by class type failed", tglValue.equals(tgl.getText()));
+ }
+
+ /**
+ * Test the coordinates of 3 buttons side by side verifying vertical and
+ * horizontal coordinates.
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testGetVisibleBounds() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ Rect rect1 = getObjectByText("Button 1").getVisibleBounds();
+ Rect rect2 = getObjectByText("Button 2").getVisibleBounds();
+ Rect rect3 = getObjectByText("Button 3").getVisibleBounds();
+
+ assertTrue("X coordinate check failed",
+ rect1.left < rect2.left && rect2.right < rect3.right);
+ assertTrue("Y coordinate check failed",
+ rect1.top == rect2.top && rect2.bottom == rect3.bottom);
+ }
+
+ /**
+ * Tests the LongClick functionality in the API
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testSelectorLongClickable() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ getObjectByText("Button 1").longClick();
+ verifyDialogActionResults("Longclick Button 1");
+ }
+
+ /**
+ * Test the UiSelector's long-clickable property
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 17
+ */
+ public void testSelectorLongClickableProperty() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ UiObject button3 = new UiObject(new UiSelector().className(
+ android.widget.Button.class).longClickable(true).instance(2));
+ button3.longClick();
+ verifyDialogActionResults("Longclick Button 3");
+ }
+
+ /**
+ * Takes a screen shot of the current display and checks if the file is
+ * created and is not zero size.
+ *
+ * @since API Level 17
+ */
+ public void testTakeScreenShots() {
+ File storePath = getInstrumentation().getContext().getFileStreamPath(SCREEN_SHOT_FILE_PATH_NAME);
+ getUiDevice().takeScreenshot(storePath);
+
+ assertTrue("Screenshot file not detected in store", storePath.exists());
+ assertTrue("Zero size for screenshot file", storePath.length() > 0);
+ }
+
+ /**
+ * Verifies the 'Resource-Id' property of UiSelector
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void testSelectorResourceId() throws UiObjectNotFoundException {
+ openTest("Test 5");
+ UiSelector toggleSelector =
+ new UiSelector().resourceId("com.android.uiautomator.tests.cts.testapp:id/test_5_toggleButton");
+ UiObject toggleButton = new UiObject(toggleSelector);
+ assertTrue("Object with selector resource-id not found", toggleButton.exists());
+ assertTrue("Incorrect object for selector resource-id returned",
+ "OFF".equals(toggleButton.getText()) || "ON".equals(toggleButton.getText()));
+ }
+
+ /**
+ * Verify the UiSelector property resourceIdMatches
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void testSelectorResourceIdMatches() throws UiObjectNotFoundException {
+ openTest("Test 2");
+ new UiObject(new UiSelector().resourceIdMatches("(?i).*button.*").instance(2)).click();
+ verifyDialogActionResults("Button 3");
+ new UiObject(new UiSelector().resourceIdMatches("(?i).*button1.*")).click();
+ verifyDialogActionResults("Button 1");
+ }
+
+ /**
+ * Performs a pinch out from the center of a view to its edges and listens to
+ * the motion events to make sure the starting and ending points of both pointers
+ * are correct.
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void testPinchOut() throws UiObjectNotFoundException {
+ openTest("Test 12");
+
+ UiObject screen = new UiObject(
+ new UiSelector().description("Details View"));
+
+ // get the current view dimensions
+ Rect screenRect = screen.getBounds();
+
+ // perform the pinch for 100% of the view dimensions starting form
+ // the center out to the edges.
+ screen.pinchOut(100, 30);
+
+ // dialog with the detected pointers motion coordinates is displayed.
+ UiObject results = new UiObject(new UiSelector().className(
+ android.widget.ScrollView.class).childSelector(new UiSelector().className(
+ android.widget.TextView.class)));
+ String allPointers = results.getText();
+ new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+ // parse pointer 1
+ Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+ Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+ // parse pointer 2
+ Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start
+ Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end
+
+ assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y);
+ assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y);
+ assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y);
+ assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY());
+
+ assertTrue("Touch-down X coordinate for pointer 1 is invalid",
+ withinMarginOfError(0.1f, screenRect.centerX(), p1s.x));
+
+ assertTrue("Touch-down X coordinate for pointer 2 is invalid",
+ withinMarginOfError(0.1f, screenRect.centerX(), p2s.x));
+
+ assertTrue("Touch-up X coordinate for pointer 1 is invalid",
+ withinMarginOfError(0.1f, screenRect.centerX() - screenRect.left,
+ screenRect.centerX() - p1e.x));
+
+ assertTrue("Touch-up X coordinate for pointer 2 is invalid",
+ withinMarginOfError(0.1f, screenRect.right, p2e.x));
+ }
+
+ /**
+ * Performs a pinch in from the edges of a view to its center and listens to
+ * the motion events to make sure the starting and ending points of both pointers
+ * are correct.
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void testPinchIn() throws UiObjectNotFoundException {
+ openTest("Test 12");
+
+ UiObject screen = new UiObject(
+ new UiSelector().description("Details View"));
+
+ // get the current view dimensions
+ Rect screenRect = screen.getBounds();
+
+ // perform the pinch for 100% of the view dimensions starting form
+ // the edges in towards the center.
+ screen.pinchIn(100, 30);
+
+ // dialog with the detected pointers motion coordinates is displayed.
+ UiObject results = new UiObject(new UiSelector().className(
+ android.widget.ScrollView.class).childSelector(new UiSelector().className(
+ android.widget.TextView.class)));
+ String allPointers = results.getText();
+ new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+ // parse pointer 1
+ Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+ Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+ // parse pointer 2
+ Point p2s = parsePointerCoordinates(allPointers, 1, 0); // start
+ Point p2e = parsePointerCoordinates(allPointers, 1, 1); // end
+
+ assertTrue("All Y axis coordinates for pointer 1 must be the same", p1s.y == p1e.y);
+ assertTrue("All Y axis coordinates for pointer 2 must be the same", p2s.y == p2e.y);
+ assertTrue("All Y axis coordinates for both pointers must be the same", p1s.y == p2s.y);
+ assertTrue("Pinch must be in center of target view", p2s.y == screenRect.centerY());
+
+ assertTrue("Touch-down X coordinate for pointer 1 is invalid",
+ withinMarginOfError(0.1f, screenRect.centerX() - screenRect.left,
+ screenRect.centerX() - p1s.x));
+
+ assertTrue("Touch-down X coordinate for pointer 2 is invalid",
+ withinMarginOfError(0.1f, screenRect.right, p2s.x));
+
+ assertTrue("Touch-up X coordinate for pointer 1 is invalid",
+ withinMarginOfError(0.1f, screenRect.centerX(), p1e.x));
+
+ assertTrue("Touch-up X coordinate for pointer 2 is invalid",
+ withinMarginOfError(0.1f, screenRect.centerX(), p2e.x));
+ }
+
+ /**
+ * Performs a drag and drop operation from one UiObject to another UiObject
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void testDragToObject() throws UiObjectNotFoundException {
+ openTest("Test 5");
+
+ UiObject imageButton = new UiObject(new UiSelector().description("Image button"));
+ UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class));
+
+ Rect starsBarRect = starsBar.getBounds();
+ Rect imageButtonRect = imageButton.getBounds();
+ imageButton.dragTo(starsBar, 30);
+
+ // dialog with the detected pointers motion coordinates is displayed.
+ UiObject results = new UiObject(new UiSelector().className(
+ android.widget.ScrollView.class).childSelector(new UiSelector().className(
+ android.widget.TextView.class)));
+ String allPointers = results.getText();
+ new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+ // parse pointer 1
+ Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+ Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+
+ assertTrue("Invalid touch starting.X reported",
+ withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x));
+ assertTrue("Invalid touch starting.Y reported",
+ withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y));
+ assertTrue("Invalid touch ending.X reported",
+ withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x));
+ assertTrue("Invalid touch ending.Y reported",
+ withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y));
+ }
+
+ /**
+ * Performs a drag and drop operation from one UiObject to a specified coordinates
+ *
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void testDragToCoordinates() throws UiObjectNotFoundException {
+ openTest("Test 5");
+
+ UiObject imageButton = new UiObject(new UiSelector().description("Image button"));
+ UiObject starsBar = new UiObject(new UiSelector().className(android.widget.RatingBar.class));
+
+ Rect starsBarRect = starsBar.getBounds();
+ Rect imageButtonRect = imageButton.getBounds();
+ imageButton.dragTo(starsBarRect.centerX(), starsBarRect.centerY(), 30);
+
+ // dialog with the detected pointers motion coordinates is displayed.
+ UiObject results = new UiObject(new UiSelector().className(
+ android.widget.ScrollView.class).childSelector(new UiSelector().className(
+ android.widget.TextView.class)));
+ String allPointers = results.getText();
+ new UiObject(new UiSelector().text("OK")).click(); // dismiss dialog
+
+ // parse pointer 1
+ Point p1s = parsePointerCoordinates(allPointers, 0, 0); // start
+ Point p1e = parsePointerCoordinates(allPointers, 0, 1); // end
+
+ assertTrue("Invalid touch starting.X reported",
+ withinMarginOfError(0.05f, imageButtonRect.centerX(), p1s.x));
+ assertTrue("Invalid touch starting.Y reported",
+ withinMarginOfError(0.05f, imageButtonRect.centerY(), p1s.y));
+ assertTrue("Invalid touch ending.X reported",
+ withinMarginOfError(0.05f, starsBarRect.centerX(), p1e.x));
+ assertTrue("Invalid touch ending.Y reported",
+ withinMarginOfError(0.05f, starsBarRect.centerY(), p1e.y));
+ }
+
+ /**
+ * Detect if actual value is within the allowable margin of error of the expected value.
+ *
+ * Used essentially with actual values that may vary from the expected values such in the
+ * cases of touch and pinch and touch and swipe where the starting or ending points may
+ * not exactly match the expected value.
+ *
+ * @param marginPrecent is values between 0 and 1
+ * @param expected
+ * @param actual
+ * @return true if actual is within the allowed range from expected
+ */
+ private boolean withinMarginOfError(float marginPrecent, int expected, int actual) {
+ int m = (int) (marginPrecent * expected);
+ return actual >= expected - m && actual <= expected + m;
+ }
+
+ /**
+ * Parses a string containing starting to ending coordinates of one or more pointers.
+ *
+ * @param allPointers is a raw string with coordinates from all detected pointers
+ * @param pointerNumber is the desired pointer to be parsed
+ * @param edge is the 0 for the start or 1 for the end of the swipe
+ * @return Point containing the start or end coordinates of the specified pointer number
+ */
+ private Point parsePointerCoordinates(String allPointers, int pointerNumber, int edge) {
+ String pointers[] = allPointers.split("\n");
+ String coordinates = pointers[pointerNumber].split(":")[edge];
+ String xy[] = coordinates.split(",");
+ return new Point(Integer.parseInt(xy[0]), Integer.parseInt(xy[1]));
+ }
+
+ /**
+ * Private helper to open test views. Also covers UiScrollable tests
+ *
+ * @param name
+ * @throws UiObjectNotFoundException
+ */
+ private void openTest(String name) throws UiObjectNotFoundException {
+ try {
+ UiDevice.getInstance().setOrientationNatural();
+ } catch (RemoteException e) {
+ // will catch it in its own test. For now try to put the device
+ // in its natural orientation prior to each test
+ }
+ UiScrollable listView = new UiScrollable(
+ new UiSelector().className(android.widget.ListView.class.getName()));
+
+ // on single fragment display
+ if (!listView.exists())
+ UiDevice.getInstance().pressBack();
+
+ UiObject testItem = listView.getChildByText(
+ new UiSelector().className(android.widget.TextView.class.getName()), name);
+
+ testItem.click();
+ }
+
+ private void verifyTestDetailsExists(String name) throws UiObjectNotFoundException {
+ // verify that we're at the right test
+ new UiObject(new UiSelector().description("Details").text(name)).getText();
+ }
+
+ private UiObject getObjectByText(String txt) {
+ return new UiObject(new UiSelector().text(txt));
+ }
+
+ private UiObject getObjectByTextMatch(String regex) {
+ return new UiObject(new UiSelector().textMatches(regex));
+ }
+
+ private UiObject getObjectByDescriptionMatch(String regex) {
+ return new UiObject(new UiSelector().descriptionMatches(regex));
+ }
+
+ private UiObject getObjectByDescription(String txt) {
+ return new UiObject(new UiSelector().description(txt));
+ }
+
+ private UiObject getObjectByClassMatch(String regex, int instance) {
+ return new UiObject(new UiSelector().classNameMatches(regex).instance(instance));
+ }
+
+ private <T> UiObject getObjectByClass(Class<T> type, int instance) {
+ return new UiObject(new UiSelector().className(type).instance(instance));
+ }
+
+ private UiObject getObjectByIndex(String className, int index) {
+ return new UiObject(new UiSelector().className(className).index(index));
+ }
+
+ private UiObject getObjectByInstance(String className, int instance) {
+ return new UiObject(new UiSelector().className(className).instance(instance));
+ }
+
+ private void verifyDialogActionResults(String txt) throws UiObjectNotFoundException {
+ if (!getObjectByText("Action results").exists() || !getObjectByText(txt).exists()) {
+ throw new UiObjectNotFoundException(txt);
+ }
+ getObjectByText("OK").click();
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/TimeoutTest.java b/tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/TimeoutTest.java
new file mode 100644
index 0000000..b35c9d9
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/src/com/android/uiautomator/tests/cts/TimeoutTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts;
+
+import com.android.uiautomator.core.UiDevice;
+import com.android.uiautomator.core.UiObject;
+import com.android.uiautomator.core.UiObjectNotFoundException;
+import com.android.uiautomator.core.UiScrollable;
+import com.android.uiautomator.core.UiSelector;
+import com.android.uiautomator.testrunner.UiAutomatorTestCase;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.RemoteException;
+
+public class TimeoutTest extends UiAutomatorTestCase {
+
+ private static final String TEST_APP_PKG = "com.android.uiautomator.tests.cts.testapp";
+
+ private static final Intent START_MAIN_ACTIVITY = new Intent(Intent.ACTION_MAIN)
+ .setComponent(new ComponentName(TEST_APP_PKG, TEST_APP_PKG + ".MainActivity"))
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ private final UiObject mActionButton = new UiObject(new UiSelector().text("Go"));
+ private final UiObject mDelayField = new UiObject(new UiSelector().description("delay"));
+
+ private static final int DEFAULT_WAIT_FOR_WINDOW_TIMEOUT = 5500;
+ private static final int SHORT_WAIT_FOR_WINDOW_TIMEOUT = 1000;
+ private static final int LONG_WAIT_FOR_WINDOW_TIMEOUT = 30000;
+ private static final int THRESHOLD = 500;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Launch the test app
+ getInstrumentation().getContext().startActivity(START_MAIN_ACTIVITY);
+
+ // Navigate to the Timeout Test
+ UiScrollable listView = new UiScrollable(new UiSelector()
+ .className(android.widget.ListView.class.getName()));
+ UiObject testItem = listView.getChildByText(new UiSelector()
+ .className(android.widget.TextView.class.getName()), "Timeout Test");
+ testItem.click();
+ }
+
+ public void testClickAndWaitForNewWindowShortTimeoutNotReached()
+ throws UiObjectNotFoundException {
+
+ // Trigger the app to start a new activity just before the short timeout expires
+ mDelayField.setText(Integer.toString(SHORT_WAIT_FOR_WINDOW_TIMEOUT - THRESHOLD));
+ assertTrue("clickAndWaitForNewWindow() timed out too early",
+ mActionButton.clickAndWaitForNewWindow(SHORT_WAIT_FOR_WINDOW_TIMEOUT));
+
+ // Wait until the new activity launches
+ mActionButton.waitUntilGone(2 * THRESHOLD);
+ getUiDevice().pressBack();
+ }
+
+ public void testClickAndWaitForNewWindowShortTimeoutReached()
+ throws UiObjectNotFoundException {
+
+ // Trigger the app to start a new activity just after the short timeout expires
+ mDelayField.setText(Integer.toString(SHORT_WAIT_FOR_WINDOW_TIMEOUT + THRESHOLD));
+ assertFalse("clickAndWaitForNewWindow() did not timeout",
+ mActionButton.clickAndWaitForNewWindow(SHORT_WAIT_FOR_WINDOW_TIMEOUT));
+
+ // Wait until the new activity launches
+ mActionButton.waitUntilGone(2 * THRESHOLD);
+ getUiDevice().pressBack();
+ }
+
+ public void testClickAndWaitForNewWindowDefaultTimeoutNotReached()
+ throws UiObjectNotFoundException {
+
+ // Trigger the app to start a new activity just before the default timeout expires
+ mDelayField.setText(Integer.toString(DEFAULT_WAIT_FOR_WINDOW_TIMEOUT - THRESHOLD));
+ assertTrue("clickAndWaitForNewWindow() timed out too early",
+ mActionButton.clickAndWaitForNewWindow());
+
+ // Wait until the new activity launches
+ mActionButton.waitUntilGone(2 * THRESHOLD);
+ getUiDevice().pressBack();
+ }
+
+ public void testClickAndWaitForNewWindowDefaultTimeoutReached()
+ throws UiObjectNotFoundException {
+
+ // Trigger the app to start a new activity just after the default timeout expires
+ mDelayField.setText(Integer.toString(DEFAULT_WAIT_FOR_WINDOW_TIMEOUT + THRESHOLD));
+ assertFalse("clickAndWaitForNewWindow() did not timeout",
+ mActionButton.clickAndWaitForNewWindow());
+
+ // Wait until the new activity launches
+ mActionButton.waitUntilGone(2 * THRESHOLD);
+ getUiDevice().pressBack();
+ }
+
+ public void testClickAndWaitForNewWindowLongTimeoutNotReached()
+ throws UiObjectNotFoundException {
+
+ // Trigger the app to start a new activity just before the short timeout expires
+ mDelayField.setText(Integer.toString(LONG_WAIT_FOR_WINDOW_TIMEOUT - THRESHOLD));
+ assertTrue("clickAndWaitForNewWindow() timed out too early",
+ mActionButton.clickAndWaitForNewWindow(LONG_WAIT_FOR_WINDOW_TIMEOUT));
+
+ // Wait until the new activity launches
+ mActionButton.waitUntilGone(2 * THRESHOLD);
+ getUiDevice().pressBack();
+ }
+
+ public void testClickAndWaitForNewWindowLongTimeoutReached()
+ throws UiObjectNotFoundException {
+
+ // Trigger the app to start a new activity just after the short timeout expires
+ mDelayField.setText(Integer.toString(LONG_WAIT_FOR_WINDOW_TIMEOUT + THRESHOLD));
+ assertFalse("clickAndWaitForNewWindow() did not timeout",
+ mActionButton.clickAndWaitForNewWindow(LONG_WAIT_FOR_WINDOW_TIMEOUT));
+
+ // Wait until the new activity launches
+ mActionButton.waitUntilGone(2 * THRESHOLD);
+ getUiDevice().pressBack();
+ }
+
+ @Override
+ protected void tearDown() {
+ // Return to the homescreen after each test
+ getUiDevice().pressHome();
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/Android.mk b/tests/CtsUiAutomatorTest/testapp/Android.mk
new file mode 100644
index 0000000..6df6028
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2013 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 := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 18
+
+LOCAL_PACKAGE_NAME := UbCtsUiAutomatorTestApp
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/tests/CtsUiAutomatorTest/testapp/AndroidManifest.xml b/tests/CtsUiAutomatorTest/testapp/AndroidManifest.xml
new file mode 100644
index 0000000..559e11c
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2013 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="com.android.uiautomator.tests.cts.testapp"
+ android:versionCode="1"
+ android:versionName="1.0" >
+ <uses-sdk
+ android:minSdkVersion="14"
+ android:targetSdkVersion="15" />
+
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/title_test_list" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".SinglePaneDetailActivity"
+ android:label="@string/title_test_detail" >
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="FragmentActivity" />
+ </activity>
+ <activity android:name=".LaunchedActivity" />
+ </application>
+
+</manifest>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_action_search.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_action_search.png
new file mode 100644
index 0000000..67de12d
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_action_search.png
Binary files differ
diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..947dbfc
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-ldpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..e075065
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_action_search.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_action_search.png
new file mode 100644
index 0000000..134d549
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_action_search.png
Binary files differ
diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f91af33
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_action_search.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_action_search.png
new file mode 100644
index 0000000..d699c6b
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_action_search.png
Binary files differ
diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..542a9cb
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/activity_main.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/activity_main.xml
new file mode 100644
index 0000000..6b7f72f
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/activity_main.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:text="@string/hello_world" />
+
+</RelativeLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/launched_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/launched_activity.xml
new file mode 100644
index 0000000..f5b3478
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/launched_activity.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/list_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/list_activity.xml
new file mode 100644
index 0000000..9593e07
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/list_activity.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<fragment xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:name="com.android.uiautomator.tests.cts.testapp.TestListFragment"
+ android:id="@+id/item_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ tools:context=".MainActivity" />
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/simple_list_item_selected.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/simple_list_item_selected.xml
new file mode 100644
index 0000000..f0b0644
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/simple_list_item_selected.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:gravity="center_vertical"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+/>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/singlepane_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/singlepane_activity.xml
new file mode 100644
index 0000000..7ebcb7d
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/singlepane_activity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/test_results_detail_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".TestResultsDetailActivity" />
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test1_detail_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test1_detail_fragment.xml
new file mode 100644
index 0000000..e157940
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test1_detail_fragment.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/test_1_detail_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/item1_test_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="5dp"
+ android:text="@string/test1_description" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
+
+ <EditText
+ android:id="@+id/test1TextField"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dp"
+ android:layout_weight="2"
+ android:inputType="textNoSuggestions"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:width="200dip" >
+
+ <requestFocus />
+ </EditText>
+
+ <Button
+ android:id="@+id/test1SubmitButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="5dip"
+ android:minWidth="64dip"
+ android:text="@string/buttonSubmit" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test2_detail_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test2_detail_fragment.xml
new file mode 100644
index 0000000..2bc397d
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test2_detail_fragment.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/test_2_detail_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="5dp"
+ android:text="@string/test2_description" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/test2button1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/button1"
+ android:text="@string/button1" />
+
+ <Button
+ android:id="@+id/test2button2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/button2"
+ android:text="@string/button2" />
+
+ <Button
+ android:id="@+id/test2button3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/button3"
+ android:text="@string/button3" />
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="5dp"
+ android:text="@string/test2_description_2" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/test2dynaButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/buttonBefore"
+ android:text="@string/buttonBefore" />
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test3_detail_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test3_detail_fragment.xml
new file mode 100644
index 0000000..1e7c930
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test3_detail_fragment.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/test_3_detail_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/item3_test_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="5dp"
+ android:text="@string/test3_description" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/test3ClockTextView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="10dip"
+ android:layout_marginTop="10dip"
+ android:contentDescription="@string/test3ClockDescription"
+ android:padding="10dp"
+ android:text="@string/test3InitialClock" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <EditText
+ android:id="@+id/test3TextField"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dp"
+ android:layout_weight="2"
+ android:inputType="numberDecimal"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:width="200dip" >
+ <requestFocus />
+ </EditText>
+
+ <Button
+ android:id="@+id/test3SubmitButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="5dip"
+ android:minWidth="64dip"
+ android:text="@string/buttonSubmit" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test4_detail_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test4_detail_fragment.xml
new file mode 100644
index 0000000..fc19b81
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test4_detail_fragment.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+ <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/test_4_detail_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".Test4DetailActivity" />
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test5_detail_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test5_detail_fragment.xml
new file mode 100644
index 0000000..51fe2f1
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test5_detail_fragment.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/test_5_Widgets_collection"
+ android:orientation="vertical" >
+
+ <CheckBox
+ android:id="@+id/test_5_checkBox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/test5_CheckBox" />
+
+ <Spinner
+ android:id="@+id/test_5_spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ProgressBar
+ android:id="@+id/test_5_progressBar"
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <GridLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:columnCount="3" >
+
+ <ImageButton
+ android:id="@+id/test_5_imageButton"
+ android:layout_column="0"
+ android:layout_gravity="left"
+ android:layout_row="0"
+ android:src="@drawable/ic_launcher" />
+
+ <RatingBar
+ android:id="@+id/test_5_ratingBar"
+ android:layout_column="1"
+ android:layout_columnSpan="2"
+ android:layout_gravity="left|bottom"
+ android:layout_row="0" />
+
+ <Button
+ android:id="@+id/test_5_button2"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left|bottom"
+ android:enabled="false"
+ android:layout_row="0"
+ android:text="@string/test5_Button_Disabled" />
+
+ <Space
+ android:layout_width="21dp"
+ android:layout_height="1dp"
+ android:layout_column="1"
+ android:layout_row="0" />
+
+ <Space
+ android:layout_width="1dp"
+ android:layout_height="21dp"
+ android:layout_column="0"
+ android:layout_row="0" />
+
+ <Space
+ android:layout_width="221dp"
+ android:layout_height="15dp"
+ android:layout_column="2"
+ android:layout_row="1" />
+
+ <ToggleButton
+ android:id="@+id/test_5_toggleButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_column="2"
+ android:text="@string/test5_ToggleButton" />
+ </GridLayout>
+
+ <SeekBar
+ android:id="@+id/test_5_seekBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:id="@+id/test_5_button1"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/test5_Button_Description"
+ android:text="@string/test5_Button" />
+
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test6_detail_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test6_detail_fragment.xml
new file mode 100644
index 0000000..49e6b8c
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test6_detail_fragment.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <WebView
+ android:id="@+id/test6WebView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test_results_detail_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test_results_detail_fragment.xml
new file mode 100644
index 0000000..e68f54a
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test_results_detail_fragment.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/test_results_detail_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/title_test_view_detail"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/textView1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="5dp"
+ android:text="@string/now_displaying_results_for" />
+
+ <TextView
+ android:id="@+id/testResultsTextView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:contentDescription="@string/title_test_detail"
+ android:paddingLeft="2dp"
+ android:paddingTop="5dp"
+ android:textColor="#00aa00"
+ android:textSize="@dimen/padding_large"
+ android:textStyle="bold" />
+
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/test_timeout_fragment.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/test_timeout_fragment.xml
new file mode 100644
index 0000000..cf0439c
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/test_timeout_fragment.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <TextView android:text="Delay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"/>
+ <EditText android:id="@+id/delay"
+ android:contentDescription="delay"
+ android:inputType="number"
+ android:layout_width="100sp"
+ android:layout_height="wrap_content"
+ android:hint="0" />
+ <Button android:id="@+id/go_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Go" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/layout/twopane_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/layout/twopane_activity.xml
new file mode 100644
index 0000000..b970961
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/layout/twopane_activity.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="middle"
+ tools:context=".TestListActivity">
+
+ <fragment
+ android:id="@+id/item_list"
+ android:name="com.android.uiautomator.tests.cts.testapp.TestListFragment"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <FrameLayout android:id="@+id/test_detail_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="3" />
+
+</LinearLayout>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/activity_main.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/activity_main.xml
new file mode 100644
index 0000000..37c04bd
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/menu_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never"
+ android:title="@string/menu_settings"/>
+
+</menu>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/test1_detail_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/test1_detail_activity.xml
new file mode 100644
index 0000000..0b776bb
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/test1_detail_activity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_settings"
+ android:title="@string/menu_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/test2_detail_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/test2_detail_activity.xml
new file mode 100644
index 0000000..ce0ca49
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/test2_detail_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_text1"
+ android:title="Submit" />
+ <item android:id="@+id/menu_text2"
+ android:icon="@drawable/ic_launcher"
+ android:title="Done" />
+ <item android:id="@+id/menu_text3"
+ android:title="OK" />
+ <item android:id="@+id/menu_text4"
+ android:title="Finish" />
+ <item android:id="@+id/menu_text5"
+ android:title="Complete" />
+ <item android:id="@+id/menu_text6"
+ android:title="Exit" />
+</menu>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/test3_detail_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/test3_detail_activity.xml
new file mode 100644
index 0000000..0b776bb
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/test3_detail_activity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_settings"
+ android:title="@string/menu_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/test4_detail_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/test4_detail_activity.xml
new file mode 100644
index 0000000..0b776bb
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/test4_detail_activity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_settings"
+ android:title="@string/menu_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/test5_detail_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/test5_detail_activity.xml
new file mode 100644
index 0000000..0b776bb
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/test5_detail_activity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_settings"
+ android:title="@string/menu_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/test6_detail_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/test6_detail_activity.xml
new file mode 100644
index 0000000..0b776bb
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/test6_detail_activity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_settings"
+ android:title="@string/menu_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/menu/test_results_detail_activity.xml b/tests/CtsUiAutomatorTest/testapp/res/menu/test_results_detail_activity.xml
new file mode 100644
index 0000000..3bf852f
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/menu/test_results_detail_activity.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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.
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_settings"
+ android:title="@string/menu_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
+
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values-large/dimens.xml b/tests/CtsUiAutomatorTest/testapp/res/values-large/dimens.xml
new file mode 100644
index 0000000..d1ffde5
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values-large/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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>
+
+ <dimen name="padding_small">8dp</dimen>
+ <dimen name="padding_medium">16dp</dimen>
+ <dimen name="padding_large">16dp</dimen>
+
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values-large/refs.xml b/tests/CtsUiAutomatorTest/testapp/res/values-large/refs.xml
new file mode 100644
index 0000000..7431c8b
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values-large/refs.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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>
+ <item type="layout" name="list_activity">@layout/twopane_activity</item>
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values-sw600dp/refs.xml b/tests/CtsUiAutomatorTest/testapp/res/values-sw600dp/refs.xml
new file mode 100644
index 0000000..7431c8b
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values-sw600dp/refs.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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>
+ <item type="layout" name="list_activity">@layout/twopane_activity</item>
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values-v11/styles.xml b/tests/CtsUiAutomatorTest/testapp/res/values-v11/styles.xml
new file mode 100644
index 0000000..a9a67e9
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values-v11/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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>
+
+ <style name="AppTheme" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values-v14/styles.xml b/tests/CtsUiAutomatorTest/testapp/res/values-v14/styles.xml
new file mode 100644
index 0000000..3cbff5f
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values-v14/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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>
+
+ <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
+
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values/dimens.xml b/tests/CtsUiAutomatorTest/testapp/res/values/dimens.xml
new file mode 100644
index 0000000..cfbac7a
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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>
+
+ <dimen name="padding_small">8dp</dimen>
+ <dimen name="padding_medium">8dp</dimen>
+ <dimen name="padding_large">16dp</dimen>
+
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values/strings.xml b/tests/CtsUiAutomatorTest/testapp/res/values/strings.xml
new file mode 100644
index 0000000..4ac5243
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2013 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="app_name">UiAutomator Test App</string>
+ <string name="test1_description">This helps verify entering text into a pre-populated field. The pop-up dialog will echo the text entered after clicking submit. The initial value in the field must first be deleted.</string>
+ <string name="menu_settings">Settings</string>
+ <string name="title_activity_item1_detail">Item1DetailActivity</string>
+ <string name="buttonSubmit">Submit</string>
+ <string name="item1_dialog_title">Text submitted</string>
+ <string name="OK">OK</string>
+ <string name="title_test_list">UiAutomator Tests</string>
+ <string name="title_test_detail">Details</string>
+ <string name="hello_world">Hello world!</string>
+ <string name="title_activity_test2_detail">Test2DetailActivity</string>
+ <string name="test2_description">This helps test selection of button using Instance, Text and Content Description. Once clicked, a dialog pops up to verify the properties of button clicked.</string>
+ <string name="test2_description_2">This tests a Button text changing dynamically after a click. The test should attempt to find the button after it has changed using its new text.</string>
+ <string name="test3_description">The tests should read the clock, then write the clock back into the EditText then press submit. A dialog will display the time it took from reading the clock until submit is press. This can be used to get an idea of performance differences.</string>
+ <string name="button1">Button 1</string>
+ <string name="button1long">Longclick Button 1</string>
+ <string name="button2">Button 2</string>
+ <string name="button2long">Longclick Button 2</string>
+ <string name="button3">Button 3</string>
+ <string name="button3long">Longclick Button 3</string>
+ <string name="buttonBefore">Before</string>
+ <string name="buttonAfter">After</string>
+ <string name="dialog_title_result">Action results</string>
+ <string name="now_displaying_results_for">Verifying scroll into view and list item selection. Now displaying results for:</string>
+ <string name="title_activity_test3_detail">Performance test</string>
+ <string name="test3ClockDescription">Performance clock</string>
+ <string name="test3InitialClock">0000000000</string>
+ <string name="test3_dialog_title">Time difference in ms</string>
+ <string name="test5_CheckBox">CheckBox</string>
+ <string name="test5_ToggleButton">ToggleButton</string>
+ <string name="test5_Button">Button</string>
+ <string name="test5_Button_Description">Description for Button</string>
+ <string name="test5_Button_Disabled">Button D</string>
+ <string name="title_section4">Section 4</string>
+ <string name="title_section3">Section 3</string>
+ <string name="title_section2">Section 2</string>
+ <string name="title_section1">Section 1</string>
+ <string name="title_activity_test4_detail">Test4DetailActivity</string>
+ <string name="title_activity_test5_detail">Test5DetailActivity</string>
+ <string name="title_activity_test6_detail">Test6DetailActivity</string>
+ <string name="test_5_Widgets_collection">Widgets Collection</string>
+ <string name="generic_item_touch_dialog_title">Multi-touch test dialog</string>
+ <string name="drag_item_touch_dialog_title">Drag and drop test dialog</string>
+ <string name="title_test_view_detail">Details View</string>
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/res/values/styles.xml b/tests/CtsUiAutomatorTest/testapp/res/values/styles.xml
new file mode 100644
index 0000000..ab1a580
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/res/values/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2013 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>
+
+ <style name="AppTheme" parent="android:Theme.Light" />
+
+</resources>
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/LaunchedActivity.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/LaunchedActivity.java
new file mode 100644
index 0000000..ca48974
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/LaunchedActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class LaunchedActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.launched_activity);
+ }
+
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/MainActivity.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/MainActivity.java
new file mode 100644
index 0000000..097d15a
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/MainActivity.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.view.WindowManager;
+
+public class MainActivity extends FragmentActivity implements TestListFragment.Callbacks {
+
+ private boolean mTwoPane;
+ public static final String LOG_TAG = "UiAutomatorApp";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // If the device is locked, this attempts to dismiss the KeyGuard
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
+ WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ setContentView(R.layout.list_activity);
+
+ if (findViewById(R.id.test_detail_container) != null) {
+ mTwoPane = true;
+ ((TestListFragment) getSupportFragmentManager().findFragmentById(R.id.item_list))
+ .setActivateOnItemClick(true);
+ }
+ }
+
+ @Override
+ public void onItemSelected(String id) {
+ if (mTwoPane) {
+ Fragment fragment = TestItems.getFragment(id);
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.test_detail_container, fragment).commit();
+ } else {
+ Intent detailIntent = new Intent(this, SinglePaneDetailActivity.class);
+ detailIntent.putExtra("item_id", id);
+ startActivity(detailIntent);
+ }
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/SinglePaneDetailActivity.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/SinglePaneDetailActivity.java
new file mode 100644
index 0000000..d45ac2b
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/SinglePaneDetailActivity.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.NavUtils;
+import android.view.Menu;
+import android.view.MenuItem;
+
+public class SinglePaneDetailActivity extends FragmentActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.singlepane_activity);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ if (savedInstanceState == null) {
+ Fragment fragment = TestItems.getFragment(getIntent().getStringExtra("item_id"));
+ getSupportFragmentManager().beginTransaction()
+ .add(R.id.test_results_detail_container, fragment).commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.test_results_detail_activity, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ NavUtils.navigateUpFromSameTask(this);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test1DetailFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test1DetailFragment.java
new file mode 100644
index 0000000..e547434
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test1DetailFragment.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+
+public class Test1DetailFragment extends Fragment {
+
+ public static final String ARG_ITEM_ID = "item_id";
+ private Button mSubmitButton;
+ private EditText mEditText;
+ TestItems.TestItem mItem;
+
+ public Test1DetailFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments().containsKey(ARG_ITEM_ID)) {
+ mItem = TestItems.getTest(getArguments().getString(ARG_ITEM_ID));
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View rootView = inflater.inflate(R.layout.test1_detail_fragment, container, false);
+ if (mItem != null) {
+ ((EditText) rootView.findViewById(R.id.test1TextField)).setText(mItem.mName);
+
+ mSubmitButton = (Button) rootView.findViewById(R.id.test1SubmitButton);
+ mEditText = (EditText) rootView.findViewById(R.id.test1TextField);
+ mEditText.setText("");
+ mSubmitButton.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final String savedInput = mEditText.getText().toString();
+ // clear so we won't be confused by the input text in
+ // validation
+ mEditText.setText("");
+ // close soft keyboard
+ InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
+ // display the submitted text
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.item1_dialog_title);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(savedInput);
+ AlertDialog diag = builder.create();
+ diag.show();
+ }
+ });
+ }
+ return rootView;
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test2DetailFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test2DetailFragment.java
new file mode 100644
index 0000000..969a5aa
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test2DetailFragment.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class Test2DetailFragment extends Fragment {
+ public static final String ARG_ITEM_ID = "item_id";
+ private Button mButton1, mButton2, mButton3, mDynaButton;
+
+ public Test2DetailFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.test2_detail_activity, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setMessage(item.getTitle());
+ builder.setPositiveButton(R.string.OK, null);
+ AlertDialog diag = builder.create();
+ diag.show();
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View rootView = inflater.inflate(R.layout.test2_detail_fragment, container, false);
+
+ mButton1 = (Button) rootView.findViewById(R.id.test2button1);
+ mButton2 = (Button) rootView.findViewById(R.id.test2button2);
+ mButton3 = (Button) rootView.findViewById(R.id.test2button3);
+ mDynaButton = (Button) rootView.findViewById(R.id.test2dynaButton);
+
+ mButton1.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(R.string.button1);
+ AlertDialog diag = builder.create();
+ diag.show();
+ }
+ });
+
+ mButton1.setOnLongClickListener(new Button.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(R.string.button1long);
+ AlertDialog diag = builder.create();
+ diag.show();
+ return true;
+ }
+ });
+
+ mButton2.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(R.string.button2);
+ AlertDialog diag = builder.create();
+ diag.show();
+ }
+ });
+
+ mButton2.setOnLongClickListener(new Button.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(R.string.button2long);
+ AlertDialog diag = builder.create();
+ diag.show();
+ return true;
+ }
+ });
+
+ mButton3.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(R.string.button3);
+ AlertDialog diag = builder.create();
+ diag.show();
+ }
+ });
+
+ mButton3.setOnLongClickListener(new Button.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(R.string.button3long);
+ AlertDialog diag = builder.create();
+ diag.show();
+ return true;
+ }
+ });
+
+ mDynaButton.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mDynaButton.setText(R.string.buttonAfter);
+ mDynaButton.setContentDescription(getString(R.string.buttonAfter));
+ }
+ });
+
+ return rootView;
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test3DetailFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test3DetailFragment.java
new file mode 100644
index 0000000..f90709b
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test3DetailFragment.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+public class Test3DetailFragment extends Fragment {
+
+ public static final String ARG_ITEM_ID = "item_id";
+ private TextView mTextClock;
+ private Button mSubmitButton;
+ private EditText mEditText;
+ private long mCurrentTime;
+ private final Object sync = new Object();
+ private boolean mRunCounter = true;
+
+ public Test3DetailFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.test2_detail_activity, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_title_result);
+ builder.setMessage(item.getTitle());
+ builder.setPositiveButton(R.string.OK, null);
+ AlertDialog diag = builder.create();
+ diag.show();
+ return super.onOptionsItemSelected(item);
+ }
+
+ private final Handler mHandler = new Handler();
+
+ final Runnable mClockRunnable = new Runnable() {
+ @Override
+ public void run() {
+ // call the activity method that updates the UI
+ updateClockOnUi();
+ }
+ };
+
+ private void updateClockOnUi() {
+ synchronized (sync) {
+ mTextClock.setText("" + mCurrentTime);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View rootView = inflater.inflate(R.layout.test3_detail_fragment, container, false);
+ mTextClock = (TextView) rootView.findViewById(R.id.test3ClockTextView);
+ mSubmitButton = (Button) rootView.findViewById(R.id.test3SubmitButton);
+ mEditText = (EditText) rootView.findViewById(R.id.test3TextField);
+ mSubmitButton.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // close soft keyboard
+ InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
+
+ // display the submitted text
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.test3_dialog_title);
+ builder.setPositiveButton(R.string.OK, null);
+ CharSequence inputText = mEditText.getText();
+ if (inputText != null && !inputText.toString().isEmpty()) {
+ long inputTime = Long.parseLong(inputText.toString());
+ builder.setMessage("" + (mCurrentTime - inputTime));
+ } else {
+ builder.setMessage("<NO DATA>");
+ }
+ AlertDialog diag = builder.create();
+ diag.show();
+ mEditText.setText("");
+ mRunCounter = false;
+ }
+ });
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while (mRunCounter) {
+ synchronized (sync) {
+ mCurrentTime = SystemClock.elapsedRealtime();
+ }
+ mHandler.post(mClockRunnable);
+ SystemClock.sleep(100);
+ }
+ }
+ }).start();
+
+ return rootView;
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test4DetailFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test4DetailFragment.java
new file mode 100644
index 0000000..ce535c4
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test4DetailFragment.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.ActionBar;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class Test4DetailFragment extends Fragment implements ActionBar.TabListener {
+ public static final String ARG_ITEM_ID = "item_id";
+
+ /**
+ * The {@link android.support.v4.view.PagerAdapter} that will provide
+ * fragments for each of the sections. We use a
+ * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
+ * will keep every loaded fragment in memory. If this becomes too memory
+ * intensive, it may be best to switch to a
+ * {@link android.support.v4.app.FragmentStatePagerAdapter}.
+ */
+ SectionsPagerAdapter mSectionsPagerAdapter;
+
+ /**
+ * The {@link ViewPager} that will host the section contents.
+ */
+ ViewPager mViewPager;
+
+ public Test4DetailFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onDestroyView() {
+ getActivity().getActionBar().removeAllTabs();
+ super.onDestroyView();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+
+ View rootView = inflater.inflate(R.layout.test4_detail_fragment, container, false);
+
+ // Set up the action bar.
+ final ActionBar actionBar = getActivity().getActionBar();
+ if (actionBar.getTabCount() > 0) {
+ return rootView;
+ }
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+ // Create the adapter that will return a fragment for each of the three
+ // primary sections of the app.
+ mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity().getSupportFragmentManager());
+
+ // Set up the ViewPager with the sections adapter.
+ mViewPager = (ViewPager) rootView.findViewById(R.id.test_4_detail_container);
+ mViewPager.setAdapter(mSectionsPagerAdapter);
+
+ // When swiping between different sections, select the corresponding
+ // tab. We can also use ActionBar.Tab#select() to do this if we have a
+ // reference to the Tab.
+ mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ actionBar.setSelectedNavigationItem(position);
+ }
+ });
+
+ // For each of the sections in the app, add a tab to the action bar.
+ for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
+ // Create a tab with text corresponding to the page title defined by
+ // the adapter. Also specify this Activity object, which implements
+ // the TabListener interface, as the listener for when this tab is
+ // selected.
+ actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i))
+ .setTabListener(this));
+ }
+ return rootView;
+ }
+
+ @Override
+ public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ }
+
+ @Override
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ }
+
+ @Override
+ public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ }
+
+ /**
+ * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
+ * one of the primary sections of the app.
+ */
+ public class SectionsPagerAdapter extends FragmentPagerAdapter {
+
+ public SectionsPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int i) {
+ Fragment fragment = new DummySectionFragment();
+ Bundle args = new Bundle();
+ args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public int getCount() {
+ return 4;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ switch (position) {
+ case 0:
+ return getString(R.string.title_section1).toUpperCase();
+ case 1:
+ return getString(R.string.title_section2).toUpperCase();
+ case 2:
+ return getString(R.string.title_section3).toUpperCase();
+ case 3:
+ return getString(R.string.title_section4).toUpperCase();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * A dummy fragment representing a section of the app, but that simply
+ * displays dummy text.
+ */
+ public static class DummySectionFragment extends Fragment {
+ public DummySectionFragment() {
+ }
+
+ public static final String ARG_SECTION_NUMBER = "section_number";
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ TextView textView = new TextView(getActivity());
+ textView.setGravity(Gravity.CENTER);
+ Bundle args = getArguments();
+ textView.setText("[ " + Integer.toString(args.getInt(ARG_SECTION_NUMBER)) + " ]");
+ return textView;
+ }
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test5DetailFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test5DetailFragment.java
new file mode 100644
index 0000000..ad22078
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test5DetailFragment.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.ImageButton;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+
+public class Test5DetailFragment extends Fragment {
+
+ public static final String ARG_ITEM_ID = "item_id";
+
+ class PointerEvent {
+ int startX;
+ int startY;
+ int endX;
+ int endY;
+ }
+
+ private final PointerEvent mPointerEvent = new PointerEvent();
+
+ public Test5DetailFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View rootView = inflater.inflate(R.layout.test5_detail_fragment, container, false);
+
+ // Set the content description for the following
+ Spinner spinner = (Spinner) rootView.findViewById(R.id.test_5_spinner);
+ spinner.setContentDescription("Spinner");
+ ImageButton imageButton = (ImageButton) rootView.findViewById(R.id.test_5_imageButton);
+ imageButton.setContentDescription("Image button");
+
+ // Each time this view is displayed, reset the following states
+ SeekBar seekBar = (SeekBar) rootView.findViewById(R.id.test_5_seekBar);
+ seekBar.setProgress(50);
+ seekBar.setContentDescription("Progress is 50 %");
+ CheckBox checkbox = (CheckBox) rootView.findViewById(R.id.test_5_checkBox);
+ checkbox.setChecked(false);
+
+ // Register click event handlers for the following
+ Button button = (Button) rootView.findViewById(R.id.test_5_button1);
+ button.setOnClickListener(new Button.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // we want an artificial crash
+ throw new RuntimeException("Artificial crash to test UiWatcher");
+ }
+ });
+
+ imageButton.setOnTouchListener(new ImageButton.OnTouchListener() {
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ resetTouchResults();
+ collectStartAction(event, v);
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ collectEndAction(event, v);
+ displayTouchResults();
+ }
+ return false;
+ }
+ });
+
+ return rootView;
+ }
+
+ private void displayTouchResults() {
+ StringBuilder output = new StringBuilder();
+
+ output.append(String.format("%d,%d:%d,%d\n",
+ mPointerEvent.startX, mPointerEvent.startY, mPointerEvent.endX,
+ mPointerEvent.endY));
+
+ // display the submitted text
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.drag_item_touch_dialog_title);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(output.toString());
+ AlertDialog diag = builder.create();
+ diag.show();
+ }
+
+ /**
+ * Clears all collected pointer results
+ */
+ private void resetTouchResults() {
+ mPointerEvent.startX = mPointerEvent.startY =
+ mPointerEvent.endX = mPointerEvent.endY = -1;
+ }
+
+ /**
+ * Collects pointer touch information converting from relative to absolute before
+ * storing it as starting touch coordinates.
+ *
+ * @param event
+ * @param view
+ * @param pointerIndex
+ */
+ private void collectStartAction(MotionEvent event, View view) {
+ int offsetInScreen[] = new int[2];
+ view.getLocationOnScreen(offsetInScreen);
+ mPointerEvent.startX = (int)(event.getX() + offsetInScreen[0]);
+ mPointerEvent.startY = (int)(event.getY() + offsetInScreen[1]);
+ }
+
+ /**
+ * Collects pointer touch information converting from relative to absolute before
+ * storing it as ending touch coordinates.
+ *
+ * @param event
+ * @param view
+ * @param pointerIndex
+ */
+ private void collectEndAction(MotionEvent event, View view) {
+ int offsetInScreen[] = new int[2];
+ view.getLocationOnScreen(offsetInScreen);
+ mPointerEvent.endX = (int)(event.getX() + offsetInScreen[0]);
+ mPointerEvent.endY = (int)(event.getY() + offsetInScreen[1]);
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test6DetailFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test6DetailFragment.java
new file mode 100644
index 0000000..ed47734
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/Test6DetailFragment.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+
+public class Test6DetailFragment extends Fragment {
+ public static final String ARG_ITEM_ID = "item_id";
+ private final static String PAGE = "<html><body>"
+ + "This is test <b>6</b> for WebView text traversal test."
+ + "<p/><a href=\"http://google.com\">This is a link to google</a><br/>"
+ + "<h5>This is h5 text</h5>"
+ + "<a href=\"http://yahoo.com\">This is a link to yahoo</a>"
+ + "<p/><h4>This is h4 text</h4>" + "</body></html>";
+
+ public Test6DetailFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View rootView = inflater.inflate(R.layout.test6_detail_fragment, container, false);
+ WebView wv = (WebView) rootView.findViewById(R.id.test6WebView);
+ wv.loadData(PAGE, "text/html", null);
+ return rootView;
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestGenericDetailFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestGenericDetailFragment.java
new file mode 100644
index 0000000..6113ca2
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestGenericDetailFragment.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class TestGenericDetailFragment extends Fragment {
+ public static final String ARG_ITEM_ID = "item_id";
+ TestItems.TestItem mItem;
+
+ private class PointerEvent {
+ int startX;
+ int startY;
+ int endX;
+ int endY;
+ }
+
+ private final PointerEvent[] mPointerEvents = new PointerEvent[10];
+
+ public TestGenericDetailFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments().containsKey(ARG_ITEM_ID)) {
+ mItem = TestItems.getTest(getArguments().getString(ARG_ITEM_ID));
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View rootView = inflater.inflate(R.layout.test_results_detail_fragment, container, false);
+ if (mItem != null) {
+ ((TextView) rootView.findViewById(R.id.testResultsTextView)).setText(mItem.mName);
+ }
+
+ // listen to touch events to verify the multiPointerGesture APIs
+ // Since API Level 18
+ rootView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+
+ switch(event.getAction() & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ // Reset any collected touch coordinate results on the primary touch down
+ resetTouchResults();
+ // collect this event
+ collectStartAction(event, v, 0);
+ break;
+
+ case MotionEvent.ACTION_POINTER_DOWN:
+ // collect this event
+ collectStartAction(event, v, getPointerIndex(event));
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ // collect this event
+ collectEndAction(event, v, getPointerIndex(event));
+ break;
+
+ case MotionEvent.ACTION_UP:
+ // collect this event
+ collectEndAction(event, v, 0);
+ // on the primary touch up display results collected for all pointers
+ displayTouchResults();
+ break;
+ }
+ return true;
+ }
+ });
+
+ return rootView;
+ }
+
+ /**
+ * Displays collected results from all pointers into a dialog view in the following
+ * format: "startX,startY:endX,endY" where each line represent data for a pointer if
+ * multiple pointers (fingers) were detected.
+ */
+ private void displayTouchResults() {
+ StringBuilder output = new StringBuilder();
+ for (int x = 0; x < mPointerEvents.length; x++) {
+ if (mPointerEvents[x].startX == -1)
+ break;
+
+ output.append(String.format("%d,%d:%d,%d\n",
+ mPointerEvents[x].startX, mPointerEvents[x].startY, mPointerEvents[x].endX,
+ mPointerEvents[x].endY));
+ }
+
+ // display the submitted text
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.generic_item_touch_dialog_title);
+ builder.setPositiveButton(R.string.OK, null);
+ builder.setMessage(output.toString());
+ AlertDialog diag = builder.create();
+ diag.show();
+ }
+
+ /**
+ * Clears all collected pointer results
+ */
+ private void resetTouchResults() {
+ for (int x = 0; x < mPointerEvents.length; x++) {
+ if (mPointerEvents[x] == null)
+ mPointerEvents[x] = new PointerEvent();
+ mPointerEvents[x].startX = mPointerEvents[x].startY =
+ mPointerEvents[x].endX = mPointerEvents[x].endY = -1;
+ }
+ }
+
+ /**
+ * Collects pointer touch information converting from relative to absolute before
+ * storing it as starting touch coordinates.
+ *
+ * @param event
+ * @param view
+ * @param pointerIndex
+ */
+ private void collectStartAction(MotionEvent event, View view, int pointerIndex) {
+ int offsetInScreen[] = new int[2];
+ view.getLocationOnScreen(offsetInScreen);
+ mPointerEvents[getPointerId(event)].startX =
+ (int)(event.getX(pointerIndex) + offsetInScreen[0]);
+ mPointerEvents[getPointerId(event)].startY =
+ (int)(event.getY(pointerIndex) + offsetInScreen[1]);
+ }
+
+ /**
+ * Collects pointer touch information converting from relative to absolute before
+ * storing it as ending touch coordinates.
+ *
+ * @param event
+ * @param view
+ * @param pointerIndex
+ */
+ private void collectEndAction(MotionEvent event, View view, int pointerIndex) {
+ int offsetInScreen[] = new int[2];
+ view.getLocationOnScreen(offsetInScreen);
+ mPointerEvents[getPointerId(event)].endX =
+ (int)(event.getX(pointerIndex) + offsetInScreen[0]);
+ mPointerEvents[getPointerId(event)].endY =
+ (int)(event.getY(pointerIndex) + offsetInScreen[1]);
+ }
+
+ private int getPointerId(MotionEvent event) {
+ return event.getPointerId(getPointerIndex(event));
+ }
+
+ private int getPointerIndex(MotionEvent event) {
+ return ((event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestItems.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestItems.java
new file mode 100644
index 0000000..17ef46d
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestItems.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TestItems {
+ private static String LOG_TAG = TestItems.class.getSimpleName();
+ private static List<TestItem> ITEMS = new ArrayList<TestItem>();
+ private static Map<String, TestItem> ITEM_MAP = new HashMap<String, TestItem>();
+
+ public static class TestItem {
+ public String mId;
+ public String mName;
+ private final Class<Fragment> mClassFragment;
+ public String mTestDescription;
+
+ @SuppressWarnings("unchecked")
+ public TestItem(String id, String name, Class<?> clsf) {
+ mId = id;
+ mName = name;
+ mClassFragment = (Class<Fragment>) clsf;
+ }
+
+ @Override
+ public String toString() {
+ return mName;
+ }
+ }
+
+ static {
+ addTestItem(new TestItem("1", "Test 1", Test1DetailFragment.class));
+ addTestItem(new TestItem("2", "Test 2", Test2DetailFragment.class));
+ addTestItem(new TestItem("3", "Test 3", Test3DetailFragment.class));
+ addTestItem(new TestItem("4", "Test 4", Test4DetailFragment.class));
+ addTestItem(new TestItem("5", "Test 5", Test5DetailFragment.class));
+ addTestItem(new TestItem("6", "Test 6", Test6DetailFragment.class));
+ addTestItem(new TestItem("7", "Test 7", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("8", "Test 8", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("9", "Test 9", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("10", "Test 10", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("11", "Test 11", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("12", "Test 12", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("13", "Test 13", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("14", "Test 14", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("15", "Test 15", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("16", "Test 16", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("17", "Test 17", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("18", "Test 18", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("19", "Test 19", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("20", "Test 20", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("21", "Test 21", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("22", "Test 22", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("23", "Test 23", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("24", "Test 24", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("25", "Test 25", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("26", "Test 26", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("27", "Test 27", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("28", "Test 28", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("29", "Test 29", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("30", "Test 30", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("31", "Test 31", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("32", "Test 32", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("33", "Test 33", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("34", "Test 34", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("35", "Test 35", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("36", "Test 36", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("37", "Test 37", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("38", "Test 38", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("39", "Test 39", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("40", "Test 40", TestGenericDetailFragment.class));
+ addTestItem(new TestItem("41", "Timeout Test", TestTimeoutFragment.class));
+ }
+
+ private static void addTestItem(TestItem item) {
+ ITEMS.add(item);
+ ITEM_MAP.put(item.mId, item);
+ }
+
+ public static List<TestItem> getTests() {
+ return ITEMS;
+ }
+
+ public static TestItem getTest(String id) {
+ return ITEM_MAP.get(id);
+ }
+
+ public static TestItem getTest(int pos) {
+ return ITEMS.get(pos);
+ }
+
+ public static Fragment getFragment(String id) {
+ try {
+ Fragment fragment = getTest(id).mClassFragment.newInstance();
+ Bundle arguments = new Bundle();
+ arguments.putString("item_id", id);
+ fragment.setArguments(arguments);
+ return fragment;
+ } catch (InstantiationException e) {
+ Log.e(LOG_TAG, "Exception", e);
+ return null;
+ } catch (IllegalAccessException e) {
+ Log.e(LOG_TAG, "Exception", e);
+ return null;
+ }
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestListFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestListFragment.java
new file mode 100644
index 0000000..f93dd04
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestListFragment.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class TestListFragment extends ListFragment {
+
+ private static final String STATE_ACTIVATED_POSITION = "activated_position";
+
+ private Callbacks mCallbacks = sDummyCallbacks;
+ private int mActivatedPosition = ListView.INVALID_POSITION;
+
+ public interface Callbacks {
+
+ public void onItemSelected(String id);
+ }
+
+ private static Callbacks sDummyCallbacks = new Callbacks() {
+ @Override
+ public void onItemSelected(String id) {
+ }
+ };
+
+ public TestListFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setListAdapter(new ArrayAdapter<TestItems.TestItem>(getActivity(),
+ R.layout.simple_list_item_selected, R.id.label, TestItems.getTests()));
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedState) {
+ super.onViewCreated(view, savedState);
+ if (savedState != null && savedState.containsKey(STATE_ACTIVATED_POSITION)) {
+ setActivatedPosition(savedState.getInt(STATE_ACTIVATED_POSITION));
+ }
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ if (!(activity instanceof Callbacks)) {
+ throw new IllegalStateException("Activity must implement fragment's callbacks.");
+ }
+
+ mCallbacks = (Callbacks) activity;
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mCallbacks = sDummyCallbacks;
+ }
+
+ @Override
+ public void onListItemClick(ListView listView, View view, int position, long id) {
+ super.onListItemClick(listView, view, position, id);
+ mCallbacks.onItemSelected(TestItems.getTest(position).mId);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (mActivatedPosition != ListView.INVALID_POSITION) {
+ outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
+ }
+ }
+
+ public void setActivateOnItemClick(boolean activateOnItemClick) {
+ getListView().setChoiceMode(
+ activateOnItemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE);
+ }
+
+ public void setActivatedPosition(int position) {
+ if (position == ListView.INVALID_POSITION) {
+ getListView().setItemChecked(mActivatedPosition, false);
+ } else {
+ getListView().setItemChecked(position, true);
+ }
+
+ mActivatedPosition = position;
+ }
+}
diff --git a/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestTimeoutFragment.java b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestTimeoutFragment.java
new file mode 100644
index 0000000..3b3fd8b
--- /dev/null
+++ b/tests/CtsUiAutomatorTest/testapp/src/com/android/uiautomator/tests/cts/testapp/TestTimeoutFragment.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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 com.android.uiautomator.tests.cts.testapp;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+
+public class TestTimeoutFragment extends Fragment {
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View v = inflater.inflate(R.layout.test_timeout_fragment, container, false);
+
+ Button goButton = (Button)v.findViewById(R.id.go_btn);
+ goButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ doAction(v);
+ }
+ });
+
+ return v;
+ }
+
+ public void doAction(View v) {
+ String delayText = ((EditText)getView().findViewById(R.id.delay)).getText().toString();
+ final int delayValue = delayText.isEmpty() ? 0 : Integer.parseInt(delayText);
+
+ new StartActivityDelayed(delayValue).execute();
+ }
+
+ private class StartActivityDelayed extends AsyncTask<Void, Void, Void> {
+ private final long mDelay;
+
+ public StartActivityDelayed(int delay) {
+ mDelay = delay;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ try {
+ Thread.sleep(mDelay);
+ } catch (InterruptedException e) { }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ getActivity().startActivity(new Intent(getActivity(), LaunchedActivity.class));
+ }
+ }
+}