diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2013-11-24 16:21:49 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2013-11-24 16:21:49 -0800 |
commit | a71ff4c34d708a2a130e5753e8ac966ddaa84c35 (patch) | |
tree | b92e8d5807b79a474daa701d016fed6ec1b49e93 | |
parent | 34f0bc324a145846e938b7737be0166dbf6b92fd (diff) | |
parent | 03b9a8ad5619b1fd045d6a1a1edcaed03e532a6c (diff) | |
download | uiautomator-a71ff4c34d708a2a130e5753e8ac966ddaa84c35.tar.gz |
Merge in Android 4.4
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> @@ -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 Binary files differnew file mode 100644 index 0000000..67de12d --- /dev/null +++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_action_search.png diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..947dbfc --- /dev/null +++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-hdpi/ic_launcher.png diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-ldpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-ldpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..e075065 --- /dev/null +++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-ldpi/ic_launcher.png diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_action_search.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_action_search.png Binary files differnew file mode 100644 index 0000000..134d549 --- /dev/null +++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_action_search.png diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..f91af33 --- /dev/null +++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-mdpi/ic_launcher.png diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_action_search.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_action_search.png Binary files differnew file mode 100644 index 0000000..d699c6b --- /dev/null +++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_action_search.png diff --git a/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_launcher.png b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..542a9cb --- /dev/null +++ b/tests/CtsUiAutomatorTest/testapp/res/drawable-xhdpi/ic_launcher.png 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)); + } + } +} |