diff options
author | Guang Zhu <guangzhu@google.com> | 2014-11-13 19:45:26 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-11-13 19:45:27 +0000 |
commit | f9b3351f18ae617ea4debddce931a9381ab76a4c (patch) | |
tree | 860c5d00013dbf6de4c80019e33bd7e87e0c8cce | |
parent | 61a929bd4642b9042bfb05b85340c1761ab90733 (diff) | |
parent | a693520e12c4a00813e3dc3b4ad2ca2edc9e8f38 (diff) | |
download | testing-lollipop-wear-release.tar.gz |
Merge "remove Espresso source code"HEADandroid-wear-5.0.0_r1master-soongmastermainlollipop-wear-release
230 files changed, 0 insertions, 20327 deletions
diff --git a/espresso/Android.mk b/espresso/Android.mk deleted file mode 100644 index a58b123..0000000 --- a/espresso/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include $(call all-subdir-makefiles) diff --git a/espresso/build.gradle b/espresso/build.gradle deleted file mode 100644 index c2d71cb..0000000 --- a/espresso/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -buildscript { - repositories { - maven { url '../../../prebuilts/gradle-plugin' } - maven { url '../../../prebuilts/tools/common/m2/repository' } - maven { url '../../../prebuilts/tools/common/m2/internal' } - } - dependencies { - classpath 'com.android.tools.build:gradle:0.10.+' - } -} - -subprojects { - project.ext { - androidSdkPath = getAndroidSdkPath() - println 'Using Android SDK at: ' + androidSdkPath - } -} - -def getAndroidSdkPath() { - if (project.has("androidCustomSdkPath")) { - project.androidCustomSdkPath - } else { - System.getenv("ANDROID_HOME") - } -} diff --git a/espresso/espresso-contrib-tests/build.gradle b/espresso/espresso-contrib-tests/build.gradle deleted file mode 100644 index 9328119..0000000 --- a/espresso/espresso-contrib-tests/build.gradle +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'android' - -repositories { - maven { url '../../../../prebuilts/tools/common/m2/repository' } - maven { url '../../../../prebuilts/tools/common/m2/internal' } -} - -android { - compileSdkVersion 19 - buildToolsVersion "19.0.3" - - packagingOptions { - exclude 'LICENSE.txt' - } - - lintOptions { - abortOnError false - } - - defaultConfig { - testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner" - } - - sourceSets { - // Setting espresso-sample as the main root of this project to avoid source code duplication. - // Temporary workaround until Android Gradle plugin supports settings custom target package - // for Android Tests. - main.setRoot("../espresso-sample/src/main") - } -} - -dependencies { - compile files('../libs/guava-14.0.1.jar') - compile 'com.android.support:support-v4:19.1.+' - compile 'com.android.support:appcompat-v7:19.1.+' - - androidTestCompile project(':espresso-contrib') -} - -apply from: "$rootDir/javadoc.gradle" diff --git a/espresso/espresso-contrib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerActionsIntegrationTest.java b/espresso/espresso-contrib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerActionsIntegrationTest.java deleted file mode 100644 index 0e1ee59..0000000 --- a/espresso/espresso-contrib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerActionsIntegrationTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.contrib; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerActions.closeDrawer; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerActions.openDrawer; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerMatchers.isClosed; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerMatchers.isOpen; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.testapp.DrawerActivity; -import com.google.android.apps.common.testing.ui.testapp.R; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Integration tests for {@link DrawerActions}. - */ -@LargeTest -public class DrawerActionsIntegrationTest extends ActivityInstrumentationTestCase2<DrawerActivity> { - - public DrawerActionsIntegrationTest() { - super(DrawerActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testOpenAndCloseDrawer() { - // Drawer should not be open to start. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - - openDrawer(R.id.drawer_layout); - - // The drawer should now be open. - onView(withId(R.id.drawer_layout)).check(matches(isOpen())); - - closeDrawer(R.id.drawer_layout); - - // Drawer should be closed again. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - } - - public void testOpenAndCloseDrawer_idempotent() { - // Drawer should not be open to start. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - - // Open drawer repeatedly. - openDrawer(R.id.drawer_layout); - openDrawer(R.id.drawer_layout); - openDrawer(R.id.drawer_layout); - - // The drawer should be open. - onView(withId(R.id.drawer_layout)).check(matches(isOpen())); - - // Close drawer repeatedly. - closeDrawer(R.id.drawer_layout); - closeDrawer(R.id.drawer_layout); - closeDrawer(R.id.drawer_layout); - - // Drawer should be closed. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - } - - @SuppressWarnings("unchecked") - public void testOpenDrawer_clickItem() { - openDrawer(R.id.drawer_layout); - - // Click an item in the drawer. - int rowIndex = 2; - String rowContents = DrawerActivity.DRAWER_CONTENTS[rowIndex]; - onData(allOf(is(instanceOf(String.class)), is(rowContents))).perform(click()); - - // clicking the item should close the drawer. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - - // The text view will now display "You picked: Pickle" - onView(withId(R.id.drawer_text_view)).check(matches(withText("You picked: " + rowContents))); - } -} diff --git a/espresso/espresso-contrib/Android.mk b/espresso/espresso-contrib/Android.mk deleted file mode 100644 index bbbb118..0000000 --- a/espresso/espresso-contrib/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := espresso-contrib - -LOCAL_SDK_VERSION := 19 - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-v4 \ - espresso-lib - -include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/espresso/espresso-contrib/build.gradle b/espresso/espresso-contrib/build.gradle deleted file mode 100644 index 24e8c03..0000000 --- a/espresso/espresso-contrib/build.gradle +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'android-library' - -sourceCompatibility = JavaVersion.VERSION_1_5 -targetCompatibility = JavaVersion.VERSION_1_5 - -repositories { - maven { url '../../../../prebuilts/tools/common/m2/repository' } - maven { url '../../../../prebuilts/tools/common/m2/internal' } -} - -android { - compileSdkVersion 19 - buildToolsVersion "19.0.3" - - packagingOptions { - exclude 'LICENSE.txt' - } - - lintOptions { - abortOnError false - } -} - -dependencies { - compile project(':espresso-lib') - compile 'com.android.support:support-v4:19.1.+' -} - -apply from: "$rootDir/javadoc.gradle"
\ No newline at end of file diff --git a/espresso/espresso-contrib/src/main/AndroidManifest.xml b/espresso/espresso-contrib/src/main/AndroidManifest.xml deleted file mode 100644 index 1dd537b..0000000 --- a/espresso/espresso-contrib/src/main/AndroidManifest.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.apps.common.testing.ui.espresso.contrib" > - - <uses-sdk - android:minSdkVersion="7"/> - - <application /> - -</manifest>
\ No newline at end of file diff --git a/espresso/espresso-contrib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerActions.java b/espresso/espresso-contrib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerActions.java deleted file mode 100644 index 733c94f..0000000 --- a/espresso/espresso-contrib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerActions.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.contrib; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerMatchers.isClosed; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerMatchers.isOpen; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; - -import com.google.android.apps.common.testing.ui.espresso.Espresso; -import com.google.android.apps.common.testing.ui.espresso.IdlingResource; -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; - -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v4.widget.DrawerLayout.DrawerListener; -import android.view.View; - -import org.hamcrest.Matcher; - -import java.lang.reflect.Field; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.annotation.Nullable; - -/** - * Espresso actions for using a {@link DrawerLayout}. - * - * @see <a href="http://developer.android.com/design/patterns/navigation-drawer.html">Navigation - * drawer design guide</a> - */ -public final class DrawerActions { - - private DrawerActions() { - // forbid instantiation - } - - private static Field listenerField; - - /** - * Opens the {@link DrawerLayout} with the given id. This method blocks until the drawer is fully - * open. No operation if the drawer is already open. - */ - public static void openDrawer(int drawerLayoutId) { - //if the drawer is already open, return. - if (checkDrawer(drawerLayoutId, isOpen())) { - return; - } - onView(withId(drawerLayoutId)).perform(registerListener()); - onView(withId(drawerLayoutId)).perform(actionOpenDrawer()); - } - - /** - * Closes the {@link DrawerLayout} with the given id. This method blocks until the drawer is fully - * closed. No operation if the drawer is already closed. - */ - public static void closeDrawer(int drawerLayoutId) { - //if the drawer is already closed, return. - if (checkDrawer(drawerLayoutId, isClosed())) { - return; - } - onView(withId(drawerLayoutId)).perform(registerListener()); - onView(withId(drawerLayoutId)).perform(actionCloseDrawer()); - } - - /** - * Returns true if the given matcher matches the drawer. - */ - private static boolean checkDrawer(int drawerLayoutId, final Matcher<View> matcher) { - final AtomicBoolean matches = new AtomicBoolean(false); - onView(withId(drawerLayoutId)).perform(new ViewAction() { - - @Override - public Matcher<View> getConstraints() { - return isAssignableFrom(DrawerLayout.class); - } - - @Override - public String getDescription() { - return "check drawer"; - } - - @Override - public void perform(UiController uiController, View view) { - matches.set(matcher.matches(view)); - } - }); - return matches.get(); - } - - private static ViewAction actionOpenDrawer() { - return new ViewAction() { - @Override - public Matcher<View> getConstraints() { - return isAssignableFrom(DrawerLayout.class); - } - - @Override - public String getDescription() { - return "open drawer"; - } - - @Override - public void perform(UiController uiController, View view) { - ((DrawerLayout) view).openDrawer(GravityCompat.START); - } - }; - } - - private static ViewAction actionCloseDrawer() { - return new ViewAction() { - @Override - public Matcher<View> getConstraints() { - return isAssignableFrom(DrawerLayout.class); - } - - @Override - public String getDescription() { - return "close drawer"; - } - - @Override - public void perform(UiController uiController, View view) { - ((DrawerLayout) view).closeDrawer(GravityCompat.START); - } - }; - } - - /** - * Returns a {@link ViewAction} that adds an {@link IdlingDrawerListener} as a drawer listener to - * the {@link DrawerLayout}. The idling drawer listener wraps any listener that already exists. - */ - private static ViewAction registerListener() { - return new ViewAction() { - @Override - public Matcher<View> getConstraints() { - return isAssignableFrom(DrawerLayout.class); - } - - @Override - public String getDescription() { - return "register idling drawer listener"; - } - - @Override - public void perform(UiController uiController, View view) { - DrawerLayout drawer = (DrawerLayout) view; - DrawerListener existingListener = getDrawerListener(drawer); - if (existingListener instanceof IdlingDrawerListener) { - // listener is already registered. No need to assign. - return; - } - drawer.setDrawerListener(IdlingDrawerListener.getInstance(existingListener)); - } - }; - } - - /** - * Pries the current {@link DrawerListener} loose from the cold dead hands of the given - * {@link DrawerLayout}. Uses reflection. - */ - @Nullable - private static DrawerListener getDrawerListener(DrawerLayout drawer) { - try { - if (listenerField == null) { - // lazy initialization of reflected field. - listenerField = DrawerLayout.class.getDeclaredField("mListener"); - listenerField.setAccessible(true); - } - return (DrawerListener) listenerField.get(drawer); - } catch (IllegalArgumentException ex) { - // Pity we can't use Java 7 multi-catch for all of these. - throw new PerformException.Builder().withCause(ex).build(); - } catch (IllegalAccessException ex) { - throw new PerformException.Builder().withCause(ex).build(); - } catch (NoSuchFieldException ex) { - throw new PerformException.Builder().withCause(ex).build(); - } catch (SecurityException ex) { - throw new PerformException.Builder().withCause(ex).build(); - } - } - - /** - * Drawer listener that wraps an existing {@link DrawerListener}, and functions as an - * {@link IdlingResource} for Espresso. - */ - private static class IdlingDrawerListener implements DrawerListener, IdlingResource { - - private static IdlingDrawerListener instance; - private static IdlingDrawerListener getInstance(DrawerListener parentListener) { - if (instance == null) { - instance = new IdlingDrawerListener(); - Espresso.registerIdlingResources(instance); - } - instance.setParentListener(parentListener); - return instance; - } - - @Nullable private DrawerListener parentListener; - private ResourceCallback callback; - // Idle state is only accessible from main thread. - private boolean idle = true; - - public void setParentListener(@Nullable DrawerListener parentListener) { - this.parentListener = parentListener; - } - - @Override - public void onDrawerClosed(View drawer) { - if (parentListener != null) { - parentListener.onDrawerClosed(drawer); - } - } - - @Override - public void onDrawerOpened(View drawer) { - if (parentListener != null) { - parentListener.onDrawerOpened(drawer); - } - } - - @Override - public void onDrawerSlide(View drawer, float slideOffset) { - if (parentListener != null) { - parentListener.onDrawerSlide(drawer, slideOffset); - } - } - - @Override - public void onDrawerStateChanged(int newState) { - if (newState == DrawerLayout.STATE_IDLE) { - idle = true; - if (callback != null) { - callback.onTransitionToIdle(); - } - } else { - idle = false; - } - if (parentListener != null) { - parentListener.onDrawerStateChanged(newState); - } - } - - @Override - public String getName() { - return "IdlingDrawerListener"; - } - - @Override - public boolean isIdleNow() { - return idle; - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback callback) { - this.callback = callback; - } - } -} diff --git a/espresso/espresso-contrib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerMatchers.java b/espresso/espresso-contrib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerMatchers.java deleted file mode 100644 index ca66af8..0000000 --- a/espresso/espresso-contrib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/DrawerMatchers.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.contrib; - -import com.google.android.apps.common.testing.ui.espresso.matcher.BoundedMatcher; - -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.view.View; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; - -/** - * Hamcrest matchers for a {@link DrawerLayout}. - */ -public final class DrawerMatchers { - - private DrawerMatchers() { - // forbid instantiation - } - - /** - * Returns a matcher that verifies that the drawer is open. Matches only when the drawer is fully - * open. Use {@link #isClosed()} instead of {@code not(isOpen())} when you wish to check that the - * drawer is fully closed. - */ - public static Matcher<View> isOpen() { - return new BoundedMatcher<View, DrawerLayout>(DrawerLayout.class) { - @Override - public void describeTo(Description description) { - description.appendText("is drawer open"); - } - - @Override - public boolean matchesSafely(DrawerLayout drawer) { - return drawer.isDrawerOpen(GravityCompat.START); - } - }; - } - - /** - * Returns a matcher that verifies that the drawer is closed. Matches only when the drawer is - * fully closed. Use {@link #isOpen()} instead of {@code not(isClosed()))} when you wish to check - * that the drawer is fully open. - */ - public static Matcher<View> isClosed() { - return new BoundedMatcher<View, DrawerLayout>(DrawerLayout.class) { - @Override - public void describeTo(Description description) { - description.appendText("is drawer closed"); - } - - @Override - public boolean matchesSafely(DrawerLayout drawer) { - return !drawer.isDrawerVisible(GravityCompat.START); - } - }; - } -} diff --git a/espresso/espresso-lib-tests/build.gradle b/espresso/espresso-lib-tests/build.gradle deleted file mode 100644 index aaff806..0000000 --- a/espresso/espresso-lib-tests/build.gradle +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'android' - -repositories { - maven { url '../../../../prebuilts/tools/common/m2/repository' } - maven { url '../../../../prebuilts/tools/common/m2/internal' } -} - -android { - compileSdkVersion 19 - buildToolsVersion "19.0.3" - - packagingOptions { - exclude 'LICENSE.txt' - } - - lintOptions { - abortOnError false - } - - defaultConfig { - testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner" - } - - sourceSets { - // Setting espresso-sample as the main root of this project to avoid source code duplication. - // Temporary workaround until Android Gradle plugin supports settings custom target package - // for Android Tests. - main.setRoot("../espresso-sample/src/main") - } -} - -dependencies { - compile files('../libs/guava-14.0.1.jar') - compile 'com.android.support:support-v4:19.1.+' - compile 'com.android.support:appcompat-v7:19.1.+' - - // run test against an un-jarjared variant of the lib - androidTestCompile project(path: ':espresso-lib', configuration: 'debug') - - androidTestCompile 'org.mockito:mockito-core:1.9.5' - androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0' -} - -apply from: "$rootDir/javadoc.gradle" diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/AmbiguousViewMatcherExceptionTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/AmbiguousViewMatcherExceptionTest.java deleted file mode 100644 index 650c426..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/AmbiguousViewMatcherExceptionTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; - -import android.test.AndroidTestCase; -import android.view.View; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.hamcrest.StringDescription; - -/** Unit tests for {@link AmbiguousViewMatcherException}. */ -public class AmbiguousViewMatcherExceptionTest extends AndroidTestCase { - private Matcher<View> alwaysTrueMatcher; - - private RelativeLayout testView; - private View child1; - private View child2; - private View child3; - private View child4; - - @Override - public void setUp() throws Exception { - super.setUp(); - alwaysTrueMatcher = Matchers.<View>notNullValue(); - testView = new RelativeLayout(getContext()); - child1 = new TextView(getContext()); - child1.setId(1); - child2 = new TextView(getContext()); - child2.setId(2); - child3 = new TextView(getContext()); - child3.setId(3); - child4 = new TextView(getContext()); - child4.setId(4); - testView.addView(child1); - testView.addView(child2); - testView.addView(child3); - testView.addView(child4); - } - - public void testExceptionContainsMatcherDescription() { - StringBuilder matcherDescription = new StringBuilder(); - alwaysTrueMatcher.describeTo(new StringDescription(matcherDescription)); - assertThat(createException().getMessage(), containsString(matcherDescription.toString())); - } - - @SuppressWarnings("unchecked") - public void testExceptionContainsView() { - String exceptionMessage = createException().getMessage(); - - assertThat("missing elements", exceptionMessage, - allOf( - containsString("{id=1,"), // child1 - containsString("{id=2,"), // child2 - containsString("{id=3,"), // child3 - containsString("{id=4,"), // child4 - containsString("{id=-1,"))); // root - } - - private AmbiguousViewMatcherException createException() { - - return new AmbiguousViewMatcherException.Builder() - .withViewMatcher(alwaysTrueMatcher) - .withRootView(testView) - .withView1(testView) - .withView2(child1) - .withOtherAmbiguousViews(child2, child3, child4) - .build(); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/AppNotIdleExceptionTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/AppNotIdleExceptionTest.java deleted file mode 100644 index 48fe347..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/AppNotIdleExceptionTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; - -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SyncActivity; - -import android.os.Handler; -import android.os.Looper; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -import java.util.concurrent.FutureTask; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Test case for {@link AppNotIdleException}. - */ -@LargeTest -public class AppNotIdleExceptionTest extends ActivityInstrumentationTestCase2<SyncActivity> { - - @SuppressWarnings("deprecation") - public AppNotIdleExceptionTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", SyncActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testAppIdleException() throws Exception { - final AtomicBoolean continueBeingBusy = new AtomicBoolean(true); - try { - final Handler handler = new Handler(Looper.getMainLooper()); - Runnable runnable = new Runnable() { - @Override - public void run() { - if (!continueBeingBusy.get()) { - return; - } else { - handler.post(this); - } - } - }; - FutureTask<Void> task = new FutureTask<Void>(runnable, null); - handler.post(task); - task.get(); // Will Make sure that the first post is sent before we do a lookup. - // Request the "hello world!" text by clicking on the request button. - onView(withId(R.id.request_button)).perform(click()); - fail("Espresso failed to throw AppNotIdleException"); - } catch (AppNotIdleException e) { - // Do Nothing. Test pass. - continueBeingBusy.getAndSet(false); - } - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/EspressoEdgeCaseTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/EspressoEdgeCaseTest.java deleted file mode 100644 index 8439a96..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/EspressoEdgeCaseTest.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeText; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; - -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.os.AsyncTask; -import android.os.Handler; -import android.os.Looper; -import android.os.SystemClock; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.view.View; - -import org.hamcrest.Matcher; - -import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Collection of some nasty edge cases. - */ -@LargeTest -public class EspressoEdgeCaseTest extends ActivityInstrumentationTestCase2<SendActivity> { - @SuppressWarnings("deprecation") - public EspressoEdgeCaseTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - private static final Callable<Void> NO_OP = new Callable<Void>() { - @Override - public Void call() { - return null; - } - }; - - private Handler mainHandler; - private OneShotResource oneShotResource; - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - mainHandler = new Handler(Looper.getMainLooper()); - oneShotResource = new OneShotResource(); - } - - @Override - public void tearDown() throws Exception { - IdlingPolicies.setMasterPolicyTimeout(60, TimeUnit.SECONDS); - IdlingPolicies.setIdlingResourceTimeout(26, TimeUnit.SECONDS); - oneShotResource.setIdle(true); - super.tearDown(); - } - - @SuppressWarnings("unchecked") - public void testRecoveryFromExceptionOnMainThreadLoopMainThreadUntilIdle() throws Exception { - final RuntimeException poison = new RuntimeException("oops"); - try { - onView(withId(R.id.enter_data_edit_text)) - .perform( - new TestAction() { - - @Override - public void perform(UiController controller, View view) { - mainHandler.post(new Runnable() { - @Override - public void run() { - throw poison; - }}); - controller.loopMainThreadUntilIdle(); - } - }); - fail("should throw"); - } catch (RuntimeException re) { - if (re == poison) { - // expected - } else { - // something else. - throw re; - } - } - // life should continue normally. - onView(withId(R.id.enter_data_edit_text)) - .perform(typeText("Hello World111")); - onView(withId(R.id.enter_data_edit_text)) - .check(matches(withText("Hello World111"))); - } - - @SuppressWarnings("unchecked") - public void testRecoveryFromExceptionOnMainThreadLoopMainThreadForAtLeast() throws Exception { - final RuntimeException poison = new RuntimeException("oops"); - final FutureTask<Void> syncTask = new FutureTask<Void>(NO_OP); - try { - onView(withId(R.id.enter_data_edit_text)) - .perform( - new TestAction() { - @Override - public void perform(UiController controller, View view) { - mainHandler.post(new Runnable() { - @Override - public void run() { - throw poison; - }}); - // block test execution until loopMainThreadForAtLeast call - // would be satisified - mainHandler.postDelayed(syncTask, 2500); - controller.loopMainThreadForAtLeast(2000); - } - }); - fail("should throw"); - } catch (RuntimeException re) { - if (re == poison) { - // expected - } else { - // something else. - throw re; - } - } - syncTask.get(); - - // life should continue normally. - onView(withId(R.id.enter_data_edit_text)) - .perform(typeText("baz bar")); - onView(withId(R.id.enter_data_edit_text)) - .check(matches(withText("baz bar"))); - } - - @SuppressWarnings("unchecked") - public void testRecoveryFromTimeOutExceptionMaster() throws Exception { - IdlingPolicies.setMasterPolicyTimeout(2, TimeUnit.SECONDS); - final FutureTask<Void> syncTask = new FutureTask<Void>(NO_OP); - try { - onView(withId(R.id.enter_data_edit_text)) - .perform( - new TestAction() { - @Override - public void perform(UiController controller, View view) { - mainHandler.post(new Runnable() { - @Override - public void run() { - SystemClock.sleep(TimeUnit.SECONDS.toMillis(8)); - } - }); - // block test execution until loopMainThreadForAtLeast call - // would be satisified - mainHandler.postDelayed(syncTask, 2500); - controller.loopMainThreadForAtLeast(1000); - } - }); - fail("should throw"); - } catch (RuntimeException re) { - if (re instanceof EspressoException) { - // expected - } else { - // something else. - throw re; - } - } - syncTask.get(); - - // life should continue normally. - onView(withId(R.id.enter_data_edit_text)) - .perform(typeText("one two three")); - onView(withId(R.id.enter_data_edit_text)) - .check(matches(withText("one two three"))); - } - - @SuppressWarnings("unchecked") - public void testRecoveryFromTimeOutExceptionDynamic() { - IdlingPolicies.setIdlingResourceTimeout(2, TimeUnit.SECONDS); - - Espresso.registerIdlingResources(oneShotResource); - oneShotResource.setIdle(false); - - try { - onView(withId(R.id.enter_data_edit_text)) - .perform(click()); - fail("should throw"); - } catch (RuntimeException re) { - if (re instanceof EspressoException) { - // expected - } else { - // something else. - throw re; - } - } - oneShotResource.setIdle(true); - - // life should continue normally. - onView(withId(R.id.enter_data_edit_text)) - .perform(typeText("Doh")); - onView(withId(R.id.enter_data_edit_text)) - .check(matches(withText("Doh"))); - } - - public void testRecoveryFromAsyncTaskTimeout() throws Exception { - IdlingPolicies.setMasterPolicyTimeout(2, TimeUnit.SECONDS); - try { - onView(withId(R.id.enter_data_edit_text)) - .perform(new TestAction() { - @Override - public void perform(UiController controller, View view) { - new AsyncTask<Void, Void, Void>() { - @Override - public Void doInBackground(Void... params) { - SystemClock.sleep(TimeUnit.SECONDS.toMillis(8)); - return null; - } - }.execute(); - // block test execution until loopMainThreadForAtLeast call - // would be satisified - controller.loopMainThreadForAtLeast(1000); - } - }); - fail("should throw"); - } catch (RuntimeException re) { - if (re instanceof EspressoException) { - // expected - } else { - // something else. - throw re; - } - } - IdlingPolicies.setMasterPolicyTimeout(60, TimeUnit.SECONDS); - // life should continue normally. - onView(withId(R.id.enter_data_edit_text)) - .perform(typeText("Har Har")); - onView(withId(R.id.enter_data_edit_text)) - .check(matches(withText("Har Har"))); - } - - - - - private abstract static class TestAction implements ViewAction { - @Override - public String getDescription() { - return "A random test action."; - } - - @Override - public Matcher<View> getConstraints() { - return isAssignableFrom(View.class); - } - } - - - private static class OneShotResource implements IdlingResource { - private static AtomicInteger counter = new AtomicInteger(0); - - private final int instance; - private volatile IdlingResource.ResourceCallback callback; - private volatile boolean isIdle = true; - - private OneShotResource() { - instance = counter.incrementAndGet(); - } - - @Override - public String getName() { - return "TestOneShotResource_" + counter; - } - - public void setIdle(boolean idle) { - isIdle = idle; - if (isIdle && callback != null) { - callback.onTransitionToIdle(); - } - } - - @Override - public boolean isIdleNow() { - return isIdle; - } - - @Override - public void registerIdleTransitionCallback(IdlingResource.ResourceCallback callback) { - this.callback = callback; - } - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/EspressoTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/EspressoTest.java deleted file mode 100644 index ff4ff39..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/EspressoTest.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.openActionBarOverflowOrOptionsMenu; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.openContextualActionModeOverflowMenu; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anything; -import static org.hamcrest.Matchers.hasValue; -import static org.hamcrest.Matchers.instanceOf; - -import com.google.android.apps.common.testing.ui.espresso.action.ViewActions; -import com.google.android.apps.common.testing.ui.testapp.ActionBarTestActivity; -import com.google.android.apps.common.testing.ui.testapp.MainActivity; -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.content.Context; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.view.View; -import android.view.inputmethod.InputMethodManager; - -import org.hamcrest.Matcher; - -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Tests Espresso top level (i.e. ones not specific to a view) actions like pressBack and - * closeSoftKeyboard. - */ -@LargeTest -public class EspressoTest extends ActivityInstrumentationTestCase2<MainActivity> { - @SuppressWarnings("deprecation") - public EspressoTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", MainActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - @SuppressWarnings("unchecked") - public void testOpenOverflowInActionMode() { - onData(allOf(instanceOf(Map.class), hasValue(ActionBarTestActivity.class.getSimpleName()))) - .perform(click()); - openContextualActionModeOverflowMenu(); - onView(withText("Key")) - .perform(click()); - onView(withId(R.id.text_action_bar_result)) - .check(matches(withText("Key"))); - } - - @SuppressWarnings("unchecked") - public void testOpenOverflowFromActionBar() { - onData(allOf(instanceOf(Map.class), hasValue(ActionBarTestActivity.class.getSimpleName()))) - .perform(click()); - onView(withId(R.id.hide_contextual_action_bar)) - .perform(click()); - openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext()); - onView(withText("World")) - .perform(click()); - onView(withId(R.id.text_action_bar_result)) - .check(matches(withText("World"))); - } - - @SuppressWarnings("unchecked") - public void testCloseSoftKeyboard() { - onData(allOf(instanceOf(Map.class), hasValue(SendActivity.class.getSimpleName()))) - .perform(click()); - - onView(withId(R.id.enter_data_edit_text)).perform(new ViewAction() { - @Override - public Matcher<View> getConstraints() { - return anything(); - } - - @Override - public void perform(UiController uiController, View view) { - InputMethodManager imm = (InputMethodManager) getInstrumentation().getTargetContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(view, 0); - uiController.loopMainThreadUntilIdle(); - } - - @Override - public String getDescription() { - return "show soft input"; - } - }); - - onView(withId(R.id.enter_data_edit_text)).perform(ViewActions.closeSoftKeyboard()); - } - - public void testSetFailureHandler() { - final AtomicBoolean handled = new AtomicBoolean(false); - Espresso.setFailureHandler(new FailureHandler() { - @Override - public void handle(Throwable error, Matcher<View> viewMatcher) { - handled.set(true); - } - }); - onView(withText("does not exist")).perform(click()); - assertTrue(handled.get()); - } - - public void testRegisterResourceWithNullName() { - try { - Espresso.registerIdlingResources(new IdlingResource() { - @Override - public boolean isIdleNow() { - return true; - } - - @Override - public String getName() { - return null; - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback callback) { - // ignore - } - }); - fail("Should have thrown NPE"); - } catch (NullPointerException expected) {} - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingViewExceptionTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingViewExceptionTest.java deleted file mode 100644 index 16571e3..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingViewExceptionTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; - -import android.test.AndroidTestCase; -import android.view.View; - -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.hamcrest.StringDescription; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** Unit tests for {@link NoMatchingViewException}. */ -public class NoMatchingViewExceptionTest extends AndroidTestCase { - private Matcher<View> alwaysFailingMatcher; - - @Mock - private View testView; - - @Override - public void setUp() throws Exception { - super.setUp(); - MockitoAnnotations.initMocks(this); - alwaysFailingMatcher = Matchers.<View>nullValue(); - } - - public void testExceptionContainsMatcherDescription() { - StringBuilder matcherDescription = new StringBuilder(); - alwaysFailingMatcher.describeTo(new StringDescription(matcherDescription)); - assertThat(createException().getMessage(), containsString(matcherDescription.toString())); - } - - public void testExceptionContainsView() { - String exceptionMessage = createException().getMessage(); - - assertThat("missing root element" + exceptionMessage, exceptionMessage, - containsString("{id=0,")); - } - - private NoMatchingViewException createException() { - return new NoMatchingViewException.Builder() - .withViewMatcher(alwaysFailingMatcher) - .withRootView(testView) - .build(); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/UnitTests.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/UnitTests.java deleted file mode 100644 index b3c3f98..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/UnitTests.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import android.test.suitebuilder.TestSuiteBuilder; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * TestSuite containing "unit tests" for the UI Framework. - * - */ -public class UnitTests extends TestSuite { - public static Test suite() { - return new TestSuiteBuilder(UnitTests.class) - .includeAllPackagesUnderHere() - .build(); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java deleted file mode 100755 index 295572c..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Throwables.propagate; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitor; -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry; -import com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers; -import com.google.common.util.concurrent.MoreExecutors; - -import android.test.AndroidTestCase; -import android.view.View; - -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.mockito.Mock; - -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicReference; - -/** Unit tests for {@link ViewInteraction}. */ -public class ViewInteractionTest extends AndroidTestCase { - @Mock - private ViewFinder mockViewFinder; - @Mock - private ViewAssertion mockAssertion; - @Mock - private ViewAction mockAction; - @Mock - private UiController mockUiController; - - - private FailureHandler failureHandler; - private Executor testExecutor = MoreExecutors.sameThreadExecutor(); - - private ActivityLifecycleMonitor realLifecycleMonitor; - private ViewInteraction testInteraction; - private View rootView; - private View targetView; - private Matcher<View> viewMatcher; - private Matcher<View> actionConstraint; - private AtomicReference<Matcher<Root>> rootMatcherRef; - - @Override - public void setUp() throws Exception { - super.setUp(); - initMocks(this); - realLifecycleMonitor = ActivityLifecycleMonitorRegistry.getInstance(); - rootView = new View(getContext()); - targetView = new View(getContext()); - viewMatcher = is(targetView); - actionConstraint = Matchers.<View>notNullValue(); - rootMatcherRef = new AtomicReference<Matcher<Root>>(RootMatchers.DEFAULT); - when(mockAction.getDescription()).thenReturn("A Mock!"); - failureHandler = new FailureHandler() { - @Override - public void handle(Throwable error, Matcher<View> viewMatcher) { - propagate(error); - } - }; - } - - @Override - public void tearDown() throws Exception { - ActivityLifecycleMonitorRegistry.registerInstance(realLifecycleMonitor); - super.tearDown(); - } - - public void testPerformViewViolatesConstraints() { - actionConstraint = not(viewMatcher); - when(mockViewFinder.getView()).thenReturn(targetView); - initInteraction(); - try { - testInteraction.perform(mockAction); - fail("should propagate constraint violation!"); - } catch (RuntimeException re) { - if (!PerformException.class.isAssignableFrom(re.getClass())) { - throw re; - } - } - } - - public void testPerformPropagatesException() { - RuntimeException exceptionToRaise = new RuntimeException(); - when(mockViewFinder.getView()).thenReturn(targetView); - doThrow(exceptionToRaise) - .when(mockAction) - .perform(mockUiController, targetView); - initInteraction(); - try { - testInteraction.perform(mockAction); - fail("Should propagate exception stored in view operation!"); - } catch (RuntimeException re) { - verify(mockAction).perform(mockUiController, targetView); - assertThat(exceptionToRaise, is(re)); - } - } - - public void testCheckPropagatesException() { - RuntimeException exceptionToRaise = new RuntimeException(); - when(mockViewFinder.getView()).thenReturn(targetView); - doThrow(exceptionToRaise) - .when(mockAssertion) - .check(targetView, null); - - initInteraction(); - try { - testInteraction.check(mockAssertion); - fail("Should propagate exception stored in view operation!"); - } catch (RuntimeException re) { - verify(mockAssertion).check(targetView, null); - assertThat(exceptionToRaise, is(re)); - } - } - - public void testPerformTwiceUpdatesPreviouslyMatched() { - View firstView = new View(getContext()); - View secondView = new View(getContext()); - when(mockViewFinder.getView()).thenReturn(firstView); - initInteraction(); - testInteraction.perform(mockAction); - verify(mockAction).perform(mockUiController, firstView); - - when(mockViewFinder.getView()).thenReturn(secondView); - testInteraction.perform(mockAction); - verify(mockAction).perform(mockUiController, secondView); - - testInteraction.check(mockAssertion); - verify(mockAssertion).check(secondView, null); - - } - - public void testPerformAndCheck() { - when(mockViewFinder.getView()).thenReturn(targetView); - initInteraction(); - testInteraction.perform(mockAction); - verify(mockAction).perform(mockUiController, targetView); - - testInteraction.check(mockAssertion); - verify(mockAssertion).check(targetView, null); - } - - public void testCheck() { - when(mockViewFinder.getView()).thenReturn(targetView); - initInteraction(); - testInteraction.check(mockAssertion); - verify(mockAssertion).check(targetView, null); - } - - public void testInRootUpdatesRef() { - initInteraction(); - Matcher<Root> testMatcher = nullValue(); - testInteraction.inRoot(testMatcher); - assertEquals(testMatcher, rootMatcherRef.get()); - } - - public void testInRoot_NullHandling() { - initInteraction(); - try { - testInteraction.inRoot(null); - fail("should throw"); - } catch (NullPointerException expected) { - } - } - - public void testCheck_ViewCannotBeFound() { - NoMatchingViewException noViewException = new NoMatchingViewException.Builder() - .withViewMatcher(viewMatcher) - .withRootView(rootView) - .build(); - - when(mockViewFinder.getView()).thenThrow(noViewException); - initInteraction(); - testInteraction.check(mockAssertion); - verify(mockAssertion).check(null, noViewException); - } - - private void initInteraction() { - when(mockAction.getConstraints()).thenReturn(actionConstraint); - - testInteraction = new ViewInteraction(mockUiController, mockViewFinder, testExecutor, - failureHandler, viewMatcher, rootMatcherRef); - - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterDataIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterDataIntegrationTest.java deleted file mode 100644 index fe37fc5..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterDataIntegrationTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasSibling; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.testapp.LongListActivity; -import com.google.android.apps.common.testing.ui.testapp.R; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -import java.util.Map; - -/** - * Integration tests for operating on data displayed in an adapter. - */ -@LargeTest -public class AdapterDataIntegrationTest extends ActivityInstrumentationTestCase2<LongListActivity> { - @SuppressWarnings("deprecation") - public AdapterDataIntegrationTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", LongListActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - @SuppressWarnings("unchecked") - public void testClickAroundList() { - onData(allOf(is(instanceOf(Map.class)), hasEntry(is(LongListActivity.STR), is("item: 99")))) - .perform(click()); - onView(withId(R.id.selection_row_value)) - .check(matches(withText("99"))); - - onData(allOf(is(instanceOf(Map.class)), hasEntry(is(LongListActivity.STR), is("item: 1")))) - .perform(click()); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("1"))); - - onData(allOf(is(instanceOf(Map.class)))) - .atPosition(20) - .perform(click()); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("20"))); - - // lets operate on a specific child of a row... - onData(allOf(is(instanceOf(Map.class)), hasEntry(is(LongListActivity.STR), is("item: 50")))) - .onChildView(withId(R.id.item_size)) - .perform(click()) - .check(matches(withText(String.valueOf("item: 50".length())))); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("50"))); - } - - @SuppressWarnings("unchecked") - public void testSelectItemWithSibling() { - onView(allOf(withText("7"), hasSibling(withText("item: 0")))) - .perform(click()); - onView(withId(R.id.selection_row_value)) - .check(matches(withText("0"))); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/ClearTextActionIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/ClearTextActionIntegrationTest.java deleted file mode 100644 index cf2835f..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/ClearTextActionIntegrationTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.clearText; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeText; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.app.Activity; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * {@link ClearTextAction} integration tests. - */ -@LargeTest -public class ClearTextActionIntegrationTest extends ActivityInstrumentationTestCase2<SendActivity> { - @SuppressWarnings("deprecation") - public ClearTextActionIntegrationTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @LargeTest - public void testClearTextActionPerform() { - Activity activity = getActivity(); - String text = activity.getText(R.string.send_data_to_message_edit_text).toString(); - onView(withId(is(R.id.send_data_to_message_edit_text))).check(matches(withText(is(text)))); - onView(withId(is(R.id.send_data_to_message_edit_text))).perform(clearText()); - onView(withId(is(R.id.send_data_to_message_edit_text))).check(matches(withText(is("")))); - } - - @LargeTest - public void testClearTextActionPerformWithTypeText() { - Activity activity = getActivity(); - String text = activity.getText(R.string.send_data_to_message_edit_text).toString(); - onView(withId(is(R.id.send_data_to_call_edit_text))).perform(typeText(text)); - onView(withId(is(R.id.send_data_to_call_edit_text))).check(matches(withText(is(text)))); - onView(withId(is(R.id.send_data_to_call_edit_text))).perform(clearText()); - onView(withId(is(R.id.send_data_to_call_edit_text))).check(matches(withText(is("")))); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EditorActionIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EditorActionIntegrationTest.java deleted file mode 100644 index 0a99be9..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EditorActionIntegrationTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.pressImeActionButton; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.scrollTo; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasImeAction; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; - -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.view.inputmethod.EditorInfo; - -/** - * Tests for {@link EditorAction}. - */ -@LargeTest -public class EditorActionIntegrationTest extends ActivityInstrumentationTestCase2<SendActivity> { - @SuppressWarnings("deprecation") - public EditorActionIntegrationTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - @SuppressWarnings("unchecked") - public void testPressImeActionButtonOnSearchBox() { - String searchFor = "rainbows and unicorns"; - onView(withId(R.id.search_box)).perform(scrollTo(), ViewActions.typeText(searchFor)); - onView(withId(R.id.search_box)) - .check(matches(hasImeAction(EditorInfo.IME_ACTION_SEARCH))) - .perform(pressImeActionButton()); - onView(withId(R.id.search_result)).perform(scrollTo()); - onView(withId(R.id.search_result)) - .check(matches(allOf(isDisplayed(), withText(containsString(searchFor))))); - } - - public void testPressImeActionButtonOnNonEditorWidget() { - try { - onView(withId(R.id.send_button)).perform(pressImeActionButton()); - fail("Expected exception on previous call"); - } catch (PerformException expected) { - assertTrue(expected.getCause() instanceof IllegalStateException); - } - } - - public void testPressSearchOnDefaultEditText() { - onView(withId(R.id.enter_data_edit_text)).perform(pressImeActionButton()); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EspressoKeyBuilderTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EspressoKeyBuilderTest.java deleted file mode 100644 index 6df907d..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EspressoKeyBuilderTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import com.google.android.apps.common.testing.ui.espresso.action.EspressoKey.Builder; - -import android.os.Build; -import android.view.KeyEvent; - -import junit.framework.TestCase; - -/** - * Unit tests for {@link Builder}. - */ -public class EspressoKeyBuilderTest extends TestCase { - - static final int KEY_CODE = KeyEvent.KEYCODE_X; - - public void testBuildWithNoMetaState() { - EspressoKey key = new Builder().withKeyCode(KEY_CODE).build(); - assertEquals(KEY_CODE, key.getKeyCode()); - assertEquals(0, key.getMetaState()); - } - - public void testBuildWithShiftPressed() { - EspressoKey key = new Builder().withKeyCode(KEY_CODE).withShiftPressed(true).build(); - assertEquals(KEY_CODE, key.getKeyCode()); - assertEquals(KeyEvent.META_SHIFT_ON, key.getMetaState()); - } - - public void testBuildWithCtrlPressed() { - EspressoKey key = new Builder().withKeyCode(KEY_CODE).withCtrlPressed(true).build(); - assertEquals(KEY_CODE, key.getKeyCode()); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - assertEquals(KeyEvent.META_CTRL_ON, key.getMetaState()); - } else { - assertEquals(0, key.getMetaState()); - } - } - - public void testBuildWithAltPressed() { - EspressoKey key = new Builder().withKeyCode(KEY_CODE).withAltPressed(true).build(); - assertEquals(KEY_CODE, key.getKeyCode()); - assertEquals(KeyEvent.META_ALT_ON, key.getMetaState()); - } - - public void testBuildWithAllMetaKeysPressed() { - EspressoKey key = new Builder().withKeyCode(KEY_CODE) - .withShiftPressed(true) - .withCtrlPressed(true) - .withAltPressed(true) - .build(); - - assertEquals(KEY_CODE, key.getKeyCode()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - assertEquals(KeyEvent.META_SHIFT_ON | KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON, - key.getMetaState()); - } else { - assertEquals(KeyEvent.META_SHIFT_ON | KeyEvent.META_ALT_ON, key.getMetaState()); - } - } -}
\ No newline at end of file diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EventActionIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EventActionIntegrationTest.java deleted file mode 100644 index fbf55ef..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/EventActionIntegrationTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.doubleClick; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.longClick; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; - -import com.google.android.apps.common.testing.testrunner.annotations.SdkSuppress; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers; -import com.google.android.apps.common.testing.ui.testapp.GestureActivity; -import com.google.android.apps.common.testing.ui.testapp.R; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.view.View; - -import org.hamcrest.Matcher; - -/** - * UI tests for ClickAction, LongClickAction and DoubleClickAction. - */ -@LargeTest -public class EventActionIntegrationTest extends ActivityInstrumentationTestCase2<GestureActivity> { - - @SuppressWarnings("deprecation") - public EventActionIntegrationTest() { - // Keep froyo happy. - super("com.google.android.apps.common.testing.ui.testapp", GestureActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testClick() { - onView(withText(is(getActivity().getString(R.string.text_click)))) - .check(matches(not(isDisplayed()))); - onView(withId(is(R.id.gesture_area))).perform(click()); - onView(withId(is(R.id.text_click))).check(matches(isDisplayed())); - onView(withText(is(getActivity().getString(R.string.text_click)))) - .check(matches(isDisplayed())); - } - - public void testBadClick() { - onView(withText(is(getActivity().getString(R.string.text_click)))) - .check(matches(not(isDisplayed()))); - getActivity().setTouchDelay(700); - - onView(withId(is(R.id.gesture_area))).perform(click( - new ViewAction() { - @Override - public String getDescription() { - return "Handle tap->longclick."; - } - @Override - public Matcher<View> getConstraints() { - return isAssignableFrom(View.class); - } - @Override - public void perform(UiController uiController, View view) { - getActivity().setTouchDelay(0); - } - })); - - - onView(withId(is(R.id.text_click))).check(matches(isDisplayed())); - onView(withText(is(getActivity().getString(R.string.text_click)))) - .check(matches(isDisplayed())); - } - - @SdkSuppress(bugId = -1, versions = {7, 8, 13}) - public void testLongClick() { - onView(withText(is(getActivity().getString(R.string.text_long_click)))) - .check(matches(not(isDisplayed()))); - onView(withId(is(R.id.gesture_area))).perform(longClick()); - onView(withId(is(R.id.text_long_click))).check(matches(isDisplayed())); - onView(withText(is(getActivity().getString(R.string.text_long_click)))) - .check(matches(isDisplayed())); - } - - @SdkSuppress(bugId = -1, versions = {7, 8, 13}) - public void testDoubleClick() { - onView(withText(is(getActivity().getString(R.string.text_double_click)))) - .check(matches(not(ViewMatchers.isDisplayed()))); - onView(withId(is(R.id.gesture_area))).perform(doubleClick()); - onView(withId(is(R.id.text_double_click))).check(matches(isDisplayed())); - onView(withText(is("Double Click"))).check(matches(isDisplayed())); - onView(withText(is(getActivity().getString(R.string.text_double_click)))) - .check(matches(isDisplayed())); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralLocationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralLocationTest.java deleted file mode 100644 index 944e660..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralLocationTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.MockitoAnnotations.initMocks; - -import android.view.View; - -import junit.framework.TestCase; - -import org.mockito.Spy; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -/** - * Unit tests for {@link GeneralLocation}. - */ -public class GeneralLocationTest extends TestCase { - - private static final int VIEW_POSITION_X = 100; - private static final int VIEW_POSITION_Y = 50; - private static final int VIEW_WIDTH = 150; - private static final int VIEW_HEIGHT = 300; - - private static final int AXIS_X = 0; - private static final int AXIS_Y = 1; - - @Spy - private View mockView; - - @Override - public void setUp() throws Exception { - super.setUp(); - initMocks(this); - - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - int[] array = (int[]) invocation.getArguments()[0]; - array[AXIS_X] = VIEW_POSITION_X; - array[AXIS_Y] = VIEW_POSITION_Y; - return null; - } - }).when(mockView).getLocationOnScreen(any(int[].class)); - - mockView.layout( - VIEW_POSITION_X, - VIEW_POSITION_Y, - VIEW_POSITION_X + VIEW_WIDTH, - VIEW_POSITION_Y + VIEW_HEIGHT); - } - - public void testLeftLocationsX() { - assertPositionEquals(VIEW_POSITION_X, GeneralLocation.TOP_LEFT, AXIS_X); - assertPositionEquals(VIEW_POSITION_X, GeneralLocation.CENTER_LEFT, AXIS_X); - assertPositionEquals(VIEW_POSITION_X, GeneralLocation.BOTTOM_LEFT, AXIS_X); - } - - public void testRightLocationsX() { - assertPositionEquals(VIEW_POSITION_X + VIEW_WIDTH, GeneralLocation.TOP_RIGHT, AXIS_X); - assertPositionEquals(VIEW_POSITION_X + VIEW_WIDTH, GeneralLocation.CENTER_RIGHT, AXIS_X); - assertPositionEquals(VIEW_POSITION_X + VIEW_WIDTH, GeneralLocation.BOTTOM_RIGHT, AXIS_X); - } - - public void testTopLocationsY() { - assertPositionEquals(VIEW_POSITION_Y, GeneralLocation.TOP_LEFT, AXIS_Y); - assertPositionEquals(VIEW_POSITION_Y, GeneralLocation.TOP_CENTER, AXIS_Y); - assertPositionEquals(VIEW_POSITION_Y, GeneralLocation.TOP_RIGHT, AXIS_Y); - } - - public void testBottomLocationsY() { - assertPositionEquals(VIEW_POSITION_Y + VIEW_HEIGHT, GeneralLocation.BOTTOM_LEFT, AXIS_Y); - assertPositionEquals(VIEW_POSITION_Y + VIEW_HEIGHT, GeneralLocation.BOTTOM_CENTER, AXIS_Y); - assertPositionEquals(VIEW_POSITION_Y + VIEW_HEIGHT, GeneralLocation.BOTTOM_RIGHT, AXIS_Y); - } - - public void testCenterLocationsX() { - assertPositionEquals(VIEW_POSITION_X + VIEW_WIDTH / 2, GeneralLocation.CENTER, AXIS_X); - assertPositionEquals(VIEW_POSITION_X + VIEW_WIDTH / 2, GeneralLocation.TOP_CENTER, AXIS_X); - assertPositionEquals(VIEW_POSITION_X + VIEW_WIDTH / 2, GeneralLocation.BOTTOM_CENTER, AXIS_X); - } - - public void testCenterLocationsY() { - assertPositionEquals(VIEW_POSITION_Y + VIEW_HEIGHT / 2, GeneralLocation.CENTER, AXIS_Y); - assertPositionEquals(VIEW_POSITION_Y + VIEW_HEIGHT / 2, GeneralLocation.CENTER_LEFT, AXIS_Y); - assertPositionEquals(VIEW_POSITION_Y + VIEW_HEIGHT / 2, GeneralLocation.CENTER_RIGHT, AXIS_Y); - } - - private void assertPositionEquals(int expected, GeneralLocation location, int axis) { - assertEquals(expected, location.calculateCoordinates(mockView)[axis], 0.1f); - } - -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/KeyEventActionIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/KeyEventActionIntegrationTest.java deleted file mode 100644 index c75c3fb..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/KeyEventActionIntegrationTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.pressBack; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isRoot; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withParent; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasValue; -import static org.hamcrest.Matchers.instanceOf; - -import com.google.android.apps.common.testing.testrunner.annotations.SdkSuppress; -import com.google.android.apps.common.testing.ui.espresso.NoActivityResumedException; -import com.google.android.apps.common.testing.ui.testapp.MainActivity; -import com.google.android.apps.common.testing.ui.testapp.R; - -import android.content.Intent; -import android.test.ActivityInstrumentationTestCase2; -import android.test.FlakyTest; -import android.test.suitebuilder.annotation.LargeTest; -import android.view.KeyEvent; -import android.widget.TextView; - -import java.util.Map; - - -/** - * Integration tests for {@link KeyEventAction}. - */ -@LargeTest -public class KeyEventActionIntegrationTest extends ActivityInstrumentationTestCase2<MainActivity> { - @SuppressWarnings("deprecation") - public KeyEventActionIntegrationTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", MainActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - } - - public void testClickBackOnRootAction() { - getActivity(); - try { - pressBack(); - fail("Should have thrown NoActivityResumedException"); - } catch (NoActivityResumedException expected) { - } - } - - @SuppressWarnings("unchecked") - public void testClickBackOnNonRootActivityLatte() { - getActivity(); - onData(allOf(instanceOf(Map.class), hasValue("SendActivity"))).perform(click()); - pressBack(); - - // Make sure we are back. - onData(allOf(instanceOf(Map.class), hasValue("SendActivity"))).check(matches(isDisplayed())); - } - - @SuppressWarnings("unchecked") - public void testClickBackOnNonRootActionNoLatte() { - getActivity(); - onData(allOf(instanceOf(Map.class), hasValue("SendActivity"))).perform(click()); - onView(isRoot()).perform(ViewActions.pressBack()); - - // Make sure we are back. - onData(allOf(instanceOf(Map.class), hasValue("SendActivity"))).check(matches(isDisplayed())); - } - - @SuppressWarnings("unchecked") - @SdkSuppress(versions = {7, 8, 10}, bugId = -1) // uses native fragments. - @FlakyTest - public void testClickOnBackFromFragment() { - Intent fragmentStack = new Intent().setClassName(getInstrumentation().getTargetContext(), - "com.google.android.apps.common.testing.ui.testapp.FragmentStack"); - fragmentStack.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getInstrumentation().startActivitySync(fragmentStack); - onView(allOf(withParent(withId(R.id.simple_fragment)), isAssignableFrom(TextView.class))) - .check(matches(withText(containsString("#1")))); - try { - pressBack(); - fail("Should have thrown NoActivityResumedException"); - } catch (NoActivityResumedException expected) { - } - getInstrumentation().startActivitySync(fragmentStack); - - onView(withId(R.id.new_fragment)).perform(click()).perform(click()).perform(click()); - - onView(allOf(withParent(withId(R.id.simple_fragment)), isAssignableFrom(TextView.class))) - .check(matches(withText(containsString("#4")))); - - pressBack(); - - onView(allOf(withParent(withId(R.id.simple_fragment)), isAssignableFrom(TextView.class))) - .check(matches(withText(containsString("#3")))); - - pressBack(); - - onView(allOf(withParent(withId(R.id.simple_fragment)), isAssignableFrom(TextView.class))) - .check(matches(withText(containsString("#2")))); - - pressBack(); - - onView(allOf(withParent(withId(R.id.simple_fragment)), isAssignableFrom(TextView.class))) - .check(matches(withText(containsString("#1")))); - - try { - pressBack(); - fail("Should have thrown NoActivityResumedException"); - } catch (NoActivityResumedException expected) { - } - } - - @SuppressWarnings("unchecked") - public void testPressKeyWithKeyCode() { - getActivity(); - onData(allOf(instanceOf(Map.class), hasValue("SendActivity"))).perform(click()); - onView(withId(R.id.enter_data_edit_text)).perform(click()); - onView(withId(R.id.enter_data_edit_text)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_X)); - onView(withId(R.id.enter_data_edit_text)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_Y)); - onView(withId(R.id.enter_data_edit_text)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_Z)); - onView(withId(R.id.enter_data_edit_text)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_ENTER)); - onView(allOf(withId(R.id.enter_data_response_text), withText("xyz"))) - .check(matches(isDisplayed())); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/ScrollToActionIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/ScrollToActionIntegrationTest.java deleted file mode 100644 index 60ca48b..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/ScrollToActionIntegrationTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.scrollTo; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; - -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.ScrollActivity; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Tests for ScrollToAction. - */ -@LargeTest -public class ScrollToActionIntegrationTest extends ActivityInstrumentationTestCase2<ScrollActivity> -{ - @SuppressWarnings("deprecation") - public ScrollToActionIntegrationTest() { - // Keep froyo happy. - super("com.google.android.apps.common.testing.ui.testapp", ScrollActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testScrollDown() { - onView(withId(is(R.id.bottom_left))) - .check(matches(not(isDisplayed()))) - .perform(scrollTo()) - .check(matches(isDisplayed())) - .perform(scrollTo()); // Should be a noop. - } - - public void testScrollVerticalAndHorizontal() { - onView(withId(is(R.id.bottom_right))) - .check(matches(not(isDisplayed()))) - .perform(scrollTo()) - .check(matches(isDisplayed())); - onView(withId(is(R.id.top_left))) - .check(matches(not(isDisplayed()))) - .perform(scrollTo()) - .check(matches(isDisplayed())); - } - - public void testScrollWithinScroll() { - onView(withId(is(R.id.double_scroll))) - .check(matches(not(isDisplayed()))) - .perform(scrollTo()) - .check(matches(isDisplayed())); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/SwipeActionIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/SwipeActionIntegrationTest.java deleted file mode 100644 index 90257bc..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/SwipeActionIntegrationTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.swipeLeft; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.swipeRight; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasDescendant; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; - -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SwipeActivity; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Integration tests for swiping actions. - */ -@LargeTest -public class SwipeActionIntegrationTest extends ActivityInstrumentationTestCase2<SwipeActivity> { - - @SuppressWarnings("deprecation") - public SwipeActionIntegrationTest() { - // Keep froyo happy. - super("com.google.android.apps.common.testing.ui.testapp", SwipeActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - /** Tests that a small view can be swiped in both directions. */ - public void testSwipeOverSmallView() { - onView(withId(R.id.small_pager)) - .check(matches(hasDescendant(withText("Position #0")))) - .perform(swipeLeft()) - .check(matches(hasDescendant(withText("Position #1")))) - .perform(swipeLeft()) - .check(matches(hasDescendant(withText("Position #2")))) - .perform(swipeRight()) - .check(matches(hasDescendant(withText("Position #1")))) - .perform(swipeRight()) - .check(matches(hasDescendant(withText("Position #0")))); - } - - /** Tests that trying to swipe beyond the start of a view pager has no effect. */ - public void testSwipingRightHasNoEffectWhenAtStart() { - onView(withId(R.id.small_pager)) - .check(matches(hasDescendant(withText("Position #0")))) - .perform(swipeRight()) - .check(matches(hasDescendant(withText("Position #0")))) - .perform(swipeRight()) - .check(matches(hasDescendant(withText("Position #0")))); - } - - /** Tests that trying to swipe beyond the end of a view pager has no effect. */ - public void testSwipingLeftHasNoEffectWhenAtEnd() { - onView(withId(R.id.small_pager)) - .perform(swipeLeft()) - .perform(swipeLeft()) - .check(matches(hasDescendant(withText("Position #2")))) - .perform(swipeLeft()) - .check(matches(hasDescendant(withText("Position #2")))) - .perform(swipeLeft()) - .check(matches(hasDescendant(withText("Position #2")))); - } - - /** Tests that swiping across a partially overlapped view works correctly. */ - public void testSwipeOverPartiallyOverlappedView() { - onView(withId(R.id.overlapped_pager)) - .check(matches(hasDescendant(withText("Position #0")))) - .perform(swipeLeft()) - .check(matches(hasDescendant(withText("Position #1")))) - .perform(swipeRight()) - .check(matches(hasDescendant(withText("Position #0")))); - } - - /** Tests that trying to swipe a view that doesn't respond to swipes has no effect. */ - @SuppressWarnings("unchecked") - public void testSwipeOverUnswipableView() { - onView(withId(R.id.text_simple)) - .check(matches(allOf(isDisplayed(), withText(R.string.text_simple)))) - .perform(swipeLeft()) - .check(matches(allOf(isDisplayed(), withText(R.string.text_simple)))) - .perform(swipeRight()) - .check(matches(allOf(isDisplayed(), withText(R.string.text_simple)))); - } - -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextActionIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextActionIntegrationTest.java deleted file mode 100644 index b1130f1..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextActionIntegrationTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.pressImeActionButton; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.scrollTo; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeText; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeTextIntoFocusedView; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withParent; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * {@link TypeTextAction} integration tests. - */ -@LargeTest -public class TypeTextActionIntegrationTest extends ActivityInstrumentationTestCase2<SendActivity> { - @SuppressWarnings("deprecation") - public TypeTextActionIntegrationTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testTypeTextActionPerform() { - onView(withId(is(R.id.send_data_to_call_edit_text))).perform(typeText("Hello!")); - } - - @SuppressWarnings("unchecked") - public void testTypeTextActionPerformWithEnter() { - onView(withId(R.id.enter_data_edit_text)).perform(typeText("Hello World!\n")); - onView(allOf(withId(R.id.enter_data_response_text), withText("Hello World!"))) - .check(matches(isDisplayed())); - } - - public void testTypeTextInFocusedView() { - onView(withId(is(R.id.send_data_to_call_edit_text))).perform(typeText( - "Hello World How Are You Today? I have alot of text to type.")); - onView(withId(is(R.id.send_data_to_call_edit_text))).perform(typeTextIntoFocusedView( - "Jolly good!")); - onView(withId(is(R.id.send_data_to_call_edit_text))).check(matches(withText( - "Hello World How Are You Today? I have alot of text to type.Jolly good!"))); - } - - public void testTypeTextInFocusedView_constraintBreakage() { - onView(withId(is(R.id.send_data_to_call_edit_text))).perform(typeText( - "Hello World How Are You Today? I have alot of text to type.")); - try { - onView(withId(is(R.id.edit_text_message))) - .perform(scrollTo(), typeTextIntoFocusedView("Jolly good!")); - fail("Should not have been able to type into focused view."); - } catch (PerformException expected) { - } - } - - @SuppressWarnings("unchecked") - public void testTypeTextInDelegatedEditText() { - String toType = "honeybadger doesn't care"; - onView(allOf(withParent(withId(R.id.delegating_edit_text)), withId(R.id.delegate_edit_text))) - .perform(scrollTo(), typeText(toType), pressImeActionButton()); - onView(withId(R.id.edit_text_message)) - .perform(scrollTo()) - .check(matches(withText(containsString(toType)))); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextActionTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextActionTest.java deleted file mode 100644 index acddc06..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextActionTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; - -import android.view.MotionEvent; -import android.view.View; - -import junit.framework.TestCase; - -import org.mockito.Mock; - -/** - * Unit tests for {@link TypeTextAction}. - */ -public class TypeTextActionTest extends TestCase { - @Mock - private UiController mockUiController; - - @Mock - private View mockView; - - private TypeTextAction typeTextAction; - - @Override - public void setUp() throws Exception { - super.setUp(); - initMocks(this); - } - - public void testTypeTextActionPerform() throws InjectEventSecurityException { - String stringToBeTyped = "Hello!"; - typeTextAction = new TypeTextAction(stringToBeTyped); - when(mockUiController.injectMotionEvent(isA(MotionEvent.class))).thenReturn(true); - when(mockUiController.injectString(stringToBeTyped)).thenReturn(true); - typeTextAction.perform(mockUiController, mockView); - } - - public void testTypeTextActionPerformFailed() throws InjectEventSecurityException { - String stringToBeTyped = "Hello!"; - typeTextAction = new TypeTextAction(stringToBeTyped); - when(mockUiController.injectMotionEvent(isA(MotionEvent.class))).thenReturn(true); - when(mockUiController.injectString(stringToBeTyped)).thenReturn(false); - - try { - typeTextAction.perform(mockUiController, mockView); - fail("Should have thrown PerformException"); - } catch (PerformException e) { - if (e.getCause() instanceof InjectEventSecurityException) { - fail("Exception cause should NOT be of type InjectEventSecurityException"); - } - } - } - - public void testTypeTextActionPerformInjectEventSecurityException() - throws InjectEventSecurityException { - String stringToBeTyped = "Hello!"; - typeTextAction = new TypeTextAction(stringToBeTyped); - when(mockUiController.injectMotionEvent(isA(MotionEvent.class))).thenReturn(true); - when(mockUiController.injectString(stringToBeTyped)) - .thenThrow(new InjectEventSecurityException("")); - - try { - typeTextAction.perform(mockUiController, mockView); - fail("Should have thrown PerformException"); - } catch (PerformException e) { - if (!(e.getCause() instanceof InjectEventSecurityException)) { - fail("Exception cause should be of type InjectEventSecurityException"); - } - } - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/WindowOrderingIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/WindowOrderingIntegrationTest.java deleted file mode 100644 index d50e409..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/action/WindowOrderingIntegrationTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.scrollTo; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.doesNotExist; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; - -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.os.Build; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Ensures view root ordering works properly. - */ -@LargeTest -public class WindowOrderingIntegrationTest extends ActivityInstrumentationTestCase2<SendActivity> { - @SuppressWarnings("deprecation") - public WindowOrderingIntegrationTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testPopupMenu() { - if (Build.VERSION.SDK_INT < 11) { - // popup menus are post honeycomb. - return; - } - onView(withText(R.string.item_1_text)) - .check(doesNotExist()); - onView(withId(R.id.make_popup_menu_button)) - .perform(scrollTo(), click()); - onView(withText(R.string.item_1_text)) - .check(matches(isDisplayed())) - .perform(click()); - onView(withText(R.string.item_1_text)) - .check(doesNotExist()); - } - - public void testPopupWindow() { - getActivity(); - onView(withId(R.id.popup_title)) - .check(doesNotExist()); - onView(withId(R.id.make_popup_view_button)) - .perform(scrollTo(), click()); - onView(withId(R.id.popup_title)) - .check(matches(withText(R.string.popup_title))) - .perform(click()); - onView(withId(R.id.popup_title)) - .check(doesNotExist()); - } - - public void testDialog() { - onView(withText(R.string.dialog_title)) - .check(doesNotExist()); - onView(withId(R.id.make_alert_dialog)) - .perform(scrollTo(), click()); - onView(withText(R.string.dialog_title)) - .check(matches(isDisplayed())); - - onView(withText("Fine")) - .perform(click()); - - onView(withText(R.string.dialog_title)) - .check(doesNotExist()); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/assertion/ViewAssertionsTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/assertion/ViewAssertionsTest.java deleted file mode 100644 index b49a822..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/assertion/ViewAssertionsTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.assertion; - -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.selectedDescendantsMatch; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasContentDescription; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; - -import com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException; - -import android.test.InstrumentationTestCase; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; -import android.widget.ScrollView; -import android.widget.TextView; - -import junit.framework.AssertionFailedError; - -import org.hamcrest.Matcher; - -/** - * Unit tests for {@link ViewAssertions}. - */ -public class ViewAssertionsTest extends InstrumentationTestCase { - - private View presentView; - private View absentView; - private NoMatchingViewException absentException; - private NoMatchingViewException presentException; - private Matcher<View> alwaysAccepts; - private Matcher<View> alwaysFails; - private Matcher<View> nullViewMatcher; - - @Override - public void setUp() throws Exception { - super.setUp(); - presentView = new View(getInstrumentation().getTargetContext()); - absentView = null; - absentException = null; - alwaysAccepts = is(presentView); - alwaysFails = not(is(presentView)); - nullViewMatcher = nullValue(); - - presentException = new NoMatchingViewException.Builder() - .withViewMatcher(alwaysFails) - .withRootView(new View(getInstrumentation().getTargetContext())) - .build(); - } - - public void testViewPresent_MatcherFail() { - try { - matches(alwaysFails).check(presentView, absentException); - } catch (AssertionFailedError expected) { - return; - } - // cannot place inside try block, would be caught. - fail("Should not accept."); - } - - public void testViewPresent_MatcherPass() { - try { - matches(alwaysAccepts).check(presentView, absentException); - } catch (AssertionError error) { - throw new RuntimeException("Should not die!!!", error); - } - } - - public void testViewAbsent_Unexpectedly() { - try { - matches(alwaysAccepts).check(absentView, presentException); - } catch (NoMatchingViewException expected) { - return; - } - - fail("should not accept, view not present."); - } - - public void testViewAbsent_AndThatsWhatIWant() { - try { - matches(nullViewMatcher).check(absentView, presentException); - } catch (NoMatchingViewException expected) { - return; - } - - fail("should not accept, view not present."); - } - - public void testSelectedDescendantsMatch_ThereAreNone() { - View grany = setUpViewHierarchy(); - - try { - selectedDescendantsMatch(withText("welfjkw"), hasContentDescription()) - .check(grany, absentException); - } catch (AssertionError error) { - throw new RuntimeException("Should not die!!!", error); - } - } - - public void testSelectedDescendantsMatch_SelectedDescendantsMatch() { - View grany = setUpViewHierarchy(); - - try { - selectedDescendantsMatch(withText("has content description"), hasContentDescription()) - .check(grany, absentException); - } catch (AssertionError error) { - throw new RuntimeException("Should not die!!!", error); - } - } - - public void testSelectedDescendantsMatch_SelectedDescendantsDoNotMatch() { - View grany = setUpViewHierarchy(); - - try { - selectedDescendantsMatch(withText("no content description"), hasContentDescription()) - .check(grany, absentException); - } catch (AssertionFailedError expected) { - return; - } - - fail("should fail because descendants do not match."); - } - - public void testSelectedDescendantsMatch_SelectedDescendantsMatchAndDoNotMatch() { - View grany = setUpViewHierarchy(); - - try { - selectedDescendantsMatch(isAssignableFrom(TextView.class), hasContentDescription()) - .check(grany, absentException); - } catch (AssertionFailedError expected) { - return; - } - - fail("should fail because not all descendants match."); - } - - private View setUpViewHierarchy() { - TextView v1 = new TextView(getInstrumentation().getTargetContext()); - v1.setText("no content description"); - TextView v2 = new TextView(getInstrumentation().getTargetContext()); - v2.setText("has content description"); - v2.setContentDescription("content description"); - ViewGroup parent = new RelativeLayout(getInstrumentation().getTargetContext()); - View grany = new ScrollView(getInstrumentation().getTargetContext()); - ((ViewGroup) grany).addView(parent); - parent.addView(v1); - parent.addView(v2); - - return grany; - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/AsyncTaskPoolMonitorTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/AsyncTaskPoolMonitorTest.java deleted file mode 100644 index f400cf0..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/AsyncTaskPoolMonitorTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import junit.framework.TestCase; - -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.FutureTask; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Unit test for {@link AsyncTaskPoolMonitor} - */ -public class AsyncTaskPoolMonitorTest extends TestCase { - - private final ThreadPoolExecutor testThreadPool = new ThreadPoolExecutor( - 4, 4, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); - - private AsyncTaskPoolMonitor monitor = new AsyncTaskPoolMonitor(testThreadPool); - - @Override - public void tearDown() throws Exception { - testThreadPool.shutdownNow(); - super.tearDown(); - } - - public void testIsIdle_onEmptyPool() throws Exception { - assertTrue(monitor.isIdleNow()); - final AtomicBoolean isIdle = new AtomicBoolean(false); - // since we're already idle, this should be ran immedately on our thread. - monitor.notifyWhenIdle(new Runnable() { - @Override - public void run() { - isIdle.set(true); - } - }); - assertTrue(isIdle.get()); - } - - public void testIsIdle_withRunningTask() throws Exception { - final CountDownLatch runLatch = new CountDownLatch(1); - testThreadPool.submit(new Runnable() { - @Override - public void run() { - runLatch.countDown(); - try { - Thread.sleep(50000); - } catch (InterruptedException ie) { - throw new RuntimeException(ie); - } - } - }); - assertTrue(runLatch.await(1, TimeUnit.SECONDS)); - assertFalse(monitor.isIdleNow()); - - final AtomicBoolean isIdle = new AtomicBoolean(false); - monitor.notifyWhenIdle(new Runnable() { - @Override - public void run() { - isIdle.set(true); - } - }); - // runnable shouldn't be run ever.. - assertFalse(isIdle.get()); - } - - - public void testIdleNotificationAndRestart() throws Exception { - - FutureTask<Thread> workerThreadFetchTask = new FutureTask<Thread>(new Callable<Thread>() { - @Override - public Thread call() { - return Thread.currentThread(); - } - }); - testThreadPool.submit(workerThreadFetchTask); - - Thread workerThread = workerThreadFetchTask.get(); - - final CountDownLatch runLatch = new CountDownLatch(1); - final CountDownLatch exitLatch = new CountDownLatch(1); - - testThreadPool.submit(new Runnable() { - @Override - public void run() { - runLatch.countDown(); - try { - exitLatch.await(); - } catch (InterruptedException ie) { - throw new RuntimeException(ie); - } - } - }); - - assertTrue(runLatch.await(1, TimeUnit.SECONDS)); - final CountDownLatch notificationLatch = new CountDownLatch(1); - monitor.notifyWhenIdle(new Runnable() { - @Override - public void run() { - notificationLatch.countDown(); - } - }); - // give some time for the idle detection threads to spin up. - Thread.sleep(2000); - // interrupt one of them - workerThread.interrupt(); - Thread.sleep(1000); - // unblock the dummy work item. - exitLatch.countDown(); - assertTrue(notificationLatch.await(1, TimeUnit.SECONDS)); - assertTrue(monitor.isIdleNow()); - } - - public void testIdleNotification_extraWork() throws Exception { - final CountDownLatch firstRunLatch = new CountDownLatch(1); - final CountDownLatch firstExitLatch = new CountDownLatch(1); - - testThreadPool.submit(new Runnable() { - @Override - public void run() { - firstRunLatch.countDown(); - try { - firstExitLatch.await(); - } catch (InterruptedException ie) { - throw new RuntimeException(ie); - } - } - }); - - assertTrue(firstRunLatch.await(1, TimeUnit.SECONDS)); - - final CountDownLatch notificationLatch = new CountDownLatch(1); - monitor.notifyWhenIdle(new Runnable() { - @Override - public void run() { - notificationLatch.countDown(); - } - }); - - final CountDownLatch secondRunLatch = new CountDownLatch(1); - final CountDownLatch secondExitLatch = new CountDownLatch(1); - testThreadPool.submit(new Runnable() { - @Override - public void run() { - secondRunLatch.countDown(); - try { - secondExitLatch.await(); - } catch (InterruptedException ie) { - throw new RuntimeException(ie); - } - } - }); - - assertFalse(notificationLatch.await(10, TimeUnit.MILLISECONDS)); - firstExitLatch.countDown(); - assertFalse(notificationLatch.await(500, TimeUnit.MILLISECONDS)); - secondExitLatch.countDown(); - assertTrue(notificationLatch.await(1, TimeUnit.SECONDS)); - assertTrue(monitor.isIdleNow()); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/DefaultFailureHandlerTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/DefaultFailureHandlerTest.java deleted file mode 100644 index b84584c..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/DefaultFailureHandlerTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isRoot; -import static com.google.common.base.Throwables.getStackTraceAsString; -import static org.hamcrest.Matchers.not; - -import com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException; -import com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException; -import com.google.android.apps.common.testing.ui.espresso.ViewAssertion; -import com.google.android.apps.common.testing.ui.testapp.MainActivity; - -import android.test.ActivityInstrumentationTestCase2; -import android.view.View; - -import junit.framework.AssertionFailedError; - -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.hamcrest.Matcher; - -/** - * Tests Espresso's default failure handling. - */ -public class DefaultFailureHandlerTest extends ActivityInstrumentationTestCase2<MainActivity> { - - @SuppressWarnings("deprecation") - public DefaultFailureHandlerTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", MainActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testMismatchInCheck() { - try { - onView(isRoot()).check(matches(not(isDisplayed()))); - fail("Previous call expected to fail"); - } catch (AssertionFailedError e) { - assertFailureStackContainsThisClass(e); - } - } - - public void testCustomAssertionError() { - try { - onView(isRoot()).check(new ViewAssertion() { - @Override - public void check(View view, NoMatchingViewException noViewFoundException) { - assertFalse(true); - } - }); - fail("Previous call expected to fail"); - } catch (AssertionFailedError e) { - assertFailureStackContainsThisClass(e); - } - } - - public void testNoMatchingViewException() { - try { - onView(withMatchesThatReturns(false)).check(matches(not(isDisplayed()))); - fail("Previous call expected to fail"); - } catch (NoMatchingViewException e) { - assertFailureStackContainsThisClass(e); - } - } - - public void testAmbiguousViewMatcherException() { - try { - onView(withMatchesThatReturns(true)).check(matches(isDisplayed())); - } catch (RuntimeException e) { - assertTrue(e instanceof AmbiguousViewMatcherException); - assertFailureStackContainsThisClass(e); - } - } - - private void assertFailureStackContainsThisClass(Throwable e) { - assertTrue(getStackTraceAsString(e).contains(getClass().getSimpleName().toString())); - } - - private static Matcher<View> withMatchesThatReturns(final boolean returnValue) { - return new BaseMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("matches=" + returnValue); - } - - @Override - public boolean matches(Object item) { - return returnValue; - } - }; - } - -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjectorTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjectorTest.java deleted file mode 100644 index bbc367a..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjectorTest.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleCallback; -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry; -import com.google.android.apps.common.testing.testrunner.Stage; -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.app.Activity; -import android.os.Build; -import android.os.SystemClock; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Tests for {@link EventInjector}. - */ -public class EventInjectorTest extends ActivityInstrumentationTestCase2<SendActivity> { - private static final String TAG = EventInjectorTest.class.getSimpleName(); - private Activity sendActivity; - private EventInjector injector; - final AtomicBoolean injectEventWorked = new AtomicBoolean(false); - final AtomicBoolean injectEventThrewSecurityException = new AtomicBoolean(false); - final CountDownLatch latch = new CountDownLatch(1); - - @SuppressWarnings("deprecation") - public EventInjectorTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - if (Build.VERSION.SDK_INT > 15) { - InputManagerEventInjectionStrategy strat = new InputManagerEventInjectionStrategy(); - strat.initialize(); - injector = new EventInjector(strat); - } else { - WindowManagerEventInjectionStrategy strat = new WindowManagerEventInjectionStrategy(); - strat.initialize(); - injector = new EventInjector(strat); - } - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - } - - @LargeTest - public void testInjectKeyEventUpWithNoDown() throws Exception { - sendActivity = getActivity(); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - View view = sendActivity.findViewById(R.id.send_data_edit_text); - assertTrue(view.requestFocus()); - latch.countDown(); - } - }); - - assertTrue("Timed out!", latch.await(10, TimeUnit.SECONDS)); - KeyCharacterMap keyCharacterMap = UiControllerImpl.getKeyCharacterMap(); - KeyEvent[] events = keyCharacterMap.getEvents("a".toCharArray()); - assertTrue(injector.injectKeyEvent(events[1])); - } - - @LargeTest - public void testInjectStaleKeyEvent() throws Exception { - sendActivity = getActivity(); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - View view = sendActivity.findViewById(R.id.send_data_edit_text); - assertTrue(view.requestFocus()); - latch.countDown(); - } - }); - - assertTrue("Timed out!", latch.await(10, TimeUnit.SECONDS)); - assertFalse("SecurityException exception was thrown.", injectEventThrewSecurityException.get()); - - KeyCharacterMap keyCharacterMap = UiControllerImpl.getKeyCharacterMap(); - KeyEvent[] events = keyCharacterMap.getEvents("a".toCharArray()); - KeyEvent event = KeyEvent.changeTimeRepeat(events[0], 1, 0); - - // Stale event does not fail for API < 13. - if (Build.VERSION.SDK_INT < 13) { - assertTrue(injector.injectKeyEvent(event)); - } else { - assertFalse(injector.injectKeyEvent(event)); - } - } - - @LargeTest - public void testInjectKeyEvent_securityException() { - KeyCharacterMap keyCharacterMap = UiControllerImpl.getKeyCharacterMap(); - KeyEvent[] events = keyCharacterMap.getEvents("a".toCharArray()); - try { - injector.injectKeyEvent(events[0]); - fail("Should have thrown a security exception!"); - } catch (InjectEventSecurityException expected) { } - } - - @LargeTest - public void testInjectMotionEvent_securityException() throws Exception { - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - MotionEvent down = MotionEvent.obtain(SystemClock.uptimeMillis(), - SystemClock.uptimeMillis(), - MotionEvent.ACTION_DOWN, - 0, - 0, - 0); - try { - injector.injectMotionEvent(down); - } catch (InjectEventSecurityException expected) { - injectEventThrewSecurityException.set(true); - } - latch.countDown(); - } - }); - - latch.await(10, TimeUnit.SECONDS); - assertTrue(injectEventThrewSecurityException.get()); - } - - @LargeTest - public void testInjectMotionEvent_upEventFailure() throws InterruptedException { - final CountDownLatch activityStarted = new CountDownLatch(1); - ActivityLifecycleCallback callback = new ActivityLifecycleCallback() { - @Override - public void onActivityLifecycleChanged(Activity activity, Stage stage) { - if (Stage.RESUMED == stage && activity instanceof SendActivity) { - activityStarted.countDown(); - } - } - }; - ActivityLifecycleMonitorRegistry - .getInstance() - .addLifecycleCallback(callback); - try { - getActivity(); - assertTrue(activityStarted.await(20, TimeUnit.SECONDS)); - final int[] xy = UiControllerImplIntegrationTest.getCoordinatesInMiddleOfSendButton( - getActivity(), getInstrumentation()); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - MotionEvent up = MotionEvent.obtain(SystemClock.uptimeMillis(), - SystemClock.uptimeMillis(), - MotionEvent.ACTION_UP, - xy[0], - xy[1], - 0); - - try { - injectEventWorked.set(injector.injectMotionEvent(up)); - } catch (InjectEventSecurityException e) { - Log.e(TAG, "injectEvent threw a SecurityException"); - } - up.recycle(); - latch.countDown(); - } - }); - - latch.await(10, TimeUnit.SECONDS); - assertFalse(injectEventWorked.get()); - } finally { - ActivityLifecycleMonitorRegistry - .getInstance() - .removeLifecycleCallback(callback); - } - - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceIntegrationTest.java deleted file mode 100644 index 98633f7..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceIntegrationTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.pressBack; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.registerIdlingResources; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.equalToIgnoringCase; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.IdlingResource; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Integration test with IdlingResources. - */ -@LargeTest -public class IdlingResourceIntegrationTest extends ActivityInstrumentationTestCase2<SendActivity> { - - private ResettingIdlingResource r1; - private ResettingIdlingResource r2; - - @SuppressWarnings("deprecation") - public IdlingResourceIntegrationTest() { - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - r1 = new ResettingIdlingResource("SlowResource", 6000); - r2 = new ResettingIdlingResource("FastResource", 500); - registerIdlingResources(r1, r2); - getActivity(); - } - - public void testClickWithCustomIdlingResources() { - onView(withText(equalToIgnoringCase("send"))).perform(click()); - r1.reset(); - r2.reset(); - onView(withText(is("Data from sender"))).check(matches(isDisplayed())); - r1.reset(); - r2.reset(); - pressBack(); - r1.reset(); - r2.reset(); - onView(withText(equalToIgnoringCase("send"))).perform(click()); - r1.reset(); - r2.reset(); - pressBack(); - r1.reset(); - r2.reset(); - onView(withText(equalToIgnoringCase("send"))).perform(click()); - } - - private class ResettingIdlingResource implements IdlingResource { - private final String name; - private final long delay; - private final AtomicBoolean isIdle = new AtomicBoolean(false); - private final ScheduledExecutorService pool; - - private ResourceCallback callback; - - public ResettingIdlingResource(String name, long delay) { - this.name = name; - this.delay = delay; - this.pool = Executors.newScheduledThreadPool(1); - } - - @Override - public void registerIdleTransitionCallback(final ResourceCallback callback) { - this.callback = callback; - scheduleDelayedCallback(); - } - - private void scheduleDelayedCallback() { - pool.schedule(new Runnable() { - @Override - public void run() { - callback.onTransitionToIdle(); - isIdle.set(true); - } - }, delay, TimeUnit.MILLISECONDS); - } - - @Override - public boolean isIdleNow() { - return isIdle.get(); - } - - @Override - public String getName() { - return name; - } - - public void reset() { - isIdle.set(false); - scheduleDelayedCallback(); - } - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistryTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistryTest.java deleted file mode 100644 index aee49a8..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistryTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.android.apps.common.testing.ui.espresso.IdlingResource; -import com.google.android.apps.common.testing.ui.espresso.base.IdlingResourceRegistry.IdleNotificationCallback; - -import android.os.Handler; -import android.os.Looper; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Unit tests for {@link IdlingResourceRegistry}. - */ -public class IdlingResourceRegistryTest extends InstrumentationTestCase { - - private IdlingResourceRegistry registry; - private Handler handler; - - @Override - public void setUp() throws Exception { - Looper looper = Looper.getMainLooper(); - handler = new Handler(looper); - registry = new IdlingResourceRegistry(looper); - } - - public void testRegisterDuplicates() { - IdlingResource r1 = new OnDemandIdlingResource("r1"); - IdlingResource r1dup = new OnDemandIdlingResource("r1"); - registry.register(r1); - registry.register(r1); - registry.register(r1dup); - } - - public void testAllResourcesAreIdle() throws InterruptedException { - OnDemandIdlingResource r1 = new OnDemandIdlingResource("r1"); - OnDemandIdlingResource r2 = new OnDemandIdlingResource("r2"); - IdlingResource r3 = new OnDemandIdlingResource("r3"); - r1.forceIdleNow(); - r2.forceIdleNow(); - registry.register(r1); - registry.register(r2); - final AtomicBoolean resourcesIdle = new AtomicBoolean(false); - final CountDownLatch latch = new CountDownLatch(1); - handler.post(new Runnable() { - @Override - public void run() { - resourcesIdle.set(registry.allResourcesAreIdle()); - latch.countDown(); - } - }); - latch.await(); - assertTrue(resourcesIdle.get()); - - final CountDownLatch latch2 = new CountDownLatch(1); - registry.register(r3); - handler.post(new Runnable() { - @Override - public void run() { - resourcesIdle.set(registry.allResourcesAreIdle()); - latch2.countDown(); - } - }); - latch2.await(); - assertFalse(resourcesIdle.get()); - } - - @LargeTest - public void testAllResourcesAreIdle_RepeatingToIdleTransitions() throws InterruptedException { - OnDemandIdlingResource r1 = new OnDemandIdlingResource("r1"); - registry.register(r1); - final AtomicBoolean resourcesIdle = new AtomicBoolean(false); - for (int i = 1; i <= 3; i++) { - final CountDownLatch latch = new CountDownLatch(1); - handler.post(new Runnable() { - @Override - public void run() { - resourcesIdle.set(registry.allResourcesAreIdle()); - latch.countDown(); - } - }); - latch.await(); - assertFalse("Busy test " + i, resourcesIdle.get()); - - r1.forceIdleNow(); - final CountDownLatch latch2 = new CountDownLatch(1); - handler.post(new Runnable() { - @Override - public void run() { - resourcesIdle.set(registry.allResourcesAreIdle()); - latch2.countDown(); - } - }); - latch2.await(); - assertTrue("Idle transition test " + i, resourcesIdle.get()); - - r1.reset(); - } - } - - @LargeTest - public void testNotifyWhenAllResourcesAreIdle_success() throws InterruptedException { - final CountDownLatch busyWarningLatch = new CountDownLatch(4); - final CountDownLatch timeoutLatch = new CountDownLatch(1); - final CountDownLatch allResourcesIdleLatch = new CountDownLatch(1); - final AtomicReference<List<String>> busysFromWarning = new AtomicReference<List<String>>(); - - OnDemandIdlingResource r1 = new OnDemandIdlingResource("r1"); - OnDemandIdlingResource r2 = new OnDemandIdlingResource("r2"); - OnDemandIdlingResource r3 = new OnDemandIdlingResource("r3"); - registry.register(r1); - registry.register(r2); - registry.register(r3); - - handler.post(new Runnable() { - - @Override - public void run() { - registry.notifyWhenAllResourcesAreIdle(new IdleNotificationCallback() { - private static final String TAG = "IdleNotificationCallback"; - @Override - public void resourcesStillBusyWarning(List<String> busyResourceNames) { - Log.w(TAG, "Timeout warning: " + busyResourceNames); - busysFromWarning.set(busyResourceNames); - busyWarningLatch.countDown(); - } - - @Override - public void resourcesHaveTimedOut(List<String> busyResourceNames) { - Log.w(TAG, "Timeout error: " + busyResourceNames); - timeoutLatch.countDown(); - } - - @Override - public void allResourcesIdle() { - allResourcesIdleLatch.countDown(); - } - }); - } - }); - - assertFalse("Expected to timeout", busyWarningLatch.await(6, TimeUnit.SECONDS)); - assertEquals(3, busysFromWarning.get().size()); - - r3.forceIdleNow(); - assertFalse("Expected to timeout", busyWarningLatch.await(6, TimeUnit.SECONDS)); - assertEquals(2, busysFromWarning.get().size()); - - r2.forceIdleNow(); - assertFalse("Expected to timeout", busyWarningLatch.await(6, TimeUnit.SECONDS)); - assertEquals(1, busysFromWarning.get().size()); - - r1.forceIdleNow(); - assertTrue(allResourcesIdleLatch.await(200, TimeUnit.MILLISECONDS)); - assertEquals(1, busyWarningLatch.getCount()); - assertEquals(1, timeoutLatch.getCount()); - } - - @LargeTest - public void testNotifyWhenAllResourcesAreIdle_timeout() throws InterruptedException { - final CountDownLatch busyWarningLatch = new CountDownLatch(5); - final CountDownLatch timeoutLatch = new CountDownLatch(1); - final CountDownLatch allResourcesIdleLatch = new CountDownLatch(1); - final AtomicReference<List<String>> busysFromWarning = new AtomicReference<List<String>>(); - - OnDemandIdlingResource r1 = new OnDemandIdlingResource("r1"); - OnDemandIdlingResource r2 = new OnDemandIdlingResource("r2"); - OnDemandIdlingResource r3 = new OnDemandIdlingResource("r3"); - registry.register(r1); - registry.register(r2); - registry.register(r3); - - handler.post(new Runnable() { - @Override - public void run() { - registry.notifyWhenAllResourcesAreIdle(new IdleNotificationCallback() { - private static final String TAG = "IdleNotificationCallback"; - @Override - public void resourcesStillBusyWarning(List<String> busyResourceNames) { - Log.w(TAG, "Timeout warning: " + busyResourceNames); - busysFromWarning.set(busyResourceNames); - busyWarningLatch.countDown(); - } - - @Override - public void resourcesHaveTimedOut(List<String> busyResourceNames) { - Log.w(TAG, "Timeout error: " + busyResourceNames); - timeoutLatch.countDown(); - } - - @Override - public void allResourcesIdle() { - allResourcesIdleLatch.countDown(); - } - }); - } - }); - - assertFalse("Expected to timeout", busyWarningLatch.await(6, TimeUnit.SECONDS)); - assertEquals(3, busysFromWarning.get().size()); - - r1.forceIdleNow(); - assertFalse("Expected to timeout", busyWarningLatch.await(6, TimeUnit.SECONDS)); - assertEquals(2, busysFromWarning.get().size()); - - r2.forceIdleNow(); - assertFalse("Expected to timeout", busyWarningLatch.await(6, TimeUnit.SECONDS)); - assertEquals(1, busysFromWarning.get().size()); - - assertTrue("Expected to finish count down", busyWarningLatch.await(8, TimeUnit.SECONDS)); - assertTrue("Should have timed out", timeoutLatch.await(2, TimeUnit.SECONDS)); - assertEquals(1, busysFromWarning.get().size()); - assertEquals(1, allResourcesIdleLatch.getCount()); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/OnDemandIdlingResource.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/OnDemandIdlingResource.java deleted file mode 100644 index ac0a5a7..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/OnDemandIdlingResource.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.android.apps.common.testing.ui.espresso.IdlingResource; - -/** - * An {@link IdlingResource} for testing that becomes idle on demand. - */ -public class OnDemandIdlingResource implements IdlingResource { - private final String name; - - private boolean isIdle = false; - private ResourceCallback callback; - - public OnDemandIdlingResource(String name) { - this.name = name; - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback callback) { - this.callback = callback; - } - - @Override - public boolean isIdleNow() { - return isIdle; - } - - @Override - public String getName() { - return name; - } - - public void forceIdleNow() { - isIdle = true; - if (callback != null) { - callback.onTransitionToIdle(); - } - } - - public void reset() { - isIdle = false; - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImplIntegrationTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImplIntegrationTest.java deleted file mode 100644 index 02a3fda..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImplIntegrationTest.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.android.apps.common.testing.ui.testapp.R; -import com.google.android.apps.common.testing.ui.testapp.SendActivity; -import com.google.common.base.Optional; - -import android.app.Activity; -import android.app.Instrumentation; -import android.os.Build; -import android.os.Looper; -import android.os.SystemClock; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Test for {@link UiControllerImpl}. - */ -public class UiControllerImplIntegrationTest - extends ActivityInstrumentationTestCase2<SendActivity> { - private Activity sendActivity; - private final AtomicBoolean injectEventWorked = new AtomicBoolean(false); - private final AtomicBoolean injectEventThrewSecurityException = new AtomicBoolean(false); - private final CountDownLatch focusLatch = new CountDownLatch(1); - private final CountDownLatch latch = new CountDownLatch(1); - private UiController uiController; - - @SuppressWarnings("deprecation") - public UiControllerImplIntegrationTest() { - // Supporting froyo. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - EventInjector injector = null; - if (Build.VERSION.SDK_INT > 15) { - InputManagerEventInjectionStrategy strat = new InputManagerEventInjectionStrategy(); - strat.initialize(); - injector = new EventInjector(strat); - } else { - WindowManagerEventInjectionStrategy strat = new WindowManagerEventInjectionStrategy(); - strat.initialize(); - injector = new EventInjector(strat); - } - uiController = new UiControllerImpl( - injector, - new AsyncTaskPoolMonitor(new ThreadPoolExecutorExtractor( - Looper.getMainLooper()).getAsyncTaskThreadPool()), - Optional.<AsyncTaskPoolMonitor>absent(), - new IdlingResourceRegistry(Looper.getMainLooper()), - Looper.getMainLooper()); - } - - - @Override - public SendActivity getActivity() { - SendActivity a = super.getActivity(); - - while (!a.hasWindowFocus()) { - getInstrumentation().waitForIdleSync(); - } - - return a; - } - - @LargeTest - public void testInjectKeyEvent() throws InterruptedException { - sendActivity = getActivity(); - getInstrumentation().waitForIdleSync(); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - try { - KeyCharacterMap keyCharacterMap = UiControllerImpl.getKeyCharacterMap(); - KeyEvent[] events = keyCharacterMap.getEvents("a".toCharArray()); - injectEventWorked.set(uiController.injectKeyEvent(events[0])); - latch.countDown(); - } catch (InjectEventSecurityException e) { - injectEventThrewSecurityException.set(true); - } - } - }); - - assertFalse("injectEvent threw a SecurityException", injectEventThrewSecurityException.get()); - assertTrue("Timed out!", latch.await(10, TimeUnit.SECONDS)); - assertTrue(injectEventWorked.get()); - } - - @LargeTest - public void testInjectString() throws InterruptedException { - sendActivity = getActivity(); - getInstrumentation().waitForIdleSync(); - final AtomicBoolean requestFocusSucceded = new AtomicBoolean(false); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - final View view = sendActivity.findViewById(R.id.send_data_to_call_edit_text); - Log.i("TEST", HumanReadables.describe(view)); - requestFocusSucceded.set(view.requestFocus() && view.hasWindowFocus()); - Log.i("TEST-post", HumanReadables.describe(view)); - focusLatch.countDown(); - } - }); - - getInstrumentation().waitForIdleSync(); - assertTrue("requestFocus timed out!", focusLatch.await(2, TimeUnit.SECONDS)); - assertTrue("requestFocus failed.", requestFocusSucceded.get()); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - try { - injectEventWorked.set(uiController.injectString("Hello! \n&*$$$")); - latch.countDown(); - } catch (InjectEventSecurityException e) { - injectEventThrewSecurityException.set(true); - } - } - }); - - assertFalse("SecurityException exception was thrown.", injectEventThrewSecurityException.get()); - assertTrue("Timed out!", latch.await(20, TimeUnit.SECONDS)); - assertTrue(injectEventWorked.get()); - } - - @LargeTest - public void testInjectLargeString() throws InterruptedException { - sendActivity = getActivity(); - getInstrumentation().waitForIdleSync(); - final AtomicBoolean requestFocusSucceded = new AtomicBoolean(false); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - final View view = sendActivity.findViewById(R.id.send_data_to_call_edit_text); - Log.i("TEST", HumanReadables.describe(view)); - requestFocusSucceded.set(view.requestFocus()); - Log.i("TEST-post", HumanReadables.describe(view)); - - focusLatch.countDown(); - } - }); - - assertTrue("requestFocus timed out!", focusLatch.await(2, TimeUnit.SECONDS)); - assertTrue("requestFocus failed.", requestFocusSucceded.get()); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - try { - injectEventWorked.set(uiController.injectString("This is a string with 32 chars!!")); - latch.countDown(); - } catch (InjectEventSecurityException e) { - injectEventThrewSecurityException.set(true); - } - } - }); - - assertFalse("SecurityException exception was thrown.", injectEventThrewSecurityException.get()); - assertTrue("Timed out!", latch.await(20, TimeUnit.SECONDS)); - assertTrue(injectEventWorked.get()); - } - - @LargeTest - public void testInjectEmptyString() throws InterruptedException { - sendActivity = getActivity(); - getInstrumentation().waitForIdleSync(); - final AtomicBoolean requestFocusSucceded = new AtomicBoolean(false); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - final View view = sendActivity.findViewById(R.id.send_data_to_call_edit_text); - requestFocusSucceded.set(view.requestFocus()); - focusLatch.countDown(); - } - }); - - assertTrue("requestFocus timed out!", focusLatch.await(2, TimeUnit.SECONDS)); - assertTrue("requestFocus failed.", requestFocusSucceded.get()); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - try { - injectEventWorked.set(uiController.injectString("")); - latch.countDown(); - } catch (InjectEventSecurityException e) { - injectEventThrewSecurityException.set(true); - } - } - }); - - assertFalse("SecurityException exception was thrown.", injectEventThrewSecurityException.get()); - assertTrue("Timed out!", latch.await(20, TimeUnit.SECONDS)); - assertTrue(injectEventWorked.get()); - } - - @LargeTest - public void testInjectStringSecurityException() throws InterruptedException { - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - try { - injectEventWorked.set(uiController.injectString("Hello! \n&*$$$")); - latch.countDown(); - } catch (InjectEventSecurityException e) { - injectEventThrewSecurityException.set(true); - } - } - }); - - assertTrue("SecurityException exception was thrown.", injectEventThrewSecurityException.get()); - assertFalse("Did NOT time out!", latch.await(3, TimeUnit.SECONDS)); - assertFalse(injectEventWorked.get()); - } - - @LargeTest - public void testInjectMotionEvent() throws InterruptedException { - sendActivity = getActivity(); - final int xy[] = getCoordinatesInMiddleOfSendButton(sendActivity, getInstrumentation()); - - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - long downTime = SystemClock.uptimeMillis(); - try { - MotionEvent event = MotionEvent.obtain(downTime, - SystemClock.uptimeMillis(), - MotionEvent.ACTION_DOWN, - xy[0], - xy[1], - 0); - - injectEventWorked.set(uiController.injectMotionEvent(event)); - event.recycle(); - latch.countDown(); - } catch (InjectEventSecurityException e) { - injectEventThrewSecurityException.set(true); - } - } - }); - - assertFalse("SecurityException exception was thrown.", injectEventThrewSecurityException.get()); - assertTrue("Timed out!", latch.await(10, TimeUnit.SECONDS)); - assertTrue(injectEventWorked.get()); - } - - static int[] getCoordinatesInMiddleOfSendButton( - Activity activity, Instrumentation instrumentation) { - final View sendButton = activity.findViewById(R.id.send_button); - final int[] xy = new int[2]; - instrumentation.runOnMainSync(new Runnable() { - @Override - public void run() { - sendButton.getLocationOnScreen(xy); - } - }); - int x = xy[0] + (sendButton.getWidth() / 2); - int y = xy[1] + (sendButton.getHeight() / 2); - int[] xyMiddle = {x, y}; - return xyMiddle; - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImplTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImplTest.java deleted file mode 100644 index 2b95fc8..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImplTest.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.android.apps.common.testing.ui.espresso.IdlingResourceTimeoutException; -import com.google.common.base.Optional; - -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import junit.framework.TestCase; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Unit test for {@link UiControllerImpl}. - */ -public class UiControllerImplTest extends TestCase { - - private static final String TAG = UiControllerImplTest.class.getSimpleName(); - - private LooperThread testThread; - private AtomicReference<UiControllerImpl> uiController = new AtomicReference<UiControllerImpl>(); - private ThreadPoolExecutor asyncPool; - private IdlingResourceRegistry idlingResourceRegistry; - - private static class LooperThread extends Thread { - private final CountDownLatch init = new CountDownLatch(1); - private Handler handler; - private Looper looper; - - @Override - public void run() { - Looper.prepare(); - handler = new Handler(); - looper = Looper.myLooper(); - init.countDown(); - Looper.loop(); - } - - public void quitLooper() { - looper.quit(); - } - - public Looper getLooper() { - try { - init.await(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - } - return looper; - } - - public Handler getHandler() { - try { - init.await(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - } - return handler; - } - } - - @Override - public void setUp() throws Exception { - super.setUp(); - testThread = new LooperThread(); - testThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread thread, Throwable ex) { - Log.e(TAG, "Looper died: ", ex); - } - }); - testThread.start(); - idlingResourceRegistry = new IdlingResourceRegistry(testThread.getLooper()); - asyncPool = new ThreadPoolExecutor(3, 3, 1, TimeUnit.SECONDS, - new LinkedBlockingQueue<Runnable>()); - EventInjector injector = null; - if (Build.VERSION.SDK_INT > 15) { - InputManagerEventInjectionStrategy strat = new InputManagerEventInjectionStrategy(); - strat.initialize(); - injector = new EventInjector(strat); - } else { - WindowManagerEventInjectionStrategy strat = new WindowManagerEventInjectionStrategy(); - strat.initialize(); - injector = new EventInjector(strat); - } - uiController.set(new UiControllerImpl( - injector, - new AsyncTaskPoolMonitor(asyncPool), - Optional.<AsyncTaskPoolMonitor>absent(), - idlingResourceRegistry, - testThread.getLooper() - )); - - - } - - @Override - public void tearDown() throws Exception { - testThread.quitLooper(); - asyncPool.shutdown(); - super.tearDown(); - } - - public void testLoopMainThreadTillIdle_sendsMessageToRightHandler() { - final CountDownLatch latch = new CountDownLatch(3); - testThread.getHandler(); // blocks till initialized; - final Handler firstHandler = new Handler( - testThread.looper, - new Handler.Callback() { - private boolean counted = false; - @Override - public boolean handleMessage(Message me) { - if (counted) { - fail("Called 2x!!!!"); - } - counted = true; - latch.countDown(); - return true; - } - }); - - final Handler secondHandler = new Handler( - testThread.looper, - new Handler.Callback() { - private boolean counted = false; - @Override - public boolean handleMessage(Message me) { - if (counted) { - fail("Called 2x!!!!"); - } - counted = true; - latch.countDown(); - return true; - } - }); - - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - firstHandler.sendEmptyMessage(1); - secondHandler.sendEmptyMessage(1); - uiController.get().loopMainThreadUntilIdle(); - - latch.countDown(); - } - })); - - try { - assertTrue( - "Timed out waiting for looper to process all events", latch.await(10, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - fail("Failed with exception " + e); - } - } - - public void testLoopForAtLeast() throws Exception { - final CountDownLatch latch = new CountDownLatch(2); - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - testThread.getHandler().post(new Runnable() { - @Override - public void run() { - latch.countDown(); - } - - }); - uiController.get().loopMainThreadForAtLeast(1000); - latch.countDown(); - } - })); - assertTrue("Never returned from UiControllerImpl.loopMainThreadForAtLeast();", - latch.await(10, TimeUnit.SECONDS)); - } - - public void testLoopMainThreadUntilIdle_fullQueue() { - final CountDownLatch latch = new CountDownLatch(3); - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "On main thread"); - Handler handler = new Handler(); - Log.i(TAG, "Equeueing test runnable 1"); - handler.post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "Running test runnable 1"); - latch.countDown(); - } - }); - Log.i(TAG, "Equeueing test runnable 2"); - handler.post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "Running test runnable 2"); - latch.countDown(); - } - }); - Log.i(TAG, "Hijacking thread and looping it."); - uiController.get().loopMainThreadUntilIdle(); - latch.countDown(); - } - })); - - try { - assertTrue( - "Timed out waiting for looper to process all events", latch.await(10, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - fail("Failed with exception " + e); - } - } - - public void testLoopMainThreadUntilIdle_fullQueueAndAsyncTasks() throws Exception { - final CountDownLatch latch = new CountDownLatch(3); - final CountDownLatch asyncTaskStarted = new CountDownLatch(1); - final CountDownLatch asyncTaskShouldComplete = new CountDownLatch(1); - asyncPool.execute(new Runnable() { - @Override - public void run() { - asyncTaskStarted.countDown(); - while (true) { - try { - asyncTaskShouldComplete.await(); - return; - } catch (InterruptedException ie) { - // cant interrupt me. ignore. - } - } - } - }); - assertTrue("async task is not starting!", asyncTaskStarted.await(2, TimeUnit.SECONDS)); - - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "On main thread"); - Handler handler = new Handler(); - Log.i(TAG, "Equeueing test runnable 1"); - handler.post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "Running test runnable 1"); - latch.countDown(); - } - }); - Log.i(TAG, "Equeueing test runnable 2"); - handler.post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "Running test runnable 2"); - latch.countDown(); - } - }); - Log.i(TAG, "Hijacking thread and looping it."); - uiController.get().loopMainThreadUntilIdle(); - latch.countDown(); - } - })); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(2, TimeUnit.SECONDS)); - assertEquals("Not all main thread tasks have checked in", 1L, latch.getCount()); - asyncTaskShouldComplete.countDown(); - assertTrue("App should be idle.", latch.await(5, TimeUnit.SECONDS)); - } - - - public void testLoopMainThreadUntilIdle_emptyQueue() { - final CountDownLatch latch = new CountDownLatch(1); - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - uiController.get().loopMainThreadUntilIdle(); - latch.countDown(); - } - })); - try { - assertTrue("Never returned from UiControllerImpl.loopMainThreadUntilIdle();", - latch.await(10, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - fail("Failed with exception " + e); - } - } - - public void testLoopMainThreadUntilIdle_oneIdlingResource() throws InterruptedException { - OnDemandIdlingResource fakeResource = new OnDemandIdlingResource("FakeResource"); - idlingResourceRegistry.register(fakeResource); - final CountDownLatch latch = new CountDownLatch(1); - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "Hijacking thread and looping it."); - uiController.get().loopMainThreadUntilIdle(); - latch.countDown(); - } - })); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(2, TimeUnit.SECONDS)); - fakeResource.forceIdleNow(); - assertTrue("App should be idle.", latch.await(5, TimeUnit.SECONDS)); - } - - public void testLoopMainThreadUntilIdle_multipleIdlingResources() throws InterruptedException { - OnDemandIdlingResource fakeResource1 = new OnDemandIdlingResource("FakeResource1"); - OnDemandIdlingResource fakeResource2 = new OnDemandIdlingResource("FakeResource2"); - OnDemandIdlingResource fakeResource3 = new OnDemandIdlingResource("FakeResource3"); - // Register the first two right away and one later (once the wait for the first two begins). - idlingResourceRegistry.register(fakeResource1); - idlingResourceRegistry.register(fakeResource2); - final CountDownLatch latch = new CountDownLatch(1); - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "Hijacking thread and looping it."); - uiController.get().loopMainThreadUntilIdle(); - latch.countDown(); - } - })); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); - fakeResource1.forceIdleNow(); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); - idlingResourceRegistry.register(fakeResource3); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); - fakeResource2.forceIdleNow(); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); - fakeResource3.forceIdleNow(); - assertTrue("App should be idle.", latch.await(5, TimeUnit.SECONDS)); - } - - @LargeTest - public void testLoopMainThreadUntilIdle_timeout() throws InterruptedException { - OnDemandIdlingResource goodResource = - new OnDemandIdlingResource("GoodResource"); - OnDemandIdlingResource kindaCrappyResource = - new OnDemandIdlingResource("KindaCrappyResource"); - OnDemandIdlingResource badResource = - new OnDemandIdlingResource("VeryBadResource"); - idlingResourceRegistry.register(goodResource); - idlingResourceRegistry.register(kindaCrappyResource); - idlingResourceRegistry.register(badResource); - final CountDownLatch latch = new CountDownLatch(1); - assertTrue(testThread.getHandler().post(new Runnable() { - @Override - public void run() { - Log.i(TAG, "Hijacking thread and looping it."); - try { - uiController.get().loopMainThreadUntilIdle(); - } catch (IdlingResourceTimeoutException e) { - latch.countDown(); - } - } - })); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(4, TimeUnit.SECONDS)); - goodResource.forceIdleNow(); - assertFalse( - "Should not have stopped looping the main thread yet!", latch.await(12, TimeUnit.SECONDS)); - kindaCrappyResource.forceIdleNow(); - assertTrue( - "Should have caught IdlingResourceTimeoutException", latch.await(11, TimeUnit.SECONDS)); - } - -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/ViewFinderImplTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/ViewFinderImplTest.java deleted file mode 100644 index 7810a83..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/base/ViewFinderImplTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.sameInstance; - -import com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException; -import com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException; -import com.google.android.apps.common.testing.ui.espresso.ViewFinder; - -import android.test.InstrumentationTestCase; -import android.test.UiThreadTest; -import android.view.View; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import org.hamcrest.Matchers; - -import javax.inject.Provider; - -/** Unit tests for {@link ViewFinderImpl}. */ -public class ViewFinderImplTest extends InstrumentationTestCase { - private Provider<View> testViewProvider; - private RelativeLayout testView; - private View child1; - private View child2; - private View child3; - private View child4; - private View nestedChild; - - @Override - public void setUp() throws Exception { - super.setUp(); - testView = new RelativeLayout(getInstrumentation().getTargetContext()); - child1 = new TextView(getInstrumentation().getTargetContext()); - child1.setId(1); - child2 = new TextView(getInstrumentation().getTargetContext()); - child2.setId(2); - child3 = new TextView(getInstrumentation().getTargetContext()); - child3.setId(3); - child4 = new TextView(getInstrumentation().getTargetContext()); - child4.setId(4); - nestedChild = new TextView(getInstrumentation().getTargetContext()); - nestedChild.setId(5); - RelativeLayout nestingLayout = new RelativeLayout(getInstrumentation().getTargetContext()); - nestingLayout.addView(nestedChild); - testView.addView(child1); - testView.addView(child2); - testView.addView(nestingLayout); - testView.addView(child3); - testView.addView(child4); - testViewProvider = new Provider<View>() { - @Override - public View get() { - return testView; - } - - @Override - public String toString() { - return "of(" + testView + ")"; - } - }; - } - - @UiThreadTest - public void testGetView_present() { - ViewFinder finder = new ViewFinderImpl(sameInstance(nestedChild), testViewProvider); - assertThat(finder.getView(), sameInstance(nestedChild)); - } - - @UiThreadTest - public void testGetView_missing() { - ViewFinder finder = new ViewFinderImpl(Matchers.<View>nullValue(), testViewProvider); - try { - finder.getView(); - fail("No children should pass that matcher!"); - } catch (NoMatchingViewException expected) {} - } - - @UiThreadTest - public void testGetView_multiple() { - ViewFinder finder = new ViewFinderImpl(Matchers.<View>notNullValue(), testViewProvider); - try { - finder.getView(); - fail("All nodes hit that matcher!"); - } catch (AmbiguousViewMatcherException expected) {} - } - - public void testFind_offUiThread() { - ViewFinder finder = new ViewFinderImpl(sameInstance(nestedChild), testViewProvider); - try { - finder.getView(); - fail("not on main thread, should die."); - } catch (IllegalStateException expected) {} - } - -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/contrib/CountingIdlingResourceTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/contrib/CountingIdlingResourceTest.java deleted file mode 100644 index 8bd2d11..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/contrib/CountingIdlingResourceTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.contrib; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.android.apps.common.testing.ui.espresso.IdlingResource.ResourceCallback; - -import android.test.InstrumentationTestCase; - -import org.mockito.Mock; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; - -/** Unit tests for {@link CountingIdlingResource}. */ -public class CountingIdlingResourceTest extends InstrumentationTestCase { - - private static final String RESOURCE_NAME = "test_resource"; - private CountingIdlingResource resource; - - @Mock - private ResourceCallback mockCallback; - - @Override - public void setUp() throws Exception { - super.setUp(); - initMocks(this); - resource = new CountingIdlingResource(RESOURCE_NAME, true); - } - - public void testResourceName() { - assertEquals(RESOURCE_NAME, resource.getName()); - } - - public void testInvalidStateDetected() throws Exception { - resource.increment(); - resource.decrement(); - try { - resource.decrement(); - fail("Should throw illegal state exception!"); - } catch (IllegalStateException expected) { } - } - - public void testIsIdle() throws Exception { - assertTrue(callIsIdle()); - resource.increment(); - assertFalse(callIsIdle()); - resource.decrement(); - assertTrue(callIsIdle()); - } - - public void testIdleNotification() throws Exception { - registerIdleCallback(); - assertTrue(callIsIdle()); - verify(mockCallback, never()).onTransitionToIdle(); - - resource.increment(); - verify(mockCallback, never()).onTransitionToIdle(); - assertFalse(callIsIdle()); - - resource.decrement(); - verify(mockCallback).onTransitionToIdle(); - assertTrue(callIsIdle()); - } - - private void registerIdleCallback() throws Exception { - FutureTask<Void> registerTask = new FutureTask<Void>(new Callable<Void>() { - @Override - public Void call() throws Exception { - resource.registerIdleTransitionCallback(mockCallback); - return null; - } - - }); - getInstrumentation().runOnMainSync(registerTask); - try { - registerTask.get(); - } catch (ExecutionException ee) { - throw new RuntimeException(ee.getCause()); - } - - } - - private boolean callIsIdle() throws Exception { - FutureTask<Boolean> isIdleTask = new FutureTask<Boolean>(new IsIdleCallable()); - getInstrumentation().runOnMainSync(isIdleTask); - try { - return isIdleTask.get(); - } catch (ExecutionException ee) { - throw new RuntimeException(ee.getCause()); - } - } - - - private class IsIdleCallable implements Callable<Boolean> { - @Override - public Boolean call() throws Exception { - return resource.isIdleNow(); - } - } - -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/matcher/PreferenceMatchersTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/matcher/PreferenceMatchersTest.java deleted file mode 100644 index 1501184..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/matcher/PreferenceMatchersTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.matcher; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - - -import static com.google.android.apps.common.testing.ui.espresso.matcher.PreferenceMatchers.withKey; -import static com.google.android.apps.common.testing.ui.espresso.matcher.PreferenceMatchers.withSummary; -import static com.google.android.apps.common.testing.ui.espresso.matcher.PreferenceMatchers.withSummaryText; -import static com.google.android.apps.common.testing.ui.espresso.matcher.PreferenceMatchers.withTitle; -import static com.google.android.apps.common.testing.ui.espresso.matcher.PreferenceMatchers.withTitleText; -import static com.google.android.apps.common.testing.ui.espresso.matcher.PreferenceMatchers.isEnabled; -import static org.hamcrest.Matchers.not; - -import com.google.android.apps.common.testing.ui.testapp.test.R; - -import android.test.InstrumentationTestCase; -import android.preference.CheckBoxPreference; -import android.preference.EditTextPreference; - -/** - * Unit tests for preference matchers. - */ -public class PreferenceMatchersTest extends InstrumentationTestCase { - - - public void testWithSummary() { - CheckBoxPreference pref = new CheckBoxPreference(getInstrumentation().getContext()); - pref.setSummary(R.string.something); - assertThat(pref, withSummary(R.string.something)); - assertThat(pref, not(withSummary(R.string.other_string))); - assertThat(pref, withSummaryText("Hello World")); - assertThat(pref, not(withSummaryText(("Hello Mars")))); - assertThat(pref, withSummaryText(is("Hello World"))); - } - - public void testWithTitle() { - CheckBoxPreference pref = new CheckBoxPreference(getInstrumentation().getContext()); - pref.setTitle(R.string.other_string); - assertThat(pref, withTitle(R.string.other_string)); - assertThat(pref, not(withTitle(R.string.something))); - assertThat(pref, withTitleText("Goodbye!!")); - assertThat(pref, not(withTitleText(("Hello Mars")))); - assertThat(pref, withTitleText(is("Goodbye!!"))); - } - - - public void testIsEnabled() { - CheckBoxPreference pref = new CheckBoxPreference(getInstrumentation().getContext()); - pref.setEnabled(true); - assertThat(pref, isEnabled()); - pref.setEnabled(false); - assertThat(pref, not(isEnabled())); - EditTextPreference pref2 = new EditTextPreference(getInstrumentation().getContext()); - pref2.setEnabled(true); - assertThat(pref2, isEnabled()); - pref2.setEnabled(false); - assertThat(pref2, not(isEnabled())); - } - - public void testWithKey() { - CheckBoxPreference pref = new CheckBoxPreference(getInstrumentation().getContext()); - pref.setKey("foo"); - assertThat(pref, withKey("foo")); - assertThat(pref, not(withKey("bar"))); - assertThat(pref, withKey(is("foo"))); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/matcher/ViewMatchersTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/matcher/ViewMatchersTest.java deleted file mode 100644 index 5000e46..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/matcher/ViewMatchersTest.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.matcher; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasContentDescription; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasDescendant; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasImeAction; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasSibling; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isChecked; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isClickable; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDescendantOfA; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isEnabled; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isFocusable; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isNotChecked; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isRoot; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.supportsInputMethods; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withChild; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withContentDescription; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withEffectiveVisibility; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withParent; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withTagKey; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withTagValue; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.Visibility; -import com.google.android.apps.common.testing.ui.testapp.test.R; - -import android.test.InstrumentationTestCase; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.Checkable; -import android.widget.CheckedTextView; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.RadioButton; -import android.widget.RelativeLayout; -import android.widget.ScrollView; -import android.widget.Spinner; -import android.widget.TextView; - -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; - -/** - * Unit tests for {@link ViewMatchers}. - */ -public class ViewMatchersTest extends InstrumentationTestCase { - public void testIsAssignableFrom_notAnInstance() { - View v = new View(getInstrumentation().getTargetContext()); - assertFalse(isAssignableFrom(Spinner.class).matches(v)); - } - - public void testIsAssignableFrom_plainView() { - View v = new View(getInstrumentation().getTargetContext()); - assertTrue(isAssignableFrom(View.class).matches(v)); - } - - public void testIsAssignableFrom_superclass() { - View v = new RadioButton(getInstrumentation().getTargetContext()); - assertTrue(isAssignableFrom(Button.class).matches(v)); - } - - @SuppressWarnings("cast") - public void testWithContentDescriptionCharSequence() { - View view = new View(getInstrumentation().getTargetContext()); - view.setContentDescription(null); - assertTrue(withContentDescription(Matchers.<CharSequence>nullValue()).matches(view)); - CharSequence testText = "test text!"; - view.setContentDescription(testText); - assertTrue(withContentDescription(is(testText)).matches(view)); - assertFalse(withContentDescription(is((CharSequence) "blah")).matches(view)); - assertFalse(withContentDescription(is((CharSequence) "")).matches(view)); - } - - public void testWithContentDescriptionNull() { - try { - withContentDescription((Matcher<CharSequence>) null); - fail("Should of thrown NPE"); - } catch (NullPointerException e) { - // Good, this is expected. - } - } - - public void testHasContentDescription() { - View view = new View(getInstrumentation().getTargetContext()); - view.setContentDescription(null); - assertFalse(hasContentDescription().matches(view)); - CharSequence testText = "test text!"; - view.setContentDescription(testText); - assertTrue(hasContentDescription().matches(view)); - } - - public void testWithContentDescriptionString() { - View view = new View(getInstrumentation().getTargetContext()); - view.setContentDescription(null); - assertTrue(withContentDescription(Matchers.<String>nullValue()).matches(view)); - String testText = "test text!"; - view.setContentDescription(testText); - assertTrue(withContentDescription(is(testText)).matches(view)); - assertFalse(withContentDescription(is("blah")).matches(view)); - assertFalse(withContentDescription(is("")).matches(view)); - } - - public void testWithId() { - View view = new View(getInstrumentation().getTargetContext()); - view.setId(R.id.testId1); - assertTrue(withId(is(R.id.testId1)).matches(view)); - assertFalse(withId(is(R.id.testId2)).matches(view)); - assertFalse(withId(is(1234)).matches(view)); - } - - public void testWithTagNull() { - try { - withTagKey(0, null); - fail("Should of thrown NPE"); - } catch (NullPointerException e) { - // Good, this is expected. - } - - try { - withTagValue(null); - fail("Should of thrown NPE"); - } catch (NullPointerException e) { - // Good, this is expected. - } - } - - public void testWithTagObject() { - View view = new View(getInstrumentation().getTargetContext()); - view.setTag(null); - assertTrue(withTagValue(Matchers.<Object>nullValue()).matches(view)); - String testObjectText = "test text!"; - view.setTag(testObjectText); - assertFalse(withTagKey(R.id.testId1).matches(view)); - assertTrue(withTagValue(is((Object) testObjectText)).matches(view)); - assertFalse(withTagValue(is((Object) "blah")).matches(view)); - assertFalse(withTagValue(is((Object) "")).matches(view)); - } - - public void testWithTagKey() { - View view = new View(getInstrumentation().getTargetContext()); - assertFalse(withTagKey(R.id.testId1).matches(view)); - view.setTag(R.id.testId1, "blah"); - assertFalse(withTagValue(is((Object) "blah")).matches(view)); - assertTrue(withTagKey(R.id.testId1).matches(view)); - assertFalse(withTagKey(R.id.testId2).matches(view)); - assertFalse(withTagKey(R.id.testId3).matches(view)); - assertFalse(withTagKey(65535).matches(view)); - - view.setTag(R.id.testId2, "blah2"); - assertTrue(withTagKey(R.id.testId1).matches(view)); - assertTrue(withTagKey(R.id.testId2).matches(view)); - assertFalse(withTagKey(R.id.testId3).matches(view)); - assertFalse(withTagKey(65535).matches(view)); - assertFalse(withTagValue(is((Object) "blah")).matches(view)); - } - - public void testWithTagKeyObject() { - View view = new View(getInstrumentation().getTargetContext()); - String testObjectText1 = "test text1!"; - String testObjectText2 = "test text2!"; - assertFalse(withTagKey(R.id.testId1, is((Object) testObjectText1)).matches(view)); - view.setTag(R.id.testId1, testObjectText1); - assertTrue(withTagKey(R.id.testId1, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagKey(R.id.testId1, is((Object) testObjectText2)).matches(view)); - assertFalse(withTagKey(R.id.testId2, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagKey(R.id.testId3, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagKey(65535, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagValue(is((Object) "blah")).matches(view)); - - view.setTag(R.id.testId2, testObjectText2); - assertTrue(withTagKey(R.id.testId1, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagKey(R.id.testId1, is((Object) testObjectText2)).matches(view)); - assertTrue(withTagKey(R.id.testId2, is((Object) testObjectText2)).matches(view)); - assertFalse(withTagKey(R.id.testId2, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagKey(R.id.testId3, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagKey(65535, is((Object) testObjectText1)).matches(view)); - assertFalse(withTagValue(is((Object) "blah")).matches(view)); - } - - public void testWithTextNull() { - try { - withText((Matcher<String>) null); - fail("Should of thrown NPE"); - } catch (NullPointerException e) { - // Good, this is expected. - } - } - - public void testCheckBoxMatchers() { - assertFalse(isChecked().matches(new Spinner(getInstrumentation().getTargetContext()))); - assertFalse(isNotChecked().matches(new Spinner(getInstrumentation().getTargetContext()))); - - CheckBox checkBox = new CheckBox(getInstrumentation().getTargetContext()); - checkBox.setChecked(true); - assertTrue(isChecked().matches(checkBox)); - assertFalse(isNotChecked().matches(checkBox)); - - checkBox.setChecked(false); - assertFalse(isChecked().matches(checkBox)); - assertTrue(isNotChecked().matches(checkBox)); - - RadioButton radioButton = new RadioButton(getInstrumentation().getTargetContext()); - radioButton.setChecked(false); - assertFalse(isChecked().matches(radioButton)); - assertTrue(isNotChecked().matches(radioButton)); - - radioButton.setChecked(true); - assertTrue(isChecked().matches(radioButton)); - assertFalse(isNotChecked().matches(radioButton)); - - CheckedTextView checkedText = new CheckedTextView(getInstrumentation().getTargetContext()); - checkedText.setChecked(false); - assertFalse(isChecked().matches(checkedText)); - assertTrue(isNotChecked().matches(checkedText)); - - checkedText.setChecked(true); - assertTrue(isChecked().matches(checkedText)); - assertFalse(isNotChecked().matches(checkedText)); - - Checkable checkable = new Checkable() { - @Override - public boolean isChecked() { return true; } - @Override - public void setChecked(boolean ignored) {} - @Override - public void toggle() {} - }; - - assertFalse(isChecked().matches(checkable)); - assertFalse(isNotChecked().matches(checkable)); - } - - public void testWithTextString() { - TextView textView = new TextView(getInstrumentation().getTargetContext()); - textView.setText(null); - assertTrue(withText(is("")).matches(textView)); - String testText = "test text!"; - textView.setText(testText); - assertTrue(withText(is(testText)).matches(textView)); - assertFalse(withText(is("blah")).matches(textView)); - assertFalse(withText(is("")).matches(textView)); - } - - public void testHasDescendant() { - View v = new TextView(getInstrumentation().getTargetContext()); - ViewGroup parent = new RelativeLayout(getInstrumentation().getTargetContext()); - ViewGroup grany = new ScrollView(getInstrumentation().getTargetContext()); - grany.addView(parent); - parent.addView(v); - assertTrue(hasDescendant(isAssignableFrom(TextView.class)).matches(grany)); - assertTrue(hasDescendant(isAssignableFrom(TextView.class)).matches(parent)); - assertFalse(hasDescendant(isAssignableFrom(ScrollView.class)).matches(parent)); - assertFalse(hasDescendant(isAssignableFrom(TextView.class)).matches(v)); - } - - public void testIsDescendantOfA() { - View v = new TextView(getInstrumentation().getTargetContext()); - ViewGroup parent = new RelativeLayout(getInstrumentation().getTargetContext()); - ViewGroup grany = new ScrollView(getInstrumentation().getTargetContext()); - grany.addView(parent); - parent.addView(v); - assertTrue(isDescendantOfA(isAssignableFrom(RelativeLayout.class)).matches(v)); - assertTrue(isDescendantOfA(isAssignableFrom(ScrollView.class)).matches(v)); - assertFalse(isDescendantOfA(isAssignableFrom(LinearLayout.class)).matches(v)); - } - - public void testIsVisible() { - View visible = new View(getInstrumentation().getTargetContext()); - visible.setVisibility(View.VISIBLE); - View invisible = new View(getInstrumentation().getTargetContext()); - invisible.setVisibility(View.INVISIBLE); - assertTrue(withEffectiveVisibility(Visibility.VISIBLE).matches(visible)); - assertFalse(withEffectiveVisibility(Visibility.VISIBLE).matches(invisible)); - - // Make the visible view invisible by giving it an invisible parent. - ViewGroup parent = new RelativeLayout(getInstrumentation().getTargetContext()); - parent.addView(visible); - parent.setVisibility(View.INVISIBLE); - assertFalse(withEffectiveVisibility(Visibility.VISIBLE).matches(visible)); - } - - public void testIsInvisible() { - View visible = new View(getInstrumentation().getTargetContext()); - visible.setVisibility(View.VISIBLE); - View invisible = new View(getInstrumentation().getTargetContext()); - invisible.setVisibility(View.INVISIBLE); - assertFalse(withEffectiveVisibility(Visibility.INVISIBLE).matches(visible)); - assertTrue(withEffectiveVisibility(Visibility.INVISIBLE).matches(invisible)); - - // Make the visible view invisible by giving it an invisible parent. - ViewGroup parent = new RelativeLayout(getInstrumentation().getTargetContext()); - parent.addView(visible); - parent.setVisibility(View.INVISIBLE); - assertTrue(withEffectiveVisibility(Visibility.INVISIBLE).matches(visible)); - } - - public void testIsGone() { - View gone = new View(getInstrumentation().getTargetContext()); - gone.setVisibility(View.GONE); - View visible = new View(getInstrumentation().getTargetContext()); - visible.setVisibility(View.VISIBLE); - assertFalse(withEffectiveVisibility(Visibility.GONE).matches(visible)); - assertTrue(withEffectiveVisibility(Visibility.GONE).matches(gone)); - - // Make the gone view gone by giving it a gone parent. - ViewGroup parent = new RelativeLayout(getInstrumentation().getTargetContext()); - parent.addView(visible); - parent.setVisibility(View.GONE); - assertTrue(withEffectiveVisibility(Visibility.GONE).matches(visible)); - } - - public void testIsClickable() { - View clickable = new View(getInstrumentation().getTargetContext()); - clickable.setClickable(true); - View notClickable = new View(getInstrumentation().getTargetContext()); - notClickable.setClickable(false); - assertTrue(isClickable().matches(clickable)); - assertFalse(isClickable().matches(notClickable)); - } - - public void testIsEnabled() { - View enabled = new View(getInstrumentation().getTargetContext()); - enabled.setEnabled(true); - View notEnabled = new View(getInstrumentation().getTargetContext()); - notEnabled.setEnabled(false); - assertTrue(isEnabled().matches(enabled)); - assertFalse(isEnabled().matches(notEnabled)); - } - - public void testIsFocusable() { - View focusable = new View(getInstrumentation().getTargetContext()); - focusable.setFocusable(true); - View notFocusable = new View(getInstrumentation().getTargetContext()); - notFocusable.setFocusable(false); - assertTrue(isFocusable().matches(focusable)); - assertFalse(isFocusable().matches(notFocusable)); - } - - public void testWithTextResourceId() { - TextView textView = new TextView(getInstrumentation().getTargetContext()); - textView.setText(R.string.something); - assertTrue(withText(R.string.something).matches(textView)); - assertFalse(withText(R.string.other_string).matches(textView)); - } - - public void testWithParent() { - View view1 = new TextView(getInstrumentation().getTargetContext()); - View view2 = new TextView(getInstrumentation().getTargetContext()); - View view3 = new TextView(getInstrumentation().getTargetContext()); - ViewGroup tiptop = new RelativeLayout(getInstrumentation().getTargetContext()); - ViewGroup secondLevel = new RelativeLayout(getInstrumentation().getTargetContext()); - secondLevel.addView(view2); - secondLevel.addView(view3); - tiptop.addView(secondLevel); - tiptop.addView(view1); - assertTrue(withParent(is((View) tiptop)).matches(view1)); - assertTrue(withParent(is((View) tiptop)).matches(secondLevel)); - assertFalse(withParent(is((View) tiptop)).matches(view2)); - assertFalse(withParent(is((View) tiptop)).matches(view3)); - assertFalse(withParent(is((View) secondLevel)).matches(view1)); - - assertTrue(withParent(is((View) secondLevel)).matches(view2)); - assertTrue(withParent(is((View) secondLevel)).matches(view3)); - - assertFalse(withParent(is(view3)).matches(view3)); - } - - public void testWithChild() { - View view1 = new TextView(getInstrumentation().getTargetContext()); - View view2 = new TextView(getInstrumentation().getTargetContext()); - View view3 = new TextView(getInstrumentation().getTargetContext()); - ViewGroup tiptop = new RelativeLayout(getInstrumentation().getTargetContext()); - ViewGroup secondLevel = new RelativeLayout(getInstrumentation().getTargetContext()); - secondLevel.addView(view2); - secondLevel.addView(view3); - tiptop.addView(secondLevel); - tiptop.addView(view1); - assertTrue(withChild(is(view1)).matches(tiptop)); - assertTrue(withChild(is((View) secondLevel)).matches(tiptop)); - assertFalse(withChild(is((View) tiptop)).matches(view1)); - assertFalse(withChild(is(view2)).matches(tiptop)); - assertFalse(withChild(is(view1)).matches(secondLevel)); - - assertTrue(withChild(is(view2)).matches(secondLevel)); - - assertFalse(withChild(is(view3)).matches(view3)); - } - - public void testIsRootView() { - ViewGroup rootView = new ViewGroup(getInstrumentation().getTargetContext()) { - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - } - }; - - View view = new View(getInstrumentation().getTargetContext()); - rootView.addView(view); - - assertTrue(isRoot().matches(rootView)); - assertFalse(isRoot().matches(view)); - } - - public void testHasSibling() { - TextView v1 = new TextView(getInstrumentation().getTargetContext()); - v1.setText("Bill Odama"); - Button v2 = new Button(getInstrumentation().getTargetContext()); - View v3 = new View(getInstrumentation().getTargetContext()); - ViewGroup parent = new LinearLayout(getInstrumentation().getTargetContext()); - parent.addView(v1); - parent.addView(v2); - parent.addView(v3); - assertTrue(hasSibling(withText("Bill Odama")).matches(v2)); - assertFalse(hasSibling(is(v3)).matches(parent)); - } - - public void testHasImeAction() { - EditText editText = new EditText(getInstrumentation().getTargetContext()); - assertFalse(hasImeAction(EditorInfo.IME_ACTION_GO).matches(editText)); - editText.setImeOptions(EditorInfo.IME_ACTION_NEXT); - assertFalse(hasImeAction(EditorInfo.IME_ACTION_GO).matches(editText)); - assertTrue(hasImeAction(EditorInfo.IME_ACTION_NEXT).matches(editText)); - } - - public void testHasImeActionNoInputConnection() { - Button button = new Button(getInstrumentation().getTargetContext()); - assertFalse(hasImeAction(0).matches(button)); - } - - public void testSupportsInputMethods() { - Button button = new Button(getInstrumentation().getTargetContext()); - EditText editText = new EditText(getInstrumentation().getTargetContext()); - assertFalse(supportsInputMethods().matches(button)); - assertTrue(supportsInputMethods().matches(editText)); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/util/TreeIterablesTest.java b/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/util/TreeIterablesTest.java deleted file mode 100644 index 9b2bdcc..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/java/com/google/android/apps/common/testing/ui/espresso/util/TreeIterablesTest.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.util; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.util.TreeIterables.DistanceRecordingTreeViewer; -import com.google.android.apps.common.testing.ui.espresso.util.TreeIterables.TreeViewer; -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import junit.framework.TestCase; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** Unit tests for {@link TreeIterables}. */ -public class TreeIterablesTest extends TestCase { - - private static class TestElement { - private final String data; - private final ImmutableList<TestElement> children; - public TestElement(String data, TestElement ... children) { - this.data = checkNotNull(data); - this.children = ImmutableList.copyOf(children); - } - } - - private static class TestElementTreeViewer implements TreeViewer<TestElement> { - @Override - public Collection<TestElement> children(TestElement element) { - return element.children; - } - } - - private static class TestElementStringConvertor implements Function<TestElement, String> { - @Override - public String apply(TestElement e) { - return e.data; - } - } - - - private static final TestElement trivialTree = - new TestElement("a", new TestElement("b", new TestElement("c", new TestElement("d")))); - - private static final TestElement complexTree = - new TestElement("a", - new TestElement("b", - new TestElement("c", - new TestElement("d"), - new TestElement("e", - new TestElement("f"))), - new TestElement("g"), - new TestElement("h", - new TestElement("i", - new TestElement("j", - new TestElement("k"))))), - new TestElement("l"), - new TestElement("m"), - new TestElement("n", - new TestElement("o", - new TestElement("p"), - new TestElement("q")))); - - public void testDistanceRecorder_unknownItemThrowsException() { - final DistanceRecordingTreeViewer<TestElement> distanceRecorder = - new DistanceRecordingTreeViewer<TestElement>(complexTree, new TestElementTreeViewer()); - try { - distanceRecorder.getDistance(new TestElement("hello")); - fail("node should be unknown"); - } catch (RuntimeException expected) { } - } - - public void testDistanceRecorder_unprocessedChildThrowsException() { - final DistanceRecordingTreeViewer<TestElement> distanceRecorder = - new DistanceRecordingTreeViewer<TestElement>(complexTree, new TestElementTreeViewer()); - - try { - distanceRecorder.getDistance(complexTree.children.iterator().next()); - fail("distance recorder hasnt processed this child yet, cannot know distance"); - } catch (RuntimeException expected) { } - } - - public void testDistanceRecorder_distanceKnownAfterChildrenCall() { - final DistanceRecordingTreeViewer<TestElement> distanceRecorder = - new DistanceRecordingTreeViewer<TestElement>(complexTree, new TestElementTreeViewer()); - - @SuppressWarnings("unused") - List<TestElement> createdForSideEffect = Lists.newArrayList( - distanceRecorder.children(complexTree)); - - assertThat(distanceRecorder.getDistance(complexTree), is(0)); - assertThat(distanceRecorder.getDistance(complexTree.children.iterator().next()), is(1)); - } - - @SuppressWarnings("unchecked") - public void testComplexTree_Distances() { - final DistanceRecordingTreeViewer<TestElement> distanceRecorder = - new DistanceRecordingTreeViewer<TestElement>(complexTree, new TestElementTreeViewer()); - Iterable<TestElement> complexIterable = TreeIterables.depthFirstTraversal(complexTree, - distanceRecorder); - Set<TestElement> complexSet = Sets.newHashSet(complexIterable); - Map<String, Integer> distancesByData = Maps.newHashMap(); - for (TestElement e : complexSet) { - distancesByData.put(e.data, distanceRecorder.getDistance(e)); - } - - assertThat(distancesByData, allOf( - hasEntry("a", 0), - hasEntry("b", 1), - hasEntry("c", 2), - hasEntry("d", 3), - hasEntry("e", 3), - hasEntry("f", 4), - hasEntry("g", 2), - hasEntry("h", 2), - hasEntry("i", 3), - hasEntry("j", 4), - hasEntry("k", 5), - hasEntry("l", 1), - hasEntry("m", 1), - hasEntry("n", 1), - hasEntry("o", 2), - hasEntry("p", 3), - hasEntry("q", 3))); - assertThat(distancesByData.size(), is(17)); - - List<String> traversalOrder = Lists.newArrayList(Iterables.transform( - complexIterable, - new TestElementStringConvertor())); - - // should be depth first if forwarding correctly. - assertThat(traversalOrder, - is((List<String>) Lists.newArrayList( - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q"))); - } - - public void testComplexTraversal_depthFirst() { - List<String> breadthFirst = Lists.newArrayList(Iterables.transform( - TreeIterables.depthFirstTraversal(complexTree, new TestElementTreeViewer()), - new TestElementStringConvertor())); - assertThat(breadthFirst, - is((Iterable<String>) Lists.newArrayList( - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q"))); - } - - public void testComplexTraversal_breadthFirst() { - List<String> breadthFirst = Lists.newArrayList(Iterables.transform( - TreeIterables.breadthFirstTraversal(complexTree, new TestElementTreeViewer()), - new TestElementStringConvertor())); - assertThat(breadthFirst, - is((List<String>) Lists.newArrayList( - "a", //root - "b", "l", "m", "n", //L1 - "c", "g", "h", "o", //L2 - "d", "e", "i", "p", "q", //L3 - "f", "j", // L4 - "k"))); //L5 - } - - public void testTrivialTraversal_breadthFirst() { - // essentially the same as depth first. - List<String> breadthFirst = Lists.newArrayList(Iterables.transform( - TreeIterables.breadthFirstTraversal(trivialTree, new TestElementTreeViewer()), - new TestElementStringConvertor())); - assertThat(breadthFirst, is((List<String>) Lists.newArrayList("a", "b", "c", "d"))); - } - - public void testTrivialTraversal_depthFirst() { - List<String> depthFirst = Lists.newArrayList(Iterables.transform( - TreeIterables.depthFirstTraversal(trivialTree, new TestElementTreeViewer()), - new TestElementStringConvertor())); - assertThat(depthFirst, is((List<String>) Lists.newArrayList("a", "b", "c", "d"))); - } - - @SuppressWarnings("unchecked") - public void testTrivial_distance() { - final DistanceRecordingTreeViewer<TestElement> distanceRecorder = - new DistanceRecordingTreeViewer<TestElement>(trivialTree, new TestElementTreeViewer()); - - Iterable<TestElement> trivialIterable = TreeIterables.depthFirstTraversal(trivialTree, - distanceRecorder); - Set<TestElement> trivialSet = Sets.newHashSet(trivialIterable); - Map<String, Integer> distancesByData = Maps.newHashMap(); - for (TestElement e : trivialSet) { - distancesByData.put(e.data, distanceRecorder.getDistance(e)); - } - - assertThat(distancesByData, allOf( - hasEntry("a", 0), - hasEntry("b", 1), - hasEntry("c", 2), - hasEntry("d", 3))); - assertThat(distancesByData.size(), is(4)); - } -} diff --git a/espresso/espresso-lib-tests/src/androidTest/res/values/id.xml b/espresso/espresso-lib-tests/src/androidTest/res/values/id.xml deleted file mode 100644 index 62358e3..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/res/values/id.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources> - <!-- IDs used for testing purposes --> - <item type="id" name="testId1" /> - <item type="id" name="testId2" /> - <item type="id" name="testId3" /> -</resources> diff --git a/espresso/espresso-lib-tests/src/androidTest/res/values/strings.xml b/espresso/espresso-lib-tests/src/androidTest/res/values/strings.xml deleted file mode 100644 index 54a4ecc..0000000 --- a/espresso/espresso-lib-tests/src/androidTest/res/values/strings.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources> - <string name="something">Hello World</string> - <string name="other_string">Goodbye!!</string> -</resources> diff --git a/espresso/espresso-lib/Android.mk b/espresso/espresso-lib/Android.mk deleted file mode 100644 index 2b98b1b..0000000 --- a/espresso/espresso-lib/Android.mk +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := espresso-lib - -LOCAL_SDK_VERSION := 19 - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_STATIC_JAVA_LIBRARIES := \ - espresso-idling-resource \ - espresso-dagger-1.2.1 \ - espresso-dagger-compiler-1.2.1 \ - espresso-guava \ - hamcrest \ - hamcrest-integration \ - hamcrest-library \ - espresso-javawriter-2.1.1 \ - espresso-javax-inject-1 \ - jsr305 \ - espresso-testrunner-1.1 \ - espresso-testrunner-runtime-1.1 - -include $(BUILD_STATIC_JAVA_LIBRARY) - -############################################################# -# Pre-built dependency jars -############################################################# - -include $(CLEAR_VARS) - -repo_prebuilts_dir := ../../../../prebuilts - -LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \ - espresso-dagger-1.2.1:../libs/dagger-1.2.1.jar \ - espresso-dagger-compiler-1.2.1:../libs/dagger-compiler-1.2.1.jar \ - espresso-guava:$(repo_prebuilts_dir)/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0.jar \ - espresso-javawriter-2.1.1:$(repo_prebuilts_dir)/tools/common/m2/repository/com/squareup/javawriter/2.1.1/javawriter-2.1.1.jar \ - espresso-javax-inject-1:$(repo_prebuilts_dir)/tools/common/m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar \ - espresso-testrunner-1.1:../libs/testrunner-1.1.jar \ - espresso-testrunner-runtime-1.1:../libs/testrunner-runtime-1.1.jar - -include $(BUILD_MULTI_PREBUILT) - -# Clean up locally defined vars -repo_prebuilts_dir := diff --git a/espresso/espresso-lib/build.gradle b/espresso/espresso-lib/build.gradle deleted file mode 100644 index 31b54be..0000000 --- a/espresso/espresso-lib/build.gradle +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'android-library' - -sourceCompatibility = JavaVersion.VERSION_1_5 -targetCompatibility = JavaVersion.VERSION_1_5 - -repositories { - maven { url '../../../../prebuilts/tools/common/m2/repository' } - maven { url '../../../../prebuilts/tools/common/m2/internal' } -} - -android { - compileSdkVersion 19 - buildToolsVersion '19.0.3' - - // to overwrite debug variant - publishNonDefault true - - lintOptions { - abortOnError false - } - - packagingOptions { - exclude 'LICENSE.txt' - } -} - -// create separate scope for jarjar -configurations { - jarjar -} - -dependencies { - // set to provided since we're manually adding the JarJar'd version - provided files('../libs/dagger-1.2.1.jar') - provided files('../libs/dagger-compiler-1.2.1.jar') - provided files('../libs/guava-14.0.1.jar') - - compile project(':idling-resource-interface') - compile 'javax.annotation:javax.annotation-api:1.2' - compile 'javax.inject:javax.inject:1' - compile 'com.google.code.findbugs:jsr305:2.0.1' - compile 'org.hamcrest:hamcrest-library:1.1' - compile 'org.hamcrest:hamcrest-integration:1.1' - compile 'org.hamcrest:hamcrest-core:1.1' - compile 'com.squareup:javawriter:2.1.1' - - jarjar files('../libs/jarjar-1.4.jar') - - // Temporarily include the Google3 TestRunner as a static jar - // until it's merged with the Android one. - compile files('../libs/testrunner-runtime-1.1.jar') - compile files('../libs/testrunner-1.1.jar') -} - -android.libraryVariants.all { variant -> - - // To run unit tests against un-jarjar version of the lib. - if (variant.buildType.name.equals(com.android.builder.BuilderConstants.DEBUG)) { - println "Skipping debug build type." - return; - } - - def classesJar = "$project.buildDir/bundles/$variant.dirName/classes.jar" - def tmpClassesJarDir = "$project.buildDir/pre-jarjar/$variant.dirName" - def tmpClassesJar = "$tmpClassesJarDir/classes.jar" - - def depDaggerJar = "../libs/dagger-1.2.1.jar" - def depGuavaJar = "../libs/guava-14.0.1.jar" - def jarJarTaskName = "jarJar${variant.name.capitalize()}" - - task "$jarJarTaskName" << { - project.ant { - taskdef name: "jarjar", classname: "com.tonicsystems.jarjar.JarJarTask", - classpath: configurations.jarjar.asPath - jarjar(jarfile: "$classesJar", filesetmanifest: "merge") { - zipfileset(src: "$depGuavaJar") - zipfileset(src: "$depDaggerJar") - zipfileset(src: "$tmpClassesJar") - rule pattern: "com.google.common.**", - result: "com.google.android.apps.common.testing.deps.guava.@1" - rule pattern: "dagger.**", - result: "com.google.android.apps.common.testing.deps.dagger.@1" - } - } - } - - // get access to the normal jar class. Change its output to somewhere else, and make jarjar depend on it. - Jar classesJarTask = (Jar) project.tasks.getByName("package${variant.name.capitalize()}Jar") - - classesJarTask.destinationDir = project.file("$tmpClassesJarDir") - project.tasks.getByName("$jarJarTaskName").dependsOn classesJarTask, configurations.provided - - variant.packageLibrary.dependsOn "$jarJarTaskName" -} - -apply from: "$rootDir/javadoc.gradle" -apply from: "$rootDir/publishLocal.gradle" diff --git a/espresso/espresso-lib/gradle.properties b/espresso/espresso-lib/gradle.properties deleted file mode 100644 index df3f7c9..0000000 --- a/espresso/espresso-lib/gradle.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -VERSION=1.2 -POM_NAME=Espresso Library -GROUP_ID=com.google.android.apps.common.testing -POM_ARTIFACT_ID=espresso-lib -POM_PACKAGING=aar
\ No newline at end of file diff --git a/espresso/espresso-lib/src/main/AndroidManifest.xml b/espresso/espresso-lib/src/main/AndroidManifest.xml deleted file mode 100644 index e6813a3..0000000 --- a/espresso/espresso-lib/src/main/AndroidManifest.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.apps.common.testing.ui.espresso" > - - <uses-sdk - android:minSdkVersion="7"/> - - <application /> - -</manifest>
\ No newline at end of file diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AmbiguousViewMatcherException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AmbiguousViewMatcherException.java deleted file mode 100644 index 41c3678..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AmbiguousViewMatcherException.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; - -import android.view.View; - -import org.hamcrest.Matcher; - -/** - * An exception which indicates that a Matcher<View> matched multiple views in the hierarchy when - * only one view was expected. It should be called only from the main thread. - * <p> - * Contains details about the matcher and the current view hierarchy to aid in debugging. - * </p> - * <p> - * Since this is usually an unrecoverable error this exception is a runtime exception. - * </p> - * <p> - * References to the view and failing matcher are purposefully not included in the state of this - * object - since it will most likely be created on the UI thread and thrown on the instrumentation - * thread, it would be invalid to touch the view on the instrumentation thread. Also the view - * hierarchy may have changed since exception creation (leading to more confusion). - * </p> - */ -public final class AmbiguousViewMatcherException extends RuntimeException - implements EspressoException { - - private Matcher<? super View> viewMatcher; - private View rootView; - private View view1; - private View view2; - private View[] others; - - private AmbiguousViewMatcherException(String description) { - super(description); - } - - private AmbiguousViewMatcherException(Builder builder) { - super(getErrorMessage(builder)); - this.viewMatcher = builder.viewMatcher; - this.rootView = builder.rootView; - this.view1 = builder.view1; - this.view2 = builder.view2; - this.others = builder.others; - } - - private static String getErrorMessage(Builder builder) { - String errorMessage = ""; - if (builder.includeViewHierarchy) { - ImmutableSet<View> ambiguousViews = - ImmutableSet.<View>builder().add(builder.view1, builder.view2).add(builder.others).build(); - errorMessage = HumanReadables.getViewHierarchyErrorMessage(builder.rootView, - Lists.newArrayList(ambiguousViews), - String.format("'%s' matches multiple views in the hierarchy.", builder.viewMatcher), - "****MATCHES****"); - } else { - errorMessage = String.format("Multiple Ambiguous Views found for matcher %s", - builder.viewMatcher); - } - return errorMessage; - } - - /** Builder for {@link AmbiguousViewMatcherException}. */ - public static class Builder { - private Matcher<? super View> viewMatcher; - private View rootView; - private View view1; - private View view2; - private View[] others; - private boolean includeViewHierarchy = true; - - public Builder from(AmbiguousViewMatcherException exception) { - this.viewMatcher = exception.viewMatcher; - this.rootView = exception.rootView; - this.view1 = exception.view1; - this.view2 = exception.view2; - this.others = exception.others; - return this; - } - - public Builder withViewMatcher(Matcher<? super View> viewMatcher) { - this.viewMatcher = viewMatcher; - return this; - } - - public Builder withRootView(View rootView) { - this.rootView = rootView; - return this; - } - - public Builder withView1(View view1) { - this.view1 = view1; - return this; - } - - public Builder withView2(View view2) { - this.view2 = view2; - return this; - } - - public Builder withOtherAmbiguousViews(View... others) { - this.others = others; - return this; - } - - public Builder includeViewHierarchy(boolean includeViewHierarchy) { - this.includeViewHierarchy = includeViewHierarchy; - return this; - } - - public AmbiguousViewMatcherException build() { - checkNotNull(viewMatcher); - checkNotNull(rootView); - checkNotNull(view1); - checkNotNull(view2); - checkNotNull(others); - return new AmbiguousViewMatcherException(this); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AndroidManifest.xml b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AndroidManifest.xml deleted file mode 100644 index e32c392..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AndroidManifest.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.apps.common.testing.ui.espresso" > - - <uses-sdk - android:minSdkVersion="7" - android:targetSdkVersion="17" /> - - <application android:label="Espresso" /> - -</manifest>
\ No newline at end of file diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AppNotIdleException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AppNotIdleException.java deleted file mode 100644 index e84fcca..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/AppNotIdleException.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.base.Joiner; - -import android.os.Looper; - -import java.util.List; - -/** - * An exception which indicates that the App has not become idle even after the specified duration. - */ -public final class AppNotIdleException extends RuntimeException implements EspressoException { - - private AppNotIdleException(String description) { - super(description); - } - - /** - * Creates a new AppNotIdleException suitable for erroring out a test case. - * - * This should be called only from the main thread if the app does not idle out within the - * specified duration. - * - * @param idleConditions list of idleConditions that failed to become idle. - * @param loopCount number of times it was tried to check if they became idle. - * @param seconds number of seconds that was tried before giving up. - * - * @return a AppNotIdleException suitable to be thrown on the instrumentation thread. - */ - @Deprecated - public static AppNotIdleException create(List<String> idleConditions, int loopCount, - int seconds) { - checkState(Looper.myLooper() == Looper.getMainLooper()); - String errorMessage = String.format("App not idle within timeout of %s seconds even" + - "after trying for %s iterations. The following Idle Conditions failed %s", - seconds, loopCount, Joiner.on(",").join(idleConditions)); - return new AppNotIdleException(errorMessage); - } - - /** - * Creates a new AppNotIdleException suitable for erroring out a test case. - * - * This should be called only from the main thread if the app does not idle out within the - * specified duration. - * - * @param idleConditions list of idleConditions that failed to become idle. - * @param message a message about the failure. - * - * @return a AppNotIdleException suitable to be thrown on the instrumentation thread. - */ - static AppNotIdleException create(List<String> idleConditions, String message) { - String errorMessage = String.format("%s The following Idle Conditions failed %s.", - message, Joiner.on(",").join(idleConditions)); - return new AppNotIdleException(errorMessage); - } -} - diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/DataInteraction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/DataInteraction.java deleted file mode 100644 index aa13d5e..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/DataInteraction.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDescendantOfA; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.hamcrest.Matchers.allOf; - -import com.google.android.apps.common.testing.ui.espresso.action.AdapterDataLoaderAction; -import com.google.android.apps.common.testing.ui.espresso.action.AdapterViewProtocol; -import com.google.android.apps.common.testing.ui.espresso.action.AdapterViewProtocol.AdaptedData; -import com.google.android.apps.common.testing.ui.espresso.action.AdapterViewProtocols; -import com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers; -import com.google.common.base.Optional; - -import android.view.View; -import android.view.ViewParent; -import android.widget.Adapter; -import android.widget.AdapterView; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -/** - * An interface to interact with data displayed in AdapterViews. - * <p> - * This interface builds on top of {@link ViewInteraction} and should be the preferred way to - * interact with elements displayed inside AdapterViews. - * </p> - * <p> - * This is necessary because an AdapterView may not load all the data held by its Adapter into the - * view hierarchy until a user interaction makes it necessary. Also it is more fluent / less brittle - * to match upon the data object being rendered into the display then the rendering itself. - * </p> - * <p> - * By default, a DataInteraction takes place against any AdapterView found within the current - * screen, if you have multiple AdapterView objects displayed, you will need to narrow the selection - * by using the inAdapterView method. - * </p> - * <p> - * The check and perform method operate on the top level child of the adapter view, if you need to - * operate on a subview (eg: a Button within the list) use the onChildView method before calling - * perform or check. - * </p> - * - */ -public class DataInteraction { - - private final Matcher<Object> dataMatcher; - private Matcher<View> adapterMatcher = isAssignableFrom(AdapterView.class); - private Optional<Matcher<View>> childViewMatcher = Optional.absent(); - private Optional<Integer> atPosition = Optional.absent(); - private AdapterViewProtocol adapterViewProtocol = AdapterViewProtocols.standardProtocol(); - private Matcher<Root> rootMatcher = RootMatchers.DEFAULT; - - DataInteraction(Matcher<Object> dataMatcher) { - this.dataMatcher = checkNotNull(dataMatcher); - } - - /** - * Causes perform and check methods to take place on a specific child view of the view returned - * by Adapter.getView() - */ - public DataInteraction onChildView(Matcher<View> childMatcher) { - this.childViewMatcher = Optional.of(checkNotNull(childMatcher)); - return this; - } - - /** - * Causes this data interaction to work within the Root specified by the given root matcher. - */ - public DataInteraction inRoot(Matcher<Root> rootMatcher) { - this.rootMatcher = checkNotNull(rootMatcher); - return this; - } - - /** - * Selects a particular adapter view to operate on, by default we operate on any adapter view - * on the screen. - */ - public DataInteraction inAdapterView(Matcher<View> adapterMatcher) { - this.adapterMatcher = checkNotNull(adapterMatcher); - return this; - } - - /** - * Selects the view which matches the nth position on the adapter - * based on the data matcher. - */ - public DataInteraction atPosition(Integer atPosition) { - this.atPosition = Optional.of(checkNotNull(atPosition)); - return this; - } - - /** - * Use a different AdapterViewProtocol if the Adapter implementation does not - * satisfy the AdapterView contract like (@code ExpandableListView) - */ - public DataInteraction usingAdapterViewProtocol(AdapterViewProtocol adapterViewProtocol) { - this.adapterViewProtocol = checkNotNull(adapterViewProtocol); - return this; - } - - /** - * Performs an action on the view after we force the data to be loaded. - * - * @return an {@link ViewInteraction} for more assertions or actions. - */ - public ViewInteraction perform(ViewAction... actions) { - AdapterDataLoaderAction adapterDataLoaderAction = load(); - - return onView(makeTargetMatcher(adapterDataLoaderAction)) - .inRoot(rootMatcher) - .perform(actions); - } - - /** - * Performs an assertion on the state of the view after we force the data to be loaded. - * - * @return an {@link ViewInteraction} for more assertions or actions. - */ - public ViewInteraction check(ViewAssertion assertion) { - AdapterDataLoaderAction adapterDataLoaderAction = load(); - - return onView(makeTargetMatcher(adapterDataLoaderAction)) - .inRoot(rootMatcher) - .check(assertion); - } - - private AdapterDataLoaderAction load() { - AdapterDataLoaderAction adapterDataLoaderAction = - new AdapterDataLoaderAction(dataMatcher, atPosition, adapterViewProtocol); - onView(adapterMatcher) - .inRoot(rootMatcher) - .perform(adapterDataLoaderAction); - return adapterDataLoaderAction; - } - - @SuppressWarnings("unchecked") - private Matcher<View> makeTargetMatcher(AdapterDataLoaderAction adapterDataLoaderAction) { - Matcher<View> targetView = displayingData(adapterMatcher, dataMatcher, adapterViewProtocol, - adapterDataLoaderAction); - if (childViewMatcher.isPresent()) { - targetView = allOf(childViewMatcher.get(), isDescendantOfA(targetView)); - } - return targetView; - } - - private Matcher<View> displayingData( - final Matcher<View> adapterMatcher, - final Matcher<Object> dataMatcher, - final AdapterViewProtocol adapterViewProtocol, - final AdapterDataLoaderAction adapterDataLoaderAction) { - checkNotNull(adapterMatcher); - checkNotNull(dataMatcher); - checkNotNull(adapterViewProtocol); - - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText(" displaying data matching: "); - dataMatcher.describeTo(description); - description.appendText(" within adapter view matching: "); - adapterMatcher.describeTo(description); - } - - @SuppressWarnings("unchecked") - @Override - public boolean matchesSafely(View view) { - - ViewParent parent = view.getParent(); - - while (parent != null && !(parent instanceof AdapterView)) { - parent = parent.getParent(); - } - - if (parent != null && adapterMatcher.matches(parent)) { - Optional<AdaptedData> data = adapterViewProtocol.getDataRenderedByView( - (AdapterView<? extends Adapter>) parent, view); - if (data.isPresent()) { - return adapterDataLoaderAction.getAdaptedData().opaqueToken.equals( - data.get().opaqueToken); - } - } - return false; - } - }; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java deleted file mode 100644 index 5e3d5f4..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.pressMenuKey; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isRoot; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withClassName; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withContentDescription; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.endsWith; - -import com.google.android.apps.common.testing.ui.espresso.action.ViewActions; -import com.google.android.apps.common.testing.ui.espresso.base.BaseLayerModule; -import com.google.android.apps.common.testing.ui.espresso.base.IdlingResourceRegistry; -import com.google.android.apps.common.testing.ui.espresso.util.TreeIterables; - -import android.content.Context; -import android.os.Build; -import android.os.Looper; -import android.view.View; -import android.view.ViewConfiguration; - -import dagger.ObjectGraph; - -import org.hamcrest.Matcher; - -/** - * Entry point to the Espresso framework. Test authors can initiate testing by using one of the on* - * methods (e.g. onView) or perform top-level user actions (e.g. pressBack). - */ -public final class Espresso { - - static ObjectGraph espressoGraph() { - return GraphHolder.graph(); - } - - private Espresso() {} - - /** - * Creates an {@link PartiallyScopedViewInteraction} for a given view. Note: the view has - * to be part of the view hierarchy. This may not be the case if it is rendered as part of - * an AdapterView (e.g. ListView). If this is the case, use Espresso.onData to load the view - * first. - * - * @param viewMatcher used to select the view. - * @see #onData - */ - public static ViewInteraction onView(final Matcher<View> viewMatcher) { - return espressoGraph().plus(new ViewInteractionModule(viewMatcher)).get(ViewInteraction.class); - } - - - - /** - * Creates an {@link DataInteraction} for a data object displayed by the application. Use this - * method to load (into the view hierarchy) items from AdapterView widgets (e.g. ListView). - * - * @param dataMatcher a matcher used to find the data object. - */ - public static DataInteraction onData(Matcher<Object> dataMatcher) { - return new DataInteraction(dataMatcher); - } - - /** - * Registers a Looper for idle checking with the framework. This is intended for use with - * non-UI thread loopers. - * - * @throws IllegalArgumentException if looper is the main looper. - */ - public static void registerLooperAsIdlingResource(Looper looper) { - registerLooperAsIdlingResource(looper, false); - } - - /** - * Registers a Looper for idle checking with the framework. This is intended for use with - * non-UI thread loopers. - * - * This method allows the caller to consider Thread.State.WAIT to be 'idle'. - * - * This is useful in the case where a looper is sending a message to the UI thread synchronously - * through a wait/notify mechanism. - * - * @throws IllegalArgumentException if looper is the main looper. - */ - public static void registerLooperAsIdlingResource(Looper looper, boolean considerWaitIdle) { - espressoGraph().get(IdlingResourceRegistry.class).registerLooper(looper, considerWaitIdle); - } - - /** - * Registers one or more {@link IdlingResource}s with the framework. It is expected, although not - * strictly required, that this method will be called at test setup time prior to any interaction - * with the application under test. When registering more than one resource, ensure that each has - * a unique name. - */ - public static void registerIdlingResources(IdlingResource... resources) { - checkNotNull(resources); - IdlingResourceRegistry registry = espressoGraph().get(IdlingResourceRegistry.class); - for (IdlingResource resource : resources) { - checkNotNull(resource.getName(), "IdlingResource.getName() should not be null"); - registry.register(resource); - } - } - - /** - * Changes the default {@link FailureHandler} to the given one. - */ - public static void setFailureHandler(FailureHandler failureHandler) { - espressoGraph().get(BaseLayerModule.FailureHandlerHolder.class) - .update(checkNotNull(failureHandler)); - } - - /********************************** Top Level Actions ******************************************/ - - // Ideally, this should be only allOf(isDisplayed(), withContentDescription("More options")) - // But the ActionBarActivity compat lib is missing a content description for this element, so - // we add the class name matcher as another option to find the view. - @SuppressWarnings("unchecked") - private static final Matcher<View> OVERFLOW_BUTTON_MATCHER = anyOf( - allOf(isDisplayed(), withContentDescription("More options")), - allOf(isDisplayed(), withClassName(endsWith("OverflowMenuButton")))); - - - /** - * Closes soft keyboard if open. - */ - public static void closeSoftKeyboard() { - onView(isRoot()).perform(ViewActions.closeSoftKeyboard()); - } - - /** - * Opens the overflow menu displayed in the contextual options of an ActionMode. - * - * This works with both native and SherlockActionBar action modes. - * - * Note the significant difference in UX between ActionMode and ActionBar overflows - ActionMode - * will always present an overflow icon and that icon only responds to clicks. The menu button - * (if present) has no impact on it. - */ - @SuppressWarnings("unchecked") - public static void openContextualActionModeOverflowMenu() { - onView(isRoot()) - .perform(new TransitionBridgingViewAction()); - - onView(OVERFLOW_BUTTON_MATCHER) - .perform(click()); - } - - /** - * Press on the back button. - * - * @throws PerformException if currently displayed activity is root activity, since pressing back - * button would result in application closing. - */ - public static void pressBack() { - onView(isRoot()).perform(ViewActions.pressBack()); - } - - /** - * Opens the overflow menu displayed within an ActionBar. - * - * This works with both native and SherlockActionBar ActionBars. - * - * Note the significant differences of UX between ActionMode and ActionBars with respect to - * overflows. If a hardware menu key is present, the overflow icon is never displayed in - * ActionBars and can only be interacted with via menu key presses. - */ - @SuppressWarnings("unchecked") - public static void openActionBarOverflowOrOptionsMenu(Context context) { - if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) { - // regardless of the os level of the device, this app will be rendering a menukey - // in the virtual navigation bar (if present) or responding to hardware option keys on - // any activity. - onView(isRoot()) - .perform(pressMenuKey()); - } else if (hasVirtualOverflowButton(context)) { - // If we're using virtual keys - theres a chance we're in mid animation of switching - // between a contextual action bar and the non-contextual action bar. In this case there - // are 2 'More Options' buttons present. Lets wait till that is no longer the case. - onView(isRoot()) - .perform(new TransitionBridgingViewAction()); - - onView(OVERFLOW_BUTTON_MATCHER) - .perform(click()); - } else { - // either a hardware button exists, or we're on a pre-HC os. - onView(isRoot()) - .perform(pressMenuKey()); - } - } - - private static boolean hasVirtualOverflowButton(Context context) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; - } else { - return !ViewConfiguration.get(context).hasPermanentMenuKey(); - } - } - - /** - * Handles the cases where the app is transitioning between a contextual action bar and a - * non contextual action bar. - */ - private static class TransitionBridgingViewAction implements ViewAction { - @Override - public void perform(UiController controller, View view) { - int loops = 0; - while (isTransitioningBetweenActionBars(view) && loops < 100) { - loops++; - controller.loopMainThreadForAtLeast(50); - } - // if we're not transitioning properly the next viewaction - // will give a decent enough exception. - } - - @Override - public String getDescription() { - return "Handle transition between action bar and action bar context."; - } - - @Override - public Matcher<View> getConstraints() { - return isRoot(); - } - - private boolean isTransitioningBetweenActionBars(View view) { - int actionButtonCount = 0; - for (View child : TreeIterables.breadthFirstViewTraversal(view)) { - if (OVERFLOW_BUTTON_MATCHER.matches(child)) { - actionButtonCount++; - } - } - return actionButtonCount > 1; - } - } - - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/EspressoException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/EspressoException.java deleted file mode 100644 index 4c6a5a2..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/EspressoException.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -/** - * Used for identifying an exception as coming from the {@link Espresso} framework. - */ -public interface EspressoException {} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/FailureHandler.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/FailureHandler.java deleted file mode 100644 index e0fb9c0..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/FailureHandler.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import android.view.View; - -import org.hamcrest.Matcher; - - - -/** - * Handles failures that happen during test execution. - */ -public interface FailureHandler { - - /** - * Handle the given error in a manner that makes sense to the environment in which the test is - * executed (e.g. take a screenshot, output extra debug info, etc). Upon handling, most handlers - * will choose to propagate the error. - */ - public void handle(Throwable error, Matcher<View> viewMatcher); - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/GraphHolder.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/GraphHolder.java deleted file mode 100644 index 3ee8e55..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/GraphHolder.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import com.google.android.apps.common.testing.testrunner.UsageTrackerRegistry; -import com.google.android.apps.common.testing.ui.espresso.base.BaseLayerModule; -import com.google.android.apps.common.testing.ui.espresso.base.IdlingResourceRegistry; - -import dagger.Module; -import dagger.ObjectGraph; - -import java.util.concurrent.atomic.AtomicReference; - -/** - * Holds Espresso's ObjectGraph. - */ -public final class GraphHolder { - - private static final AtomicReference<GraphHolder> instance = - new AtomicReference<GraphHolder>(null); - - private final ObjectGraph graph; - - private GraphHolder(ObjectGraph graph) { - this.graph = checkNotNull(graph); - } - - static ObjectGraph graph() { - GraphHolder instanceRef = instance.get(); - if (null == instanceRef) { - instanceRef = new GraphHolder(ObjectGraph.create(EspressoModule.class)); - if (instance.compareAndSet(null, instanceRef)) { - UsageTrackerRegistry.getInstance().trackUsage("Espresso"); - return instanceRef.graph; - } else { - return instance.get().graph; - } - } else { - return instanceRef.graph; - } - } - - // moe:begin_strip - public static void initialize(Object... modules) { - checkNotNull(modules); - Object[] allModules = new Object[modules.length + 1]; - allModules[0] = EspressoModule.class; - System.arraycopy(modules, 0, allModules, 1, modules.length); - GraphHolder holder = new GraphHolder(ObjectGraph.create(modules)); - checkState(instance.compareAndSet(null, holder), "Espresso already initialized."); - } - // moe:end_strip - - @Module( - includes = BaseLayerModule.class, - injects = IdlingResourceRegistry.class - ) - static class EspressoModule { - } - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingPolicies.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingPolicies.java deleted file mode 100644 index 17fdc8d..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingPolicies.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.concurrent.TimeUnit; - -/** - * Allows users fine grain control over idling policies. - * - * Espresso's default idling policies are suitable for most usecases - however - * certain execution environments (like the ARM emulator) might be very slow. - * This class allows users the ability to adjust defaults to sensible values - * for their environments. - */ -public final class IdlingPolicies { - - private IdlingPolicies() { } - - private static volatile IdlingPolicy masterIdlingPolicy = new IdlingPolicy.Builder() - .withIdlingTimeout(60) - .withIdlingTimeoutUnit(TimeUnit.SECONDS) - .throwAppNotIdleException() - .build(); - - - private static volatile IdlingPolicy dynamicIdlingResourceErrorPolicy = new IdlingPolicy.Builder() - .withIdlingTimeout(26) - .withIdlingTimeoutUnit(TimeUnit.SECONDS) - .throwIdlingResourceTimeoutException() - .build(); - - private static volatile IdlingPolicy dynamicIdlingResourceWarningPolicy = - new IdlingPolicy.Builder() - .withIdlingTimeout(5) - .withIdlingTimeoutUnit(TimeUnit.SECONDS) - .logWarning() - .build(); - - - /** - * Updates the IdlingPolicy used in UiController.loopUntil to detect AppNotIdleExceptions. - * - * @param timeout the timeout before an AppNotIdleException is created. - * @param unit the unit of the timeout value. - */ - public static void setMasterPolicyTimeout(long timeout, TimeUnit unit) { - checkArgument(timeout > 0); - checkNotNull(unit); - masterIdlingPolicy = masterIdlingPolicy.toBuilder() - .withIdlingTimeout(timeout) - .withIdlingTimeoutUnit(unit) - .build(); - } - - /** - * Updates the IdlingPolicy used by IdlingResourceRegistry to determine when IdlingResources - * timeout. - * - * @param timeout the timeout before an IdlingResourceTimeoutException is created. - * @param unit the unit of the timeout value. - */ - public static void setIdlingResourceTimeout(long timeout, TimeUnit unit) { - checkArgument(timeout > 0); - checkNotNull(unit); - dynamicIdlingResourceErrorPolicy = dynamicIdlingResourceErrorPolicy.toBuilder() - .withIdlingTimeout(timeout) - .withIdlingTimeoutUnit(unit) - .build(); - } - - - public static IdlingPolicy getMasterIdlingPolicy() { - return masterIdlingPolicy; - } - - public static IdlingPolicy getDynamicIdlingResourceWarningPolicy() { - return dynamicIdlingResourceWarningPolicy; - } - - public static IdlingPolicy getDynamicIdlingResourceErrorPolicy() { - return dynamicIdlingResourceErrorPolicy; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingPolicy.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingPolicy.java deleted file mode 100644 index 533afdd..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingPolicy.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import android.util.Log; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Allows users to control idling idleTimeouts in Espresso. - */ -public final class IdlingPolicy { - private static final String TAG = "IdlingPolicy"; - private enum ResponseAction { THROW_APP_NOT_IDLE, THROW_IDLE_TIMEOUT, LOG_ERROR }; - - private final long idleTimeout; - private final TimeUnit unit; - private final ResponseAction errorHandler; - - /** - * The amount of time the policy allows a resource to be non-idle. - */ - public long getIdleTimeout(){ - return idleTimeout; - } - - /** - * The unit for {@linkgetIdleTimeout}. - */ - public TimeUnit getIdleTimeoutUnit() { - return unit; - } - - /** - * Invoked when the idle idleTimeout has been exceeded. - * - * @param busyResources the resources that are not idle. - * @param message an additional message to include in an exception. - */ - public void handleTimeout(List<String> busyResources, String message) { - switch (errorHandler) { - case THROW_APP_NOT_IDLE: - throw AppNotIdleException.create(busyResources, message); - case THROW_IDLE_TIMEOUT: - throw new IdlingResourceTimeoutException(busyResources); - case LOG_ERROR: - Log.w(TAG, "These resources are not idle: " + busyResources); - break; - default: - throw new IllegalStateException("should never reach here." + busyResources); - } - } - - Builder toBuilder() { - return new Builder(this); - } - - private IdlingPolicy(Builder builder) { - checkArgument(builder.idleTimeout > 0); - this.idleTimeout = builder.idleTimeout; - this.unit = checkNotNull(builder.unit); - this.errorHandler = checkNotNull(builder.errorHandler); - } - - static class Builder { - private long idleTimeout = -1; - private TimeUnit unit = null; - private ResponseAction errorHandler = null; - - public Builder() { } - - public IdlingPolicy build() { - return new IdlingPolicy(this); - } - - private Builder(IdlingPolicy copy) { - this.idleTimeout = copy.idleTimeout; - this.unit = copy.unit; - this.errorHandler = copy.errorHandler; - } - - public Builder withIdlingTimeout(long idleTimeout) { - this.idleTimeout = idleTimeout; - return this; - } - - public Builder withIdlingTimeoutUnit(TimeUnit unit) { - this.unit = unit; - return this; - } - - public Builder throwAppNotIdleException() { - this.errorHandler = ResponseAction.THROW_APP_NOT_IDLE; - return this; - } - - public Builder throwIdlingResourceTimeoutException() { - this.errorHandler = ResponseAction.THROW_IDLE_TIMEOUT; - return this; - } - - public Builder logWarning() { - this.errorHandler = ResponseAction.LOG_ERROR; - return this; - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingResourceTimeoutException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingResourceTimeoutException.java deleted file mode 100644 index 6a9ec69..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingResourceTimeoutException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.List; - -/** - * Indicates that an {@link IdlingResource}, which has been registered with the framework, has not - * idled within the allowed time. - * - * Since it is not safe to proceed with test execution while the registered resource is busy (as it - * is likely to cause inconsistent results in the test), this is an unrecoverable error. The test - * author should verify that the {@link IdlingResource} interface has been implemented correctly. - */ -public final class IdlingResourceTimeoutException extends RuntimeException - implements EspressoException { - - public IdlingResourceTimeoutException(List<String> resourceNames) { - super(String.format("Wait for %s to become idle timed out", checkNotNull(resourceNames))); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/InjectEventSecurityException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/InjectEventSecurityException.java deleted file mode 100644 index 5e6158e..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/InjectEventSecurityException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -/** - * An checked {@link Exception} indicating that event injection failed with a - * {@link SecurityException}. - */ -public final class InjectEventSecurityException extends Exception implements EspressoException { - - public InjectEventSecurityException(String message) { - super(message); - } - - public InjectEventSecurityException(Throwable cause) { - super(cause); - } - - public InjectEventSecurityException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoActivityResumedException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoActivityResumedException.java deleted file mode 100644 index 77f1c03..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoActivityResumedException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -/** - * An exception which indicates that there are no activities in stage RESUMED. - */ -public final class NoActivityResumedException extends RuntimeException - implements EspressoException { - public NoActivityResumedException(String description) { - super(description); - } - - public NoActivityResumedException(String description, Throwable cause) { - super(description, cause); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingRootException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingRootException.java deleted file mode 100644 index 9b02aa6..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingRootException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkNotNull; - -import org.hamcrest.Matcher; - -import java.util.List; - -/** - * Indicates that a given matcher did not match any {@link Root}s (windows) from those that are - * currently available. - */ -public final class NoMatchingRootException extends RuntimeException implements EspressoException { - - private NoMatchingRootException(String description) { - super(description); - } - - public static NoMatchingRootException create(Matcher<Root> rootMatcher, List<Root> roots) { - checkNotNull(rootMatcher); - checkNotNull(roots); - return new NoMatchingRootException(String.format( - "Matcher '%s' did not match any of the following roots: %s", rootMatcher, roots)); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingViewException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingViewException.java deleted file mode 100644 index 984f206..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/NoMatchingViewException.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.common.base.Optional; -import com.google.common.collect.Lists; - -import android.view.View; - -import org.hamcrest.Matcher; - -import java.util.List; - -/** - * Indicates that a given matcher did not match any elements in the view hierarchy. - * <p> - * Contains details about the matcher and the current view hierarchy to aid in debugging. - * </p> - * <p> - * Since this is usually an unrecoverable error this exception is a runtime exception. - * </p> - * <p> - * References to the view and failing matcher are purposefully not included in the state of this - * object - since it will most likely be created on the UI thread and thrown on the instrumentation - * thread, it would be invalid to touch the view on the instrumentation thread. Also the view - * hierarchy may have changed since exception creation (leading to more confusion). - * </p> - */ -public final class NoMatchingViewException extends RuntimeException implements EspressoException { - - private Matcher<? super View> viewMatcher; - private View rootView; - private List<View> adapterViews = Lists.newArrayList(); - private boolean includeViewHierarchy = true; - private Optional<String> adapterViewWarning = Optional.<String>absent(); - - private NoMatchingViewException(String description) { - super(description); - } - - private NoMatchingViewException(Builder builder) { - super(getErrorMessage(builder)); - this.viewMatcher = builder.viewMatcher; - this.rootView = builder.rootView; - this.adapterViews = builder.adapterViews; - this.adapterViewWarning = builder.adapterViewWarning; - this.includeViewHierarchy = builder.includeViewHierarchy; - } - - private static String getErrorMessage(Builder builder) { - String errorMessage = ""; - if (builder.includeViewHierarchy) { - String message = String.format("No views in hierarchy found matching: %s", - builder.viewMatcher); - if (builder.adapterViewWarning.isPresent()) { - message = message + builder.adapterViewWarning.get(); - } - errorMessage = HumanReadables.getViewHierarchyErrorMessage(builder.rootView, - null /* problemViews */, - message, - null /* problemViewSuffix */); - } else { - errorMessage = String.format("Could not find a view that matches %s" , builder.viewMatcher); - } - return errorMessage; - } - - /** Builder for {@link NoMatchingViewException}. */ - public static class Builder { - - private Matcher<? super View> viewMatcher; - private View rootView; - private List<View> adapterViews = Lists.newArrayList(); - private boolean includeViewHierarchy = true; - private Optional<String> adapterViewWarning = Optional.<String>absent(); - - public Builder from(NoMatchingViewException exception) { - this.viewMatcher = exception.viewMatcher; - this.rootView = exception.rootView; - this.adapterViews = exception.adapterViews; - this.adapterViewWarning = exception.adapterViewWarning; - this.includeViewHierarchy = exception.includeViewHierarchy; - return this; - } - - public Builder withViewMatcher(Matcher<? super View> viewMatcher) { - this.viewMatcher = viewMatcher; - return this; - } - - public Builder withRootView(View rootView) { - this.rootView = rootView; - return this; - } - - public Builder withAdapterViews(List<View> adapterViews) { - this.adapterViews = adapterViews; - return this; - } - - public Builder includeViewHierarchy(boolean includeViewHierarchy) { - this.includeViewHierarchy = includeViewHierarchy; - return this; - } - - public Builder withAdapterViewWarning(Optional<String> adapterViewWarning) { - this.adapterViewWarning = adapterViewWarning; - return this; - } - - public NoMatchingViewException build() { - checkNotNull(viewMatcher); - checkNotNull(rootView); - checkNotNull(adapterViews); - checkNotNull(adapterViewWarning); - return new NoMatchingViewException(this); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/PerformException.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/PerformException.java deleted file mode 100644 index ac18e77..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/PerformException.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Indicates that an exception occurred while performing a ViewAction on the UI thread. - * - * A description of the {@link ViewAction}, the view being performed on and the cause are included - * in the error. Note: {@link FailureHandler}s can mutate the exception later to make it more user - * friendly. - * - * This is generally not recoverable so it is thrown on the instrumentation thread. - */ -public final class PerformException extends RuntimeException implements EspressoException { - - private static final String MESSAGE_FORMAT = "Error performing '%s' on view '%s'."; - - private final String actionDescription; - private final String viewDescription; - - private PerformException(Builder builder) { - super(String.format(MESSAGE_FORMAT, builder.actionDescription, builder.viewDescription), - builder.cause); - this.actionDescription = checkNotNull(builder.actionDescription); - this.viewDescription = checkNotNull(builder.viewDescription); - } - - public String getActionDescription() { - return actionDescription; - } - - public String getViewDescription() { - return viewDescription; - } - - /** - * Builder for {@link PerformException}. - */ - public static class Builder { - private String actionDescription; - private String viewDescription; - private Throwable cause; - - public Builder from(PerformException instance) { - this.actionDescription = instance.getActionDescription(); - this.viewDescription = instance.getViewDescription(); - this.cause = instance.getCause(); - return this; - } - - public Builder withActionDescription(String actionDescription) { - this.actionDescription = actionDescription; - return this; - } - - public Builder withViewDescription(String viewDescription) { - this.viewDescription = viewDescription; - return this; - } - - public Builder withCause(Throwable cause) { - this.cause = cause; - return this; - } - - public PerformException build() { - return new PerformException(this); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Root.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Root.java deleted file mode 100644 index 0d900de..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Root.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Objects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.common.base.Objects.ToStringHelper; -import com.google.common.base.Optional; - -import android.view.View; -import android.view.WindowManager; - -/** - * Represents a root view in the application and optionally the layout params of the window holding - * it. - * - * This class is used internally to determine which view root to run user provided matchers against - * it is not part of the public api. - */ -public final class Root { - private final View decorView; - private final Optional<WindowManager.LayoutParams> windowLayoutParams; - - private Root(Builder builder) { - this.decorView = checkNotNull(builder.decorView); - this.windowLayoutParams = Optional.fromNullable(builder.windowLayoutParams); - } - - public View getDecorView() { - return decorView; - } - - public Optional<WindowManager.LayoutParams> getWindowLayoutParams() { - return windowLayoutParams; - } - - @Override - public String toString() { - ToStringHelper helper = toStringHelper(this) - .add("application-window-token", decorView.getApplicationWindowToken()) - .add("window-token", decorView.getWindowToken()) - .add("has-window-focus", decorView.hasWindowFocus()); - if (windowLayoutParams.isPresent()) { - helper - .add("layout-params-type", windowLayoutParams.get().type) - .add("layout-params-string", windowLayoutParams.get()); - } - helper - .add("decor-view-string", HumanReadables.describe(decorView)); - return helper.toString(); - } - - public static class Builder { - private View decorView; - private WindowManager.LayoutParams windowLayoutParams; - - public Root build() { - return new Root(this); - } - - public Builder withDecorView(View view) { - this.decorView = view; - return this; - } - - public Builder withWindowLayoutParams(WindowManager.LayoutParams windowLayoutParams) { - this.windowLayoutParams = windowLayoutParams; - return this; - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/UiController.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/UiController.java deleted file mode 100644 index cf53d08..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/UiController.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import android.view.KeyEvent; -import android.view.MotionEvent; - -/** - * Provides base-level UI operations (such as injection of {@link MotionEvent}s) that can be used to - * build user actions such as clicks, scrolls, swipes, etc. This replaces parts of the android - * Instrumentation class that provides similar functionality. However, it provides a more advanced - * synchronization mechanism for test actions. The key differentiators are: - * <ul> - * <li>test actions are assumed to be called on the main thread - * <li>after a test action is initiated, execution blocks until all messages in the main message - * queue have been cleared. - * </ul> - */ -public interface UiController { - /** - * Injects a motion event into the application. - * - * @param event the (non-null!) event to inject - * @return true if the event was injected, false otherwise - * @throws InjectEventSecurityException if the event couldn't be injected because it would - * interact with another application. - */ - boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException; - - /** - * Injects a key event into the application. - * - * @param event the (non-null!) event to inject - * @return true if the event was injected, false otherwise - * @throws InjectEventSecurityException if the event couldn't be injected because it would - * interact with another application. - */ - boolean injectKeyEvent(KeyEvent event) throws InjectEventSecurityException; - - /** - * Types a string into the application using series of {@link KeyEvent}s. It is up to the - * implementor to decide how to map the string to {@link KeyEvent} objects. if you need specific - * control over the key events generated use {@link #injectKeyEvent(KeyEvent)}. - * - * @param str the (non-null!) string to type - * @return true if the string was injected, false otherwise - * @throws InjectEventSecurityException if the events couldn't be injected because it would - * interact with another application. - */ - boolean injectString(String str) throws InjectEventSecurityException; - - /** - * Loops the main thread until the application goes idle. - * - * An empty task is immediately inserted into the task queue to ensure that if we're idle at this - * moment we'll return instantly. - */ - void loopMainThreadUntilIdle(); - - /** - * Loops the main thread for a specified period of time. - * - * Control may not return immediately, instead it'll return after the time has passed and the - * queue is in an idle state again. - * - * @param millisDelay time to spend in looping the main thread - */ - void loopMainThreadForAtLeast(long millisDelay); -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewAction.java deleted file mode 100644 index 12e607e..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewAction.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import android.view.View; - -import org.hamcrest.Matcher; - -/** - * Responsible for performing an interaction on the given View element.<br> - * <p> - * This is part of the test framework public API - developers are free to write their own ViewAction - * implementations when necessary. When implementing a new ViewAction, follow these rules: - * <ul> - * <li>Inject motion events or key events via the UiController to simulate user interactions. - * <li>Do not mutate the view directly via setter methods and other state changing methods on the - * view parameter. - * <li>Do not throw AssertionErrors. Assertions belong in ViewAssertion classes. - * <li>View action code will executed on the UI thread, therefore you should not block, perform - * sleeps, or perform other expensive computations. - * <li>The test framework will wait for the UI thread to be idle both before and after perform() is - * called. This means that the action is guaranteed to be synchronized with any other view - * operations. - * <li>Downcasting the View object to an expected subtype is allowed, so long as the object - * expresses the subtype matches the constraints as specified in {@code getConstraints}. - * </ul> - */ -public interface ViewAction { - - /** - * A mechanism for ViewActions to specify what type of views they can operate on. - * - * A ViewAction can demand that the view passed to perform meets certain constraints. For example - * it may want to ensure the view is already in the viewable physical screen of the device or is - * of a certain type. - * - * @return a {@link Matcher} that will be tested prior to calling perform. - */ - public Matcher<View> getConstraints(); - - /** - * Returns a description of the view action. The description should not be overly long and should - * fit nicely in a sentence like: "performing %description% action on view with id ..." - */ - public String getDescription(); - - /** - * Performs this action on the given view. - * - * @param uiController the controller to use to interact with the UI. - * @param view the view to act upon. never null. - */ - public void perform(UiController uiController, View view); -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewAssertion.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewAssertion.java deleted file mode 100644 index 9329b57..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewAssertion.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import android.view.View; - -import javax.annotation.Nullable; - -/** - * Responsible for performing assertions on a View element.<br> - * <p> - * This is considered part of the test framework public API - developers are free to write their own - * assertions as long as they meet the following requirements: - * <ul> - * <li>Do not mutate the passed in view. - * <li>Throw junit.framework.AssertionError when the view assertion does not hold. - * <li>Implementation runs on the UI thread - so it should not do any blocking operations - * <li>Downcasting the view to a specific type is allowed, provided there is a test that view is an - * instance of that type before downcasting. If not, an AssertionError should be thrown. - * <li>It is encouraged to access non-mutating methods on the view to perform assertion. - * </ul> - * <br> - * <p> - * Strongly consider using a existing ViewAssertion via the ViewAssertions utility class before - * writing your own assertion. - */ -public interface ViewAssertion { - - /** - * Checks the state of the given view (if such a view is present). - * - * @param view the view, if one was found during the view interaction or null if it was not - * (which may be an acceptable option for an assertion) - * @param noViewFoundException an exception detailing why the view could not be found or null if - * the view was found - */ - void check(@Nullable View view, @Nullable NoMatchingViewException noViewFoundException); -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewFinder.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewFinder.java deleted file mode 100644 index 31e0d11..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewFinder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import android.view.View; - -/** - * Uses matchers to locate particular views within the view hierarchy. - */ -public interface ViewFinder { - - /** - * Immediately locates a single view within the provided view hierarchy. - * - * If multiple views match, or if no views match the appropriate exception is thrown. - * - * @return A singular view which matches the matcher we were constructed with. - * @throws AmbiguousViewMatcherException when multiple views match - * @throws NoMatchingViewException when no views match. - */ - public View getView() throws AmbiguousViewMatcherException, NoMatchingViewException; -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java deleted file mode 100644 index 5207083..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDescendantOfA; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.action.ScrollToAction; -import com.google.android.apps.common.testing.ui.espresso.base.MainThread; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; - -import android.util.Log; -import android.view.View; -import android.widget.AdapterView; - -import org.hamcrest.Matcher; -import org.hamcrest.StringDescription; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.FutureTask; -import java.util.concurrent.atomic.AtomicReference; - -import javax.inject.Inject; - -/** - * Provides the primary interface for test authors to perform actions or asserts on views. - * <p> - * Each interaction is associated with a view identified by a view matcher. All view actions and - * asserts are performed on the UI thread (thus ensuring sequential execution). The same goes for - * retrieval of views (this is done to ensure that view state is "fresh" prior to execution of each - * operation). - * <p> - */ -public final class ViewInteraction { - - private static final String TAG = ViewInteraction.class.getSimpleName(); - - private final UiController uiController; - private final ViewFinder viewFinder; - private final Executor mainThreadExecutor; - private final FailureHandler failureHandler; - private final Matcher<View> viewMatcher; - private final AtomicReference<Matcher<Root>> rootMatcherRef; - - @Inject - ViewInteraction( - UiController uiController, - ViewFinder viewFinder, - @MainThread Executor mainThreadExecutor, - FailureHandler failureHandler, - Matcher<View> viewMatcher, - AtomicReference<Matcher<Root>> rootMatcherRef) { - this.viewFinder = checkNotNull(viewFinder); - this.uiController = checkNotNull(uiController); - this.failureHandler = checkNotNull(failureHandler); - this.mainThreadExecutor = checkNotNull(mainThreadExecutor); - this.viewMatcher = checkNotNull(viewMatcher); - this.rootMatcherRef = checkNotNull(rootMatcherRef); - } - - /** - * Performs the given action(s) on the view selected by the current view matcher. If more than one - * action is provided, actions are executed in the order provided with precondition checks running - * prior to each action. - * - * @param viewActions one or more actions to execute. - * @return this interaction for further perform/verification calls. - */ - public ViewInteraction perform(final ViewAction... viewActions) { - checkNotNull(viewActions); - for (ViewAction action : viewActions) { - doPerform(action); - } - return this; - } - - - /** - * Makes this ViewInteraction scoped to the root selected by the given root matcher. - */ - public ViewInteraction inRoot(Matcher<Root> rootMatcher) { - this.rootMatcherRef.set(checkNotNull(rootMatcher)); - return this; - } - - private void doPerform(final ViewAction viewAction) { - checkNotNull(viewAction); - final Matcher<? extends View> constraints = checkNotNull(viewAction.getConstraints()); - runSynchronouslyOnUiThread(new Runnable() { - - @Override - public void run() { - uiController.loopMainThreadUntilIdle(); - View targetView = viewFinder.getView(); - Log.i(TAG, String.format( - "Performing '%s' action on view %s", viewAction.getDescription(), viewMatcher)); - if (!constraints.matches(targetView)) { - // TODO(valeraz): update this to describeMismatch once hamcrest is updated to new - // version in google3 (we are waiting for version 1.4 to avoid issues with generics) - StringDescription stringDescription = new StringDescription(new StringBuilder( - "Action will not be performed because the target view " - + "does not match one or more of the following constraints:\n")); - constraints.describeTo(stringDescription); - stringDescription.appendText("\nTarget view: ") - .appendValue(HumanReadables.describe(targetView)); - - if (viewAction instanceof ScrollToAction - && isDescendantOfA(isAssignableFrom((AdapterView.class))).matches(targetView)) { - stringDescription.appendText( - "\nFurther Info: ScrollToAction on a view inside an AdapterView will not work. " - + "Use Espresso.onData to load the view."); - } - throw new PerformException.Builder() - .withActionDescription(viewAction.getDescription()) - .withViewDescription(viewMatcher.toString()) - .withCause(new RuntimeException(stringDescription.toString())) - .build(); - } else { - viewAction.perform(uiController, targetView); - } - } - }); - } - - /** - * Checks the given {@link ViewAssertion} on the the view selected by the current view matcher. - * - * @param viewAssert the assertion to perform. - * @return this interaction for further perform/verification calls. - */ - public ViewInteraction check(final ViewAssertion viewAssert) { - checkNotNull(viewAssert); - runSynchronouslyOnUiThread(new Runnable() { - @Override - public void run() { - uiController.loopMainThreadUntilIdle(); - - View targetView = null; - NoMatchingViewException missingViewException = null; - try { - targetView = viewFinder.getView(); - } catch (NoMatchingViewException nsve) { - missingViewException = nsve; - } - viewAssert.check(targetView, missingViewException); - } - }); - return this; - } - - private void runSynchronouslyOnUiThread(Runnable action) { - FutureTask<Void> uiTask = new FutureTask<Void>(action, null); - mainThreadExecutor.execute(uiTask); - try { - uiTask.get(); - } catch (InterruptedException ie) { - throw new RuntimeException("Interrupted running UI task", ie); - } catch (ExecutionException ee) { - failureHandler.handle(ee.getCause(), viewMatcher); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java deleted file mode 100644 index 30eccc9..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.base.RootViewPicker; -import com.google.android.apps.common.testing.ui.espresso.base.ViewFinderImpl; -import com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers; - -import android.view.View; - -import dagger.Module; -import dagger.Provides; - -import org.hamcrest.Matcher; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Adds the user interaction scope to the Espresso graph. - */ -@Module( - addsTo = GraphHolder.EspressoModule.class, - injects = {ViewInteraction.class}) -class ViewInteractionModule { - - private final Matcher<View> viewMatcher; - private final AtomicReference<Matcher<Root>> rootMatcher = - new AtomicReference<Matcher<Root>>(RootMatchers.DEFAULT); - - ViewInteractionModule(Matcher<View> viewMatcher) { - this.viewMatcher = checkNotNull(viewMatcher); - } - - @Provides - AtomicReference<Matcher<Root>> provideRootMatcher() { - return rootMatcher; - } - - @Provides - Matcher<View> provideViewMatcher() { - return viewMatcher; - } - - @Provides - ViewFinder provideViewFinder(ViewFinderImpl impl) { - return impl; - } - - @Provides - public View provideRootView(RootViewPicker rootViewPicker) { - // RootsOracle acts as a provider, but returning Providers is illegal, so delegate. - return rootViewPicker.get(); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterDataLoaderAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterDataLoaderAction.java deleted file mode 100644 index d682f6b..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterDataLoaderAction.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static org.hamcrest.Matchers.allOf; - -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.common.base.Optional; -import com.google.common.collect.Lists; - -import android.view.View; -import android.widget.Adapter; -import android.widget.AdapterView; - -import org.hamcrest.Matcher; -import org.hamcrest.StringDescription; - -import java.util.List; - -/** - * Forces an AdapterView to ensure that the data matching a provided data matcher - * is loaded into the current view hierarchy. - * - */ -public final class AdapterDataLoaderAction implements ViewAction { - private final Matcher<Object> dataToLoadMatcher; - private final AdapterViewProtocol adapterViewProtocol; - private final Optional<Integer> atPosition; - private AdapterViewProtocol.AdaptedData adaptedData; - private boolean performed = false; - private Object dataLock = new Object(); - - public AdapterDataLoaderAction(Matcher<Object> dataToLoadMatcher, Optional<Integer> atPosition, - AdapterViewProtocol adapterViewProtocol) { - this.dataToLoadMatcher = checkNotNull(dataToLoadMatcher); - this.atPosition = checkNotNull(atPosition); - this.adapterViewProtocol = checkNotNull(adapterViewProtocol); - } - - public AdapterViewProtocol.AdaptedData getAdaptedData() { - synchronized (dataLock) { - checkState(performed, "perform hasn't been called yet!"); - return adaptedData; - } - } - - @SuppressWarnings("unchecked") - @Override - public Matcher<View> getConstraints() { - return allOf(isAssignableFrom(AdapterView.class), isDisplayed()); - } - - @SuppressWarnings("unchecked") - @Override - public void perform(UiController uiController, View view) { - AdapterView<? extends Adapter> adapterView = (AdapterView<? extends Adapter>) view; - List<AdapterViewProtocol.AdaptedData> matchedDataItems = Lists.newArrayList(); - - for (AdapterViewProtocol.AdaptedData data : adapterViewProtocol.getDataInAdapterView( - adapterView)) { - - if (dataToLoadMatcher.matches(data.data)) { - matchedDataItems.add(data); - } - } - - if (matchedDataItems.size() == 0) { - StringDescription dataMatcherDescription = new StringDescription(); - dataToLoadMatcher.describeTo(dataMatcherDescription); - - if (matchedDataItems.isEmpty()) { - dataMatcherDescription.appendText(" contained values: "); - dataMatcherDescription.appendValue( - adapterViewProtocol.getDataInAdapterView(adapterView)); - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException("No data found matching: " + dataMatcherDescription)) - .build(); - } - } - - synchronized (dataLock) { - checkState(!performed, "perform called 2x!"); - performed = true; - if (atPosition.isPresent()) { - int matchedDataItemsSize = matchedDataItems.size() - 1; - if (atPosition.get() > matchedDataItemsSize) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException(String.format( - "There are only %d elements that matched but requested %d element.", - matchedDataItemsSize, atPosition.get()))) - .build(); - } else { - adaptedData = matchedDataItems.get(atPosition.get()); - } - } else { - if (matchedDataItems.size() != 1) { - StringDescription dataMatcherDescription = new StringDescription(); - dataToLoadMatcher.describeTo(dataMatcherDescription); - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException("Multiple data elements " + - "matched: " + dataMatcherDescription + ". Elements: " + matchedDataItems)) - .build(); - } else { - adaptedData = matchedDataItems.get(0); - } - } - } - - int requestCount = 0; - while (!adapterViewProtocol.isDataRenderedWithinAdapterView(adapterView, adaptedData)) { - if (requestCount > 1) { - if ((requestCount % 50) == 0) { - // sometimes an adapter view will receive an event that will block its attempts to scroll. - adapterView.invalidate(); - adapterViewProtocol.makeDataRenderedWithinAdapterView(adapterView, adaptedData); - } - } else { - adapterViewProtocol.makeDataRenderedWithinAdapterView(adapterView, adaptedData); - } - uiController.loopMainThreadForAtLeast(100); - requestCount++; - } - } - - @Override - public String getDescription() { - return "load adapter data"; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterViewProtocol.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterViewProtocol.java deleted file mode 100644 index c85a76d..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterViewProtocol.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.Optional; - -import android.view.View; -import android.widget.Adapter; -import android.widget.AdapterView; - -import javax.annotation.Nullable; - -/** - * A sadly necessary layer of indirection to interact with AdapterViews. - * <p> - * Generally any subclass should respect the contracts and behaviors of its superclass. Otherwise - * it becomes impossible to work generically with objects that all claim to share a supertype - you - * need special cases to perform the same operation 'owned' by the supertype for each sub-type. The - * 'is - a' relationship is broken. - * </p> - * - * <p> - * Android breaks the Liskov substitution principal with ExpandableListView - you can't use - * getAdapter(), getItemAtPosition(), and other methods common to AdapterViews on an - * ExpandableListView because an ExpandableListView isn't an adapterView - they just share a lot of - * code. - * </p> - * - * <p> - * This interface exists to work around this wart (which sadly is copied in other projects too) and - * lets the implementor translate Espresso's needs and manipulations of the AdapterView into calls - * that make sense for the given subtype and context. - * </p> - * - * <p><i> - * If you have to implement this to talk to widgets your own project defines - I'm sorry. - * </i><p> - * - */ -public interface AdapterViewProtocol { - - /** - * Returns all data this AdapterViewProtocol can find within the given AdapterView. - * - * <p> - * Any AdaptedData returned by this method can be passed to makeDataRenderedWithinView and the - * implementation should make the AdapterView bring that data item onto the screen. - * </p> - * - * @param adapterView the AdapterView we want to interrogate the contents of. - * @return an {@link Iterable} of AdaptedDatas representing all data the implementation sees in - * this view - * @throws IllegalArgumentException if the implementation doesn't know how to manipulate the given - * adapter view. - */ - Iterable<AdaptedData> getDataInAdapterView(AdapterView<? extends Adapter> adapterView); - - /** - * Returns the data object this particular view is rendering if possible. - * - * <p> - * Implementations are expected to create a relationship between the data in the AdapterView and - * the descendant views of the AdapterView that obeys the following conditions: - * </p> - * - * <ul> - * <li>For each descendant view there exists either 0 or 1 data objects it is rendering.</li> - * <li>For each data object the AdapterView there exists either 0 or 1 descendant views which - * claim to be rendering it.</li> - * </ul> - * - * <p> For example - if a PersonObject is rendered into: </p> - * <code> - * LinearLayout - * ImageView picture - * TextView firstName - * TextView lastName - * </code> - * - * <p> - * It would be expected that getDataRenderedByView(adapter, LinearLayout) would return the - * PersonObject. If it were called instead with the TextView or ImageView it would return - * Object.absent(). - * </p> - * - * @param adapterView the adapterview hosting the data. - * @param descendantView a view which is a child, grand-child, or deeper descendant of adapterView - * @return an optional data object the descendant view is rendering. - * @throws IllegalArgumentException if this protocol cannot interrogate this class of adapterView - */ - Optional<AdaptedData> getDataRenderedByView( - AdapterView<? extends Adapter> adapterView, View descendantView); - - /** - * Requests that a particular piece of data held in this AdapterView is actually rendered by it. - * - * <p> - * After calling this method it expected that there will exist some descendant view of adapterView - * for which calling getDataRenderedByView(adapterView, descView).get() == data.data is true. - * <p> - * - * </p> - * Note: this need not happen immediately. EG: an implementor handling ListView may call - * listView.smoothScrollToPosition(data.opaqueToken) - which kicks off an animated scroll over - * the list to the given position. The animation may be in progress after this call returns. The - * only guarantee is that eventually - with no further interaction necessary - this data item - * will be rendered as a child or deeper descendant of this AdapterView. - * </p> - * - * @param adapterView the adapterView hosting the data. - * @param data an AdaptedData instance retrieved by a prior call to getDataInAdapterView - * @throws IllegalArgumentException if this protocol cannot manipulate adapterView or if data is - * not owned by this AdapterViewProtocol. - */ - void makeDataRenderedWithinAdapterView( - AdapterView<? extends Adapter> adapterView, AdaptedData data); - - - /** - * Indicates whether or not there now exists a descendant view within adapterView that - * is rendering this data. - * - * @param adapterView the AdapterView hosting this data. - * @param adaptedData the data we are checking the display state for. - * @return true if the data is rendered by a view in the adapterView, false otherwise. - */ - boolean isDataRenderedWithinAdapterView( - AdapterView<? extends Adapter> adapterView, AdaptedData adaptedData); - - - /** - * A holder that associates a data object from an AdapterView with a token the - * AdapterViewProtocol can use to force that data object to be rendered as a child or deeper - * descendant of the adapter view. - */ - public static class AdaptedData { - - /** - * One of the objects the AdapterView is exposing to the user. - */ - @Nullable - public final Object data; - - /** - * A token the implementor of AdapterViewProtocol can use to force the adapterView to display - * this data object as a child or deeper descendant in it. Equal opaqueToken point to the same - * data object on the AdapterView. - */ - public final Object opaqueToken; - - @Override - public String toString() { - return String.format("Data: %s (class: %s) token: %s", data, - null == data ? null : data.getClass(), opaqueToken); - } - - private AdaptedData(Object data, Object opaqueToken) { - this.data = data; - this.opaqueToken = checkNotNull(opaqueToken); - } - - public static class Builder { - private Object data; - private Object opaqueToken; - - public Builder withData(@Nullable Object data) { - this.data = data; - return this; - } - - public Builder withOpaqueToken(@Nullable Object opaqueToken) { - this.opaqueToken = opaqueToken; - return this; - } - - public AdaptedData build() { - return new AdaptedData(data, opaqueToken); - } - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterViewProtocols.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterViewProtocols.java deleted file mode 100644 index 5fc6032..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/AdapterViewProtocols.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayingAtLeast; -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import com.google.common.collect.Range; - -import android.os.Build; -import android.view.View; -import android.widget.AbsListView; -import android.widget.Adapter; -import android.widget.AdapterView; -import android.widget.AdapterViewAnimator; -import android.widget.AdapterViewFlipper; - -import java.util.List; - -/** - * Implementations of {@link AdapterViewProtocol} for standard SDK Widgets. - * - */ -public final class AdapterViewProtocols { - - /** - * Consider views which have over this percentage of their area visible to the user - * to be fully rendered. - */ - private static final int FULLY_RENDERED_PERCENTAGE_CUTOFF = 90; - - private AdapterViewProtocols() {} - - private static final AdapterViewProtocol STANDARD_PROTOCOL = new StandardAdapterViewProtocol(); - - /** - * Creates an implementation of AdapterViewProtocol that can work with AdapterViews that do not - * break method contracts on AdapterView. - * - */ - public static AdapterViewProtocol standardProtocol() { - return STANDARD_PROTOCOL; - } - - // TODO(user): expandablelistview protocols - - private static final class StandardAdapterViewProtocol implements AdapterViewProtocol { - @Override - public Iterable<AdaptedData> getDataInAdapterView(AdapterView<? extends Adapter> adapterView) { - List<AdaptedData> datas = Lists.newArrayList(); - for (int i = 0; i < adapterView.getCount(); i++) { - datas.add( - new AdaptedData.Builder() - .withData(adapterView.getItemAtPosition(i)) - .withOpaqueToken(i) - .build()); - } - return datas; - } - - @Override - public Optional<AdaptedData> getDataRenderedByView(AdapterView<? extends Adapter> adapterView, - View descendantView) { - if (adapterView == descendantView.getParent()) { - int position = adapterView.getPositionForView(descendantView); - if (position != AdapterView.INVALID_POSITION) { - return Optional.of(new AdaptedData.Builder() - .withData(adapterView.getItemAtPosition(position)) - .withOpaqueToken(Integer.valueOf(position)) - .build()); - } - } - return Optional.absent(); - } - - @Override - public void makeDataRenderedWithinAdapterView( - AdapterView<? extends Adapter> adapterView, AdaptedData data) { - checkArgument(data.opaqueToken instanceof Integer, "Not my data: %s", data); - int position = ((Integer) data.opaqueToken).intValue(); - - boolean moved = false; - // set selection should always work, we can give a little better experience if per subtype - // though. - if (Build.VERSION.SDK_INT > 7) { - if (adapterView instanceof AbsListView) { - if (Build.VERSION.SDK_INT > 10) { - ((AbsListView) adapterView).smoothScrollToPositionFromTop(position, - adapterView.getPaddingTop(), 0); - } else { - ((AbsListView) adapterView).smoothScrollToPosition(position); - } - moved = true; - } - if (Build.VERSION.SDK_INT > 10) { - if (adapterView instanceof AdapterViewAnimator) { - if (adapterView instanceof AdapterViewFlipper) { - ((AdapterViewFlipper) adapterView).stopFlipping(); - } - ((AdapterViewAnimator) adapterView).setDisplayedChild(position); - moved = true; - } - } - } - if (!moved) { - adapterView.setSelection(position); - } - } - - @SuppressWarnings("deprecation") - @Override - public boolean isDataRenderedWithinAdapterView( - AdapterView<? extends Adapter> adapterView, AdaptedData adaptedData) { - checkArgument(adaptedData.opaqueToken instanceof Integer, "Not my data: %s", adaptedData); - int dataPosition = ((Integer) adaptedData.opaqueToken).intValue(); - - if (Range.closed(adapterView.getFirstVisiblePosition(), adapterView.getLastVisiblePosition()) - .contains(dataPosition)) { - if (adapterView.getFirstVisiblePosition() == adapterView.getLastVisiblePosition()) { - // thats a huge element. - return true; - } else { - return isElementFullyRendered(adapterView, - dataPosition - adapterView.getFirstVisiblePosition()); - } - } else { - return false; - } - } - - private boolean isElementFullyRendered(AdapterView<? extends Adapter> adapterView, - int childAt) { - View element = adapterView.getChildAt(childAt); - // Occassionally we'll have to fight with smooth scrolling logic on our definition of when - // there is extra scrolling to be done. In particular if the element is the first or last - // element of the list, the smooth scroller may decide that no work needs to be done to scroll - // to the element if a certain percentage of it is on screen. Ugh. Sigh. Yuck. - - return isDisplayingAtLeast(FULLY_RENDERED_PERCENTAGE_CUTOFF).matches(element); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ClearTextAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ClearTextAction.java deleted file mode 100644 index e3d997a..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ClearTextAction.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static org.hamcrest.Matchers.allOf; - -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; - -import android.view.View; -import android.widget.EditText; - -import org.hamcrest.Matcher; - -/** - * Clears view text by setting {@link EditText}s text property to "". - */ -public final class ClearTextAction implements ViewAction { - @SuppressWarnings("unchecked") - @Override - public Matcher<View> getConstraints() { - return allOf(isDisplayed(), isAssignableFrom(EditText.class)); - } - - @Override - public void perform(UiController uiController, View view) { - ((EditText) view).setText(""); - } - - @Override - public String getDescription() { - return "clear text"; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/CloseKeyboardAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/CloseKeyboardAction.java deleted file mode 100644 index 6026a68..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/CloseKeyboardAction.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.common.collect.Iterables.getOnlyElement; -import static org.hamcrest.Matchers.anything; - -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry; -import com.google.android.apps.common.testing.testrunner.Stage; -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.os.ResultReceiver; -import android.util.Log; -import android.view.View; -import android.view.inputmethod.InputMethodManager; - -import org.hamcrest.Matcher; - -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Closes soft keyboard. - */ -public final class CloseKeyboardAction implements ViewAction { - - private static final int NUM_RETRIES = 3; - private static final String TAG = CloseKeyboardAction.class.getSimpleName(); - - @SuppressWarnings("unchecked") - @Override - public Matcher<View> getConstraints() { - return anything(); - } - - @Override - public void perform(UiController uiController, View view) { - // Retry in case of timeout exception to avoid flakiness in IMM. - for (int i = 0; i < NUM_RETRIES; i++) { - try { - tryToCloseKeyboard(view, uiController); - return; - } catch (TimeoutException te) { - Log.w(TAG, "Caught timeout exception. Retrying."); - if (i == 2) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(te) - .build(); - } - } - } - } - - private void tryToCloseKeyboard(View view, UiController uiController) throws TimeoutException { - InputMethodManager imm = (InputMethodManager) getRootActivity(uiController) - .getSystemService(Context.INPUT_METHOD_SERVICE); - final AtomicInteger atomicResultCode = new AtomicInteger(); - final CountDownLatch latch = new CountDownLatch(1); - - ResultReceiver result = new ResultReceiver(null) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - atomicResultCode.set(resultCode); - latch.countDown(); - } - }; - - if (!imm.hideSoftInputFromWindow(view.getWindowToken(), 0, result)) { - Log.w(TAG, "Attempting to close soft keyboard, while it is not shown."); - return; - } - - try { - if (!latch.await(2, TimeUnit.SECONDS)) { - throw new TimeoutException("Wait on operation result timed out."); - } - } catch (InterruptedException e) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException("Waiting for soft keyboard close result was interrupted.")) - .build(); - } - - if (atomicResultCode.get() != InputMethodManager.RESULT_UNCHANGED_HIDDEN - && atomicResultCode.get() != InputMethodManager.RESULT_HIDDEN) { - String error = - "Attempt to close the soft keyboard did not result in soft keyboard to be hidden." - + "resultCode = " + atomicResultCode.get(); - Log.e(TAG, error); - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException(error)) - .build(); - } - } - - private static Activity getRootActivity(UiController uiController) { - Collection<Activity> resumedActivities = - ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED); - if (resumedActivities.isEmpty()) { - uiController.loopMainThreadUntilIdle(); - resumedActivities = - ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED); - } - Activity topActivity = getOnlyElement(resumedActivities); - return topActivity; - } - - @Override - public String getDescription() { - return "close keyboard"; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/CoordinatesProvider.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/CoordinatesProvider.java deleted file mode 100644 index c8c9823..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/CoordinatesProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import android.view.View; - -/** - * Interface to implement calculation of Coordinates. - */ -public interface CoordinatesProvider { - - /** - * Calculates coordinates of given view. - * - * @param view the View which is used for the calculation. - * @return a float[] with x and y values of the calculated coordinates. - */ - public float[] calculateCoordinates(View view); -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/EditorAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/EditorAction.java deleted file mode 100644 index 6b78cb9..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/EditorAction.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; - -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; - -import android.view.View; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; - -import org.hamcrest.Matcher; - -/** - * Performs whatever editor (IME) action is available on a view. - */ -public final class EditorAction implements ViewAction { - - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return "input method editor"; - } - - @Override - public void perform(UiController uiController, View view) { - EditorInfo editorInfo = new EditorInfo(); - InputConnection inputConnection = view.onCreateInputConnection(editorInfo); - if (inputConnection == null) { - throw new PerformException.Builder() - .withActionDescription(this.toString()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new IllegalStateException("View does not support input methods")) - .build(); - } - - int actionId = editorInfo.actionId != 0 ? editorInfo.actionId : - editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION; - - if (actionId == EditorInfo.IME_ACTION_NONE) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new IllegalStateException("No available action on view")) - .build(); - } - - if (!inputConnection.performEditorAction(actionId)) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException(String.format( - "Failed to perform action %#x. Input connection no longer valid", actionId))) - .build(); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/EspressoKey.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/EspressoKey.java deleted file mode 100644 index 530ddde..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/EspressoKey.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.common.base.Preconditions.checkState; - -import android.os.Build; -import android.view.KeyEvent; - -/** - * Class that wraps the key code and meta state of the desired key press. - */ -public final class EspressoKey { - private final int keyCode; - private final int metaState; - - private EspressoKey(Builder builder) { - this.keyCode = builder.builderKeyCode; - this.metaState = builder.getMetaState(); - } - - public int getKeyCode() { - return keyCode; - } - - public int getMetaState() { - return metaState; - } - - @Override - public String toString() { - return String.format("keyCode: %s, metaState: %s", keyCode, metaState); - } - - /** - * Builder for the EspressoKey class. - */ - public static class Builder { - private int builderKeyCode = -1; - private boolean isShiftPressed; - private boolean isAltPressed; - private boolean isCtrlPressed; - - public Builder withKeyCode(int keyCode) { - builderKeyCode = keyCode; - return this; - } - - /** - * Sets the SHIFT_ON meta state of the resulting key. - */ - public Builder withShiftPressed(boolean shiftPressed) { - isShiftPressed = shiftPressed; - return this; - } - - /** - * On Honeycomb and above, sets the CTRL_ON meta state of the resulting key. On Gingerbread and - * below, this is a noop. - */ - public Builder withCtrlPressed(boolean ctrlPressed) { - isCtrlPressed = ctrlPressed; - return this; - } - - /** - * Sets the ALT_ON meta state of the resulting key. - */ - public Builder withAltPressed(boolean altPressed) { - isAltPressed = altPressed; - return this; - } - - private int getMetaState() { - int metaState = 0; - if (isShiftPressed) { - metaState |= KeyEvent.META_SHIFT_ON; - } - - if (isAltPressed) { - metaState |= KeyEvent.META_ALT_ON; - } - - if (isCtrlPressed && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - metaState |= KeyEvent.META_CTRL_ON; - } - - return metaState; - } - - public EspressoKey build() { - checkState(builderKeyCode > 0 && builderKeyCode < KeyEvent.getMaxKeyCode(), - "Invalid key code: %s", builderKeyCode); - return new EspressoKey(this); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralClickAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralClickAction.java deleted file mode 100644 index 857501d..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralClickAction.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayingAtLeast; -import static org.hamcrest.Matchers.allOf; - -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.common.base.Optional; - -import android.view.View; -import android.view.ViewConfiguration; -import android.webkit.WebView; - -import org.hamcrest.Matcher; - -/** - * Enables clicking on views. - */ -public final class GeneralClickAction implements ViewAction { - - private final CoordinatesProvider coordinatesProvider; - private final Tapper tapper; - private final PrecisionDescriber precisionDescriber; - private final Optional<ViewAction> rollbackAction; - - public GeneralClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider, - PrecisionDescriber precisionDescriber) { - this(tapper, coordinatesProvider, precisionDescriber, null); - } - - public GeneralClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider, - PrecisionDescriber precisionDescriber, ViewAction rollbackAction) { - this.coordinatesProvider = coordinatesProvider; - this.tapper = tapper; - this.precisionDescriber = precisionDescriber; - this.rollbackAction = Optional.fromNullable(rollbackAction); - } - - @Override - @SuppressWarnings("unchecked") - public Matcher<View> getConstraints() { - Matcher<View> standardConstraint = isDisplayingAtLeast(90); - if (rollbackAction.isPresent()) { - return allOf(standardConstraint, rollbackAction.get().getConstraints()); - } else { - return standardConstraint; - } - } - - @Override - public void perform(UiController uiController, View view) { - float[] coordinates = coordinatesProvider.calculateCoordinates(view); - float[] precision = precisionDescriber.describePrecision(); - - Tapper.Status status = Tapper.Status.FAILURE; - int loopCount = 0; - // Native event injection is quite a tricky process. A tap is actually 2 - // seperate motion events which need to get injected into the system. Injection - // makes an RPC call from our app under test to the Android system server, the - // system server decides which window layer to deliver the event to, the system - // server makes an RPC to that window layer, that window layer delivers the event - // to the correct UI element, activity, or window object. Now we need to repeat - // that 2x. for a simple down and up. Oh and the down event triggers timers to - // detect whether or not the event is a long vs. short press. The timers are - // removed the moment the up event is received (NOTE: the possibility of eventTime - // being in the future is totally ignored by most motion event processors). - // - // Phew. - // - // The net result of this is sometimes we'll want to do a regular tap, and for - // whatever reason the up event (last half) of the tap is delivered after long - // press timeout (depending on system load) and the long press behaviour is - // displayed (EG: show a context menu). There is no way to avoid or handle this more - // gracefully. Also the longpress behavour is app/widget specific. So if you have - // a seperate long press behaviour from your short press, you can pass in a - // 'RollBack' ViewAction which when executed will undo the effects of long press. - - while (status != Tapper.Status.SUCCESS && loopCount < 3) { - try { - status = tapper.sendTap(uiController, coordinates, precision); - } catch (RuntimeException re) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(re) - .build(); - } - - // ensures that all work enqueued to process the tap has been run. - uiController.loopMainThreadForAtLeast(ViewConfiguration.getPressedStateDuration()); - if (status == Tapper.Status.WARNING) { - if (rollbackAction.isPresent()) { - rollbackAction.get().perform(uiController, view); - } else { - break; - } - } - loopCount++; - } - if (status == Tapper.Status.FAILURE) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException(String.format("Couldn't " - + "click at: %s,%s precision: %s, %s . Tapper: %s coordinate provider: %s precision " + - "describer: %s. Tried %s times. With Rollback? %s", coordinates[0], coordinates[1], - precision[0], precision[1], tapper, coordinatesProvider, precisionDescriber, loopCount, - rollbackAction.isPresent()))) - .build(); - } - - if (tapper == Tap.SINGLE && view instanceof WebView) { - // WebViews will not process click events until double tap - // timeout. Not the best place for this - but good for now. - uiController.loopMainThreadForAtLeast(ViewConfiguration.getDoubleTapTimeout()); - } - } - - @Override - public String getDescription() { - return tapper.toString().toLowerCase() + " click"; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralLocation.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralLocation.java deleted file mode 100644 index f74775e..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralLocation.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import android.view.View; - -/** - * Calculates coordinate position for general locations. - */ -public enum GeneralLocation implements CoordinatesProvider { - - TOP_LEFT { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.BEGIN, Position.BEGIN); - } - }, - TOP_CENTER { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.BEGIN, Position.MIDDLE); - } - }, - TOP_RIGHT { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.BEGIN, Position.END); - } - }, - CENTER_LEFT { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.MIDDLE, Position.BEGIN); - } - }, - CENTER { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.MIDDLE, Position.MIDDLE); - } - }, - CENTER_RIGHT { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.MIDDLE, Position.END); - } - }, - BOTTOM_LEFT { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.END, Position.BEGIN); - } - }, - BOTTOM_CENTER { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.END, Position.MIDDLE); - } - }, - BOTTOM_RIGHT { - @Override - public float[] calculateCoordinates(View view) { - return getCoordinates(view, Position.END, Position.END); - } - }; - - private static float[] getCoordinates(View view, Position vertical, Position horizontal) { - final int[] xy = new int[2]; - view.getLocationOnScreen(xy); - final float x = horizontal.getPosition(xy[0], view.getWidth()); - final float y = vertical.getPosition(xy[1], view.getHeight()); - float[] coordinates = {x, y}; - return coordinates; - } - - private static enum Position { - BEGIN { - @Override - public float getPosition(int viewPos, int viewLength) { - return viewPos; - } - }, - MIDDLE { - @Override - public float getPosition(int viewPos, int viewLength) { - return viewPos + (viewLength / 2.0f); - } - }, - END { - @Override - public float getPosition(int viewPos, int viewLength) { - return viewPos + viewLength; - } - }; - - abstract float getPosition(int widgetPos, int widgetLength); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralSwipeAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralSwipeAction.java deleted file mode 100644 index 6482250..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/GeneralSwipeAction.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayingAtLeast; - -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; - -import android.view.View; -import android.view.ViewConfiguration; - -import org.hamcrest.Matcher; - -/** - * Enables swiping across a view. - */ -public final class GeneralSwipeAction implements ViewAction { - - /** Maximum number of times to attempt sending a swipe action. */ - private static final int MAX_TRIES = 3; - - /** The minimum amount of a view that must be displayed in order to swipe across it. */ - private static final int VIEW_DISPLAY_PERCENTAGE = 90; - - private final CoordinatesProvider startCoordinatesProvider; - private final CoordinatesProvider endCoordinatesProvider; - private final Swiper swiper; - private final PrecisionDescriber precisionDescriber; - - public GeneralSwipeAction(Swiper swiper, CoordinatesProvider startCoordinatesProvider, - CoordinatesProvider endCoordinatesProvider, PrecisionDescriber precisionDescriber) { - this.swiper = swiper; - this.startCoordinatesProvider = startCoordinatesProvider; - this.endCoordinatesProvider = endCoordinatesProvider; - this.precisionDescriber = precisionDescriber; - } - - @Override - public Matcher<View> getConstraints() { - return isDisplayingAtLeast(VIEW_DISPLAY_PERCENTAGE); - } - - @Override - public void perform(UiController uiController, View view) { - float[] startCoordinates = startCoordinatesProvider.calculateCoordinates(view); - float[] endCoordinates = endCoordinatesProvider.calculateCoordinates(view); - float[] precision = precisionDescriber.describePrecision(); - - Swiper.Status status = Swiper.Status.FAILURE; - - for (int tries = 0; tries < MAX_TRIES && status != Swiper.Status.SUCCESS; tries++) { - try { - status = swiper.sendSwipe(uiController, startCoordinates, endCoordinates, precision); - } catch (RuntimeException re) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(re) - .build(); - } - - // ensures that all work enqueued to process the swipe has been run. - uiController.loopMainThreadForAtLeast(ViewConfiguration.getPressedStateDuration()); - } - - if (status == Swiper.Status.FAILURE) { - throw new PerformException.Builder() - .withActionDescription(getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException(String.format( - "Couldn't swipe from: %s,%s to: %s,%s precision: %s, %s . Swiper: %s " - + "start coordinate provider: %s precision describer: %s. Tried %s times", - startCoordinates[0], - startCoordinates[1], - endCoordinates[0], - endCoordinates[1], - precision[0], - precision[1], - swiper, - startCoordinatesProvider, - precisionDescriber, - MAX_TRIES))) - .build(); - } - } - - @Override - public String getDescription() { - return swiper.toString().toLowerCase() + " swipe"; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/KeyEventAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/KeyEventAction.java deleted file mode 100644 index 1be85f7..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/KeyEventAction.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry; -import com.google.android.apps.common.testing.testrunner.Stage; -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; -import com.google.android.apps.common.testing.ui.espresso.NoActivityResumedException; -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; - -import android.os.SystemClock; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; - -import org.hamcrest.Matcher; - -/** - * Enables pressing KeyEvents on views. - */ -public final class KeyEventAction implements ViewAction { - private static final String TAG = KeyEventAction.class.getSimpleName(); - - private final EspressoKey key; - - public KeyEventAction(EspressoKey key) { - this.key = checkNotNull(key); - } - - @SuppressWarnings("unchecked") - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public void perform(UiController uiController, View view) { - try { - if (!sendKeyEvent(uiController, view)) { - Log.e(TAG, "Failed to inject key event: " + this.key); - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException("Failed to inject key event " + this.key)) - .build(); - } - } catch (InjectEventSecurityException e) { - Log.e(TAG, "Failed to inject key event: " + this.key); - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(e) - .build(); - } - } - - private final boolean sendKeyEvent(UiController controller, View view) - throws InjectEventSecurityException { - - boolean injected = false; - long eventTime = SystemClock.uptimeMillis(); - for (int attempts = 0; !injected && attempts < 4; attempts++) { - injected = controller.injectKeyEvent(new KeyEvent(eventTime, - eventTime, - KeyEvent.ACTION_DOWN, - this.key.getKeyCode(), - 0, - this.key.getMetaState())); - } - - if (!injected) { - // it is not a transient failure... :( - return false; - } - - injected = false; - eventTime = SystemClock.uptimeMillis(); - for (int attempts = 0; !injected && attempts < 4; attempts++) { - injected = controller.injectKeyEvent( - new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, this.key.getKeyCode(), 0)); - } - - - if (this.key.getKeyCode() == KeyEvent.KEYCODE_BACK) { - controller.loopMainThreadUntilIdle(); - boolean activeActivities = !ActivityLifecycleMonitorRegistry.getInstance() - .getActivitiesInStage(Stage.RESUMED) - .isEmpty(); - if (!activeActivities) { - Throwable cause = new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .build(); - throw new NoActivityResumedException("Pressed back and killed the app", cause); - } - } - - return injected; - } - - @Override - public String getDescription() { - return String.format("send %s key event", this.key); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/MotionEvents.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/MotionEvents.java deleted file mode 100644 index 1f38339..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/MotionEvents.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.testrunner.UsageTrackerRegistry; -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.common.annotations.VisibleForTesting; - -import android.os.SystemClock; -import android.util.Log; -import android.view.MotionEvent; -import android.view.ViewConfiguration; - -/** - * Facilitates sending of motion events to a {@link UiController}. - */ -final class MotionEvents { - - private static final String TAG = MotionEvents.class.getSimpleName(); - - @VisibleForTesting - static final int MAX_CLICK_ATTEMPTS = 3; - - private MotionEvents() { - // Shouldn't be instantiated - } - - static DownResultHolder sendDown( - UiController uiController, float[] coordinates, float[] precision) { - checkNotNull(uiController); - checkNotNull(coordinates); - checkNotNull(precision); - - for (int retry = 0; retry < MAX_CLICK_ATTEMPTS; retry++) { - MotionEvent motionEvent = null; - try { - // Algorithm of sending click event adopted from android.test.TouchUtils. - // When the click event was first initiated. Needs to be same for both down and up press - // events. - long downTime = SystemClock.uptimeMillis(); - - // Down press. - motionEvent = MotionEvent.obtain(downTime, - SystemClock.uptimeMillis(), - MotionEvent.ACTION_DOWN, - coordinates[0], - coordinates[1], - 0, // pressure - 1, // size - 0, // metaState - precision[0], // xPrecision - precision[1], // yPrecision - 0, // deviceId - 0); // edgeFlags - // The down event should be considered a tap if it is long enough to be detected - // but short enough not to be a long-press. Assume that TapTimeout is set at least - // twice the detection time for a tap (no need to sleep for the whole TapTimeout since - // we aren't concerned about scrolling here). - long isTapAt = downTime + (ViewConfiguration.getTapTimeout() / 2); - - boolean injectEventSucceeded = uiController.injectMotionEvent(motionEvent); - - while (true) { - long delayToBeTap = isTapAt - SystemClock.uptimeMillis(); - if (delayToBeTap <= 10) { - break; - } - // Sleep only a fraction of the time, since there may be other events in the UI queue - // that could cause us to start sleeping late, and then oversleep. - uiController.loopMainThreadForAtLeast(delayToBeTap / 4); - } - - boolean longPress = false; - if (SystemClock.uptimeMillis() > (downTime + ViewConfiguration.getLongPressTimeout())) { - longPress = true; - Log.e(TAG, "Overslept and turned a tap into a long press"); - UsageTrackerRegistry.getInstance().trackUsage("Espresso.Tap.Error.tapToLongPress"); - } - - if (!injectEventSucceeded) { - motionEvent.recycle(); - motionEvent = null; - continue; - } - - return new DownResultHolder(motionEvent, longPress); - } catch (InjectEventSecurityException e) { - throw new PerformException.Builder() - .withActionDescription("Send down montion event") - .withViewDescription("unknown") // likely to be replaced by FailureHandler - .withCause(e) - .build(); - } - } - throw new PerformException.Builder() - .withActionDescription(String.format("click (after %s attempts)", MAX_CLICK_ATTEMPTS)) - .withViewDescription("unknown") // likely to be replaced by FailureHandler - .build(); - } - - static boolean sendUp(UiController uiController, MotionEvent downEvent) { - return sendUp(uiController, downEvent, new float[] { downEvent.getX(), downEvent.getY() }); - } - - static boolean sendUp(UiController uiController, MotionEvent downEvent, float[] coordinates) { - checkNotNull(uiController); - checkNotNull(downEvent); - checkNotNull(coordinates); - - MotionEvent motionEvent = null; - try { - // Up press. - motionEvent = MotionEvent.obtain(downEvent.getDownTime(), - SystemClock.uptimeMillis(), - MotionEvent.ACTION_UP, - coordinates[0], - coordinates[1], - 0); - boolean injectEventSucceeded = uiController.injectMotionEvent(motionEvent); - - if (!injectEventSucceeded) { - Log.e(TAG, String.format( - "Injection of up event failed (corresponding down event: %s)", downEvent.toString())); - return false; - } - } catch (InjectEventSecurityException e) { - throw new PerformException.Builder() - .withActionDescription( - String.format("inject up event (corresponding down event: %s)", downEvent.toString())) - .withViewDescription("unknown") // likely to be replaced by FailureHandler - .withCause(e) - .build(); - } finally { - if (null != motionEvent) { - motionEvent.recycle(); - motionEvent = null; - } - } - return true; - } - - static void sendCancel(UiController uiController, MotionEvent downEvent) { - checkNotNull(uiController); - checkNotNull(downEvent); - - MotionEvent motionEvent = null; - try { - // Up press. - motionEvent = MotionEvent.obtain(downEvent.getDownTime(), - SystemClock.uptimeMillis(), - MotionEvent.ACTION_CANCEL, - downEvent.getX(), - downEvent.getY(), - 0); - boolean injectEventSucceeded = uiController.injectMotionEvent(motionEvent); - - if (!injectEventSucceeded) { - throw new PerformException.Builder() - .withActionDescription(String.format( - "inject cancel event (corresponding down event: %s)", downEvent.toString())) - .withViewDescription("unknown") // likely to be replaced by FailureHandler - .build(); - } - } catch (InjectEventSecurityException e) { - throw new PerformException.Builder() - .withActionDescription(String.format( - "inject cancel event (corresponding down event: %s)", downEvent.toString())) - .withViewDescription("unknown") // likely to be replaced by FailureHandler - .withCause(e) - .build(); - } finally { - if (null != motionEvent) { - motionEvent.recycle(); - motionEvent = null; - } - } - } - - static boolean sendMovement(UiController uiController, MotionEvent downEvent, - float[] coordinates) { - checkNotNull(uiController); - checkNotNull(downEvent); - checkNotNull(coordinates); - - MotionEvent motionEvent = null; - try { - motionEvent = MotionEvent.obtain(downEvent.getDownTime(), - SystemClock.uptimeMillis(), - MotionEvent.ACTION_MOVE, - coordinates[0], - coordinates[1], - 0); - boolean injectEventSucceeded = uiController.injectMotionEvent(motionEvent); - - if (!injectEventSucceeded) { - Log.e(TAG, String.format( - "Injection of motion event failed (corresponding down event: %s)", - downEvent.toString())); - return false; - } - } catch (InjectEventSecurityException e) { - throw new PerformException.Builder() - .withActionDescription(String.format( - "inject motion event (corresponding down event: %s)", downEvent.toString())) - .withViewDescription("unknown") // likely to be replaced by FailureHandler - .withCause(e) - .build(); - } finally { - if (null != motionEvent) { - motionEvent.recycle(); - motionEvent = null; - } - } - - return true; - } - - /** - * Holds the result of a down motion. - */ - static class DownResultHolder { - public final MotionEvent down; - public final boolean longPress; - - DownResultHolder(MotionEvent down, boolean longPress) { - this.down = down; - this.longPress = longPress; - } - } - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/PrecisionDescriber.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/PrecisionDescriber.java deleted file mode 100644 index 422de8e..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/PrecisionDescriber.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -/** - * Interface to implement size of click area. - */ -public interface PrecisionDescriber { - - /** - * Different touch target sizes. - * - * @return a float[] with x and y values of size of click area. - */ - public float[] describePrecision(); -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Press.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Press.java deleted file mode 100644 index 883c852..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Press.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -/** - * Returns different touch target sizes. - */ -public enum Press implements PrecisionDescriber { - PINPOINT { - @Override - public float[] describePrecision() { - float[] pinpoint = {1f, 1f}; - return pinpoint; - } - }, - FINGER { - // average width of the index finger is 16 – 20 mm. - @Override - public float[] describePrecision() { - float finger[] = {16f, 16f}; - return finger; - } - }, - // average width of an adult thumb is 25 mm (1 inch). - THUMB { - @Override - public float[] describePrecision() { - float thumb[] = {25f, 25f}; - return thumb; - } - }; -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ScrollToAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ScrollToAction.java deleted file mode 100644 index 9d613c3..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ScrollToAction.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDescendantOfA; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayingAtLeast; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withEffectiveVisibility; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; - -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.Visibility; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; - -import android.graphics.Rect; -import android.util.Log; -import android.view.View; -import android.widget.HorizontalScrollView; -import android.widget.ScrollView; - -import org.hamcrest.Matcher; - -/** - * Enables scrolling to the given view. View must be a descendant of a ScrollView. - */ -public final class ScrollToAction implements ViewAction { - private static final String TAG = ScrollToAction.class.getSimpleName(); - - @SuppressWarnings("unchecked") - @Override - public Matcher<View> getConstraints() { - return allOf(withEffectiveVisibility(Visibility.VISIBLE), isDescendantOfA(anyOf( - isAssignableFrom(ScrollView.class), isAssignableFrom(HorizontalScrollView.class)))); - } - - @Override - public void perform(UiController uiController, View view) { - if (isDisplayingAtLeast(90).matches(view)) { - Log.i(TAG, "View is already displayed. Returning."); - return; - } - Rect rect = new Rect(); - view.getDrawingRect(rect); - if (!view.requestRectangleOnScreen(rect, true /* immediate */)) { - Log.w(TAG, "Scrolling to view was requested, but none of the parents scrolled."); - } - uiController.loopMainThreadUntilIdle(); - if (!isDisplayingAtLeast(90).matches(view)) { - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException( - "Scrolling to view was attempted, but the view is not displayed")) - .build(); - } - } - - @Override - public String getDescription() { - return "scroll to"; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Swipe.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Swipe.java deleted file mode 100644 index 06e8dc8..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Swipe.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.common.base.Preconditions.checkElementIndex; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.UiController; - -import android.os.SystemClock; -import android.util.Log; -import android.view.MotionEvent; - -/** - * Executes different swipe types to given positions. - */ -public enum Swipe implements Swiper { - - /** Swipes quickly between the co-ordinates. */ - FAST { - @Override - public Swiper.Status sendSwipe(UiController uiController, float[] startCoordinates, - float[] endCoordinates, float[] precision) { - return sendLinearSwipe(uiController, startCoordinates, endCoordinates, precision, - SWIPE_FAST_DURATION_MS); - } - }, - - /** Swipes deliberately slowly between the co-ordinates, to aid in visual debugging. */ - SLOW { - @Override - public Swiper.Status sendSwipe(UiController uiController, float[] startCoordinates, - float[] endCoordinates, float[] precision) { - return sendLinearSwipe(uiController, startCoordinates, endCoordinates, precision, - SWIPE_SLOW_DURATION_MS); - } - }; - - private static final String TAG = Swipe.class.getSimpleName(); - - /** The number of motion events to send for each swipe. */ - private static final int SWIPE_EVENT_COUNT = 10; - - /** Length of time a "fast" swipe should last for, in milliseconds. */ - private static final int SWIPE_FAST_DURATION_MS = 100; - - /** Length of time a "slow" swipe should last for, in milliseconds. */ - private static final int SWIPE_SLOW_DURATION_MS = 1500; - - private static float[][] interpolate(float[] start, float[] end, int steps) { - checkElementIndex(1, start.length); - checkElementIndex(1, end.length); - - float[][] res = new float[steps][2]; - - for (int i = 1; i < steps + 1; i++) { - res[i - 1][0] = start[0] + (end[0] - start[0]) * i / (steps + 2f); - res[i - 1][1] = start[1] + (end[1] - start[1]) * i / (steps + 2f); - } - - return res; - } - - private static Swiper.Status sendLinearSwipe(UiController uiController, float[] startCoordinates, - float[] endCoordinates, float[] precision, int duration) { - checkNotNull(uiController); - checkNotNull(startCoordinates); - checkNotNull(endCoordinates); - checkNotNull(precision); - - float[][] steps = interpolate(startCoordinates, endCoordinates, SWIPE_EVENT_COUNT); - final int delayBetweenMovements = duration / steps.length; - - MotionEvent downEvent = MotionEvents.sendDown(uiController, steps[0], precision).down; - try { - for (int i = 1; i < steps.length; i++) { - if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) { - Log.e(TAG, "Injection of move event as part of the swipe failed. Sending cancel event."); - MotionEvents.sendCancel(uiController, downEvent); - return Swiper.Status.FAILURE; - } - - long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i; - long timeUntilDesired = desiredTime - SystemClock.uptimeMillis(); - if (timeUntilDesired > 10) { - uiController.loopMainThreadForAtLeast(timeUntilDesired); - } - } - - if (!MotionEvents.sendUp(uiController, downEvent, endCoordinates)) { - Log.e(TAG, "Injection of up event as part of the swipe failed. Sending cancel event."); - MotionEvents.sendCancel(uiController, downEvent); - return Swiper.Status.FAILURE; - } - } finally { - downEvent.recycle(); - } - return Swiper.Status.SUCCESS; - } - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Swiper.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Swiper.java deleted file mode 100644 index 41ac593..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Swiper.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import com.google.android.apps.common.testing.ui.espresso.UiController; - -import android.view.MotionEvent; - -/** - * Interface to implement different swipe types. - */ -public interface Swiper { - - /** - * The result of the swipe. - */ - public enum Status { - /** - * The swipe action completed successfully. - */ - SUCCESS, - /** - * Injecting the event was a complete failure. - */ - FAILURE - } - - /** - * Swipes from {@code startCoordinates} to {@code endCoordinates} using the given - * {@code uiController} to send {@link MotionEvent}s. - * - * @param uiController a UiController to use to send MotionEvents to the screen. - * @param startCoordinates a float[] with x and y co-ordinates of the start of the swipe. - * @param endCoordinates a float[] with x and y co-ordinates of the end of the swipe. - * @param precision a float[] with x and y values of precision of the tap. - * @return The status of the swipe. - */ - public Status sendSwipe(UiController uiController, float[] startCoordinates, - float[] endCoordinates, float[] precision); - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Tap.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Tap.java deleted file mode 100644 index 712f8cc..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Tap.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.action.MotionEvents.DownResultHolder; - -import android.util.Log; -import android.view.MotionEvent; -import android.view.ViewConfiguration; - -/** - * Executes different click types to given position. - */ -public enum Tap implements Tapper { - SINGLE { - @Override - public Tapper.Status sendTap(UiController uiController, float[] coordinates, - float[] precision) { - checkNotNull(uiController); - - checkNotNull(coordinates); - checkNotNull(precision); - DownResultHolder res = MotionEvents.sendDown(uiController, coordinates, precision); - try { - if (!MotionEvents.sendUp(uiController, res.down)) { - Log.d(TAG, "Injection of up event as part of the click failed. Send cancel event."); - MotionEvents.sendCancel(uiController, res.down); - return Tapper.Status.FAILURE; - } - } finally { - res.down.recycle(); - } - return res.longPress ? Tapper.Status.WARNING : Tapper.Status.SUCCESS; - } - }, - LONG { - @Override - public Tapper.Status sendTap(UiController uiController, float[] coordinates, - float[] precision) { - checkNotNull(uiController); - checkNotNull(coordinates); - checkNotNull(precision); - - MotionEvent downEvent = MotionEvents.sendDown(uiController, coordinates, precision).down; - try { - // Duration before a press turns into a long press. - // Factor 1.5 is needed, otherwise a long press is not safely detected. - // See android.test.TouchUtils longClickView - long longPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); - uiController.loopMainThreadForAtLeast(longPressTimeout); - - if (!MotionEvents.sendUp(uiController, downEvent)) { - MotionEvents.sendCancel(uiController, downEvent); - return Tapper.Status.FAILURE; - } - } finally { - downEvent.recycle(); - downEvent = null; - } - return Tapper.Status.SUCCESS; - } - }, - DOUBLE { - @Override - public Tapper.Status sendTap(UiController uiController, float[] coordinates, - float[] precision) { - checkNotNull(uiController); - checkNotNull(coordinates); - checkNotNull(precision); - Tapper.Status stat = SINGLE.sendTap(uiController, coordinates, precision); - if (stat == Tapper.Status.FAILURE) { - return Tapper.Status.FAILURE; - } - - Tapper.Status secondStat = SINGLE.sendTap(uiController, coordinates, precision); - - if (secondStat == Tapper.Status.FAILURE) { - return Tapper.Status.FAILURE; - } - - if (secondStat == Tapper.Status.WARNING || stat == Tapper.Status.WARNING) { - return Tapper.Status.WARNING; - } else { - return Tapper.Status.SUCCESS; - } - } - }; - - private static final String TAG = Tap.class.getSimpleName(); - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Tapper.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Tapper.java deleted file mode 100644 index 8a57c53..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/Tapper.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import com.google.android.apps.common.testing.ui.espresso.UiController; - -/** - * Interface to implement different click types. - */ -public interface Tapper { - - /** - * The result of the tap. - */ - public enum Status { - /** - * The Tap action completed successfully. - */ - SUCCESS, - /** - * The action seemed to have completed - but may have been misinterpreted - * by the application. (For Example a TAP became a LONG PRESS by measuring - * its time between the down and up events). - */ - WARNING, - /** - * Injecting the event was a complete failure. - */ - FAILURE } - - /** - * Sends a MotionEvent to the given UiController. - * - * @param uiController a UiController to use to send MotionEvents to the screen. - * @param coordinates a float[] with x and y values of center of the tap. - * @param precision a float[] with x and y values of precision of the tap. - * @return The status of the tap. - */ - public Status sendTap(UiController uiController, float[] coordinates, float[] precision); -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextAction.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextAction.java deleted file mode 100644 index 81d388b..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/TypeTextAction.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.hasFocus; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isAssignableFrom; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.supportsInputMethods; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; - -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; -import com.google.android.apps.common.testing.ui.espresso.PerformException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.ViewAction; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; - -import android.os.Build; -import android.util.Log; -import android.view.View; -import android.widget.SearchView; - -import org.hamcrest.Matcher; - -/** - * Enables typing text on views. - */ -public final class TypeTextAction implements ViewAction { - private static final String TAG = TypeTextAction.class.getSimpleName(); - private final String stringToBeTyped; - private final boolean tapToFocus; - - /** - * Constructs {@link TypeTextAction} with given string. If the string is empty it results in no-op - * (nothing is typed). By default this action sends a tap event to the center of the view to - * attain focus before typing. - * - * @param stringToBeTyped String To be typed by {@link TypeTextAction} - */ - public TypeTextAction(String stringToBeTyped) { - this(stringToBeTyped, true); - } - - /** - * Constructs {@link TypeTextAction} with given string. If the string is empty it results in no-op - * (nothing is typed). - * - * @param stringToBeTyped String To be typed by {@link TypeTextAction} - * @param tapToFocus indicates whether a tap should be sent to the underlying view before typing. - */ - public TypeTextAction(String stringToBeTyped, boolean tapToFocus) { - checkNotNull(stringToBeTyped); - this.stringToBeTyped = stringToBeTyped; - this.tapToFocus = tapToFocus; - } - - @SuppressWarnings("unchecked") - @Override - public Matcher<View> getConstraints() { - Matcher<View> matchers = allOf(isDisplayed()); - if (!tapToFocus) { - matchers = allOf(matchers, hasFocus()); - } - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - return allOf(matchers, supportsInputMethods()); - } else { - // SearchView does not support input methods itself (rather it delegates to an internal text - // view for input). - return allOf(matchers, anyOf(supportsInputMethods(), isAssignableFrom(SearchView.class))); - } - } - - @Override - public void perform(UiController uiController, View view) { - // No-op if string is empty. - if (stringToBeTyped.length() == 0) { - Log.w(TAG, "Supplied string is empty resulting in no-op (nothing is typed)."); - return; - } - - if (tapToFocus) { - // Perform a click. - new GeneralClickAction(Tap.SINGLE, GeneralLocation.CENTER, Press.FINGER) - .perform(uiController, view); - uiController.loopMainThreadUntilIdle(); - } - - try { - if (!uiController.injectString(stringToBeTyped)) { - Log.e(TAG, "Failed to type text: " + stringToBeTyped); - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(new RuntimeException("Failed to type text: " + stringToBeTyped)) - .build(); - } - } catch (InjectEventSecurityException e) { - Log.e(TAG, "Failed to type text: " + stringToBeTyped); - throw new PerformException.Builder() - .withActionDescription(this.getDescription()) - .withViewDescription(HumanReadables.describe(view)) - .withCause(e) - .build(); - } - } - - @Override - public String getDescription() { - return "type text"; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ViewActions.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ViewActions.java deleted file mode 100644 index 07b0e3d..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/action/ViewActions.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.action; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.ViewAction; - -import android.view.KeyEvent; - -/** - * A collection of common {@link ViewActions}. - */ -public final class ViewActions { - - private ViewActions() {} - - /** - * Returns an action that clears text on the view.<br> - * <br> - * View constraints: - * <ul> - * <li>must be displayed on screen - * <ul> - */ - public static ViewAction clearText() { - return new ClearTextAction(); - } - - /** - * Returns an action that clicks the view.<br> - * <br> - * View constraints: - * <ul> - * <li>must be displayed on screen - * <ul> - */ - public static ViewAction click() { - return new GeneralClickAction(Tap.SINGLE, GeneralLocation.CENTER, Press.FINGER); - } - - /** - * Returns an action that performs a single click on the view. - * - * If the click takes longer than the 'long press' duration (which is possible) the provided - * rollback action is invoked on the view and a click is attempted again. - * - * This is only necessary if the view being clicked on has some different behaviour for long press - * versus a normal tap. - * - * For example - if a long press on a particular view element opens a popup menu - - * ViewActions.pressBack() may be an acceptable rollback action. - * - * <br> - * View constraints: - * <ul> - * <li>must be displayed on screen</li> - * <li>any constraints of the rollbackAction</li> - * <ul> - */ - public static ViewAction click(ViewAction rollbackAction) { - checkNotNull(rollbackAction); - return new GeneralClickAction(Tap.SINGLE, GeneralLocation.CENTER, Press.FINGER, - rollbackAction); - } - - /** - * Returns an action that performs a swipe right-to-left across the vertical center of the - * view.<br> - * <br> - * View constraints: - * <ul> - * <li>must be displayed on screen - * <ul> - */ - public static ViewAction swipeLeft() { - return new GeneralSwipeAction(Swipe.FAST, GeneralLocation.CENTER_RIGHT, - GeneralLocation.CENTER_LEFT, Press.FINGER); - } - - /** - * Returns an action that performs a swipe left-to-right across the vertical center of the - * view.<br> - * <br> - * View constraints: - * <ul> - * <li>must be displayed on screen - * <ul> - */ - public static ViewAction swipeRight() { - return new GeneralSwipeAction(Swipe.FAST, GeneralLocation.CENTER_LEFT, - GeneralLocation.CENTER_RIGHT, Press.FINGER); - } - - /** - * Returns an action that closes soft keyboard. If the keyboard is already closed, it is a no-op. - */ - public static ViewAction closeSoftKeyboard() { - return new CloseKeyboardAction(); - } - - /** - * Returns an action that presses the current action button (next, done, search, etc) on the IME - * (Input Method Editor). The selected view will have its onEditorAction method called. - */ - public static ViewAction pressImeActionButton() { - return new EditorAction(); - } - - /** - * Returns an action that clicks the back button. - */ - public static ViewAction pressBack() { - return pressKey(KeyEvent.KEYCODE_BACK); - } - - /** - * Returns an action that presses the hardware menu key. - */ - public static ViewAction pressMenuKey() { - return pressKey(KeyEvent.KEYCODE_MENU); - } - - /** - * Returns an action that presses the key specified by the keyCode (eg. Keyevent.KEYCODE_BACK). - */ - public static ViewAction pressKey(int keyCode) { - return new KeyEventAction(new EspressoKey.Builder().withKeyCode(keyCode).build()); - } - - /** - * Returns an action that presses the specified key with the specified modifiers. - */ - public static ViewAction pressKey(EspressoKey key) { - return new KeyEventAction(key); - } - - /** - * Returns an action that double clicks the view.<br> - * <br> - * View preconditions: - * <ul> - * <li>must be displayed on screen - * <ul> - */ - public static ViewAction doubleClick() { - return new GeneralClickAction(Tap.DOUBLE, GeneralLocation.CENTER, Press.FINGER); - } - - /** - * Returns an action that long clicks the view.<br> - * - * <br> - * View preconditions: - * <ul> - * <li>must be displayed on screen - * <ul> - */ - public static ViewAction longClick() { - return new GeneralClickAction(Tap.LONG, GeneralLocation.CENTER, Press.FINGER); - } - - /** - * Returns an action that scrolls to the view.<br> - * <br> - * View preconditions: - * <ul> - * <li>must be a descendant of ScrollView - * <li>must have visibility set to View.VISIBLE - * <ul> - */ - public static ViewAction scrollTo() { - return new ScrollToAction(); - } - - /** - * Returns an action that types the provided string into the view. - * Appending a \n to the end of the string translates to a ENTER key event. Note: this method - * does not change cursor position in the focused view - text is inserted at the location where - * the cursor is currently pointed.<br> - * <br> - * View preconditions: - * <ul> - * <li>must be displayed on screen - * <li>must support input methods - * <li>must be already focused - * <ul> - */ - public static ViewAction typeTextIntoFocusedView(String stringToBeTyped) { - return new TypeTextAction(stringToBeTyped, false /* tapToFocus */); - } - - /** - * Returns an action that selects the view (by clicking on it) and types the provided string into - * the view. Appending a \n to the end of the string translates to a ENTER key event. Note: this - * method performs a tap on the view before typing to force the view into focus, if the view - * already contains text this tap may place the cursor at an arbitrary position within the text. - * <br> - * <br> - * View preconditions: - * <ul> - * <li>must be displayed on screen - * <li>must support input methods - * <ul> - */ - public static ViewAction typeText(String stringToBeTyped) { - return new TypeTextAction(stringToBeTyped); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/assertion/ViewAssertions.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/assertion/ViewAssertions.java deleted file mode 100644 index eb14861..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/assertion/ViewAssertions.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.assertion; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.assertThat; -import static com.google.android.apps.common.testing.ui.espresso.util.TreeIterables.breadthFirstViewTraversal; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException; -import com.google.android.apps.common.testing.ui.espresso.ViewAssertion; -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; - -import android.util.Log; -import android.view.View; - -import junit.framework.AssertionFailedError; - -import org.hamcrest.Matcher; -import org.hamcrest.StringDescription; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * A collection of common {@link ViewAssertion}s. - */ -public final class ViewAssertions { - - private static final String TAG = ViewAssertions.class.getSimpleName(); - - - private ViewAssertions() {} - - /** - * Returns an assert that ensures the view matcher does not find any matching view in the - * hierarchy. - */ - public static ViewAssertion doesNotExist() { - return new ViewAssertion() { - @Override - public void check(View view, NoMatchingViewException noView) { - if (view != null) { - assertThat("View is present in the hierarchy: " + HumanReadables.describe(view), true, - is(false)); - } - } - }; - } - - /** - * Returns a generic {@link ViewAssertion} that asserts that a view exists in the view hierarchy - * and is matched by the given view matcher. - */ - public static ViewAssertion matches(final Matcher<? super View> viewMatcher) { - checkNotNull(viewMatcher); - return new ViewAssertion() { - @Override - public void check(View view, NoMatchingViewException noViewException) { - StringDescription description = new StringDescription(); - description.appendText("'"); - viewMatcher.describeTo(description); - if (noViewException != null) { - description.appendText(String.format( - "' check could not be performed because view '%s' was not found.\n", viewMatcher)); - Log.e(TAG, description.toString()); - throw noViewException; - } else { - // TODO(valeraz): ideally, we should append the matcher used to find the view - // This can be done in DefaultFailureHandler (just like we currently to with - // PerformException) - description.appendText("' doesn't match the selected view."); - assertThat(description.toString(), view, viewMatcher); - } - } - }; - } - - - /** - * Returns a generic {@link ViewAssertion} that asserts that the descendant views selected by the - * selector match the specified matcher. - * - * Example: onView(rootView).check(selectedDescendantsMatch( - * not(isAssignableFrom(TextView.class)), hasContentDescription())); - */ - public static ViewAssertion selectedDescendantsMatch( - final Matcher<View> selector, final Matcher<View> matcher) { - return new ViewAssertion() { - @SuppressWarnings("unchecked") - @Override - public void check(View view, NoMatchingViewException noViewException) { - Preconditions.checkNotNull(view); - - final Predicate<View> viewPredicate = new Predicate<View>() { - @Override - public boolean apply(View input) { - return selector.matches(input); - } - }; - - Iterator<View> selectedViewIterator = - Iterables.filter(breadthFirstViewTraversal(view), viewPredicate).iterator(); - - List<View> nonMatchingViews = new ArrayList<View>(); - while (selectedViewIterator.hasNext()) { - View selectedView = selectedViewIterator.next(); - - if (!matcher.matches(selectedView)) { - nonMatchingViews.add(selectedView); - } - } - - if (nonMatchingViews.size() > 0) { - String errorMessage = HumanReadables.getViewHierarchyErrorMessage(view, - nonMatchingViews, - String.format("At least one view did not match the required matcher: %s", matcher), - "****DOES NOT MATCH****"); - throw new AssertionFailedError(errorMessage); - } - } - }; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/AsyncTaskPoolMonitor.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/AsyncTaskPoolMonitor.java deleted file mode 100644 index 082c045..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/AsyncTaskPoolMonitor.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Provides a way to monitor AsyncTask's work queue to ensure that there is no work pending - * or executing (and to allow notification of idleness). - * - * This class is based on the assumption that we can get at the ThreadPoolExecutor AsyncTask uses. - * That is currently possible and easy in Froyo to JB. If it ever becomes impossible, as long as we - * know the max # of executor threads the AsyncTask framework allows we can still use this - * interface, just need a different implementation. - */ -class AsyncTaskPoolMonitor { - private final AtomicReference<IdleMonitor> monitor = new AtomicReference<IdleMonitor>(null); - private final ThreadPoolExecutor pool; - private final AtomicInteger activeBarrierChecks = new AtomicInteger(0); - - AsyncTaskPoolMonitor(ThreadPoolExecutor pool) { - this.pool = checkNotNull(pool); - } - - /** - * Checks if the pool is idle at this moment. - * - * @return true if the pool is idle, false otherwise. - */ - boolean isIdleNow() { - if (!pool.getQueue().isEmpty()) { - return false; - } else { - int activeCount = pool.getActiveCount(); - if (0 != activeCount) { - if (monitor.get() == null) { - // if there's no idle monitor scheduled and there are still barrier - // checks running, they are about to exit, ignore them. - activeCount = activeCount - activeBarrierChecks.get(); - } - } - return 0 == activeCount; - } - } - - /** - * Notifies caller once the pool is idle. - * - * We check for idle-ness by submitting the max # of tasks the pool will take and blocking - * the tasks until they are all executing. Then we know there are no other tasks _currently_ - * executing in the pool, we look back at the work queue to see if its backed up, if it is - * we reenqueue ourselves and try again. - * - * Obviously this strategy will fail horribly if 2 parties are doing it at the same time, - * we prevent recursion here the best we can. - * - * @param idleCallback called once the pool is idle. - */ - void notifyWhenIdle(final Runnable idleCallback) { - checkNotNull(idleCallback); - IdleMonitor myMonitor = new IdleMonitor(idleCallback); - checkState(monitor.compareAndSet(null, myMonitor), "cannot monitor for idle recursively!"); - myMonitor.monitorForIdle(); - } - - /** - * Stops the idle monitoring mechanism if it is in place. - * - * Note: the callback may still be invoked after this method is called. The only thing - * this method guarantees is that we will stop/cancel any blockign tasks we've placed - * on the thread pool. - */ - void cancelIdleMonitor() { - IdleMonitor myMonitor = monitor.getAndSet(null); - if (null != myMonitor) { - myMonitor.poison(); - } - } - - private class IdleMonitor { - private final Runnable onIdle; - private final AtomicInteger barrierGeneration = new AtomicInteger(0); - private final CyclicBarrier barrier; - // written by main, read by all. - private volatile boolean poisoned; - - private IdleMonitor(final Runnable onIdle) { - this.onIdle = checkNotNull(onIdle); - this.barrier = new CyclicBarrier(pool.getCorePoolSize(), - new Runnable() { - @Override - public void run() { - if (pool.getQueue().isEmpty()) { - // no one is behind us, so the queue is idle! - monitor.compareAndSet(IdleMonitor.this, null); - onIdle.run(); - } else { - // work is waiting behind us, enqueue another block of tasks and - // hopefully when they're all running, the queue will be empty. - monitorForIdle(); - } - - } - }); - } - - /** - * Stops this monitor from using the thread pool's resources, it may still cause the - * callback to be executed though. - */ - private void poison() { - poisoned = true; - barrier.reset(); - } - - private void monitorForIdle() { - if (poisoned) { - return; - } - - if (isIdleNow()) { - monitor.compareAndSet(this, null); - onIdle.run(); - } else { - // Submit N tasks that will block until they are all running on the thread pool. - // at this point we can check the pool's queue and verify that there are no new - // tasks behind us and deem the queue idle. - - int poolSize = pool.getCorePoolSize(); - final BarrierRestarter restarter = new BarrierRestarter(barrier, barrierGeneration); - - for (int i = 0; i < poolSize; i++) { - pool.execute(new Runnable() { - @Override - public void run() { - while (!poisoned) { - activeBarrierChecks.incrementAndGet(); - int myGeneration = barrierGeneration.get(); - try { - barrier.await(); - return; - } catch (InterruptedException ie) { - // sorry - I cant let you interrupt me! - restarter.restart(myGeneration); - } catch (BrokenBarrierException bbe) { - restarter.restart(myGeneration); - } finally { - activeBarrierChecks.decrementAndGet(); - } - } - } - }); - } - } - } - } - - - private static class BarrierRestarter { - private final CyclicBarrier barrier; - private final AtomicInteger barrierGeneration; - BarrierRestarter(CyclicBarrier barrier, AtomicInteger barrierGeneration) { - this.barrier = barrier; - this.barrierGeneration = barrierGeneration; - } - - /** - * restarts the barrier. - * - * After the calling this function it is guaranteed that barrier generation has been incremented - * and the barrier can be awaited on again. - * - * @param fromGeneration the generation that encountered the breaking exception. - */ - synchronized void restart(int fromGeneration) { - // must be synchronized. T1 could pass the if check, be suspended before calling reset, T2 - // sails thru - and awaits on the barrier again before T1 has awoken and reset it. - int nextGen = fromGeneration + 1; - if (barrierGeneration.compareAndSet(fromGeneration, nextGen)) { - // first time we've seen fromGeneration request a reset. lets reset the barrier. - barrier.reset(); - } else { - // some other thread has already reset the barrier - this request is a no op. - } - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/BaseLayerModule.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/BaseLayerModule.java deleted file mode 100644 index 6615b1d..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/BaseLayerModule.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitor; -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry; -import com.google.android.apps.common.testing.testrunner.InstrumentationRegistry; -import com.google.android.apps.common.testing.testrunner.inject.TargetContext; -import com.google.android.apps.common.testing.ui.espresso.FailureHandler; -import com.google.android.apps.common.testing.ui.espresso.Root; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.common.base.Optional; - -import android.content.Context; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; - -import dagger.Module; -import dagger.Provides; - -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.atomic.AtomicReference; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Dagger module for creating the implementation classes within the base package. - */ -@Module(library = true, injects = { - BaseLayerModule.FailureHandlerHolder.class, FailureHandler.class}) -public class BaseLayerModule { - - @Provides @Singleton - public ActivityLifecycleMonitor provideLifecycleMonitor() { - // TODO(user): replace with installation of AndroidInstrumentationModule once - // proguard issues resolved. - return ActivityLifecycleMonitorRegistry.getInstance(); - } - - @Provides @TargetContext - public Context provideTargetContext() { - // TODO(user): replace with installation of AndroidInstrumentationModule once - // proguard issues resolved. - return InstrumentationRegistry.getInstance().getTargetContext(); - } - - @Provides @Singleton - public Looper provideMainLooper() { - return Looper.getMainLooper(); - } - - @Provides - public UiController provideUiController(UiControllerImpl uiControllerImpl) { - return uiControllerImpl; - } - - @Provides @Singleton @CompatAsyncTask - public Optional<AsyncTaskPoolMonitor> provideCompatAsyncTaskMonitor( - ThreadPoolExecutorExtractor extractor) { - Optional<ThreadPoolExecutor> compatThreadPool = extractor.getCompatAsyncTaskThreadPool(); - if (compatThreadPool.isPresent()) { - return Optional.of(new AsyncTaskPoolMonitor(compatThreadPool.get())); - } else { - return Optional.<AsyncTaskPoolMonitor>absent(); - } - } - - @Provides @Singleton @MainThread - public Executor provideMainThreadExecutor(Looper mainLooper) { - final Handler handler = new Handler(mainLooper); - return new Executor() { - @Override - public void execute(Runnable runnable) { - handler.post(runnable); - } - }; - } - - @Provides @Singleton @SdkAsyncTask - public AsyncTaskPoolMonitor provideSdkAsyncTaskMonitor(ThreadPoolExecutorExtractor extractor) { - return new AsyncTaskPoolMonitor(extractor.getAsyncTaskThreadPool()); - - } - - @Provides - public List<Root> provideKnownRoots(RootsOracle rootsOracle) { - // RootsOracle acts as a provider, but returning Providers is illegal, so delegate. - return rootsOracle.get(); - } - - @Provides @Singleton - public EventInjector provideEventInjector() { - // On API 16 and above, android uses input manager to inject events. On API < 16, - // they use Window Manager. So we need to create our InjectionStrategy depending on the api - // level. Instrumentation does not check if the event presses went through by checking the - // boolean return value of injectInputEvent, which is why we created this class to better - // handle lost/dropped press events. Instrumentation cannot be used as a fallback strategy, - // since this will be executed on the main thread. - int sdkVersion = Build.VERSION.SDK_INT; - EventInjectionStrategy injectionStrategy = null; - if (sdkVersion >= 16) { // Use InputManager for API level 16 and up. - InputManagerEventInjectionStrategy strategy = new InputManagerEventInjectionStrategy(); - strategy.initialize(); - injectionStrategy = strategy; - } else if (sdkVersion >= 7) { - // else Use WindowManager for API level 15 through 7. - WindowManagerEventInjectionStrategy strategy = new WindowManagerEventInjectionStrategy(); - strategy.initialize(); - injectionStrategy = strategy; - } else { - throw new RuntimeException( - "API Level 6 and below is not supported. You are running: " + sdkVersion); - } - return new EventInjector(injectionStrategy); - } - - /** - * Holder for AtomicReference<FailureHandler> which allows updating it at runtime. - */ - @Singleton - public static class FailureHandlerHolder { - private final AtomicReference<FailureHandler> holder; - - @Inject - public FailureHandlerHolder(@Default FailureHandler defaultHandler) { - holder = new AtomicReference<FailureHandler>(defaultHandler); - } - - public void update(FailureHandler handler) { - holder.set(handler); - } - - public FailureHandler get() { - return holder.get(); - } - } - - @Provides - FailureHandler provideFailureHandler(FailureHandlerHolder holder) { - return holder.get(); - } - - @Provides - @Default - FailureHandler provideFailureHander(DefaultFailureHandler impl) { - return impl; - } - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/CompatAsyncTask.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/CompatAsyncTask.java deleted file mode 100644 index 11ec6ab..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/CompatAsyncTask.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -/** - * Annotates a AsyncTaskMonitor as monitoring the CompatAsyncTask pool - */ -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -@interface CompatAsyncTask { } diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/Default.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/Default.java deleted file mode 100644 index b54440d..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/Default.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -/** - * Annotates a default provider. - */ -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface Default { -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/DefaultFailureHandler.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/DefaultFailureHandler.java deleted file mode 100644 index b1e43da..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/DefaultFailureHandler.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Throwables.propagate; - -import com.google.android.apps.common.testing.testrunner.inject.TargetContext; -import com.google.android.apps.common.testing.ui.espresso.EspressoException; -import com.google.android.apps.common.testing.ui.espresso.FailureHandler; -import com.google.android.apps.common.testing.ui.espresso.PerformException; - -import android.content.Context; -import android.view.View; - -import junit.framework.AssertionFailedError; - -import org.hamcrest.Matcher; - -import java.util.concurrent.atomic.AtomicInteger; - -import javax.inject.Inject; - -/** - * Espresso's default {@link FailureHandler}. If this does not fit your needs, feel free to provide - * your own implementation via Espresso.setFailureHandler(FailureHandler). - */ -public final class DefaultFailureHandler implements FailureHandler { - - private static final AtomicInteger failureCount = new AtomicInteger(0); - private final Context appContext; - - @Inject - public DefaultFailureHandler(@TargetContext Context appContext) { - this.appContext = checkNotNull(appContext); - } - - @Override - public void handle(Throwable error, Matcher<View> viewMatcher) { - if (error instanceof EspressoException || error instanceof AssertionFailedError - || error instanceof AssertionError) { - throw propagate(getUserFriendlyError(error, viewMatcher)); - } else { - throw propagate(error); - } - } - - /** - * When the error is coming from espresso, it is more user friendly to: - * 1. propagate assertions as assertions - * 2. swap the stack trace of the error to that of current thread (which will show - * directly where the actual problem is) - */ - private Throwable getUserFriendlyError(Throwable error, Matcher<View> viewMatcher) { - if (error instanceof PerformException) { - // Re-throw the exception with the viewMatcher (used to locate the view) as the view - // description (makes the error more readable). The reason we do this here: not all creators - // of PerformException have access to the viewMatcher. - throw new PerformException.Builder() - .from((PerformException) error) - .withViewDescription(viewMatcher.toString()) - .build(); - } - - if (error instanceof AssertionError) { - // reports Failure instead of Error. - // assertThat(...) throws an AssertionFailedError. - error = new AssertionFailedWithCauseError(error.getMessage(), error); - } - - error.setStackTrace(Thread.currentThread().getStackTrace()); - return error; - } - - private static final class AssertionFailedWithCauseError extends AssertionFailedError { - /* junit hides the cause constructor. */ - public AssertionFailedWithCauseError(String message, Throwable cause) { - super(message); - initCause(cause); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjectionStrategy.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjectionStrategy.java deleted file mode 100644 index 3378197..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjectionStrategy.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; - -import android.view.KeyEvent; -import android.view.MotionEvent; - -/** - * Injects Events into the application under test. Implementors should expect to be called - * from the UI thread and are responsible for ensuring the event gets delivered or indicating that - * it could not be delivered. - */ -interface EventInjectionStrategy { - /** - * Injects the given {@link KeyEvent} into the android system. - * - * @param keyEvent The event to inject - * @return {@code true} if the input was inject successfully, {@code false} otherwise. - * @throws InjectEventSecurityException if the MotionEvent would be delivered to an area of the - * screen that is not owned by the application under test. - */ - boolean injectKeyEvent(KeyEvent keyEvent) throws InjectEventSecurityException; - - /** - * Injects the given {@link MotionEvent} into the android system. - * - * @param motionEvent The event to inject - * @return {@code true} if the input was inject successfully, {@code false} otherwise. - * @throws InjectEventSecurityException if the MotionEvent would be delivered to an area of the - * screen that is not owned by the application under test. - */ - boolean injectMotionEvent(MotionEvent motionEvent) throws InjectEventSecurityException; - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjector.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjector.java deleted file mode 100644 index 0728331..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjector.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; - -import android.os.Build; -import android.os.SystemClock; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; - -/** - * Responsible for selecting the proper strategy for injecting MotionEvents to the application under - * test. - */ -final class EventInjector { - private static final String TAG = EventInjector.class.getSimpleName(); - private final EventInjectionStrategy injectionStrategy; - - EventInjector(EventInjectionStrategy injectionStrategy) { - this.injectionStrategy = checkNotNull(injectionStrategy); - } - - boolean injectKeyEvent(KeyEvent event) throws InjectEventSecurityException { - long downTime = event.getDownTime(); - long eventTime = event.getEventTime(); - int action = event.getAction(); - int code = event.getKeyCode(); - int repeatCount = event.getRepeatCount(); - int metaState = event.getMetaState(); - int deviceId = event.getDeviceId(); - int scancode = event.getScanCode(); - int flags = event.getFlags(); - - if (eventTime == 0) { - eventTime = SystemClock.uptimeMillis(); - } - - if (downTime == 0) { - downTime = eventTime; - } - - // API < 9 does not have constructor with source (nor has source field). - KeyEvent newEvent; - if (Build.VERSION.SDK_INT < 9) { - newEvent = new KeyEvent(downTime, - eventTime, - action, - code, - repeatCount, - metaState, - deviceId, - scancode, - flags | KeyEvent.FLAG_FROM_SYSTEM); - } else { - int source = event.getSource(); - newEvent = new KeyEvent(downTime, - eventTime, - action, - code, - repeatCount, - metaState, - deviceId, - scancode, - flags | KeyEvent.FLAG_FROM_SYSTEM, - source); - } - - Log.v( - "ESP_TRACE", - String.format( - "%s:Injecting event for character (%c) with key code (%s) downtime: (%s)", TAG, - newEvent.getUnicodeChar(), newEvent.getKeyCode(), newEvent.getDownTime())); - - return injectionStrategy.injectKeyEvent(newEvent); - } - - boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException { - return injectionStrategy.injectMotionEvent(event); - } - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java deleted file mode 100644 index e390f0f..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import com.google.android.apps.common.testing.ui.espresso.IdlingPolicies; -import com.google.android.apps.common.testing.ui.espresso.IdlingPolicy; -import com.google.android.apps.common.testing.ui.espresso.IdlingResource; -import com.google.android.apps.common.testing.ui.espresso.IdlingResource.ResourceCallback; -import com.google.common.collect.Lists; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - -import java.util.BitSet; -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Keeps track of user-registered {@link IdlingResource}s. - */ -@Singleton -public final class IdlingResourceRegistry { - private static final String TAG = IdlingResourceRegistry.class.getSimpleName(); - - private static final int DYNAMIC_RESOURCE_HAS_IDLED = 1; - private static final int TIMEOUT_OCCURRED = 2; - private static final int IDLE_WARNING_REACHED = 3; - private static final int POSSIBLE_RACE_CONDITION_DETECTED = 4; - private static final Object TIMEOUT_MESSAGE_TAG = new Object(); - - private static final IdleNotificationCallback NO_OP_CALLBACK = new IdleNotificationCallback() { - - @Override - public void allResourcesIdle() {} - - @Override - public void resourcesStillBusyWarning(List<String> busys) {} - - @Override - public void resourcesHaveTimedOut(List<String> busys) {} - }; - - // resources and idleState should only be accessed on main thread - private final List<IdlingResource> resources = Lists.newArrayList(); - // idleState.get(i) == true indicates resources.get(i) is idle, false indicates it's busy - private final BitSet idleState = new BitSet(); - private final Looper looper; - private final Handler handler; - private final Dispatcher dispatcher; - private IdleNotificationCallback idleNotificationCallback = NO_OP_CALLBACK; - - @Inject - public IdlingResourceRegistry(Looper looper) { - this.looper = looper; - this.dispatcher = new Dispatcher(); - this.handler = new Handler(looper, dispatcher); - } - - /** - * Registers the given resource. - */ - public void register(final IdlingResource resource) { - checkNotNull(resource); - if (Looper.myLooper() != looper) { - handler.post(new Runnable() { - @Override - public void run() { - register(resource); - } - }); - } else { - for (IdlingResource oldResource : resources) { - if (resource.getName().equals(oldResource.getName())) { - // This does not throw an error to avoid leaving tests that register resource in test - // setup in an undeterministic state (we cannot assume that everyone clears vm state - // between each test run) - Log.e(TAG, String.format("Attempted to register resource with same names:" + - " %s. R1: %s R2: %s.\nDuplicate resource registration will be ignored.", - resource.getName(), resource, oldResource)); - return; - } - } - resources.add(resource); - final int position = resources.size() - 1; - registerToIdleCallback(resource, position); - idleState.set(position, resource.isIdleNow()); - } - } - - public void registerLooper(Looper looper, boolean considerWaitIdle) { - checkNotNull(looper); - checkArgument(Looper.getMainLooper() != looper, "Not intended for use with main looper!"); - register(new LooperIdlingResource(looper, considerWaitIdle)); - } - - private void registerToIdleCallback(IdlingResource resource, final int position) { - resource.registerIdleTransitionCallback(new ResourceCallback() { - @Override - public void onTransitionToIdle() { - Message m = handler.obtainMessage(DYNAMIC_RESOURCE_HAS_IDLED); - m.arg1 = position; - handler.sendMessage(m); - } - }); - } - - boolean allResourcesAreIdle() { - checkState(Looper.myLooper() == looper); - for (int i = idleState.nextSetBit(0); i >= 0 && i < resources.size(); - i = idleState.nextSetBit(i + 1)) { - idleState.set(i, resources.get(i).isIdleNow()); - } - return idleState.cardinality() == resources.size(); - } - - interface IdleNotificationCallback { - public void allResourcesIdle(); - - public void resourcesStillBusyWarning(List<String> busyResourceNames); - - public void resourcesHaveTimedOut(List<String> busyResourceNames); - } - - void notifyWhenAllResourcesAreIdle(IdleNotificationCallback callback) { - checkNotNull(callback); - checkState(Looper.myLooper() == looper); - checkState(idleNotificationCallback == NO_OP_CALLBACK, "Callback has already been registered."); - if (allResourcesAreIdle()) { - callback.allResourcesIdle(); - } else { - idleNotificationCallback = callback; - scheduleTimeoutMessages(); - } - } - - void cancelIdleMonitor() { - dispatcher.deregister(); - } - - private void scheduleTimeoutMessages() { - IdlingPolicy warning = IdlingPolicies.getDynamicIdlingResourceWarningPolicy(); - Message timeoutWarning = handler.obtainMessage(IDLE_WARNING_REACHED, TIMEOUT_MESSAGE_TAG); - handler.sendMessageDelayed(timeoutWarning, warning.getIdleTimeoutUnit().toMillis( - warning.getIdleTimeout())); - Message timeoutError = handler.obtainMessage(TIMEOUT_OCCURRED, TIMEOUT_MESSAGE_TAG); - IdlingPolicy error = IdlingPolicies.getDynamicIdlingResourceErrorPolicy(); - - handler.sendMessageDelayed(timeoutError, error.getIdleTimeoutUnit().toMillis( - error.getIdleTimeout())); - } - - private List<String> getBusyResources() { - List<String> busyResourceNames = Lists.newArrayList(); - List<Integer> racyResources = Lists.newArrayList(); - - for (int i = 0; i < resources.size(); i++) { - IdlingResource resource = resources.get(i); - if (!idleState.get(i)) { - if (resource.isIdleNow()) { - // We have not been notified of a BUSY -> IDLE transition, but the resource is telling us - // its that its idle. Either it's a race condition or is this resource buggy. - racyResources.add(i); - } else { - busyResourceNames.add(resource.getName()); - } - } - } - - if (!racyResources.isEmpty()) { - Message raceBuster = handler.obtainMessage(POSSIBLE_RACE_CONDITION_DETECTED, - TIMEOUT_MESSAGE_TAG); - raceBuster.obj = racyResources; - handler.sendMessage(raceBuster); - return null; - } else { - return busyResourceNames; - } - } - - - private class Dispatcher implements Handler.Callback { - @Override - public boolean handleMessage(Message m) { - switch (m.what) { - case DYNAMIC_RESOURCE_HAS_IDLED: - handleResourceIdled(m); - break; - case IDLE_WARNING_REACHED: - handleTimeoutWarning(); - break; - case TIMEOUT_OCCURRED: - handleTimeout(); - break; - case POSSIBLE_RACE_CONDITION_DETECTED: - handleRaceCondition(m); - break; - default: - Log.w(TAG, "Unknown message type: " + m); - return false; - } - return true; - } - - private void handleResourceIdled(Message m) { - idleState.set(m.arg1, true); - if (idleState.cardinality() == resources.size()) { - try { - idleNotificationCallback.allResourcesIdle(); - } finally { - deregister(); - } - } - } - - private void handleTimeoutWarning() { - List<String> busyResources = getBusyResources(); - if (busyResources == null) { - // null indicates that there is either a race or a programming error - // a race detector message has been inserted into the q. - // reinsert the idle_warning_reached message into the q directly after it - // so we generate warnings if the system is still sane. - handler.sendMessage(handler.obtainMessage(IDLE_WARNING_REACHED, TIMEOUT_MESSAGE_TAG)); - } else { - IdlingPolicy warning = IdlingPolicies.getDynamicIdlingResourceWarningPolicy(); - idleNotificationCallback.resourcesStillBusyWarning(busyResources); - handler.sendMessageDelayed( - handler.obtainMessage(IDLE_WARNING_REACHED, TIMEOUT_MESSAGE_TAG), - warning.getIdleTimeoutUnit().toMillis(warning.getIdleTimeout())); - } - } - - private void handleTimeout() { - List<String> busyResources = getBusyResources(); - if (busyResources == null) { - // detected a possible race... we've enqueued a race busting message - // so either that'll resolve the race or kill the app because it's buggy. - // if the race resolves, we need to timeout properly. - handler.sendMessage(handler.obtainMessage(TIMEOUT_OCCURRED, TIMEOUT_MESSAGE_TAG)); - } else { - try { - idleNotificationCallback.resourcesHaveTimedOut(busyResources); - } finally { - deregister(); - } - } - } - - @SuppressWarnings("unchecked") - private void handleRaceCondition(Message m) { - for (Integer i : (List<Integer>) m.obj) { - if (idleState.get(i)) { - // it was a race... i is now idle, everything is fine... - } else { - throw new IllegalStateException(String.format( - "Resource %s isIdleNow() is returning true, but a message indicating that the " - + "resource has transitioned from busy to idle was never sent.", - resources.get(i).getName())); - } - } - } - - private void deregister() { - handler.removeCallbacksAndMessages(TIMEOUT_MESSAGE_TAG); - idleNotificationCallback = NO_OP_CALLBACK; - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/InputManagerEventInjectionStrategy.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/InputManagerEventInjectionStrategy.java deleted file mode 100644 index d324795..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/InputManagerEventInjectionStrategy.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Throwables.propagate; - -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; - -import android.os.Build; -import android.util.Log; -import android.view.InputDevice; -import android.view.InputEvent; -import android.view.KeyEvent; -import android.view.MotionEvent; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * An {@link EventInjectionStrategy} that uses the input manager to inject Events. - * This strategy supports API level 16 and above. - */ -final class InputManagerEventInjectionStrategy implements EventInjectionStrategy { - private static final String TAG = InputManagerEventInjectionStrategy.class.getSimpleName(); - - // Used in reflection - private boolean initComplete; - private Method injectInputEventMethod; - private Method setSourceMotionMethod; - private Object instanceInputManagerObject; - private int motionEventMode; - private int keyEventMode; - - InputManagerEventInjectionStrategy() { - checkState(Build.VERSION.SDK_INT >= 16, "Unsupported API level."); - } - - void initialize() { - if (initComplete) { - return; - } - - try { - Log.d(TAG, "Creating injection strategy with input manager."); - - // Get the InputputManager class object and initialize if necessary. - Class<?> inputManagerClassObject = Class.forName("android.hardware.input.InputManager"); - Method getInstanceMethod = inputManagerClassObject.getDeclaredMethod("getInstance"); - getInstanceMethod.setAccessible(true); - - instanceInputManagerObject = getInstanceMethod.invoke(inputManagerClassObject); - - injectInputEventMethod = instanceInputManagerObject.getClass() - .getDeclaredMethod("injectInputEvent", InputEvent.class, Integer.TYPE); - injectInputEventMethod.setAccessible(true); - - // Setting event mode to INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH to ensure - // that we've dispatched the event and any side effects its had on the view hierarchy - // have occurred. - Field motionEventModeField = - inputManagerClassObject.getField("INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH"); - motionEventModeField.setAccessible(true); - motionEventMode = motionEventModeField.getInt(inputManagerClassObject); - - Field keyEventModeField = - inputManagerClassObject.getField("INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH"); - keyEventModeField.setAccessible(true); - keyEventMode = keyEventModeField.getInt(inputManagerClassObject); - - setSourceMotionMethod = MotionEvent.class.getDeclaredMethod("setSource", Integer.TYPE); - InputEvent.class.getDeclaredMethod("getSequenceNumber"); - initComplete = true; - } catch (ClassNotFoundException e) { - propagate(e); - } catch (IllegalAccessException e) { - propagate(e); - } catch (IllegalArgumentException e) { - propagate(e); - } catch (InvocationTargetException e) { - propagate(e); - } catch (NoSuchMethodException e) { - propagate(e); - } catch (SecurityException e) { - propagate(e); - } catch (NoSuchFieldException e) { - propagate(e); - } - } - - @Override - public boolean injectKeyEvent(KeyEvent keyEvent) throws InjectEventSecurityException { - try { - return (Boolean) injectInputEventMethod.invoke(instanceInputManagerObject, - keyEvent, keyEventMode); - } catch (IllegalAccessException e) { - propagate(e); - } catch (IllegalArgumentException e) { - propagate(e); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof SecurityException) { - throw new InjectEventSecurityException(cause); - } - propagate(e); - } catch (SecurityException e) { - throw new InjectEventSecurityException(e); - } - return false; - } - - @Override - public boolean injectMotionEvent(MotionEvent motionEvent) throws InjectEventSecurityException { - try { - // Need to set the event source to touch screen, otherwise the input can be ignored even - // though injecting it would be successful. - // TODO(user): proper handling of events from a trackball (SOURCE_TRACKBALL) and joystick. - if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0 - && !isFromTouchpadInGlassDevice(motionEvent)) { - // Need to do runtime invocation of setSource because it was not added until 2.3_r1. - setSourceMotionMethod.invoke(motionEvent, InputDevice.SOURCE_TOUCHSCREEN); - } - return (Boolean) injectInputEventMethod.invoke(instanceInputManagerObject, - motionEvent, motionEventMode); - } catch (IllegalAccessException e) { - propagate(e); - } catch (IllegalArgumentException e) { - propagate(e); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof SecurityException) { - throw new InjectEventSecurityException(cause); - } - propagate(e); - } catch (SecurityException e) { - throw new InjectEventSecurityException(e); - } - return false; - } - - // We'd like to inject non-pointer events sourced from touchpad in Glass. - private static boolean isFromTouchpadInGlassDevice(MotionEvent motionEvent) { - return (Build.DEVICE.contains("glass") - || Build.DEVICE.contains("Glass") || Build.DEVICE.contains("wingman")) - && ((motionEvent.getSource() & InputDevice.SOURCE_TOUCHPAD) != 0); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/LooperIdlingResource.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/LooperIdlingResource.java deleted file mode 100644 index b75fd36..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/LooperIdlingResource.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import com.google.android.apps.common.testing.ui.espresso.IdlingResource; -import com.google.android.apps.common.testing.ui.espresso.IdlingResource.ResourceCallback; -import com.google.android.apps.common.testing.ui.espresso.base.QueueInterrogator.QueueState; - -import android.os.Handler; -import android.os.Looper; -import android.os.MessageQueue.IdleHandler; - -/** - * An Idling Resource Adapter for Loopers. - */ -final class LooperIdlingResource implements IdlingResource { - - private static final String TAG = "LooperIdleResource"; - - private final boolean considerWaitIdle; - private final Looper monitoredLooper; - private final Handler monitoredHandler; - - private ResourceCallback resourceCallback; - - LooperIdlingResource(Looper monitoredLooper, boolean considerWaitIdle) { - this.monitoredLooper = checkNotNull(monitoredLooper); - this.monitoredHandler = new Handler(monitoredLooper); - this.considerWaitIdle = considerWaitIdle; - checkState(Looper.getMainLooper() != monitoredLooper, "Not for use with main looper."); - } - - // Only assigned and read from the main loop. - private QueueInterrogator queueInterrogator; - - @Override - public String getName() { - return monitoredLooper.getThread().getName(); - } - - @Override - public boolean isIdleNow() { - // on main thread here. - QueueState state = queueInterrogator.determineQueueState(); - boolean idle = state == QueueState.EMPTY || state == QueueState.TASK_DUE_LONG; - boolean idleWait = considerWaitIdle - && monitoredLooper.getThread().getState() == Thread.State.WAITING; - if (idleWait) { - if (resourceCallback != null) { - resourceCallback.onTransitionToIdle(); - } - } - return idle || idleWait; - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - // on main thread here. - queueInterrogator = new QueueInterrogator(monitoredLooper); - - // must load idle handlers from monitored looper thread. - IdleHandler idleHandler = new ResourceCallbackIdleHandler(resourceCallback, queueInterrogator, - monitoredHandler); - - checkState(monitoredHandler.postAtFrontOfQueue(new Initializer(idleHandler)), - "Monitored looper exiting."); - } - - private static class ResourceCallbackIdleHandler implements IdleHandler { - private final ResourceCallback resourceCallback; - private final QueueInterrogator myInterrogator; - private final Handler myHandler; - - ResourceCallbackIdleHandler(ResourceCallback resourceCallback, - QueueInterrogator myInterrogator, Handler myHandler) { - this.resourceCallback = checkNotNull(resourceCallback); - this.myInterrogator = checkNotNull(myInterrogator); - this.myHandler = checkNotNull(myHandler); - } - - @Override - public boolean queueIdle() { - // invoked on the monitored looper thread. - QueueState queueState = myInterrogator.determineQueueState(); - if (queueState == QueueState.EMPTY || queueState == QueueState.TASK_DUE_LONG) { - // no block and no task coming 'shortly'. - resourceCallback.onTransitionToIdle(); - } else if (queueState == QueueState.BARRIER) { - // send a sentinal message that'll cause us to queueIdle again once the - // block is lifted. - myHandler.sendEmptyMessage(-1); - } - - return true; - } - } - - private static class Initializer implements Runnable { - private final IdleHandler myIdleHandler; - - Initializer(IdleHandler myIdleHandler) { - this.myIdleHandler = checkNotNull(myIdleHandler); - } - - @Override - public void run() { - // on monitored looper thread. - Looper.myQueue().addIdleHandler(myIdleHandler); - } - } - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/MainThread.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/MainThread.java deleted file mode 100644 index c431f48..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/MainThread.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -/** - * Annotates an Executor that executes tasks on the main thread - */ -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface MainThread { } diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/QueueInterrogator.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/QueueInterrogator.java deleted file mode 100644 index cd63eb8..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/QueueInterrogator.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Throwables.propagate; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.MessageQueue; -import android.os.SystemClock; -import android.util.Log; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; - -/** - * Isolates the nasty details of touching the message queue. - */ -final class QueueInterrogator { - - enum QueueState { EMPTY, TASK_DUE_SOON, TASK_DUE_LONG, BARRIER }; - - private static final String TAG = "QueueInterrogator"; - - private static final Method messageQueueNextMethod; - private static final Field messageQueueHeadField; - private static final int LOOKAHEAD_MILLIS = 15; - - private final Looper interrogatedLooper; - private volatile MessageQueue interrogatedQueue; - - static { - Method nextMethod = null; - Field headField = null; - try { - nextMethod = MessageQueue.class.getDeclaredMethod("next"); - nextMethod.setAccessible(true); - - headField = MessageQueue.class.getDeclaredField("mMessages"); - headField.setAccessible(true); - } catch (IllegalArgumentException e) { - nextMethod = null; - headField = null; - Log.e(TAG, "Could not initialize interrogator!", e); - } catch (NoSuchFieldException e) { - nextMethod = null; - headField = null; - Log.e(TAG, "Could not initialize interrogator!", e); - } catch (NoSuchMethodException e) { - nextMethod = null; - headField = null; - Log.e(TAG, "Could not initialize interrogator!", e); - } catch (SecurityException e) { - nextMethod = null; - headField = null; - Log.e(TAG, "Could not initialize interrogator!", e); - } finally { - messageQueueNextMethod = nextMethod; - messageQueueHeadField = headField; - } - } - - QueueInterrogator(Looper interrogatedLooper) { - this.interrogatedLooper = checkNotNull(interrogatedLooper); - checkNotNull(messageQueueHeadField); - checkNotNull(messageQueueNextMethod); - } - - // Only for use by espresso - keep package private. - Message getNextMessage() { - checkThread(); - - if (null == interrogatedQueue) { - initializeQueue(); - } - - try { - return (Message) messageQueueNextMethod.invoke(Looper.myQueue()); - } catch (IllegalAccessException e) { - throw propagate(e); - } catch (IllegalArgumentException e) { - throw propagate(e); - } catch (InvocationTargetException e) { - throw propagate(e); - } catch (SecurityException e) { - throw propagate(e); - } - } - - QueueState determineQueueState() { - // may be called from any thread. - - if (null == interrogatedQueue) { - initializeQueue(); - } - synchronized (interrogatedQueue) { - try { - Message head = (Message) messageQueueHeadField.get(interrogatedQueue); - if (null == head) { - // no messages pending - AT ALL! - return QueueState.EMPTY; - } - if (null == head.getTarget()) { - // null target is a sync barrier token. - return QueueState.BARRIER; - } else { - long headWhen = head.getWhen(); - long nowFuz = SystemClock.uptimeMillis() + LOOKAHEAD_MILLIS; - - if (nowFuz > headWhen) { - return QueueState.TASK_DUE_SOON; - } else { - return QueueState.TASK_DUE_LONG; - } - } - } catch (IllegalAccessException e) { - throw propagate(e); - } - } - } - - private void initializeQueue() { - if (interrogatedLooper == Looper.myLooper()) { - interrogatedQueue = Looper.myQueue(); - } else { - Handler oneShotHandler = new Handler(interrogatedLooper); - FutureTask<MessageQueue> queueCapture = new FutureTask<MessageQueue>( - new Callable<MessageQueue>() { - @Override - public MessageQueue call() { - return Looper.myQueue(); - } - }); - oneShotHandler.postAtFrontOfQueue(queueCapture); - try { - interrogatedQueue = queueCapture.get(); - } catch (ExecutionException ee) { - throw propagate(ee.getCause()); - } catch (InterruptedException ie) { - throw propagate(ie); - } - } - } - - private void checkThread() { - checkState(interrogatedLooper == Looper.myLooper(), "Calling from non-owning thread!"); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java deleted file mode 100644 index 6870aa3..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers.isDialog; -import static com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers.isFocusable; -import static com.google.common.base.Preconditions.checkState; - -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitor; -import com.google.android.apps.common.testing.testrunner.Stage; -import com.google.android.apps.common.testing.ui.espresso.NoActivityResumedException; -import com.google.android.apps.common.testing.ui.espresso.NoMatchingRootException; -import com.google.android.apps.common.testing.ui.espresso.Root; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; - -import android.app.Activity; -import android.os.Looper; -import android.util.Log; -import android.view.View; - -import org.hamcrest.Matcher; - -import java.util.Collection; -import java.util.EnumSet; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import javax.inject.Inject; -import javax.inject.Provider; -import javax.inject.Singleton; - -/** - * Provides the root View of the top-most Window, with which the user can interact. View is - * guaranteed to be in a stable state - i.e. not pending any updates from the application. - * - * This provider can only be accessed from the main thread. - */ -@Singleton -public final class RootViewPicker implements Provider<View> { - private static final String TAG = RootViewPicker.class.getSimpleName(); - - private final Provider<List<Root>> rootsOracle; - private final UiController uiController; - private final ActivityLifecycleMonitor activityLifecycleMonitor; - private final AtomicReference<Matcher<Root>> rootMatcherRef; - - private List<Root> roots; - - @Inject - RootViewPicker(Provider<List<Root>> rootsOracle, UiController uiController, - ActivityLifecycleMonitor activityLifecycleMonitor, - AtomicReference<Matcher<Root>> rootMatcherRef) { - this.rootsOracle = rootsOracle; - this.uiController = uiController; - this.activityLifecycleMonitor = activityLifecycleMonitor; - this.rootMatcherRef = rootMatcherRef; - } - - @Override - public View get() { - checkState(Looper.getMainLooper().equals(Looper.myLooper()), "must be called on main thread."); - Matcher<Root> rootMatcher = rootMatcherRef.get(); - - Root root = findRoot(rootMatcher); - - // we only want to propagate a root view that the user can interact with and is not - // about to relay itself out. An app should be in this state the majority of the time, - // if we happen not to be in this state at the moment, process the queue some more - // we should come to it quickly enough. - int loops = 0; - - while (!isReady(root)) { - if (loops < 3) { - uiController.loopMainThreadUntilIdle(); - } else if (loops < 1001) { - - // loopUntil idle effectively is polling and pegs the CPU... if we don't have an update to - // process immediately, we might have something coming very very soon. - uiController.loopMainThreadForAtLeast(10); - } else { - // we've waited for the root view to be fully laid out and have window focus - // for over 10 seconds. something is wrong. - throw new RuntimeException(String.format("Waited for the root of the view hierarchy to have" - + " window focus and not be requesting layout for over 10 seconds. If you specified a" - + " non default root matcher, it may be picking a root that never takes focus." - + " Otherwise, something is seriously wrong. Selected Root:\n%s\n. All Roots:\n%s" - , root, Joiner.on("\n").join(roots))); - } - - root = findRoot(rootMatcher); - loops++; - } - - return root.getDecorView(); - } - - private boolean isReady(Root root) { - // Root is ready (i.e. UI is no longer in flux) if layout of the root view is not being - // requested and the root view has window focus (if it is focusable). - View rootView = root.getDecorView(); - if (!rootView.isLayoutRequested()) { - return rootView.hasWindowFocus() || !isFocusable().matches(root); - } - return false; - } - - private Root findRoot(Matcher<Root> rootMatcher) { - waitForAtLeastOneActivityToBeResumed(); - - roots = rootsOracle.get(); - - // TODO(user): move these checks into the RootsOracle. - if (roots.isEmpty()) { - // Reflection broke - throw new RuntimeException("No root window were discovered."); - } - - if (roots.size() > 1) { - // Multiple roots only occur: - // when multiple activities are in some state of their lifecycle in the application - // - we don't care about this, since we only want to interact with the RESUMED - // activity, all other activities windows are not visible to the user so, out of - // scope. - // when a PopupWindow or PopupMenu is used - // - this is a case where we definitely want to consider the top most window, since - // it probably has the most useful info in it. - // when an android.app.dialog is shown - // - again, this is getting all the users attention, so it gets the test attention - // too. - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, String.format("Multiple windows detected: %s", roots)); - } - } - - List<Root> selectedRoots = Lists.newArrayList(); - for (Root root : roots) { - if (rootMatcher.matches(root)) { - selectedRoots.add(root); - } - } - - if (selectedRoots.isEmpty()) { - throw NoMatchingRootException.create(rootMatcher, roots); - } - - return reduceRoots(selectedRoots); - } - - @SuppressWarnings("unused") - private void waitForAtLeastOneActivityToBeResumed() { - Collection<Activity> resumedActivities = - activityLifecycleMonitor.getActivitiesInStage(Stage.RESUMED); - if (resumedActivities.isEmpty()) { - uiController.loopMainThreadUntilIdle(); - resumedActivities = activityLifecycleMonitor.getActivitiesInStage(Stage.RESUMED); - } - if (resumedActivities.isEmpty()) { - List<Activity> activities = Lists.newArrayList(); - for (Stage s : EnumSet.range(Stage.PRE_ON_CREATE, Stage.RESTARTED)) { - activities.addAll(activityLifecycleMonitor.getActivitiesInStage(s)); - } - if (activities.isEmpty()) { - throw new RuntimeException("No activities found. Did you forget to launch the activity " - + "by calling getActivity() or startActivitySync or similar?"); - } - // well at least there are some activities in the pipeline - lets see if they resume. - - long[] waitTimes = - {10, 50, 100, 500, TimeUnit.SECONDS.toMillis(2), TimeUnit.SECONDS.toMillis(30)}; - - for (int waitIdx = 0; waitIdx < waitTimes.length; waitIdx++) { - Log.w(TAG, "No activity currently resumed - waiting: " + waitTimes[waitIdx] - + "ms for one to appear."); - uiController.loopMainThreadForAtLeast(waitTimes[waitIdx]); - resumedActivities = activityLifecycleMonitor.getActivitiesInStage(Stage.RESUMED); - if (!resumedActivities.isEmpty()) { - return; // one of the pending activities has resumed - } - } - throw new NoActivityResumedException("No activities in stage RESUMED. Did you forget to " - + "launch the activity. (test.getActivity() or similar)?"); - } - } - - private Root reduceRoots(List<Root> subpanels) { - Root topSubpanel = subpanels.get(0); - if (subpanels.size() >= 1) { - for (Root subpanel : subpanels) { - if (isDialog().matches(subpanel)) { - return subpanel; - } - if (subpanel.getWindowLayoutParams().get().type - > topSubpanel.getWindowLayoutParams().get().type) { - topSubpanel = subpanel; - } - } - } - return topSubpanel; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootsOracle.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootsOracle.java deleted file mode 100644 index a284ede..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootsOracle.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkState; - -import com.google.android.apps.common.testing.ui.espresso.Root; -import com.google.common.collect.Lists; - -import android.os.Build; -import android.os.Looper; -import android.util.Log; -import android.view.View; -import android.view.WindowManager.LayoutParams; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Provider; -import javax.inject.Singleton; - -/** - * Provides access to all root views in an application. - * - * 95% of the time this is unnecessary and we can operate solely on current Activity's root view - * as indicated by getWindow().getDecorView(). However in the case of popup windows, menus, and - * dialogs the actual view hierarchy we should be operating on is not accessible thru public apis. - * - * In the spirit of degrading gracefully when new api levels break compatibility, callers should - * handle a list of size 0 by assuming getWindow().getDecorView() on the currently resumed activity - * is the sole root - this assumption will be correct often enough. - * - * Obviously, you need to be on the main thread to use this. - */ -@Singleton -final class RootsOracle implements Provider<List<Root>> { - - private static final String TAG = RootsOracle.class.getSimpleName(); - private static final String WINDOW_MANAGER_IMPL_CLAZZ = - "android.view.WindowManagerImpl"; - private static final String WINDOW_MANAGER_GLOBAL_CLAZZ = - "android.view.WindowManagerGlobal"; - private static final String VIEWS_FIELD = "mViews"; - private static final String WINDOW_PARAMS_FIELD = "mParams"; - private static final String GET_DEFAULT_IMPL = "getDefault"; - private static final String GET_GLOBAL_INSTANCE = "getInstance"; - - private final Looper mainLooper; - private boolean initialized; - private Object windowManagerObj; - private Field viewsField; - private Field paramsField; - - @Inject - RootsOracle(Looper mainLooper) { - this.mainLooper = mainLooper; - } - - @SuppressWarnings("unchecked") - @Override - public List<Root> get() { - checkState(mainLooper.equals(Looper.myLooper()), "must be called on main thread."); - - if (!initialized) { - initialize(); - } - - if (null == windowManagerObj) { - Log.w(TAG, "No reflective access to windowmanager object."); - return Lists.newArrayList(); - } - - if (null == viewsField) { - Log.w(TAG, "No reflective access to mViews"); - return Lists.newArrayList(); - } - if (null == paramsField) { - Log.w(TAG, "No reflective access to mPArams"); - return Lists.newArrayList(); - } - - List<View> views = null; - List<LayoutParams> params = null; - - try { - if (Build.VERSION.SDK_INT < 19) { - views = Arrays.asList((View[]) viewsField.get(windowManagerObj)); - params = Arrays.asList((LayoutParams[]) paramsField.get(windowManagerObj)); - } else { - views = (List<View>) viewsField.get(windowManagerObj); - params = (List<LayoutParams>) paramsField.get(windowManagerObj); - } - } catch (RuntimeException re) { - Log.w(TAG, String.format("Reflective access to %s or %s on %s failed.", - viewsField, paramsField, windowManagerObj), re); - return Lists.newArrayList(); - } catch (IllegalAccessException iae) { - Log.w(TAG, String.format("Reflective access to %s or %s on %s failed.", - viewsField, paramsField, windowManagerObj), iae); - return Lists.newArrayList(); - } - - - List<Root> roots = Lists.newArrayList(); - for (int i = views.size() - 1; i > -1; i--) { - roots.add( - new Root.Builder() - .withDecorView(views.get(i)) - .withWindowLayoutParams(params.get(i)) - .build()); - } - - return roots; - } - - private void initialize() { - initialized = true; - String accessClass = Build.VERSION.SDK_INT > 16 ? WINDOW_MANAGER_GLOBAL_CLAZZ - : WINDOW_MANAGER_IMPL_CLAZZ; - String instanceMethod = Build.VERSION.SDK_INT > 16 ? GET_GLOBAL_INSTANCE : GET_DEFAULT_IMPL; - - try { - Class<?> clazz = Class.forName(accessClass); - Method getMethod = clazz.getMethod(instanceMethod); - windowManagerObj = getMethod.invoke(null); - viewsField = clazz.getDeclaredField(VIEWS_FIELD); - viewsField.setAccessible(true); - paramsField = clazz.getDeclaredField(WINDOW_PARAMS_FIELD); - paramsField.setAccessible(true); - } catch (InvocationTargetException ite) { - Log.e(TAG, String.format("could not invoke: %s on %s", instanceMethod, accessClass), - ite.getCause()); - } catch (ClassNotFoundException cnfe) { - Log.e(TAG, String.format("could not find class: %s", accessClass), cnfe); - } catch (NoSuchFieldException nsfe) { - Log.e(TAG, String.format("could not find field: %s or %s on %s", WINDOW_PARAMS_FIELD, - VIEWS_FIELD, accessClass), nsfe); - } catch (NoSuchMethodException nsme) { - Log.e(TAG, String.format("could not find method: %s on %s", instanceMethod, accessClass), - nsme); - } catch (RuntimeException re) { - Log.e(TAG, String.format("reflective setup failed using obj: %s method: %s field: %s", - accessClass, instanceMethod, VIEWS_FIELD), re); - } catch (IllegalAccessException iae) { - Log.e(TAG, String.format("reflective setup failed using obj: %s method: %s field: %s", - accessClass, instanceMethod, VIEWS_FIELD), iae); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/SdkAsyncTask.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/SdkAsyncTask.java deleted file mode 100644 index b28255e..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/SdkAsyncTask.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -/** - * Annotates a AsyncTaskMonitor as monitoring the SdkAsyncTask pool - */ -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -@interface SdkAsyncTask { } diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/ThreadPoolExecutorExtractor.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/ThreadPoolExecutorExtractor.java deleted file mode 100644 index 1a719a3..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/ThreadPoolExecutorExtractor.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import com.google.common.base.Optional; - -import android.os.Build; -import android.os.Handler; -import android.os.Looper; - -import java.lang.reflect.Field; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; -import java.util.concurrent.ThreadPoolExecutor; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Extracts ThreadPoolExecutors used by pieces of android. - * - * We do some work to ensure that we load the classes containing these thread pools - * on the main thread, since they may have static initialization that assumes access - * to the main looper. - */ -@Singleton -final class ThreadPoolExecutorExtractor { - private static final String ASYNC_TASK_CLASS_NAME = "android.os.AsyncTask"; - private static final String MODERN_ASYNC_TASK_CLASS_NAME = - "android.support.v4.content.ModernAsyncTask"; - private static final String MODERN_ASYNC_TASK_FIELD_NAME = "THREAD_POOL_EXECUTOR"; - private static final String LEGACY_ASYNC_TASK_FIELD_NAME = "sExecutor"; - private final Handler mainHandler; - - @Inject - ThreadPoolExecutorExtractor(Looper looper) { - mainHandler = new Handler(looper); - } - - - public ThreadPoolExecutor getAsyncTaskThreadPool() { - FutureTask<Optional<ThreadPoolExecutor>> getTask = null; - if (Build.VERSION.SDK_INT < 11) { - getTask = new FutureTask<Optional<ThreadPoolExecutor>>(LEGACY_ASYNC_TASK_EXECUTOR); - } else { - getTask = new FutureTask<Optional<ThreadPoolExecutor>>(POST_HONEYCOMB_ASYNC_TASK_EXECUTOR); - } - - try { - return runOnMainThread(getTask).get().get(); - } catch (InterruptedException ie) { - throw new RuntimeException("Interrupted while trying to get the async task executor!", ie); - } catch (ExecutionException ee) { - throw new RuntimeException(ee.getCause()); - } - } - - public Optional<ThreadPoolExecutor> getCompatAsyncTaskThreadPool() { - try { - return runOnMainThread( - new FutureTask<Optional<ThreadPoolExecutor>>(MODERN_ASYNC_TASK_EXTRACTOR)).get(); - } catch (InterruptedException ie) { - throw new RuntimeException("Interrupted while trying to get the compat async executor!", ie); - } catch (ExecutionException ee) { - throw new RuntimeException(ee.getCause()); - } - } - - private <T> FutureTask<T> runOnMainThread(final FutureTask<T> futureToRun) { - if (Looper.myLooper() != Looper.getMainLooper()) { - final CountDownLatch latch = new CountDownLatch(1); - mainHandler.post(new Runnable() { - @Override - public void run() { - try { - futureToRun.run(); - } finally { - latch.countDown(); - } - } - }); - try { - latch.await(); - } catch (InterruptedException ie) { - if (!futureToRun.isDone()) { - throw new RuntimeException("Interrupted while waiting for task to complete."); - } - } - } else { - futureToRun.run(); - } - - return futureToRun; - } - - private static final Callable<Optional<ThreadPoolExecutor>> MODERN_ASYNC_TASK_EXTRACTOR = - new Callable<Optional<ThreadPoolExecutor>>() { - @Override - public Optional<ThreadPoolExecutor> call() throws Exception { - try { - Class<?> modernClazz = Class.forName(MODERN_ASYNC_TASK_CLASS_NAME); - Field executorField = modernClazz.getField(MODERN_ASYNC_TASK_FIELD_NAME); - return Optional.of((ThreadPoolExecutor) executorField.get(null)); - } catch (ClassNotFoundException cnfe) { - return Optional.<ThreadPoolExecutor>absent(); - } - } - }; - - private static final Callable<Class<?>> LOAD_ASYNC_TASK_CLASS = - new Callable<Class<?>>() { - @Override - public Class<?> call() throws Exception { - return Class.forName(ASYNC_TASK_CLASS_NAME); - } - }; - - private static final Callable<Optional<ThreadPoolExecutor>> LEGACY_ASYNC_TASK_EXECUTOR = - new Callable<Optional<ThreadPoolExecutor>>() { - @Override - public Optional<ThreadPoolExecutor> call() throws Exception { - Field executorField = LOAD_ASYNC_TASK_CLASS.call() - .getDeclaredField(LEGACY_ASYNC_TASK_FIELD_NAME); - executorField.setAccessible(true); - return Optional.of((ThreadPoolExecutor) executorField.get(null)); - } - }; - - private static final Callable<Optional<ThreadPoolExecutor>> POST_HONEYCOMB_ASYNC_TASK_EXECUTOR = - new Callable<Optional<ThreadPoolExecutor>>() { - @Override - public Optional<ThreadPoolExecutor> call() throws Exception { - Field executorField = LOAD_ASYNC_TASK_CLASS.call() - .getField(MODERN_ASYNC_TASK_FIELD_NAME); - return Optional.of((ThreadPoolExecutor) executorField.get(null)); - } - }; -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImpl.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImpl.java deleted file mode 100644 index c1aaa5c..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/UiControllerImpl.java +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Throwables.propagate; - -import com.google.android.apps.common.testing.ui.espresso.IdlingPolicies; -import com.google.android.apps.common.testing.ui.espresso.IdlingPolicy; -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; -import com.google.android.apps.common.testing.ui.espresso.UiController; -import com.google.android.apps.common.testing.ui.espresso.base.IdlingResourceRegistry.IdleNotificationCallback; -import com.google.android.apps.common.testing.ui.espresso.base.QueueInterrogator.QueueState; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.Lists; - -import android.annotation.SuppressLint; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.SystemClock; -import android.util.Log; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.MotionEvent; - -import java.util.BitSet; -import java.util.EnumSet; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Implementation of {@link UiController}. - */ -@Singleton -final class UiControllerImpl implements UiController, Handler.Callback { - - private static final String TAG = UiControllerImpl.class.getSimpleName(); - - private static final Callable<Void> NO_OP = new Callable<Void>() { - @Override - public Void call() { - return null; - } - }; - - /** - * Responsible for signaling a particular condition is met / verifying that signal. - */ - enum IdleCondition { - DELAY_HAS_PAST, - ASYNC_TASKS_HAVE_IDLED, - COMPAT_TASKS_HAVE_IDLED, - KEY_INJECT_HAS_COMPLETED, - MOTION_INJECTION_HAS_COMPLETED, - DYNAMIC_TASKS_HAVE_IDLED; - - /** - * Checks whether this condition has been signaled. - */ - public boolean isSignaled(BitSet conditionSet) { - return conditionSet.get(ordinal()); - } - - /** - * Resets the signal state for this condition. - */ - public void reset(BitSet conditionSet) { - conditionSet.set(ordinal(), false); - } - - /** - * Creates a message that when sent will raise the signal of this condition. - */ - public Message createSignal(Handler handler, int myGeneration) { - return Message.obtain(handler, ordinal(), myGeneration, 0, null); - } - - /** - * Handles a message that is raising a signal and updates the condition set accordingly. - * Messages from a previous generation will be ignored. - */ - public static boolean handleMessage(Message message, BitSet conditionSet, - int currentGeneration) { - IdleCondition [] allConditions = values(); - if (message.what < 0 || message.what >= allConditions.length) { - return false; - } else { - IdleCondition condition = allConditions[message.what]; - if (message.arg1 == currentGeneration) { - condition.signal(conditionSet); - } else { - Log.w(TAG, "ignoring signal of: " + condition + " from previous generation: " + - message.arg1 + " current generation: " + currentGeneration); - } - return true; - } - } - - public static BitSet createConditionSet() { - return new BitSet(values().length); - } - - /** - * Requests that the given bitset be updated to indicate that this condition has been - * signaled. - */ - protected void signal(BitSet conditionSet) { - conditionSet.set(ordinal()); - } - } - - private final EventInjector eventInjector; - private final BitSet conditionSet; - private final AsyncTaskPoolMonitor asyncTaskMonitor; - private final Optional<AsyncTaskPoolMonitor> compatTaskMonitor; - private final IdlingResourceRegistry idlingResourceRegistry; - private final ExecutorService keyEventExecutor = Executors.newSingleThreadExecutor(); - private final QueueInterrogator queueInterrogator; - private final Looper mainLooper; - - private Handler controllerHandler; - // only updated on main thread. - private boolean looping = false; - private int generation = 0; - - @VisibleForTesting - @Inject - UiControllerImpl(EventInjector eventInjector, - @SdkAsyncTask AsyncTaskPoolMonitor asyncTaskMonitor, - @CompatAsyncTask Optional<AsyncTaskPoolMonitor> compatTaskMonitor, - IdlingResourceRegistry registry, - Looper mainLooper) { - this.eventInjector = checkNotNull(eventInjector); - this.asyncTaskMonitor = checkNotNull(asyncTaskMonitor); - this.compatTaskMonitor = checkNotNull(compatTaskMonitor); - this.conditionSet = IdleCondition.createConditionSet(); - this.idlingResourceRegistry = checkNotNull(registry); - this.mainLooper = checkNotNull(mainLooper); - this.queueInterrogator = new QueueInterrogator(mainLooper); - } - - @SuppressWarnings("deprecation") - @Override - public boolean injectKeyEvent(final KeyEvent event) throws InjectEventSecurityException { - checkNotNull(event); - checkState(Looper.myLooper() == mainLooper, "Expecting to be on main thread!"); - initialize(); - loopMainThreadUntilIdle(); - - FutureTask<Boolean> injectTask = new SignalingTask<Boolean>( - new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - return eventInjector.injectKeyEvent(event); - } - }, - IdleCondition.KEY_INJECT_HAS_COMPLETED, - generation); - - // Inject the key event. - keyEventExecutor.submit(injectTask); - - loopUntil(IdleCondition.KEY_INJECT_HAS_COMPLETED); - - try { - checkState(injectTask.isDone(), "Key injection was signaled - but it wasnt done."); - return injectTask.get(); - } catch (ExecutionException ee) { - if (ee.getCause() instanceof InjectEventSecurityException) { - throw (InjectEventSecurityException) ee.getCause(); - } else { - throw new RuntimeException(ee.getCause()); - } - } catch (InterruptedException neverHappens) { - // we only call get() after done() is signaled. - // we should never block. - throw new RuntimeException("impossible.", neverHappens); - } - } - - @Override - public boolean injectMotionEvent(final MotionEvent event) throws InjectEventSecurityException { - checkNotNull(event); - checkState(Looper.myLooper() == mainLooper, "Expecting to be on main thread!"); - initialize(); - - FutureTask<Boolean> injectTask = new SignalingTask<Boolean>( - new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - return eventInjector.injectMotionEvent(event); - } - }, - IdleCondition.MOTION_INJECTION_HAS_COMPLETED, - generation); - keyEventExecutor.submit(injectTask); - loopUntil(IdleCondition.MOTION_INJECTION_HAS_COMPLETED); - try { - checkState(injectTask.isDone(), "Key injection was signaled - but it wasnt done."); - return injectTask.get(); - } catch (ExecutionException ee) { - if (ee.getCause() instanceof InjectEventSecurityException) { - throw (InjectEventSecurityException) ee.getCause(); - } else { - throw propagate(ee.getCause() != null ? ee.getCause() : ee); - } - } catch (InterruptedException neverHappens) { - // we only call get() after done() is signaled. - // we should never block. - throw propagate(neverHappens); - } finally { - loopMainThreadUntilIdle(); - } - } - - @Override - public boolean injectString(String str) throws InjectEventSecurityException { - checkNotNull(str); - checkState(Looper.myLooper() == mainLooper, "Expecting to be on main thread!"); - initialize(); - - // No-op if string is empty. - if (str.length() == 0) { - Log.w(TAG, "Supplied string is empty resulting in no-op (nothing is typed)."); - return true; - } - - boolean eventInjected = false; - KeyCharacterMap keyCharacterMap = getKeyCharacterMap(); - - // TODO(user): Investigate why not use (as suggested in javadoc of keyCharacterMap.getEvents): - // http://developer.android.com/reference/android/view/KeyEvent.html#KeyEvent(long, - // java.lang.String, int, int) - KeyEvent[] events = keyCharacterMap.getEvents(str.toCharArray()); - checkNotNull(events, "Failed to get events for string " + str); - Log.d(TAG, String.format("Injecting string: \"%s\"", str)); - - for (KeyEvent event : events) { - checkNotNull(event, String.format("Failed to get event for character (%c) with key code (%s)", - event.getKeyCode(), event.getUnicodeChar())); - - eventInjected = false; - for (int attempts = 0; !eventInjected && attempts < 4; attempts++) { - attempts++; - - // We have to change the time of an event before injecting it because - // all KeyEvents returned by KeyCharacterMap.getEvents() have the same - // time stamp and the system rejects too old events. Hence, it is - // possible for an event to become stale before it is injected if it - // takes too long to inject the preceding ones. - event = KeyEvent.changeTimeRepeat(event, SystemClock.uptimeMillis(), 0); - eventInjected = injectKeyEvent(event); - } - - if (!eventInjected) { - Log.e(TAG, String.format("Failed to inject event for character (%c) with key code (%s)", - event.getUnicodeChar(), event.getKeyCode())); - break; - } - } - - return eventInjected; - } - - @SuppressLint("InlinedApi") - @VisibleForTesting - @SuppressWarnings("deprecation") - public static KeyCharacterMap getKeyCharacterMap() { - KeyCharacterMap keyCharacterMap = null; - - // KeyCharacterMap.VIRTUAL_KEYBOARD is present from API11. - // For earlier APIs we use KeyCharacterMap.BUILT_IN_KEYBOARD - if (Build.VERSION.SDK_INT < 11) { - keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD); - } else { - keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); - } - return keyCharacterMap; - } - - - @Override - public void loopMainThreadUntilIdle() { - initialize(); - checkState(Looper.myLooper() == mainLooper, "Expecting to be on main thread!"); - do { - EnumSet<IdleCondition> condChecks = EnumSet.noneOf(IdleCondition.class); - if (!asyncTaskMonitor.isIdleNow()) { - asyncTaskMonitor.notifyWhenIdle(new SignalingTask<Void>(NO_OP, - IdleCondition.ASYNC_TASKS_HAVE_IDLED, generation)); - - condChecks.add(IdleCondition.ASYNC_TASKS_HAVE_IDLED); - } - - if (!compatIdle()) { - compatTaskMonitor.get().notifyWhenIdle(new SignalingTask<Void>(NO_OP, - IdleCondition.COMPAT_TASKS_HAVE_IDLED, generation)); - condChecks.add(IdleCondition.COMPAT_TASKS_HAVE_IDLED); - } - - if (!idlingResourceRegistry.allResourcesAreIdle()) { - final IdlingPolicy warning = IdlingPolicies.getDynamicIdlingResourceWarningPolicy(); - final IdlingPolicy error = IdlingPolicies.getDynamicIdlingResourceErrorPolicy(); - final SignalingTask<Void> idleSignal = new SignalingTask<Void>(NO_OP, - IdleCondition.DYNAMIC_TASKS_HAVE_IDLED, generation); - idlingResourceRegistry.notifyWhenAllResourcesAreIdle(new IdleNotificationCallback() { - @Override - public void resourcesStillBusyWarning(List<String> busyResourceNames) { - warning.handleTimeout(busyResourceNames, "IdlingResources are still busy!"); - } - - @Override - public void resourcesHaveTimedOut(List<String> busyResourceNames) { - error.handleTimeout(busyResourceNames, "IdlingResources have timed out!"); - controllerHandler.post(idleSignal); - } - - @Override - public void allResourcesIdle() { - controllerHandler.post(idleSignal); - } - }); - condChecks.add(IdleCondition.DYNAMIC_TASKS_HAVE_IDLED); - } - - try { - loopUntil(condChecks); - } finally { - asyncTaskMonitor.cancelIdleMonitor(); - if (compatTaskMonitor.isPresent()) { - compatTaskMonitor.get().cancelIdleMonitor(); - } - idlingResourceRegistry.cancelIdleMonitor(); - } - } while (!asyncTaskMonitor.isIdleNow() || !compatIdle() - || !idlingResourceRegistry.allResourcesAreIdle()); - - } - - private boolean compatIdle() { - if (compatTaskMonitor.isPresent()) { - return compatTaskMonitor.get().isIdleNow(); - } else { - return true; - } - } - - @Override - public void loopMainThreadForAtLeast(long millisDelay) { - initialize(); - checkState(Looper.myLooper() == mainLooper, "Expecting to be on main thread!"); - checkState(!IdleCondition.DELAY_HAS_PAST.isSignaled(conditionSet), "recursion detected!"); - - checkArgument(millisDelay > 0); - controllerHandler.postDelayed(new SignalingTask(NO_OP, IdleCondition.DELAY_HAS_PAST, - generation), - millisDelay); - loopUntil(IdleCondition.DELAY_HAS_PAST); - loopMainThreadUntilIdle(); - } - - @Override - public boolean handleMessage(Message msg) { - if (!IdleCondition.handleMessage(msg, conditionSet, generation)) { - Log.i(TAG, "Unknown message type: " + msg); - return false; - } else { - return true; - } - } - - private void loopUntil(IdleCondition condition) { - loopUntil(EnumSet.of(condition)); - } - - /** - * Loops the main thread until all IdleConditions have been signaled. - * - * Once they've been signaled, the conditions are reset and the generation value - * is incremented. - * - * Signals should only be raised thru SignalingTask instances, and care should be - * taken to ensure that the signaling task is created before loopUntil is called. - * - * Good: - * idlingType.runOnIdle(new SignalingTask(NO_OP, IdleCondition.MY_IDLE_CONDITION, generation)); - * loopUntil(IdleCondition.MY_IDLE_CONDITION); - * - * Bad: - * idlingType.runOnIdle(new CustomCallback() { - * @Override - * public void itsDone() { - * // oh no - The creation of this signaling task is delayed until this method is - * // called, so it will not have the right value for generation. - * new SignalingTask(NO_OP, IdleCondition.MY_IDLE_CONDITION, generation).run(); - * } - * }) - * loopUntil(IdleCondition.MY_IDLE_CONDITION); - */ - private void loopUntil(EnumSet<IdleCondition> conditions) { - checkState(!looping, "Recursive looping detected!"); - looping = true; - IdlingPolicy masterIdlePolicy = IdlingPolicies.getMasterIdlingPolicy(); - try { - int loopCount = 0; - long start = SystemClock.uptimeMillis(); - long end = start + masterIdlePolicy.getIdleTimeoutUnit().toMillis( - masterIdlePolicy.getIdleTimeout()); - while (SystemClock.uptimeMillis() < end) { - boolean conditionsMet = true; - boolean shouldLogConditionState = loopCount > 0 && loopCount % 100 == 0; - - for (IdleCondition condition : conditions) { - if (!condition.isSignaled(conditionSet)) { - conditionsMet = false; - if (shouldLogConditionState) { - Log.w(TAG, "Waiting for: " + condition.name() + " for " + loopCount + " iterations."); - } else { - break; - } - } - } - - if (conditionsMet) { - QueueState queueState = queueInterrogator.determineQueueState(); - if (queueState == QueueState.EMPTY || queueState == QueueState.TASK_DUE_LONG) { - return; - } else { - Log.v( - "ESP_TRACE", - - "Barrier detected or task avaliable for running shortly."); - } - } - - Message message = queueInterrogator.getNextMessage(); - String callbackString = "unknown"; - String messageString = "unknown"; - try { - if (null == message.getCallback()) { - callbackString = "no callback."; - } else { - callbackString = message.getCallback().toString(); - } - messageString = message.toString(); - } catch (NullPointerException e) { - /* - * Ignore. android.app.ActivityThread$ActivityClientRecord#toString() fails for API level - * 15. - */ - } - - Log.v( - "ESP_TRACE", - String.format("%s: MessageQueue.next(): %s, with target: %s, callback: %s", TAG, - messageString, message.getTarget().getClass().getCanonicalName(), callbackString)); - message.getTarget().dispatchMessage(message); - message.recycle(); - loopCount++; - } - List<String> idleConditions = Lists.newArrayList(); - for (IdleCondition condition : conditions) { - if (!condition.isSignaled(conditionSet)) { - idleConditions.add(condition.name()); - } - } - masterIdlePolicy.handleTimeout(idleConditions, String.format( - "Looped for %s iterations over %s %s.", loopCount, masterIdlePolicy.getIdleTimeout(), - masterIdlePolicy.getIdleTimeoutUnit().name())); - } finally { - looping = false; - generation++; - for (IdleCondition condition : conditions) { - condition.reset(conditionSet); - } - } - } - - - private void initialize() { - if (controllerHandler == null) { - controllerHandler = new Handler(this); - } - } - - - /** - * Encapsulates posting a signal message to update the conditions set after a task has - * executed. - */ - private class SignalingTask<T> extends FutureTask<T> { - - private final IdleCondition condition; - private final int myGeneration; - - public SignalingTask(Callable<T> callable, IdleCondition condition, int myGeneration) { - super(callable); - this.condition = checkNotNull(condition); - this.myGeneration = myGeneration; - } - - @Override - protected void done() { - controllerHandler.sendMessage(condition.createSignal(controllerHandler, myGeneration)); - } - - } - -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/ViewFinderImpl.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/ViewFinderImpl.java deleted file mode 100644 index 30e0658..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/ViewFinderImpl.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.android.apps.common.testing.ui.espresso.util.TreeIterables.breadthFirstViewTraversal; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException; -import com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException; -import com.google.android.apps.common.testing.ui.espresso.ViewFinder; -import com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers; -import com.google.common.base.Joiner; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; - -import android.os.Looper; -import android.view.View; -import android.widget.AdapterView; - -import org.hamcrest.Matcher; - -import java.util.Iterator; -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Provider; - -/** - * Implementation of {@link ViewFinder}. - */ -// TODO(user): in the future we may want to collect stats here about the size of the view -// hierarchy, average matcher execution time, warn when matchers take too long to execute, etc. -public final class ViewFinderImpl implements ViewFinder { - - private final Matcher<View> viewMatcher; - private final Provider<View> rootViewProvider; - - @Inject - ViewFinderImpl(Matcher<View> viewMatcher, Provider<View> rootViewProvider) { - this.viewMatcher = viewMatcher; - this.rootViewProvider = rootViewProvider; - } - - @Override - public View getView() throws AmbiguousViewMatcherException, NoMatchingViewException { - checkMainThread(); - final Predicate<View> matcherPredicate = new MatcherPredicateAdapter<View>( - checkNotNull(viewMatcher)); - - View root = rootViewProvider.get(); - Iterator<View> matchedViewIterator = Iterables.filter( - breadthFirstViewTraversal(root), - matcherPredicate).iterator(); - - View matchedView = null; - - while (matchedViewIterator.hasNext()) { - if (matchedView != null) { - // Ambiguous! - throw new AmbiguousViewMatcherException.Builder() - .withViewMatcher(viewMatcher) - .withRootView(root) - .withView1(matchedView) - .withView2(matchedViewIterator.next()) - .withOtherAmbiguousViews(Iterators.toArray(matchedViewIterator, View.class)) - .build(); - } else { - matchedView = matchedViewIterator.next(); - } - } - if (null == matchedView) { - final Predicate<View> adapterViewPredicate = new MatcherPredicateAdapter<View>( - ViewMatchers.isAssignableFrom(AdapterView.class)); - List<View> adapterViews = Lists.newArrayList( - Iterables.filter(breadthFirstViewTraversal(root), adapterViewPredicate).iterator()); - if (adapterViews.isEmpty()) { - throw new NoMatchingViewException.Builder() - .withViewMatcher(viewMatcher) - .withRootView(root) - .build(); - } - - String warning = String.format("\nIf the target view is not part of the view hierarchy, you " - + "may need to use Espresso.onData to load it from one of the following AdapterViews:%s" - , Joiner.on("\n- ").join(adapterViews)); - throw new NoMatchingViewException.Builder() - .withViewMatcher(viewMatcher) - .withRootView(root) - .withAdapterViews(adapterViews) - .withAdapterViewWarning(Optional.of(warning)) - .build(); - } else { - return matchedView; - } - } - - private void checkMainThread() { - checkState(Thread.currentThread().equals(Looper.getMainLooper().getThread()), - "Executing a query on the view hierarchy outside of the main thread (on: %s)", - Thread.currentThread().getName()); - } - - private static class MatcherPredicateAdapter<T> implements Predicate<T> { - private final Matcher<? super T> matcher; - - private MatcherPredicateAdapter(Matcher<? super T> matcher) { - this.matcher = checkNotNull(matcher); - } - - @Override - public boolean apply(T input) { - return matcher.matches(input); - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/WindowManagerEventInjectionStrategy.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/WindowManagerEventInjectionStrategy.java deleted file mode 100644 index 05792e7..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/WindowManagerEventInjectionStrategy.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.base; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Throwables.propagate; - -import com.google.android.apps.common.testing.ui.espresso.InjectEventSecurityException; - -import android.os.Build; -import android.os.IBinder; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * An {@link EventInjectionStrategy} that uses the window manager to inject {@link MotionEvent}s. - * This strategy supports API level 15 and below. - */ -final class WindowManagerEventInjectionStrategy implements EventInjectionStrategy { - private static final String TAG = WindowManagerEventInjectionStrategy.class.getSimpleName(); - - - WindowManagerEventInjectionStrategy() { - checkState(Build.VERSION.SDK_INT >= 7 && Build.VERSION.SDK_INT <= 15, "Unsupported API level."); - } - - // Reflection members. - private boolean initComplete; - private Object wmInstance; - private Method injectInputKeyEventMethod; - private Method injectInputMotionEventMethod; - - void initialize() { - if (initComplete) { - return; - } - - try { - Log.d(TAG, "Trying to create injection strategy."); - - Class<?> serviceManagerClassObj = Class.forName("android.os.ServiceManager"); - Method windowServiceMethod = - serviceManagerClassObj.getDeclaredMethod("getService", String.class); - windowServiceMethod.setAccessible(true); - - Object windowServiceBinderObj = windowServiceMethod.invoke(serviceManagerClassObj, "window"); - - Class<?> windowManagerStubObject = Class.forName("android.view.IWindowManager$Stub"); - Method asInterfaceMethod = - windowManagerStubObject.getDeclaredMethod("asInterface", IBinder.class); - asInterfaceMethod.setAccessible(true); - - wmInstance = asInterfaceMethod.invoke(windowManagerStubObject, windowServiceBinderObj); - - injectInputMotionEventMethod = wmInstance.getClass() - .getDeclaredMethod("injectPointerEvent", MotionEvent.class, Boolean.TYPE); - injectInputMotionEventMethod.setAccessible(true); - - injectInputKeyEventMethod = - wmInstance.getClass().getDeclaredMethod("injectKeyEvent", KeyEvent.class, Boolean.TYPE); - injectInputMotionEventMethod.setAccessible(true); - - initComplete = true; - } catch (ClassNotFoundException e) { - propagate(e); - } catch (IllegalAccessException e) { - propagate(e); - } catch (IllegalArgumentException e) { - propagate(e); - } catch (InvocationTargetException e) { - propagate(e); - } catch (NoSuchMethodException e) { - propagate(e); - } catch (SecurityException e) { - propagate(e); - } - } - - @Override - public boolean injectKeyEvent(KeyEvent keyEvent) throws InjectEventSecurityException { - try { - // From javadoc of com.android.server.WindowManagerService.injectKeyEvent: - // @param sync If true, wait for the event to be completed before returning to the caller. - // @return true if event was dispatched, false if it was dropped for any reason - // - // Key events are delivered OFF the main thread, and we block until they are processed. - return (Boolean) injectInputKeyEventMethod.invoke(wmInstance, keyEvent, true); - } catch (IllegalAccessException e) { - propagate(e); - } catch (IllegalArgumentException e) { - propagate(e); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof SecurityException) { - throw new InjectEventSecurityException(cause); - } - propagate(e); - } catch (SecurityException e) { - throw new InjectEventSecurityException(e); - } - return false; - } - - @Override - public boolean injectMotionEvent(MotionEvent motionEvent) throws InjectEventSecurityException { - try { - // From javadoc of com.android.server.WindowManagerService.injectKeyEvent: - // @param sync If true, wait for the event to be completed before returning to the caller. - // @return true if event was dispatched, false if it was dropped for any reason - // - // We inject the pointer with sync=true to ensure the event is dispatched before control - // is returned to our code. - return (Boolean) injectInputMotionEventMethod.invoke( - wmInstance, - motionEvent, - true /* sync */); - } catch (IllegalAccessException e) { - propagate(e); - } catch (IllegalArgumentException e) { - propagate(e); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - if (cause instanceof SecurityException) { - throw new InjectEventSecurityException(cause); - } - propagate(e); - } catch (SecurityException e) { - throw new InjectEventSecurityException(e); - } - return false; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/CountingIdlingResource.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/CountingIdlingResource.java deleted file mode 100644 index c67f199..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/contrib/CountingIdlingResource.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.contrib; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import com.google.android.apps.common.testing.ui.espresso.IdlingResource; - -import android.os.SystemClock; -import android.util.Log; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * An implementation of {@link IdlingResource} that determines idleness by maintaining an internal - * counter. When the counter is 0 - it is considered to be idle, when it is non-zero it is not - * idle. This is very similar to the way a {@link java.util.concurrent.Semaphore} behaves. - * <p> - * The counter may be incremented or decremented from any thread. If it reaches an illogical state - * (like counter less than zero) it will throw an IllegalStateException. - * </p> - * <p> - * This class can then be used to wrap up operations that while in progress should block tests from - * accessing the UI. - * </p> - * - * <pre> - * {@code - * public interface FooServer { - * public Foo newFoo(); - * public void updateFoo(Foo foo); - * } - * - * public DecoratedFooServer implements FooServer { - * private final FooServer realFooServer; - * private final CountingIdlingResource fooServerIdlingResource; - * - * public DecoratedFooServer(FooServer realFooServer, - * CountingIdlingResource fooServerIdlingResource) { - * this.realFooServer = checkNotNull(realFooServer); - * this.fooServerIdlingResource = checkNotNull(fooServerIdlingResource); - * } - * - * public Foo newFoo() { - * fooServerIdlingResource.increment(); - * try { - * return realFooServer.newFoo(); - * } finally { - * fooServerIdlingResource.decrement(); - * } - * } - * - * public void updateFoo(Foo foo) { - * fooServerIdlingResource.increment(); - * try { - * realFooServer.updateFoo(foo); - * } finally { - * fooServerIdlingResource.decrement(); - * } - * } - * } - * } - * </pre> - * - * Then in your test setup: - * <pre> - * {@code - * public void setUp() throws Exception { - * super.setUp(); - * FooServer realServer = FooApplication.getFooServer(); - * CountingIdlingResource countingResource = new CountingIdlingResource("FooServerCalls"); - * FooApplication.setFooServer(new DecoratedFooServer(realServer, countingResource)); - * Espresso.registerIdlingResource(countingResource); - * } - * } - * </pre> - * - */ -@SuppressWarnings("javadoc") -public final class CountingIdlingResource implements IdlingResource { - private static final String TAG = "CountingIdlingResource"; - private final String resourceName; - private final AtomicInteger counter = new AtomicInteger(0); - private final boolean debugCounting; - - // written from main thread, read from any thread. - private volatile ResourceCallback resourceCallback; - - // read/written from any thread - used for debugging messages. - private volatile long becameBusyAt = 0; - private volatile long becameIdleAt = 0; - - /** - * Creates a CountingIdlingResource without debug tracing. - * - * @param resourceName the resource name this resource should report to Espresso. - */ - public CountingIdlingResource(String resourceName) { - this(resourceName, false); - } - - /** - * Creates a CountingIdlingResource. - * - * @param resourceName the resource name this resource should report to Espresso. - * @param debugCounting if true increment & decrement calls will print trace information to logs. - */ - public CountingIdlingResource(String resourceName, boolean debugCounting) { - this.resourceName = checkNotNull(resourceName); - this.debugCounting = debugCounting; - } - - @Override - public String getName() { - return resourceName; - } - - @Override - public boolean isIdleNow() { - return counter.get() == 0; - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - - /** - * Increments the count of in-flight transactions to the resource being monitored. - * - * This method can be called from any thread. - */ - public void increment() { - int counterVal = counter.getAndIncrement(); - if (0 == counterVal) { - becameBusyAt = SystemClock.uptimeMillis(); - } - - if (debugCounting) { - Log.i(TAG, "Resource: " + resourceName + " in-use-count incremented to: " + (counterVal + 1)); - } - } - - /** - * Decrements the count of in-flight transactions to the resource being monitored. - * - * If this operation results in the counter falling below 0 - an exception is raised. - * - * @throws IllegalStateException if the counter is below 0. - */ - public void decrement() { - int counterVal = counter.decrementAndGet(); - - if (counterVal == 0) { - // we've gone from non-zero to zero. That means we're idle now! Tell espresso. - if (null != resourceCallback) { - resourceCallback.onTransitionToIdle(); - } - becameIdleAt = SystemClock.uptimeMillis(); - } - - if (debugCounting) { - if (counterVal == 0) { - Log.i(TAG, "Resource: " + resourceName + " went idle! (Time spent not idle: " + - (becameIdleAt - becameBusyAt) + ")"); - } else { - Log.i(TAG, "Resource: " + resourceName + " in-use-count decremented to: " + counterVal); - } - } - checkState(counterVal > -1, "Counter has been corrupted!"); - } - - /** - * Prints the current state of this resource to the logcat at info level. - */ - public void dumpStateToLogs() { - StringBuilder message = new StringBuilder("Resource: ") - .append(resourceName) - .append(" inflight transaction count: ") - .append(counter.get()); - if (0 == becameBusyAt) { - Log.i(TAG, message.append(" and has never been busy!").toString()); - } else { - message.append(" and was last busy at: ") - .append(becameBusyAt); - if (0 == becameIdleAt) { - Log.w(TAG, message.append(" AND NEVER WENT IDLE!").toString()); - } else { - message.append(" and last went idle at: ") - .append(becameIdleAt); - Log.i(TAG, message.toString()); - } - } - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/BoundedMatcher.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/BoundedMatcher.java deleted file mode 100644 index 55e8dde..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/BoundedMatcher.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.matcher; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import org.hamcrest.BaseMatcher; - -/** - * Some matcher sugar that lets you create a matcher for a given type - * but only process items of a specific subtype of that matcher. - * - * @param <T> The desired type of the Matcher. - * @param <S> the subtype of T that your matcher applies safely to. - */ -public abstract class BoundedMatcher<T, S extends T> extends BaseMatcher<T> { - - private final Class<?> expectedType; - private final Class<?>[] interfaceTypes; - - public BoundedMatcher(Class<? extends S> expectedType) { - this.expectedType = checkNotNull(expectedType); - this.interfaceTypes = new Class[0]; - } - - public BoundedMatcher(Class<?> expectedType, Class<?> interfaceType1, - Class<?>... otherInterfaces) { - this.expectedType = checkNotNull(expectedType); - checkNotNull(otherInterfaces); - int interfaceCount = otherInterfaces.length + 1; - this.interfaceTypes = new Class[interfaceCount]; - - interfaceTypes[0] = checkNotNull(interfaceType1); - checkArgument(interfaceType1.isInterface()); - int interfaceTypeIdx = 1; - for (Class<?> intfType : otherInterfaces) { - interfaceTypes[interfaceTypeIdx] = checkNotNull(intfType); - checkArgument(intfType.isInterface()); - interfaceTypeIdx++; - } - } - - protected abstract boolean matchesSafely(S item); - - @Override - @SuppressWarnings({"unchecked"}) - public final boolean matches(Object item) { - if (item == null) { - return false; - } - - if (expectedType.isInstance(item)) { - for (Class<?> intfType : interfaceTypes) { - if (!intfType.isInstance(item)) { - return false; - } - } - return matchesSafely((S) item); - } - return false; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/PreferenceMatchers.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/PreferenceMatchers.java deleted file mode 100644 index 13b6506..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/PreferenceMatchers.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.matcher; - -import static org.hamcrest.Matchers.is; - -import android.content.res.Resources; -import android.preference.Preference; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -/** - * A collection of hamcrest matchers that match {@link Preference}s. - */ -public final class PreferenceMatchers { - - private PreferenceMatchers() {} - - public static Matcher<Preference> withSummary(final int resourceId) { - return new TypeSafeMatcher<Preference>() { - private String resourceName = null; - private String expectedText = null; - - @Override - public void describeTo(Description description) { - description.appendText(" with summary string from resource id: "); - description.appendValue(resourceId); - if (null != resourceName) { - description.appendText("["); - description.appendText(resourceName); - description.appendText("]"); - } - if (null != expectedText) { - description.appendText(" value: " ); - description.appendText(expectedText); - } - } - - @Override - public boolean matchesSafely(Preference preference) { - if (null == expectedText) { - try { - expectedText = preference.getContext().getResources().getString(resourceId); - resourceName = preference.getContext().getResources().getResourceEntryName(resourceId); - } catch (Resources.NotFoundException ignored) { - /* view could be from a context unaware of the resource id. */ - } - } - if (null != expectedText) { - return expectedText.equals(preference.getSummary().toString()); - } else { - return false; - } - } - }; - } - - public static Matcher<Preference> withSummaryText(String summary) { - return withSummaryText(is(summary)); - } - - public static Matcher<Preference> withSummaryText(final Matcher<String> summaryMatcher) { - return new TypeSafeMatcher<Preference>() { - @Override - public void describeTo(Description description) { - description.appendText(" a preference with summary matching: "); - summaryMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(Preference pref) { - String summary = pref.getSummary().toString(); - return summaryMatcher.matches(summary); - } - }; - } - - public static Matcher<Preference> withTitle(final int resourceId) { - return new TypeSafeMatcher<Preference>() { - private String resourceName = null; - private String expectedText = null; - - @Override - public void describeTo(Description description) { - description.appendText(" with title string from resource id: "); - description.appendValue(resourceId); - if (null != resourceName) { - description.appendText("["); - description.appendText(resourceName); - description.appendText("]"); - } - if (null != expectedText) { - description.appendText(" value: " ); - description.appendText(expectedText); - } - } - - @Override - public boolean matchesSafely(Preference preference) { - if (null == expectedText) { - try { - expectedText = preference.getContext().getResources().getString(resourceId); - resourceName = preference.getContext().getResources().getResourceEntryName(resourceId); - } catch (Resources.NotFoundException ignored) { - /* view could be from a context unaware of the resource id. */ - } - } - if (null != expectedText) { - return expectedText.equals(preference.getTitle().toString()); - } else { - return false; - } - } - }; - } - - public static Matcher<Preference> withTitleText(String title) { - return withTitleText(is(title)); - } - - public static Matcher<Preference> withTitleText(final Matcher<String> titleMatcher) { - return new TypeSafeMatcher<Preference>() { - @Override - public void describeTo(Description description) { - description.appendText(" a preference with title matching: "); - titleMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(Preference pref) { - String title = pref.getTitle().toString(); - return titleMatcher.matches(title); - } - }; - } - - public static Matcher<Preference> isEnabled() { - return new TypeSafeMatcher<Preference>() { - @Override - public void describeTo(Description description) { - description.appendText(" is an enabled preference"); - } - - @Override - public boolean matchesSafely(Preference pref) { - return pref.isEnabled(); - } - }; - } - - public static Matcher<Preference> withKey(String key) { - return withKey(is(key)); - } - - public static Matcher<Preference> withKey(final Matcher<String> keyMatcher) { - return new TypeSafeMatcher<Preference>() { - @Override - public void describeTo(Description description) { - description.appendText(" preference with key matching: "); - keyMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(Preference pref) { - return keyMatcher.matches(pref.getKey()); - } - }; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/RootMatchers.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/RootMatchers.java deleted file mode 100644 index 03be6c7..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/RootMatchers.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.matcher; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; - -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitor; -import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry; -import com.google.android.apps.common.testing.testrunner.Stage; -import com.google.android.apps.common.testing.ui.espresso.NoActivityResumedException; -import com.google.android.apps.common.testing.ui.espresso.Root; -import com.google.common.collect.Lists; - -import android.app.Activity; -import android.os.IBinder; -import android.view.View; -import android.view.WindowManager; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -import java.util.Collection; -import java.util.List; - -/** - * A collection of matchers for {@link Root} objects. - */ -public final class RootMatchers { - - private RootMatchers() {} - - /** - * Espresso's default {@link Root} matcher. - */ - @SuppressWarnings("unchecked") - public static final Matcher<Root> DEFAULT = - allOf( - hasWindowLayoutParams(), - allOf( - anyOf( - allOf(isDialog(), withDecorView(hasWindowFocus())), - isSubwindowOfCurrentActivity()), - isFocusable())); - - - /** - * Matches {@link Root}s that can take window focus. - */ - public static Matcher<Root> isFocusable() { - return new TypeSafeMatcher<Root>() { - - @Override - public void describeTo(Description description) { - description.appendText("is focusable"); - } - - @Override - public boolean matchesSafely(Root root) { - int flags = root.getWindowLayoutParams().get().flags; - boolean r = !((flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0); - return r; - } - }; - } - - /** - * Matches {@link Root}s that can receive touch events. - */ - public static Matcher<Root> isTouchable() { - return new TypeSafeMatcher<Root>() { - - @Override - public void describeTo(Description description) { - description.appendText("is touchable"); - } - - @Override - public boolean matchesSafely(Root root) { - int flags = root.getWindowLayoutParams().get().flags; - boolean r = !((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0); - return r; - } - }; - } - - /** - * Matches {@link Root}s that are dialogs (i.e. is not a window of the currently resumed - * activity). - */ - public static Matcher<Root> isDialog() { - return new TypeSafeMatcher<Root>() { - - @Override - public void describeTo(Description description) { - description.appendText("is dialog"); - } - - @Override - public boolean matchesSafely(Root root) { - int type = root.getWindowLayoutParams().get().type; - if ((type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION - && type < WindowManager.LayoutParams.LAST_APPLICATION_WINDOW)) { - IBinder windowToken = root.getDecorView().getWindowToken(); - IBinder appToken = root.getDecorView().getApplicationWindowToken(); - if (windowToken == appToken) { - // windowToken == appToken means this window isn't contained by any other windows. - // if it was a window for an activity, it would have TYPE_BASE_APPLICATION. - // therefore it must be a dialog box. - return true; - } - } - return false; - } - }; - } - - /** - * Matches {@link Root}s with decor views that match the given view matcher. - */ - public static Matcher<Root> withDecorView(final Matcher<View> decorViewMatcher) { - checkNotNull(decorViewMatcher); - return new TypeSafeMatcher<Root>() { - - @Override - public void describeTo(Description description) { - description.appendText("with decor view "); - decorViewMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(Root root) { - return decorViewMatcher.matches(root.getDecorView()); - } - }; - } - - private static Matcher<View> hasWindowFocus() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has window focus"); - } - - @Override - public boolean matchesSafely(View view) { - return view.hasWindowFocus(); - } - }; - } - - private static Matcher<Root> hasWindowLayoutParams() { - return new TypeSafeMatcher<Root>() { - - @Override - public void describeTo(Description description) { - description.appendText("has window layout params"); - } - - @Override - public boolean matchesSafely(Root root) { - if (!root.getWindowLayoutParams().isPresent()) { - return false; - } - return true; - } - }; - } - - private static Matcher<Root> isSubwindowOfCurrentActivity() { - return new TypeSafeMatcher<Root>() { - - @Override - public void describeTo(Description description) { - description.appendText("is subwindow of current activity"); - } - - @Override - public boolean matchesSafely(Root root) { - boolean r = - getResumedActivityTokens().contains(root.getDecorView().getApplicationWindowToken()); - return r; - } - }; - } - - private static List<IBinder> getResumedActivityTokens() { - ActivityLifecycleMonitor activityLifecycleMonitor = - ActivityLifecycleMonitorRegistry.getInstance(); - Collection<Activity> resumedActivities = - activityLifecycleMonitor.getActivitiesInStage(Stage.RESUMED); - if (resumedActivities.isEmpty()) { - throw new NoActivityResumedException("At least one activity should be in RESUMED stage."); - } - List<IBinder> tokens = Lists.newArrayList(); - for (Activity activity : resumedActivities) { - tokens.add(activity.getWindow().getDecorView().getApplicationWindowToken()); - } - return tokens; - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/ViewMatchers.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/ViewMatchers.java deleted file mode 100644 index 286f494..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/matcher/ViewMatchers.java +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.matcher; - -import static com.google.android.apps.common.testing.ui.espresso.util.TreeIterables.breadthFirstViewTraversal; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.util.HumanReadables; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; - -import android.content.res.Resources; -import android.graphics.Rect; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; -import android.widget.Checkable; -import android.widget.TextView; - -import junit.framework.AssertionFailedError; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.hamcrest.StringDescription; -import org.hamcrest.TypeSafeMatcher; - -import java.util.Iterator; - -/** - * A collection of hamcrest matchers that match {@link View}s. - */ -public final class ViewMatchers { - - private ViewMatchers() {} - - /** - * Returns a matcher that matches Views which are an instance of or subclass of the provided - * class. Some versions of Hamcrest make the generic typing of this a nightmare, so we have a - * special case for our users. - */ - public static Matcher<View> isAssignableFrom(final Class<? extends View> clazz) { - checkNotNull(clazz); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("is assignable from class: " + clazz); - } - - @Override - public boolean matchesSafely(View view) { - return clazz.isAssignableFrom(view.getClass()); - } - }; - } - - /** - * Returns a matcher that matches Views with class name matching the given matcher. - */ - public static Matcher<View> withClassName(final Matcher<String> classNameMatcher) { - checkNotNull(classNameMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("with class name: "); - classNameMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - return classNameMatcher.matches(view.getClass().getName()); - } - }; - } - - /** - * Returns a matcher that matches {@link View}s that are currently displayed on the screen to the - * user. - * - * Note: isDisplayed will select views that are partially displayed (eg: the full height/width of - * the view is greater then the height/width of the visible rectangle). If you wish to ensure the - * entire rectangle this view draws is displayed to the user use isCompletelyDisplayed. - */ - public static Matcher<View> isDisplayed() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("is displayed on the screen to the user"); - } - - @Override - public boolean matchesSafely(View view) { - return view.getGlobalVisibleRect(new Rect()) && - withEffectiveVisibility(Visibility.VISIBLE).matches(view); - } - }; - } - - /** - * Returns a matcher which only accepts a view whose height and width fit perfectly within - * the currently displayed region of this view. - * - * There exist views (such as ScrollViews) whose height and width are larger then the physical - * device screen by design. Such views will _never_ be completely displayed. - */ - public static Matcher<View> isCompletelyDisplayed() { - return isDisplayingAtLeast(100); - } - - /** - * Returns a matcher which accepts a view so long as a given percentage of that view's area is - * not obscured by any other view and is thus visible to the user. - * - * @param areaPercentage an integer ranging from (0, 100] indicating how much percent of the - * surface area of the view must be shown to the user to be accepted. - */ - public static Matcher<View> isDisplayingAtLeast(final int areaPercentage) { - checkState(areaPercentage <= 100, "Cannot have over 100 percent: %s", areaPercentage); - checkState(areaPercentage > 0, "Must have a positive, non-zero value: %s", areaPercentage); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText(String.format( - "at least %s percent of the view's area is displayed to the user.", areaPercentage)); - } - - @Override - public boolean matchesSafely(View view) { - Rect visibleParts = new Rect(); - boolean visibleAtAll = view.getGlobalVisibleRect(visibleParts); - if (!visibleAtAll) { - return false; - } - double maxArea = view.getHeight() * view.getWidth(); - double visibleArea = visibleParts.height() * visibleParts.width(); - int displayedPercentage = (int) ((visibleArea / maxArea) * 100); - - return displayedPercentage >= areaPercentage - && withEffectiveVisibility(Visibility.VISIBLE).matches(view); - } - }; - } - - - - /** - * Returns a matcher that matches {@link View}s that are enabled. - */ - public static Matcher<View> isEnabled() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("is enabled"); - } - - @Override - public boolean matchesSafely(View view) { - return view.isEnabled(); - } - }; - } - - /** - * Returns a matcher that matches {@link View}s that are focusable. - */ - public static Matcher<View> isFocusable() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("is focusable"); - } - - @Override - public boolean matchesSafely(View view) { - return view.isFocusable(); - } - }; - } - - /** - * Returns a matcher that matches {@link View}s currently have focus. - */ - public static Matcher<View> hasFocus() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has focus on the screen to the user"); - } - - @Override - public boolean matchesSafely(View view) { - return view.hasFocus(); - } - }; - } - - /** - * Returns an {@link Matcher} that matches {@link View}s based on their siblings.<br> - * <br> - * This may be particularly useful when a view cannot be uniquely selected on properties such as - * text or R.id. For example: a call button is repeated several times in a contacts layout and the - * only way to differentiate the call button view is by what appears next to it (e.g. the unique - * name of the contact). - * - * @param siblingMatcher a {@link Matcher} for the sibling of the view. - */ - public static Matcher<View> hasSibling(final Matcher<View> siblingMatcher) { - checkNotNull(siblingMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has sibling: "); - siblingMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - ViewParent parent = view.getParent(); - if (!(parent instanceof ViewGroup)) { - return false; - } - ViewGroup parentGroup = (ViewGroup) parent; - for (int i = 0; i < parentGroup.getChildCount(); i++) { - if (siblingMatcher.matches(parentGroup.getChildAt(i))) { - return true; - } - } - return false; - } - }; - } - - /** - * Returns an {@link Matcher} that matches {@link View}s based on content description property - * value. Sugar for withContentDescription(is("string")). - * - * @param text the text to match on. - */ - public static Matcher<View> withContentDescription(String text) { - return withContentDescription(is(text)); - } - - /** - * Returns an {@link Matcher} that matches {@link View}s based on content description property - * value. - * - * @param charSequenceMatcher a {@link CharSequence} {@link Matcher} for the content description - */ - public static Matcher<View> withContentDescription( - final Matcher<? extends CharSequence> charSequenceMatcher) { - checkNotNull(charSequenceMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("with content description: "); - charSequenceMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - return charSequenceMatcher.matches(view.getContentDescription()); - } - }; - } - - /** - * Sugar for withId(is(int)). - * - * @param id the resource id. - */ - public static Matcher<View> withId(int id) { - return withId(is(id)); - } - - /** - * Returns a matcher that matches {@link View}s based on resource ids. Note: Android resource ids - * are not guaranteed to be unique. You may have to pair this matcher with another one to - * guarantee a unique view selection. - * - * @param integerMatcher a Matcher for resource ids - */ - public static Matcher<View> withId(final Matcher<Integer> integerMatcher) { - checkNotNull(integerMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("with id: "); - integerMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - return integerMatcher.matches(view.getId()); - } - }; - } - - /** - * Returns a matcher that matches {@link View} based on tag keys. - * - * @param key to match - */ - public static Matcher<View> withTagKey(final int key) { - return withTagKey(key, Matchers.<Object>notNullValue()); - } - - /** - * Returns a matcher that matches {@link View}s based on tag keys. - * - * @param key to match - * @param objectMatcher Object to match - */ - public static Matcher<View> withTagKey(final int key, final Matcher<Object> objectMatcher) { - checkNotNull(objectMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("with key: " + key); - objectMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - return objectMatcher.matches(view.getTag(key)); - } - }; - } - - /** - * Returns a matcher that matches {@link View}s based on tag property values. - * - * @param tagValueMatcher a Matcher for the view's tag property value - */ - public static Matcher<View> withTagValue(final Matcher<Object> tagValueMatcher) { - checkNotNull(tagValueMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("with tag value: "); - tagValueMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - return tagValueMatcher.matches(view.getTag()); - } - }; - } - - /** - * Returns a matcher that matches {@link TextView} based on it's text property value. Note: View's - * Sugar for withText(is("string")). - */ - public static Matcher<View> withText(String text) { - return withText(is(text)); - } - - /** - * Returns a matcher that matches {@link TextView}s based on text property value. Note: View's - * text property is never null. If you setText(null) it will still be "". Do not use null matcher. - * - * @param stringMatcher {@link Matcher} of {@link String} with text to match - */ - public static Matcher<View> withText(final Matcher<String> stringMatcher) { - checkNotNull(stringMatcher); - return new BoundedMatcher<View, TextView>(TextView.class) { - @Override - public void describeTo(Description description) { - description.appendText("with text: "); - stringMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(TextView textView) { - return stringMatcher.matches(textView.getText().toString()); - } - }; - } - - /** - * Returns a matcher that matches a descendant of {@link TextView} that is displaying the string - * associated with the given resource id. - * - * @param resourceId the string resource the text view is expected to hold. - */ - public static Matcher<View> withText(final int resourceId) { - - return new BoundedMatcher<View, TextView>(TextView.class) { - private String resourceName = null; - private String expectedText = null; - - @Override - public void describeTo(Description description) { - description.appendText("with string from resource id: "); - description.appendValue(resourceId); - if (null != resourceName) { - description.appendText("["); - description.appendText(resourceName); - description.appendText("]"); - } - if (null != expectedText) { - description.appendText(" value: "); - description.appendText(expectedText); - } - } - - @Override - public boolean matchesSafely(TextView textView) { - if (null == expectedText) { - try { - expectedText = textView.getResources().getString(resourceId); - resourceName = textView.getResources().getResourceEntryName(resourceId); - } catch (Resources.NotFoundException ignored) { - /* view could be from a context unaware of the resource id. */ - } - } - if (null != expectedText) { - return expectedText.equals(textView.getText()); - } else { - return false; - } - } - }; - } - - /** - * Returns a matcher that accepts if and only if the view is a CompoundButton (or subtype of) and - * is in checked state. - */ - public static Matcher<View> isChecked() { - return withCheckBoxState(is(true)); - } - - /** - * Returns a matcher that accepts if and only if the view is a CompoundButton (or subtype of) and - * is not in checked state. - */ - public static Matcher<View> isNotChecked() { - return withCheckBoxState(is(false)); - } - - private static <E extends View & Checkable> Matcher<View> withCheckBoxState( - final Matcher<Boolean> checkStateMatcher) { - - return new BoundedMatcher<View, E>(View.class, Checkable.class) { - @Override - public void describeTo(Description description) { - description.appendText("with checkbox state: "); - checkStateMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(E checkable) { - return checkStateMatcher.matches(checkable.isChecked()); - } - }; - } - - /** - * Returns an {@link Matcher} that matches {@link View}s with any content description. - */ - public static Matcher<View> hasContentDescription() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has content description"); - } - - @Override - public boolean matchesSafely(View view) { - return view.getContentDescription() != null; - } - }; - } - - /** - * Returns a matcher that matches {@link View}s based on the presence of a descendant in its view - * hierarchy. - * - * @param descendantMatcher the type of the descendant to match on - */ - public static Matcher<View> hasDescendant(final Matcher<View> descendantMatcher) { - checkNotNull(descendantMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has descendant: "); - descendantMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(final View view) { - final Predicate<View> matcherPredicate = new Predicate<View>() { - @Override - public boolean apply(View input) { - return input != view && descendantMatcher.matches(input); - } - }; - - Iterator<View> matchedViewIterator = - Iterables.filter(breadthFirstViewTraversal(view), matcherPredicate).iterator(); - - return matchedViewIterator.hasNext(); - } - }; - } - - /** - * Returns a matcher that matches {@link View}s that are clickable. - */ - public static Matcher<View> isClickable() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("is clickable"); - } - - @Override - public boolean matchesSafely(View view) { - return view.isClickable(); - } - }; - } - - /** - * Returns a matcher that matches {@link View}s based on the given ancestor type. - * - * @param ancestorMatcher the type of the ancestor to match on - */ - public static Matcher<View> isDescendantOfA(final Matcher<View> ancestorMatcher) { - checkNotNull(ancestorMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("is descendant of a: "); - ancestorMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - return checkAncestors(view.getParent(), ancestorMatcher); - } - - private boolean checkAncestors( - ViewParent viewParent, Matcher<View> ancestorMatcher) { - if (!(viewParent instanceof View)) { - return false; - } - if (ancestorMatcher.matches(viewParent)) { - return true; - } - return checkAncestors(viewParent.getParent(), ancestorMatcher); - } - }; - } - - /** - * Returns a matcher that matches {@link View}s that have "effective" visibility set to the given - * value. Effective visibility takes into account not only the view's visibility value, but also - * that of its ancestors. In case of View.VISIBLE, this means that the view and all of its - * ancestors have visibility=VISIBLE. In case of GONE and INVISIBLE, it's the opposite - any GONE - * or INVISIBLE parent will make all of its children have their effective visibility. - * - * <p> - * <p> - * Note: Contrary to what the name may imply, view visibility does not directly translate into - * whether the view is displayed on screen (use isDisplayed() for that). For example, the view and - * all of its ancestors can have visibility=VISIBLE, but the view may need to be scrolled to in - * order to be actually visible to the user. Unless you're specifically targeting the visibility - * value with your test, use isDisplayed. - */ - public static Matcher<View> withEffectiveVisibility(final Visibility visibility) { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText( - String.format("view has effective visibility=%s", visibility)); - } - - @Override - public boolean matchesSafely(View view) { - if (visibility.getValue() == View.VISIBLE) { - if (view.getVisibility() != visibility.getValue()) { - return false; - } - while (view.getParent() != null && view.getParent() instanceof View) { - view = (View) view.getParent(); - if (view.getVisibility() != visibility.getValue()) { - return false; - } - } - return true; - } else { - if (view.getVisibility() == visibility.getValue()) { - return true; - } - while (view.getParent() != null && view.getParent() instanceof View) { - view = (View) view.getParent(); - if (view.getVisibility() == visibility.getValue()) { - return true; - } - } - return false; - } - } - }; - } - - /** - * Enumerates the possible list of values for View.getVisibility(). - */ - public enum Visibility { - VISIBLE(View.VISIBLE), INVISIBLE(View.INVISIBLE), GONE(View.GONE); - - private final int value; - - private Visibility(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - } - - /** - * A matcher that accepts a view if and only if the view's parent is accepted by the provided - * matcher. - * - * @param parentMatcher the matcher to apply on getParent. - */ - public static Matcher<View> withParent(final Matcher<View> parentMatcher) { - checkNotNull(parentMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has parent matching: "); - parentMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - return parentMatcher.matches(view.getParent()); - } - }; - } - - /** - * A matcher that returns true if and only if the view's child is accepted by the provided - * matcher. - * - * @param childMatcher the matcher to apply on the child views. - */ - public static Matcher<View> withChild(final Matcher<View> childMatcher) { - checkNotNull(childMatcher); - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has child: "); - childMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof ViewGroup)) { - return false; - } - - ViewGroup group = (ViewGroup) view; - for (int i = 0; i < group.getChildCount(); i++) { - if (childMatcher.matches(group.getChildAt(i))) { - return true; - } - } - - return false; - } - }; - } - - - /** - * Returns a matcher that matches root {@link View}. - */ - public static Matcher<View> isRoot() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("is a root view."); - } - - @Override - public boolean matchesSafely(View view) { - return view.getRootView().equals(view); - } - }; - } - - /** - * Returns a matcher that matches views that support input methods. - */ - public static Matcher<View> supportsInputMethods() { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("supports input methods"); - } - - @Override - public boolean matchesSafely(View view) { - // At first glance, it would make sense to use view.onCheckIsTextEditor, but the android - // javadoc is wishy-washy about whether authors are required to implement this method when - // implementing onCreateInputConnection. - return view.onCreateInputConnection(new EditorInfo()) != null; - } - }; - } - - /** - * Returns a matcher that matches views that support input methods (e.g. EditText) and have the - * specified IME action set in its {@link EditorInfo}. - * - * @param imeAction the IME action to match - */ - public static Matcher<View> hasImeAction(int imeAction) { - return hasImeAction(is(imeAction)); - } - - /** - * Returns a matcher that matches views that support input methods (e.g. EditText) and have the - * specified IME action set in its {@link EditorInfo}. - * - * @param imeActionMatcher a matcher for the IME action - */ - public static Matcher<View> hasImeAction(final Matcher<Integer> imeActionMatcher) { - return new TypeSafeMatcher<View>() { - @Override - public void describeTo(Description description) { - description.appendText("has ime action: "); - imeActionMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - EditorInfo editorInfo = new EditorInfo(); - InputConnection inputConnection = view.onCreateInputConnection(editorInfo); - if (inputConnection == null) { - return false; - } - int actionId = editorInfo.actionId != 0 ? editorInfo.actionId - : editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION; - return imeActionMatcher.matches(actionId); - } - }; - } - - /** - * A replacement for MatcherAssert.assertThat that renders View objects nicely. - * - * @param actual the actual value. - * @param matcher a matcher that accepts or rejects actual. - */ - public static <T> void assertThat(T actual, Matcher<T> matcher) { - assertThat("", actual, matcher); - } - - /** - * A replacement for MatcherAssert.assertThat that renders View objects nicely. - * - * @param message the message to display. - * @param actual the actual value. - * @param matcher a matcher that accepts or rejects actual. - */ - public static <T> void assertThat(String message, T actual, Matcher<T> matcher) { - if (!matcher.matches(actual)) { - Description description = new StringDescription(); - description.appendText(message) - .appendText("\nExpected: ") - .appendDescriptionOf(matcher) - .appendText("\n Got: "); - if (actual instanceof View) { - description.appendValue(HumanReadables.describe((View) actual)); - } else { - description.appendValue(actual); - } - description.appendText("\n"); - throw new AssertionFailedError(description.toString()); - } - } -} - diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/util/HumanReadables.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/util/HumanReadables.java deleted file mode 100644 index a160cea..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/util/HumanReadables.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.util; - -import static com.google.android.apps.common.testing.ui.espresso.util.TreeIterables.depthFirstViewTraversalWithDistance; - -import com.google.android.apps.common.testing.ui.espresso.util.TreeIterables.ViewAndDistance; -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.base.Objects; -import com.google.common.base.Objects.ToStringHelper; -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import com.google.common.collect.Iterables; - -import android.content.res.Resources; -import android.os.Build; -import android.util.Printer; -import android.util.StringBuilderPrinter; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; -import android.widget.Checkable; -import android.widget.TextView; - -import java.util.List; - -/** - * Text converters for various Android objects. - */ -public final class HumanReadables { - - private HumanReadables() {} - - /** - * Prints out an error message feature the view hierarchy starting at the rootView. - * - * @param rootView the root of the hierarchy tree to print out. - * @param problemViews list of the views that you would like to point out are causing the error - * message or null, if you want to skip this feature. - * @param errorHeader the header of the error message (should contain the description of why the - * error is happening). - * @param problemViewSuffix the message to append to the view description in the tree printout. - * Required if problemViews is supplied. Otherwise, null is acceptable. - * @return a string for human consumption. - */ - public static String getViewHierarchyErrorMessage(View rootView, - final List<View> problemViews, - String errorHeader, - final String problemViewSuffix) { - Preconditions.checkArgument(problemViews == null || problemViewSuffix != null); - StringBuilder errorMessage = new StringBuilder(errorHeader); - if (problemViewSuffix != null) { - errorMessage.append( - String.format("\nProblem views are marked with '%s' below.", problemViewSuffix)); - } - - errorMessage.append("\n\nView Hierarchy:\n"); - - Joiner.on("\n").appendTo(errorMessage, Iterables.transform( - depthFirstViewTraversalWithDistance(rootView), new Function<ViewAndDistance, String>() { - @Override - public String apply(ViewAndDistance viewAndDistance) { - String formatString = "+%s%s "; - if (problemViews != null - && problemViews.contains(viewAndDistance.getView())) { - formatString += problemViewSuffix; - } - formatString += "\n|"; - - return String.format(formatString, - Strings.padStart(">", viewAndDistance.getDistanceFromRoot() + 1, '-'), - HumanReadables.describe(viewAndDistance.getView())); - } - })); - - return errorMessage.toString(); - } - - /** - * Transforms an arbitrary view into a string with (hopefully) enough debug info. - * - * @param v nullable view - * @return a string for human consumption. - */ - public static String describe(View v) { - if (null == v) { - return "null"; - } - ToStringHelper helper = Objects.toStringHelper(v).add("id", v.getId()); - if (v.getId() != -1 && v.getResources() != null) { - try { - helper.add("res-name", v.getResources().getResourceEntryName(v.getId())); - } catch (Resources.NotFoundException ignore) { - // Do nothing. - } - } - if (null != v.getContentDescription()) { - helper.add("desc", v.getContentDescription()); - } - - switch (v.getVisibility()) { - case View.GONE: - helper.add("visibility", "GONE"); - break; - case View.INVISIBLE: - helper.add("visibility", "INVISIBLE"); - break; - case View.VISIBLE: - helper.add("visibility", "VISIBLE"); - break; - default: - helper.add("visibility", v.getVisibility()); - } - - helper.add("width", v.getWidth()) - .add("height", v.getHeight()) - .add("has-focus", v.hasFocus()) - .add("has-focusable", v.hasFocusable()) - .add("has-window-focus", v.hasWindowFocus()) - .add("is-clickable", v.isClickable()) - .add("is-enabled", v.isEnabled()) - .add("is-focused", v.isFocused()) - .add("is-focusable", v.isFocusable()) - .add("is-layout-requested", v.isLayoutRequested()) - .add("is-selected", v.isSelected()); - - if (null != v.getRootView()) { - // pretty much only true in unit-tests. - helper.add("root-is-layout-requested", v.getRootView().isLayoutRequested()); - } - - EditorInfo ei = new EditorInfo(); - InputConnection ic = v.onCreateInputConnection(ei); - boolean hasInputConnection = ic != null; - helper.add("has-input-connection", hasInputConnection); - if (hasInputConnection) { - StringBuilder sb = new StringBuilder(); - sb.append("["); - Printer p = new StringBuilderPrinter(sb); - ei.dump(p, ""); - sb.append("]"); - helper.add("editor-info", sb.toString().replace("\n", " ")); - } - - if (Build.VERSION.SDK_INT > 10) { - helper.add("x", v.getX()).add("y", v.getY()); - } - - if (v instanceof TextView) { - innerDescribe((TextView) v, helper); - } - if (v instanceof Checkable) { - innerDescribe((Checkable) v, helper); - } - if (v instanceof ViewGroup) { - innerDescribe((ViewGroup) v, helper); - } - return helper.toString(); - } - - private static void innerDescribe(TextView textBox, ToStringHelper helper) { - if (null != textBox.getText()) { - helper.add("text", textBox.getText()); - } - - if (null != textBox.getError()) { - helper.add("error-text", textBox.getError()); - } - - if (null != textBox.getHint()) { - helper.add("hint", textBox.getHint()); - } - - helper.add("input-type", textBox.getInputType()); - helper.add("ime-target", textBox.isInputMethodTarget()); - } - - private static void innerDescribe(Checkable checkable, ToStringHelper helper) { - helper.add("is-checked", checkable.isChecked()); - } - - private static void innerDescribe(ViewGroup viewGroup, ToStringHelper helper) { - helper.add("child-count", viewGroup.getChildCount()); - } -} diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/util/TreeIterables.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/util/TreeIterables.java deleted file mode 100644 index 7fd0c4f..0000000 --- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/util/TreeIterables.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso.util; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.collect.AbstractIterator; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import android.view.View; -import android.view.ViewGroup; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * Utility methods for iterating over tree structured items. - * - * Since the view hierarchy is a tree - having a method of iterating over its contents - * is useful. - * - * This is generalized for any object which can display tree like qualities - but this - * generalization was done for testability concerns (since creating View hierarchies is a pain). - * - * Only public methods of this utility class are considered public API of the test framework. - */ -public final class TreeIterables { - private static final TreeViewer<View> VIEW_TREE_VIEWER = new ViewTreeViewer(); - - private TreeIterables() { } - - /** - * Creates an iterable that traverses the tree formed by the given root. - * - * Along with iteration order, the distance from the root element is also tracked. - * - * @param root the root view to track from. - * @return An iterable of ViewAndDistance containing the view tree in a depth first order with - * the distance of a given node from the root. - */ - public static Iterable<ViewAndDistance> depthFirstViewTraversalWithDistance(View root) { - final DistanceRecordingTreeViewer<View> distanceRecorder = - new DistanceRecordingTreeViewer<View>(root, VIEW_TREE_VIEWER); - - - return Iterables.transform( - depthFirstTraversal(root, distanceRecorder), - new Function<View, ViewAndDistance>() { - @Override - public ViewAndDistance apply(View view) { - return new ViewAndDistance(view, distanceRecorder.getDistance(view)); - } - }); - } - - /** - * Returns an iterable which iterates thru the provided view and its children in a - * depth-first, in-order traversal. That is to say that for a view such as: - * Root - * / | \ - * A R U - * /| |\ - * B D G N - * Will be iterated: Root, A, B, D, R, G, N, U. - * - * @param root the non-null, root view. - */ - public static Iterable<View> depthFirstViewTraversal(View root) { - return depthFirstTraversal(root, VIEW_TREE_VIEWER); - } - - /** - * Returns an iterable which iterates thru the provided view and its children in a - * breadth-first, row-level-order traversal. That is to say that for a view such as: - * Root - * / | \ - * A R U - * /| |\ - * B D G N - * Will be iterated: Root, A, R, U, B, D, G, N - * - * @param root the non-null, root view. - */ - public static Iterable<View> breadthFirstViewTraversal(View root) { - return breadthFirstTraversal(root, VIEW_TREE_VIEWER); - } - - /** - * Creates a depth first traversing iterator of the tree rooted at root. - * - * @param root the root of the tree - * @param viewer a TreeViewer which can determine leafiness of any instance of T and generate - * Iterables for the direct children of any instance of T. - */ - @VisibleForTesting - static <T> Iterable<T> depthFirstTraversal(final T root, final TreeViewer<T> viewer) { - checkNotNull(root); - checkNotNull(viewer); - return new TreeTraversalIterable<T>(root, TraversalStrategy.DEPTH_FIRST, viewer); - } - - /** - * Creates a breadth first traversing iterator of the tree rooted at root. - * - * @param root the root of the tree - * @param viewer a TreeViewer which can determine leafiness of any instance of T and generate - * Iterables for the direct children of any instance of T. - */ - @VisibleForTesting - static <T> Iterable<T> breadthFirstTraversal(final T root, final TreeViewer<T> viewer) { - checkNotNull(root); - checkNotNull(viewer); - return new TreeTraversalIterable<T>(root, TraversalStrategy.BREADTH_FIRST, viewer); - } - - /** - * Converts a tree into an Iterable of the tree's nodes presented in a given traversal order. - */ - private static class TreeTraversalIterable<T> implements Iterable<T> { - private final T root; - private final TraversalStrategy traversalStrategy; - private final TreeViewer<T> treeViewer; - - private TreeTraversalIterable(T root, TraversalStrategy traversalStrategy, - TreeViewer<T> treeViewer) { - this.root = checkNotNull(root); - this.traversalStrategy = checkNotNull(traversalStrategy); - this.treeViewer = checkNotNull(treeViewer); - } - - @Override - public Iterator<T> iterator() { - final LinkedList<T> nodes = Lists.newLinkedList(); - nodes.add(root); - return new AbstractIterator<T>() { - @Override - public T computeNext() { - if (nodes.isEmpty()) { - return endOfData(); - } else { - T nextItem = checkNotNull(traversalStrategy.next(nodes), "Null items not allowed!"); - traversalStrategy.combineNewChildren(nodes, treeViewer.children(nextItem)); - return nextItem; - } - } - }; - } - } - - private enum TraversalStrategy { - BREADTH_FIRST() { - @Override - <T> void combineNewChildren(LinkedList<T> nodes, Collection<T> newChildren) { - nodes.addAll(newChildren); - } - }, DEPTH_FIRST() { - @Override - <T> void combineNewChildren(LinkedList<T> nodes, Collection<T> newChildren) { - nodes.addAll(0, newChildren); - } - }; - - abstract <T> void combineNewChildren(LinkedList<T> nodes, Collection<T> newChildren); - <T> T next(LinkedList<T> nodes) { - return nodes.removeFirst(); - } - - } - - /** - * A TreeView providing access to the children of a given View. - * - * The only way views can have children is if they are a subclass of - * ViewGroup. - */ - @VisibleForTesting - static class ViewTreeViewer implements TreeViewer<View> { - @Override - public Collection<View> children(View view) { - checkNotNull(view); - if (view instanceof ViewGroup) { - ViewGroup group = (ViewGroup) view; - int childCount = group.getChildCount(); - List<View> children = Lists.newArrayList(); - for (int i = 0; i < childCount; i++) { - children.add(group.getChildAt(i)); - } - return children; - } else { - return Collections.<View>emptyList(); - } - } - } - - /** - * Provides a tree view of items of instance T and records their distance from - * a well known root. - * - * It is assumed that this TreeViewer will only be called with nodes that it - * has processed via its children method, or the root node itself. Otherwise it - * will not be able to determine distance from the root and an exception will be thrown. - * - * This class is stateful and only provides the correct distances after the underlying - * tree has been iterated over. - */ - @VisibleForTesting - static class DistanceRecordingTreeViewer<T> implements TreeViewer<T> { - private final T root; - private final Map<T, Integer> nodeToDistance = Maps.newHashMap(); - private final TreeViewer<T> delegateViewer; - - DistanceRecordingTreeViewer(T root, TreeViewer<T> delegateViewer) { - this.root = checkNotNull(root); - this.delegateViewer = checkNotNull(delegateViewer); - } - - int getDistance(T node) { - return checkNotNull(nodeToDistance.get(node), "Never seen %s before", node); - } - - @Override - public Collection<T> children(final T node) { - if (node == root) { - // base case. - nodeToDistance.put(node, 0); - } - - int myDistance = getDistance(node); - final int childDistance = myDistance + 1; - Collection<T> children = delegateViewer.children(node); - - for (T child : children) { - nodeToDistance.put(child, childDistance); - } - return children; - } - } - - /** - * Provides a way of viewing any instance of T as a tree so long as there exists a method - * for converting the instance of T into a Collection of that instance's direct children. - * - * This nice, sensible abstraction for dealing with objects with treelike properties was - * stolen from Guava's bug tracker. The Guava team is still working out the way trees - * should be exposed as Guava collections - so we have to provide our own. - */ - @VisibleForTesting - interface TreeViewer<T> { - - /** - * Returns a collection view of the children of this node. - */ - Collection<T> children(T instance); - } - - - - /** - * Represents the distance a given view is from the root view. - */ - public static class ViewAndDistance { - private final View view; - private final int distanceFromRoot; - - private ViewAndDistance(View view, int distanceFromRoot) { - this.view = view; - this.distanceFromRoot = distanceFromRoot; - } - - public View getView() { - return view; - } - - public int getDistanceFromRoot() { - return distanceFromRoot; - } - } -} diff --git a/espresso/espresso-sample/Android.mk b/espresso/espresso-sample/Android.mk deleted file mode 100644 index a58b123..0000000 --- a/espresso/espresso-sample/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include $(call all-subdir-makefiles) diff --git a/espresso/espresso-sample/build.gradle b/espresso/espresso-sample/build.gradle deleted file mode 100644 index b2ff8ec..0000000 --- a/espresso/espresso-sample/build.gradle +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'android' - -repositories { - maven { url '../../../../prebuilts/tools/common/m2/repository' } - maven { url '../../../../prebuilts/tools/common/m2/internal' } -} - -android { - compileSdkVersion 19 - buildToolsVersion "19.0.3" - - packagingOptions { - exclude 'LICENSE.txt' - } - - lintOptions { - abortOnError false - } - - defaultConfig { - testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner" - } -} - -dependencies { - compile files('../libs/guava-14.0.1.jar') - compile 'com.android.support:support-v4:19.1.+' - compile 'com.android.support:appcompat-v7:19.1.+' - compile project(':idling-resource-interface') - androidTestCompile project(':espresso-contrib') -} - -apply from: "$rootDir/javadoc.gradle" diff --git a/espresso/espresso-sample/src/Android.mk b/espresso/espresso-sample/src/Android.mk deleted file mode 100644 index a58b123..0000000 --- a/espresso/espresso-sample/src/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include $(call all-subdir-makefiles) diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/ActionBarTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/ActionBarTest.java deleted file mode 100644 index 10485c9..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/ActionBarTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.openActionBarOverflowOrOptionsMenu; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.openContextualActionModeOverflowMenu; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Demonstrates Espresso with action bar and contextual action mode. - * {@link openActionBarOverflowOrOptionsMenu()} opens the overflow menu from an action bar. - * {@link openContextualActionModeOverflowMenu()} opens the overflow menu from an contextual action - * mode. - */ -@LargeTest -public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarTestActivity> { - @SuppressWarnings("deprecation") - public ActionBarTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", ActionBarTestActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - // Espresso will not launch our activity for us, we must launch it via getActivity(). - getActivity(); - } - - @SuppressWarnings("unchecked") - public void testClickActionBarItem() { - onView(withId(R.id.hide_contextual_action_bar)) - .perform(click()); - - onView(withId(R.id.action_save)) - .perform(click()); - - onView(withId(R.id.text_action_bar_result)) - .check(matches(withText("Save"))); - } - - @SuppressWarnings("unchecked") - public void testClickActionModeItem() { - onView(withId(R.id.show_contextual_action_bar)) - .perform(click()); - - onView((withId(R.id.action_lock))) - .perform(click()); - - onView(withId(R.id.text_action_bar_result)) - .check(matches(withText("Lock"))); - } - - - @SuppressWarnings("unchecked") - public void testActionBarOverflow() { - onView(withId(R.id.hide_contextual_action_bar)) - .perform(click()); - - // Open the overflow menu from action bar - openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext()); - - onView(withText("World")) - .perform(click()); - - onView(withId(R.id.text_action_bar_result)) - .check(matches(withText("World"))); - } - - @SuppressWarnings("unchecked") - public void testActionModeOverflow() { - onView(withId(R.id.show_contextual_action_bar)) - .perform(click()); - - // Open the overflow menu from contextual action mode. - openContextualActionModeOverflowMenu(); - - onView(withText("Key")) - .perform(click()); - - onView(withId(R.id.text_action_bar_result)) - .check(matches(withText("Key"))); - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/AdapterViewTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/AdapterViewTest.java deleted file mode 100644 index fd531ec..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/AdapterViewTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static com.google.android.apps.common.testing.ui.testapp.LongListMatchers.isFooter; -import static com.google.android.apps.common.testing.ui.testapp.LongListMatchers.withItemContent; -import static com.google.android.apps.common.testing.ui.testapp.LongListMatchers.withItemSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.view.View; -import android.widget.Adapter; -import android.widget.AdapterView; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -/** - * Demonstrates the usage of - * {@link com.google.android.apps.common.testing.ui.espresso.Espresso#onData(org.hamcrest.Matcher)} - * to match data within list views. - */ -@LargeTest -public class AdapterViewTest extends ActivityInstrumentationTestCase2<LongListActivity> { - - @SuppressWarnings("deprecation") - public AdapterViewTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", LongListActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testClickOnItem50() { - // The text view "item: 50" may not exist if we haven't scrolled to it. - // By using onData api we tell Espresso to look into the Adapter for an item matching - // the matcher we provide it. Espresso will then bring that item into the view hierarchy - // and we can click on it. - - onData(withItemContent("item: 50")) - .perform(click()); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("50"))); - } - - public void testClickOnSpecificChildOfRow60() { - onData(withItemContent("item: 60")) - .onChildView(withId(R.id.item_size)) // resource id of second column from xml layout - .perform(click()); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("60"))); - - onView(withId(R.id.selection_column_value)) - .check(matches(withText("2"))); - } - - public void testClickOnFirstAndFifthItemOfLength8() { - onData(is(withItemSize(8))) - .atPosition(0) - .perform(click()); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("10"))); - - onData(is(withItemSize(8))) - .atPosition(4) - .perform(click()); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("14"))); - } - - @SuppressWarnings("unchecked") - public void testClickFooter() { - onData(isFooter()) - .perform(click()); - - onView(withId(R.id.selection_row_value)) - .check(matches(withText("100"))); - } - - @SuppressWarnings("unchecked") - public void testDataItemNotInAdapter(){ - onView(withId(R.id.list)) - .check(matches(not(withAdaptedData(withItemContent("item: 168"))))); - } - - private static Matcher<View> withAdaptedData(final Matcher<Object> dataMatcher) { - return new TypeSafeMatcher<View>() { - - @Override - public void describeTo(Description description) { - description.appendText("with class name: "); - dataMatcher.describeTo(description); - } - - @Override - public boolean matchesSafely(View view) { - if (!(view instanceof AdapterView)) { - return false; - } - @SuppressWarnings("rawtypes") - Adapter adapter = ((AdapterView) view).getAdapter(); - for (int i = 0; i < adapter.getCount(); i++) { - if (dataMatcher.matches(adapter.getItem(i))) { - return true; - } - } - return false; - } - }; - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/AdvancedSynchronizationTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/AdvancedSynchronizationTest.java deleted file mode 100644 index d19fb69..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/AdvancedSynchronizationTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.registerIdlingResources; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.android.apps.common.testing.ui.espresso.contrib.CountingIdlingResource; -import com.google.android.apps.common.testing.ui.testapp.SyncActivity.HelloWorldServer; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Example for {@link CountingIdlingResource}. Demonstrates how to wait on a delayed response from - * request before continuing with a test. - */ -@LargeTest -public class AdvancedSynchronizationTest extends ActivityInstrumentationTestCase2<SyncActivity> { - - private class DecoratedHelloWorldServer implements HelloWorldServer { - private final HelloWorldServer realHelloWorldServer; - private final CountingIdlingResource helloWorldServerIdlingResource; - - private DecoratedHelloWorldServer(HelloWorldServer realHelloWorldServer, - CountingIdlingResource helloWorldServerIdlingResource) { - this.realHelloWorldServer = checkNotNull(realHelloWorldServer); - this.helloWorldServerIdlingResource = checkNotNull(helloWorldServerIdlingResource); - } - - @Override - public String getHelloWorld() { - // Use CountingIdlingResource to track in-flight calls to getHelloWorld (a simulation of a - // network call). Whenever the count goes to zero, Espresso will be notified that this - // resource is idle and the test will be able to proceed. - helloWorldServerIdlingResource.increment(); - try { - return realHelloWorldServer.getHelloWorld(); - } finally { - helloWorldServerIdlingResource.decrement(); - } - } - } - - @SuppressWarnings("deprecation") - public AdvancedSynchronizationTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", SyncActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - SyncActivity activity = getActivity(); - HelloWorldServer realServer = activity.getHelloWorldServer(); - // Here, we use CountingIdlingResource - a common convenience class - to track the idle state of - // the server. You could also do this yourself, by implementing the IdlingResource interface. - CountingIdlingResource countingResource = new CountingIdlingResource("HelloWorldServerCalls"); - activity.setHelloWorldServer(new DecoratedHelloWorldServer(realServer, countingResource)); - registerIdlingResources(countingResource); - } - - public void testCountingIdlingResource() { - // Request the "hello world!" text by clicking on the request button. - onView(withId(R.id.request_button)).perform(click()); - - // Espresso waits for the resource to go idle and then continues. - - // The check if the text is visible can pass now. - onView(withId(R.id.status_text)).check(matches(withText(R.string.hello_world))); - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/BasicTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/BasicTest.java deleted file mode 100644 index ba2b282..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/BasicTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.pressBack; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeText; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Highlights basic - * {@link com.google.android.apps.common.testing.ui.espresso.Espresso#onView(org.hamcrest.Matcher)} - * functionality. - */ -@LargeTest -public class BasicTest extends ActivityInstrumentationTestCase2<SimpleActivity> { - - @SuppressWarnings("deprecation") - public BasicTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", SimpleActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - // Espresso will not launch our activity for us, we must launch it via getActivity(). - getActivity(); - } - - public void testSimpleClickAndCheckText() { - onView(withId(R.id.button_simple)) - .perform(click()); - - onView(withId(R.id.text_simple)) - .check(matches(withText("Hello Espresso!"))); - } - - public void testTypingAndPressBack() { - onView(withId(R.id.sendtext_simple)) - .perform(typeText("Have a cup of Espresso.")); - - onView(withId(R.id.send_simple)) - .perform(click()); - - // Clicking launches a new activity that shows the text entered above. You don't need to do - // anything special to handle the activity transitions. Espresso takes care of waiting for the - // new activity to be resumed and its view hierarchy to be laid out. - onView(withId(R.id.display_data)) - .check(matches(withText(("Have a cup of Espresso.")))); - - // Going back to the previous activity - lets make sure our text was perserved. - pressBack(); - - onView(withId(R.id.sendtext_simple)) - .check(matches(withText(containsString("Espresso")))); - } - - @SuppressWarnings("unchecked") - public void testClickOnSpinnerItemAmericano(){ - // Open the spinner. - onView(withId(R.id.spinner_simple)) - .perform(click()); - // Spinner creates a List View with its contents - this can be very long and the element not - // contributed to the ViewHierarchy - by using onData we force our desired element into the - // view hierarchy. - onData(allOf(is(instanceOf(String.class)), is("Americano"))) - .perform(click()); - - onView(withId(R.id.spinnertext_simple)) - .check(matches(withText(containsString("Americano")))); - } -} - - diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/CustomFailureHandlerTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/CustomFailureHandlerTest.java deleted file mode 100644 index 14a3baf..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/CustomFailureHandlerTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.setFailureHandler; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; - -import com.google.android.apps.common.testing.ui.espresso.FailureHandler; -import com.google.android.apps.common.testing.ui.espresso.NoMatchingViewException; -import com.google.android.apps.common.testing.ui.espresso.base.DefaultFailureHandler; - -import android.content.Context; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; -import android.view.View; - -import org.hamcrest.Matcher; - -/** - * A sample of how to set a non-default {@link FailureHandler}. - */ -@LargeTest -public class CustomFailureHandlerTest extends ActivityInstrumentationTestCase2<MainActivity> { - - private static final String TAG = "CustomFailureHandlerTest"; - - @SuppressWarnings("deprecation") - public CustomFailureHandlerTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", MainActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - setFailureHandler(new CustomFailureHandler(getInstrumentation().getTargetContext())); - } - - public void testWithCustomFailureHandler() { - try { - onView(withText("does not exist")).perform(click()); - } catch (MySpecialException expected) { - Log.e(TAG, "Special exception is special and expected: ", expected); - } - } - - /** - * A {@link FailureHandler} that re-throws {@link NoMatchingViewException} as - * {@link MySpecialException}. All other functionality is delegated to - * {@link DefaultFailureHandler}. - */ - private static class CustomFailureHandler implements FailureHandler { - private final FailureHandler delegate; - - public CustomFailureHandler(Context targetContext) { - delegate = new DefaultFailureHandler(targetContext); - } - - @Override - public void handle(Throwable error, Matcher<View> viewMatcher) { - try { - delegate.handle(error, viewMatcher); - } catch (NoMatchingViewException e) { - throw new MySpecialException(e); - } - } - } - - private static class MySpecialException extends RuntimeException { - MySpecialException(Throwable cause) { - super(cause); - } - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/DrawerActionsTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/DrawerActionsTest.java deleted file mode 100644 index b7c1337..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/DrawerActionsTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerActions.closeDrawer; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerActions.openDrawer; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerMatchers.isClosed; -import static com.google.android.apps.common.testing.ui.espresso.contrib.DrawerMatchers.isOpen; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.contrib.DrawerActions; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Demonstrates use of {@link DrawerActions}. - */ -@LargeTest -public class DrawerActionsTest extends ActivityInstrumentationTestCase2<DrawerActivity> { - - public DrawerActionsTest() { - super(DrawerActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testOpenAndCloseDrawer() { - // Drawer should not be open to start. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - - openDrawer(R.id.drawer_layout); - - // The drawer should now be open. - onView(withId(R.id.drawer_layout)).check(matches(isOpen())); - - closeDrawer(R.id.drawer_layout); - - // Drawer should be closed again. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - } - - @SuppressWarnings("unchecked") - public void testDrawerOpenAndClick() { - openDrawer(R.id.drawer_layout); - - onView(withId(R.id.drawer_layout)).check(matches(isOpen())); - - // Click an item in the drawer. We use onData because the drawer is backed by a ListView, and - // the item may not necessarily be visible in the view hierarchy. - int rowIndex = 2; - String rowContents = DrawerActivity.DRAWER_CONTENTS[rowIndex]; - onData(allOf(is(instanceOf(String.class)), is(rowContents))).perform(click()); - - // clicking the item should close the drawer. - onView(withId(R.id.drawer_layout)).check(matches(isClosed())); - - // The text view will now display "You picked: Pickle" - onView(withId(R.id.drawer_text_view)).check(matches(withText("You picked: " + rowContents))); - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/LongListMatchers.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/LongListMatchers.java deleted file mode 100644 index 1518697..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/LongListMatchers.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; - -import com.google.android.apps.common.testing.ui.espresso.matcher.BoundedMatcher; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; - -import java.util.Map; - -/** - * Static utility methods to create {@link Matcher} instances that can be applied to the data - * objects created by {@link com.google.android.apps.common.testing.ui.testapp.LongListActivity}. - * <p> - * These matchers are used by the - * {@link com.google.android.apps.common.testing.ui.espresso.Espresso#onData(Matcher)} API and are - * applied against the data exposed by @{link android.widget.ListView#getAdapter()}. - * </p> - * <p> - * In LongListActivity's case - each row is a Map containing 2 key value pairs. The key "STR" is - * mapped to a String which will be rendered into a TextView with the R.id.item_content. The other - * key "LEN" is an Integer which is the length of the string "STR" refers to. This length is - * rendered into a TextView with the id R.id.item_size. - * </p> - */ -public final class LongListMatchers { - - private LongListMatchers() { } - - - /** - * Creates a matcher against the text stored in R.id.item_content. This text is roughly - * "item: $row_number". - */ - public static Matcher<Object> withItemContent(String expectedText) { - // use preconditions to fail fast when a test is creating an invalid matcher. - checkNotNull(expectedText); - return withItemContent(equalTo(expectedText)); - } - - /** - * Creates a matcher against the text stored in R.id.item_content. This text is roughly - * "item: $row_number". - */ - @SuppressWarnings("rawtypes") - public static Matcher<Object> withItemContent(final Matcher<String> itemTextMatcher) { - // use preconditions to fail fast when a test is creating an invalid matcher. - checkNotNull(itemTextMatcher); - return new BoundedMatcher<Object, Map>(Map.class) { - @Override - public boolean matchesSafely(Map map) { - return hasEntry(equalTo("STR"), itemTextMatcher).matches(map); - } - - @Override - public void describeTo(Description description) { - description.appendText("with item content: "); - itemTextMatcher.describeTo(description); - } - }; - } - - /** - * Creates a matcher against the text stored in R.id.item_size. This text is the size of the text - * printed in R.id.item_content. - */ - public static Matcher<Object> withItemSize(int itemSize) { - // use preconditions to fail fast when a test is creating an invalid matcher. - checkArgument(itemSize > -1); - return withItemSize(equalTo(itemSize)); - } - - /** - * Creates a matcher against the text stored in R.id.item_size. This text is the size of the text - * printed in R.id.item_content. - */ - @SuppressWarnings("rawtypes") - public static Matcher<Object> withItemSize(final Matcher<Integer> itemSizeMatcher) { - // use preconditions to fail fast when a test is creating an invalid matcher. - checkNotNull(itemSizeMatcher); - return new BoundedMatcher<Object, Map>(Map.class) { - @Override - public boolean matchesSafely(Map map) { - return hasEntry(equalTo("LEN"), itemSizeMatcher).matches(map); - } - - @Override - public void describeTo(Description description) { - description.appendText("with item size: "); - itemSizeMatcher.describeTo(description); - } - }; - } - - /** - * Creates a matcher against the footer of this list view. - */ - @SuppressWarnings("unchecked") - public static Matcher<Object> isFooter() { - // This depends on LongListActivity.FOOTER being passed as data in the addFooterView method. - return allOf(is(instanceOf(String.class)), is(LongListActivity.FOOTER)); - } - -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/LongListMatchersTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/LongListMatchersTest.java deleted file mode 100644 index 3b80757..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/LongListMatchersTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.assertThat; -import static com.google.android.apps.common.testing.ui.testapp.LongListMatchers.withItemContent; -import static com.google.android.apps.common.testing.ui.testapp.LongListMatchers.withItemSize; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.Matchers.equalTo; - -import android.content.Intent; -import android.test.ActivityUnitTestCase; - -/** - * UnitTests for LongListMatchers matcher factory. - */ -public final class LongListMatchersTest extends ActivityUnitTestCase<LongListActivity> { - - public LongListMatchersTest() { - super(LongListActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - startActivity(new Intent(getInstrumentation().getTargetContext(), LongListActivity.class), - null, null); - } - - public void testWithContent() { - assertThat(getActivity().makeItem(54), withItemContent("item: 54")); - assertThat(getActivity().makeItem(54), withItemContent(endsWith("54"))); - assertFalse(withItemContent("hello world").matches(getActivity().makeItem(54))); - } - - @SuppressWarnings("unchecked") - public void testWithItemSize() { - assertThat(getActivity().makeItem(54), withItemSize(8)); - assertThat(getActivity().makeItem(54), withItemSize(anyOf(equalTo(8), equalTo(7)))); - assertFalse(withItemSize(7).matches(getActivity().makeItem(54))); - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/MenuTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/MenuTest.java deleted file mode 100644 index 9ea8898..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/MenuTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.longClick; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.pressMenuKey; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.doesNotExist; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isRoot; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; - -import android.os.Build; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Ensures view root ordering works properly. - */ -@LargeTest -public class MenuTest extends ActivityInstrumentationTestCase2<MenuActivity> { - @SuppressWarnings("deprecation") - public MenuTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", MenuActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testPopupMenu() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - // popup menus are post honeycomb. - return; - } - onView(withText(R.string.popup_item_1_text)).check(doesNotExist()); - onView(withId(R.id.popup_button)).perform(click()); - onView(withText(R.string.popup_item_1_text)).check(matches(isDisplayed())).perform(click()); - - onView(withId(R.id.text_menu_result)).check(matches(withText(R.string.popup_item_1_text))); - } - - public void testContextMenu() { - onView(withText(R.string.context_item_2_text)).check(doesNotExist()); - onView(withId(R.id.text_context_menu)).perform(longClick()); - onView(withText(R.string.context_item_2_text)).check(matches(isDisplayed())).perform(click()); - - onView(withId(R.id.text_menu_result)).check(matches(withText(R.string.context_item_2_text))); - } - - public void testOptionMenu() { - onView(withText(R.string.options_item_3_text)).check(doesNotExist()); - onView(isRoot()).perform(pressMenuKey()); - onView(withText(R.string.options_item_3_text)).check(matches(isDisplayed())).perform(click()); - - onView(withId(R.id.text_menu_result)).check(matches(withText(R.string.options_item_3_text))); - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/MultipleWindowTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/MultipleWindowTest.java deleted file mode 100644 index 23c3ea3..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/MultipleWindowTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.clearText; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.scrollTo; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeText; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeTextIntoFocusedView; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers.withDecorView; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; - -import android.os.Build; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Demonstrates dealing with multiple windows. - * - * Espresso provides the ability to switch the default window matcher used in both onView and onData - * interactions. - * - * @see com.google.android.apps.common.testing.ui.espresso.Espresso#onView - * @see com.google.android.apps.common.testing.ui.espresso.Espresso#onData - */ -@LargeTest -public class MultipleWindowTest extends ActivityInstrumentationTestCase2<SendActivity> { - - @SuppressWarnings("deprecation") - public MultipleWindowTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", SendActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - // Espresso will not launch our activity for us, we must launch it via getActivity(). - getActivity(); - } - - public void testInteractionsWithAutoCompletePopup() { - if (Build.VERSION.SDK_INT < 10) { - // Froyo's AutoCompleteTextBox is broken - do not bother testing with it. - return; - } - // Android's Window system allows multiple view hierarchies to layer on top of each other. - // - // A real world analogy would be an overhead projector with multiple transparencies placed - // on top of each other. Each Window is a transparency, and what is drawn on top of this - // transparency is the view hierarchy. - // - // By default Espresso uses a heuristic to guess which Window you intend to interact with. - // This heuristic is normally 'good enough' however if you want to interact with a Window - // that it does not select then you'll have to swap in your own root window matcher. - - - // Initially we only have 1 window, but by typing into the auto complete text view another - // window will be layered on top of the screen. Espresso ignore's this layer because it is - // not connected to the keyboard/ime. - onView(withId(R.id.auto_complete_text_view)) - .perform(scrollTo()) - .perform(typeText("So")); - - // As you can see, we continue typing oblivious to the new window on the screen. - // At the moment there should be 2 completions (South China Sea and Southern Ocean) - // Lets narrow that down to 1 completion. - onView(withId(R.id.auto_complete_text_view)) - .perform(typeTextIntoFocusedView("uth ")); - - // Now we may want to explicitly tap on a completion. We must override Espresso's - // default window selection heuristic with our own. - onView(withText("South China Sea")) - .inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView())))) - .perform(click()); - - // And by clicking on the auto complete term, the text should be filled in. - onView(withId(R.id.auto_complete_text_view)) - .check(matches(withText("South China Sea"))); - - - // NB: The autocompletion box is implemented with a ListView, so the preferred way - // to interact with it is onData(). We can use inRoot here too! - onView(withId(R.id.auto_complete_text_view)) - .perform(clearText()) - .perform(typeText("S")); - - // Which is useful because some of the completions may not be part of the View Hierarchy - // unless you scroll around the list. - onData(allOf(instanceOf(String.class), is("Baltic Sea"))) - .inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView())))) - .perform(click()); - - onView(withId(R.id.auto_complete_text_view)) - .check(matches(withText("Baltic Sea"))); - } - -} - - diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/ScrollToTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/ScrollToTest.java deleted file mode 100644 index 6cf7836..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/ScrollToTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.scrollTo; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static org.hamcrest.Matchers.is; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - - -/** - * Demonstrates the usage of - * {@link com.google.android.apps.common.testing.ui.espresso.action.ViewActions#scrollTo()}. - */ -@LargeTest -public class ScrollToTest extends ActivityInstrumentationTestCase2<ScrollActivity> { - - @SuppressWarnings("deprecation") - public ScrollToTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", ScrollActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - // Espresso will not launch our activity for us, we must launch it via getActivity(). - getActivity(); - } - - // You can pass more than one action to perform. This is useful if you are performing two actions - // back-to-back on the same view. - // Note - scrollTo is a no-op if the view is already displayed on the screen. - public void testScrollToInScrollView() { - onView(withId(is(R.id.bottom_left))) - .perform(scrollTo(), click()); - } -} diff --git a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/SwipeTest.java b/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/SwipeTest.java deleted file mode 100644 index 46704ec..0000000 --- a/espresso/espresso-sample/src/androidTest/java/com/google/android/apps/common/testing/ui/testapp/SwipeTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.swipeLeft; -import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.swipeRight; -import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; -import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; - -import com.google.android.apps.common.testing.ui.espresso.action.ViewActions; - -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Demonstrates use of {@link ViewActions#swipeLeft()} and {@link ViewActions#swipeRight()}. - */ -@LargeTest -public class SwipeTest extends ActivityInstrumentationTestCase2<ViewPagerActivity> { - - @SuppressWarnings("deprecation") - public SwipeTest() { - // This constructor was deprecated - but we want to support lower API levels. - super("com.google.android.apps.common.testing.ui.testapp", ViewPagerActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - getActivity(); - } - - public void testSwipingThroughViews() { - // Should be on position 0 to start with. - onView(withText("Position #0")).check(matches(isDisplayed())); - - // Swipe left once. - onView(withId(R.id.pager_layout)).perform(swipeLeft()); - - // Now position 1 should be visible. - onView(withText("Position #1")).check(matches(isDisplayed())); - - // Swipe left again. - onView(withId(R.id.pager_layout)).perform(swipeLeft()); - - // Now position 2 should be visible. - onView(withText("Position #2")).check(matches(isDisplayed())); - - // Swipe left again. - onView(withId(R.id.pager_layout)).perform(swipeLeft()); - - // Position 2 should still be visible as this is the last view in the pager. - onView(withText("Position #2")).check(matches(isDisplayed())); - } - - public void testSwipingBackAndForward() { - // Should be on position 0 to start with. - onView(withText("Position #0")).check(matches(isDisplayed())); - - // Swipe left once. - onView(withId(R.id.pager_layout)).perform(swipeLeft()); - - // Now position 1 should be visible. - onView(withText("Position #1")).check(matches(isDisplayed())); - - // Swipe back to the right. - onView(withId(R.id.pager_layout)).perform(swipeRight()); - - // Now position 0 should be visible again. - onView(withText("Position #0")).check(matches(isDisplayed())); - - // Swipe right again. - onView(withId(R.id.pager_layout)).perform(swipeRight()); - - // Position 0 should still be visible as this is the first view in the pager. - onView(withText("Position #0")).check(matches(isDisplayed())); - } - -} diff --git a/espresso/espresso-sample/src/main/Android.mk b/espresso/espresso-sample/src/main/Android.mk deleted file mode 100644 index cbd6837..0000000 --- a/espresso/espresso-sample/src/main/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_PACKAGE_NAME := espresso-sample -LOCAL_MODULE_TAGS := tests # used to avoid lint errors for string errors -LOCAL_PROGUARD_ENABLED := disabled - -LOCAL_SDK_VERSION := current - -LOCAL_SRC_FILES := $(call all-java-files-under, java) - -LOCAL_RESOURCE_DIR := \ - $(LOCAL_PATH)/res \ - prebuilts/sdk/current/support/v7/appcompat/res - -LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-v4 \ - android-support-v7-appcompat \ - espresso-guava \ - jsr305 - -LOCAL_AAPT_FLAGS := \ - --auto-add-overlay \ - --extra-packages android.support.v7.appcompat - -include $(BUILD_PACKAGE) diff --git a/espresso/espresso-sample/src/main/AndroidManifest.xml b/espresso/espresso-sample/src/main/AndroidManifest.xml deleted file mode 100644 index cf8e548..0000000 --- a/espresso/espresso-sample/src/main/AndroidManifest.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.apps.common.testing.ui.testapp"> - - <uses-sdk android:minSdkVersion = "7" android:targetSdkVersion= "16"/> - - <application android:label="UI Test App" android:icon="@drawable/ic_launcher" > - <activity android:name="MainActivity" android:label="UI Test App"> - <intent-filter> - <action android:name="android.intent.action.MAIN"/> - <category android:name="android.intent.category.LAUNCHER"/> - </intent-filter> - </activity> - <activity android:name="ActionBarTestActivity" android:label="actionbar test activity" android:theme="@style/Theme.AppCompat.Light.DarkActionBar"/> - <activity android:name="SimpleActivity" android:label="simple activity"/> - <activity android:name="SendActivity" android:label="send activity"/> - <activity android:name="DisplayActivity" android:label="display activity"/> - <activity android:name="DrawerActivity" android:label="drawer activity" android:theme="@style/Theme.AppCompat.Light"/> - <activity android:name="GestureActivity" android:label="gesture activity" android:exported="true"/> - <activity android:name="ScrollActivity" android:label="scroll activity" android:exported="true"/> - <activity android:name="LongListActivity" android:label="list activity" android:exported="true"/> - <activity android:name="MenuActivity" android:label="menu activity"/> - <activity android:name="FragmentStack" android:label="fragment stack activity"/> - <activity android:name="SyncActivity" android:label="sync activity"/> - <activity android:name="SimpleWebViewActivity" android:label="web view"/> - <activity android:name="SwipeActivity" android:label="swipe activity"/> - <activity android:name="ViewPagerActivity" android:label="view pager activity"/> - </application> - - <uses-permission android:name="android.permission.CALL_PHONE"></uses-permission> -</manifest> diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ActionBarTestActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ActionBarTestActivity.java deleted file mode 100644 index 5c1ac60..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ActionBarTestActivity.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.support.v7.view.ActionMode; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -/** - * Shows ActionBar with a lot of items to get Action overflow on large displays. Click on item - * changes text of R.id.textActionBarResult. - */ -public class ActionBarTestActivity extends ActionBarActivity { - private ActionMode mode; - private MenuInflater inflater; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.actionbar_activity); - inflater = getMenuInflater(); - mode = startSupportActionMode(new TestActionMode()); - - ((Button) findViewById(R.id.show_contextual_action_bar)).setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - mode = startSupportActionMode(new TestActionMode()); - } - }); - ((Button) findViewById(R.id.hide_contextual_action_bar)).setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mode != null) { - mode.finish(); - } - } - }); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - inflater.inflate(R.menu.actionbar_context_actions, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem menu) { - setResult(menu.getTitle()); - return true; - } - - private void setResult(CharSequence result) { - TextView text = (TextView) findViewById(R.id.text_action_bar_result); - text.setText(result); - } - - private final class TestActionMode implements ActionMode.Callback { - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - inflater.inflate(R.menu.actionbar_activity_actions, menu); - return true; - } - - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - return false; - } - - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - setResult(item.getTitle()); - return true; - } - - @Override - public void onDestroyActionMode(ActionMode mode) {} - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DelegatingEditText.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DelegatingEditText.java deleted file mode 100644 index dace49c..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DelegatingEditText.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; - -/** - * Custom edit text widget. - */ -public class DelegatingEditText extends LinearLayout { - - private final EditText delegateEditText; - private final TextView messageView; - private final Context mContext; - - public DelegatingEditText(Context context) { - this(context, null); - } - - public DelegatingEditText(Context context, AttributeSet attrs) { - super(context, attrs); - setOrientation(VERTICAL); - mContext = context; - LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.delegating_edit_text, this, /* attachToRoot */ true); - messageView = (TextView) findViewById(R.id.edit_text_message); - delegateEditText = (EditText) findViewById(R.id.delegate_edit_text); - delegateEditText.setOnEditorActionListener(new OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionCode, KeyEvent event) { - messageView.setText("typed: " + delegateEditText.getText()); - messageView.setVisibility(View.VISIBLE); - InputMethodManager imm = - (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(delegateEditText.getWindowToken(), 0); - return true; - } - }); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DisplayActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DisplayActivity.java deleted file mode 100644 index d05ee00..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DisplayActivity.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - - -import android.app.Activity; -import android.os.Bundle; -import android.widget.TextView; - -/** - * Simple activity used to display data received from another activity. - */ -public class DisplayActivity extends Activity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.display_activity); - TextView textView = (TextView) findViewById(R.id.display_data); - textView.setText(getIntent().getStringExtra(SendActivity.EXTRA_DATA)); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DrawerActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DrawerActivity.java deleted file mode 100644 index a13f688..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/DrawerActivity.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.content.res.Configuration; -import android.os.Bundle; -import android.support.v4.app.ActionBarDrawerToggle; -import android.support.v4.widget.DrawerLayout; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.TextView; - -/** - * Activity to demonstrate actions on a {@link DrawerLayout}. - */ -public class DrawerActivity extends Activity { - - public static final String[] DRAWER_CONTENTS = - new String[] {"Platypus", "Wombat", "Pickle", "Badger"}; - - private ActionBarDrawerToggle drawerToggle; - private CharSequence title; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.drawer_activity); - - ListAdapter listAdapter = new ArrayAdapter<String>( - getApplicationContext(), R.layout.drawer_row, R.id.drawer_row_name, DRAWER_CONTENTS); - final DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); - ListView drawerList = (ListView) findViewById(R.id.drawer_list); - drawerList.setAdapter(listAdapter); - - final TextView textView = (TextView) findViewById(R.id.drawer_text_view); - - drawerList.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - textView.setText("You picked: " + DRAWER_CONTENTS[(int) id]); - drawerLayout.closeDrawers(); - } - }); - - // enable ActionBar app icon to behave as action to toggle nav drawer - // TODO(user): use compat lib for lower API levels - if (android.os.Build.VERSION.SDK_INT >= 11) { - getActionBar().setDisplayHomeAsUpEnabled(true); - getActionBar().setHomeButtonEnabled(true); - } - - title = getTitle(); - - drawerToggle = new ActionBarDrawerToggle( - this, - drawerLayout, - R.drawable.ic_drawer, - R.string.nav_drawer_open, - R.string.nav_drawer_close) { - - /** Called when a drawer has settled in a completely closed state. */ - public void onDrawerClosed(View view) { - if (android.os.Build.VERSION.SDK_INT >= 11) { - getActionBar().setTitle(title); - } - } - - /** Called when a drawer has settled in a completely open state. */ - public void onDrawerOpened(View drawerView) { - if (android.os.Build.VERSION.SDK_INT >= 11) { - getActionBar().setTitle(title); - } - } - }; - drawerLayout.setDrawerListener(drawerToggle); - } - - @Override - public void setTitle(CharSequence title) { - this.title = title; - if (android.os.Build.VERSION.SDK_INT >= 11) { - getActionBar().setTitle(title); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // The action bar home/up action should open or close the drawer. - // ActionBarDrawerToggle will take care of this. - if (drawerToggle.onOptionsItemSelected(item)) { - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - // Sync the toggle state after onRestoreInstanceState has occurred. - drawerToggle.syncState(); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - // Pass any configuration change to the drawer toggls - drawerToggle.onConfigurationChanged(newConfig); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/FragmentStack.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/FragmentStack.java deleted file mode 100644 index e89ce27..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/FragmentStack.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -/** - * Displays a counter using fragments. - */ -public class FragmentStack extends Activity { - int stackLevel = 1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.fragment_stack); - - // Watch for button clicks. - Button button = (Button) findViewById(R.id.new_fragment); - button.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - addFragmentToStack(); - } - }); - - if (savedInstanceState == null) { - // Do first time initialization -- add initial fragment. - Fragment newFragment = CountingFragment.newInstance(stackLevel); - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.add(R.id.simple_fragment, newFragment).commit(); - } else { - stackLevel = savedInstanceState.getInt("level"); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt("level", stackLevel); - } - - - void addFragmentToStack() { - stackLevel++; - - // Instantiate a new fragment. - Fragment newFragment = CountingFragment.newInstance(stackLevel); - - // Add the fragment to the activity, pushing this transaction - // on to the back stack. - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.replace(R.id.simple_fragment, newFragment); - ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); - ft.addToBackStack(null); - ft.commit(); - } - - - - /** - * A fragment that displays a number. - */ - public static class CountingFragment extends Fragment { - int counter; - - /** - * Create a new instance of CountingFragment, providing "num" - * as an argument. - */ - static CountingFragment newInstance(int num) { - CountingFragment f = new CountingFragment(); - - // Supply num input as an argument. - Bundle args = new Bundle(); - args.putInt("num", num); - f.setArguments(args); - - return f; - } - - /** - * When creating, retrieve this instance's number from its arguments. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - counter = getArguments() != null ? getArguments().getInt("num") : 1; - } - - /** - * The Fragment's UI is just a simple text view showing its - * instance number. - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - TextView text = new TextView(getActivity()); - text.setText("Fragment #" + counter); - return text; - } - } - -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/GestureActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/GestureActivity.java deleted file mode 100644 index b2cbc32..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/GestureActivity.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import com.google.common.collect.Lists; - -import android.app.Activity; -import android.os.Bundle; -import android.os.SystemClock; -import android.util.Log; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.View; - -import java.util.List; - -/** - * Displays a large touchable area and logs the events it receives. - */ -public class GestureActivity extends Activity { - private static final String TAG = GestureActivity.class.getSimpleName(); - - - private View gestureArea; - private List<MotionEvent> downEvents = Lists.newArrayList(); - private List<MotionEvent> scrollEvents = Lists.newArrayList(); - private List<MotionEvent> longPressEvents = Lists.newArrayList(); - private List<MotionEvent> showPresses = Lists.newArrayList(); - private List<MotionEvent> singleTaps = Lists.newArrayList(); - private List<MotionEvent> confirmedSingleTaps = Lists.newArrayList(); - private List<MotionEvent> doubleTapEvents = Lists.newArrayList(); - private List<MotionEvent> doubleTaps = Lists.newArrayList(); - - public void clearDownEvents() { - downEvents.clear(); - } - - public void clearScrollEvents() { - scrollEvents.clear(); - } - - public void clearLongPressEvents() { - longPressEvents.clear(); - } - - public void clearShowPresses() { - showPresses.clear(); - } - - public void clearSingleTaps() { - singleTaps.clear(); - } - - public void clearConfirmedSingleTaps() { - confirmedSingleTaps.clear(); - } - - public void clearDoubleTapEvents() { - doubleTapEvents.clear(); - } - - public void clearDoubleTaps() { - doubleTaps.clear(); - } - - public List<MotionEvent> getDownEvents() { - return Lists.newArrayList(downEvents); - } - - public List<MotionEvent> getScrollEvents() { - return Lists.newArrayList(scrollEvents); - } - - public List<MotionEvent> getLongPressEvents() { - return Lists.newArrayList(longPressEvents); - } - - public List<MotionEvent> getShowPresses() { - return Lists.newArrayList(showPresses); - } - - public List<MotionEvent> getSingleTaps() { - return Lists.newArrayList(singleTaps); - } - - public List<MotionEvent> getConfirmedSingleTaps() { - return Lists.newArrayList(confirmedSingleTaps); - } - - public List<MotionEvent> getDoubleTapEvents() { - return Lists.newArrayList(doubleTapEvents); - } - - public List<MotionEvent> getDoubleTaps() { - return Lists.newArrayList(doubleTaps); - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.gesture_activity); - gestureArea = findViewById(R.id.gesture_area); - final GestureDetector simpleDetector = new GestureDetector(this, new GestureListener()); - simpleDetector.setIsLongpressEnabled(true); - simpleDetector.setOnDoubleTapListener(new DoubleTapListener()); - gestureArea.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent m) { - boolean res = simpleDetector.onTouchEvent(m); - if (-1 != touchDelay) { - Log.i(TAG, "sleeping for: " + touchDelay); - SystemClock.sleep(touchDelay); - - } - return res; - } - }); - } - - private volatile long touchDelay = -1; - - public void setTouchDelay(long touchDelay) { - this.touchDelay = touchDelay; - } - - public void areaClicked(@SuppressWarnings("unused") View v) { - Log.v(TAG, "onClick called!"); - } - - private class DoubleTapListener implements GestureDetector.OnDoubleTapListener { - @Override - public boolean onDoubleTap(MotionEvent e) { - doubleTaps.add(MotionEvent.obtain(e)); - Log.v(TAG, "onDoubleTap: " + e); - setVisible(R.id.text_double_click); - return false; - } - - @Override - public boolean onDoubleTapEvent(MotionEvent e) { - doubleTapEvents.add(MotionEvent.obtain(e)); - Log.v(TAG, "onDoubleTapEvent: " + e); - return false; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - confirmedSingleTaps.add(MotionEvent.obtain(e)); - Log.v(TAG, "onSingleTapConfirmed: " + e); - return false; - } - } - - private class GestureListener implements GestureDetector.OnGestureListener { - @Override - public boolean onDown(MotionEvent e) { - downEvents.add(MotionEvent.obtain(e)); - Log.v(TAG, "Down: " + e); - return false; - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - singleTaps.add(MotionEvent.obtain(e)); - Log.v(TAG, "on single tap: " + e); - setVisible(R.id.text_click); - return false; - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distX, float distY) { - scrollEvents.add(MotionEvent.obtain(e1)); - scrollEvents.add(MotionEvent.obtain(e2)); - Log.v(TAG, "Scroll: e1: " + e1 + " e2: " + e2 + " distX: " + distX + " distY: " + distY); - setVisible(R.id.text_swipe); - return false; - } - - @Override - public void onShowPress(MotionEvent e) { - showPresses.add(MotionEvent.obtain(e)); - Log.v(TAG, "ShowPress: " + e); - } - - @Override - public void onLongPress(MotionEvent e) { - longPressEvents.add(MotionEvent.obtain(e)); - Log.v(TAG, "LongPress: " + e); - setVisible(R.id.text_long_click); - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float veloX, float veloY) { - Log.v(TAG, "Fling: e1: " + e1 + " e2: " + e2 + " veloX: " + veloX + " veloY: " + veloY); - return false; - } - } - - private void setVisible(int id) { - hideAll(); - findViewById(id).setVisibility(View.VISIBLE); - } - - private void hideAll() { - findViewById(R.id.text_click).setVisibility(View.GONE); - findViewById(R.id.text_long_click).setVisibility(View.GONE); - findViewById(R.id.text_swipe).setVisibility(View.GONE); - findViewById(R.id.text_double_click).setVisibility(View.GONE); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/LongListActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/LongListActivity.java deleted file mode 100644 index 300c0ee..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/LongListActivity.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.SimpleAdapter; -import android.widget.TextView; - -import java.util.List; -import java.util.Map; - -/** - * An activity displaying a long list. - */ -public class LongListActivity extends Activity { - - @VisibleForTesting - public static final String STR = "STR"; - @VisibleForTesting - public static final String LEN = "LEN"; - @VisibleForTesting - public static final String FOOTER = "FOOTER"; - - private List<Map<String, Object>> data = Lists.newArrayList(); - private LayoutInflater layoutInflater; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - populateData(); - setContentView(R.layout.list_activity); - ((TextView) findViewById(R.id.selection_row_value)).setText(""); - ((TextView) findViewById(R.id.selection_column_value)).setText(""); - - ListView listView = (ListView) findViewById(R.id.list); - String[] from = new String[] {STR, LEN}; - int[] to = new int[] {R.id.item_content, R.id.item_size}; - layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - ListAdapter adapter = new SimpleAdapter(this, data, R.layout.list_item, from, to) { - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = layoutInflater.inflate(R.layout.list_item, null); - } - - TextView textViewOne = (TextView) convertView.findViewById(R.id.item_content); - if (textViewOne != null) { - textViewOne.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - ((TextView) findViewById(R.id.selection_row_value)).setText(String.valueOf(position)); - ((TextView) findViewById(R.id.selection_column_value)).setText("1"); - } - }); - } - - TextView textViewTwo = (TextView) convertView.findViewById(R.id.item_size); - if (textViewTwo != null) { - textViewTwo.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - ((TextView) findViewById(R.id.selection_row_value)).setText(String.valueOf(position)); - ((TextView) findViewById(R.id.selection_column_value)).setText("2"); - } - }); - } - return super.getView(position, convertView, parent); - } - }; - - View footerView = layoutInflater.inflate(R.layout.list_item, listView, false); - ((TextView) footerView.findViewById(R.id.item_content)).setText("count:"); - ((TextView) footerView.findViewById(R.id.item_size)).setText(String.valueOf(data.size())); - listView.addFooterView(footerView, FOOTER, true); - - listView.setAdapter(adapter); - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick( - AdapterView<?> unusedParent, View clickedView, int position, long id) { - ((TextView) findViewById(R.id.selection_column_value)).setText(""); - ((TextView) findViewById(R.id.selection_row_value)).setText(String.valueOf(position)); - } - }); - } - - public Map<String, Object> makeItem(int forRow) { - Map<String, Object> dataRow = Maps.newHashMap(); - dataRow.put(STR, "item: " + forRow); - dataRow.put(LEN, ((String) dataRow.get(STR)).length()); - return dataRow; - } - - private void populateData() { - for (int i = 0; i < 100; i++) { - data.add(makeItem(i)); - } - } - -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/MainActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/MainActivity.java deleted file mode 100644 index c5ad762..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/MainActivity.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.ListActivity; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.util.Log; -import android.view.View; -import android.widget.ListView; -import android.widget.SimpleAdapter; - -import java.text.Collator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Displays a list with all available activities. - */ -public class MainActivity extends ListActivity { - private static final String TAG = MainActivity.class.getSimpleName(); - - private static final Comparator<Map<String, Object>> sDisplayNameComparator = - new Comparator<Map<String, Object>>() { - private final Collator collator = Collator.getInstance(); - - @Override - public int compare(Map<String, Object> map1, Map<String, Object> map2) { - return collator.compare(map1.get("title"), map2.get("title")); - } - }; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setListAdapter(new SimpleAdapter( - this, getData(), android.R.layout.simple_list_item_1, new String[] {"title"}, - new int[] {android.R.id.text1})); - getListView().setTextFilterEnabled(true); - } - - private List<Map<String, Object>> getData() { - List<Map<String, Object>> data = new ArrayList<Map<String, Object>>(); - - PackageInfo info = null; - try { - info = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_ACTIVITIES); - } catch (NameNotFoundException e) { - Log.e(TAG, "Packageinfo not found in: " + getPackageName()); - } - - if (null == info) { - return data; - } else { - for (ActivityInfo activityInfo : info.activities) { - - if (!activityInfo.name.equals(getComponentName().getClassName())) { - String[] label = activityInfo.name.split(getPackageName() + "."); - addItem(data, label[1], - createActivityIntent(activityInfo.applicationInfo.packageName, activityInfo.name)); - } - } - } - - Collections.sort(data, sDisplayNameComparator); - return data; - } - - private Intent createActivityIntent(String pkg, String componentName) { - Intent result = new Intent(); - result.setClassName(pkg, componentName); - return result; - } - - private void addItem(List<Map<String, Object>> data, String name, Intent intent) { - Map<String, Object> temp = new HashMap<String, Object>(); - temp.put("title", name); - temp.put("intent", intent); - data.add(temp); - } - - @Override - protected void onListItemClick(ListView listView, View view, int position, long id) { - Map<?, ?> map = (Map<?, ?>) listView.getItemAtPosition(position); - - Intent intent = (Intent) map.get("intent"); - startActivity(intent); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/MenuActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/MenuActivity.java deleted file mode 100644 index e893cea..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/MenuActivity.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.os.Build; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.PopupMenu; -import android.widget.PopupMenu.OnMenuItemClickListener; -import android.widget.TextView; - -/** - * Shows MenuActivity with Options menu, Context menu and Popup menu. Click on a menu item changes - * text of R.id.textMenuResult. - */ -public class MenuActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.menu_activity); - registerForContextMenu(findViewById(R.id.text_context_menu)); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.contextmenu, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - TextView text = (TextView) findViewById(R.id.text_menu_result); - text.setText(item.getTitle()); - return true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.optionsmenu, menu); - return true; - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - TextView text = (TextView) findViewById(R.id.text_menu_result); - text.setText(item.getTitle()); - return true; - } - - public void showPopup(View view) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - TextView text = (TextView) findViewById(R.id.text_menu_result); - text.setText("Not supported in API " + Build.VERSION.SDK_INT); - } else { - PopupMenu popup = new PopupMenu(this, view); - popup.setOnMenuItemClickListener(new PopupMenuListener()); - popup.getMenuInflater().inflate(R.menu.popupmenu, popup.getMenu()); - popup.show(); - } - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - return super.onMenuItemSelected(featureId, item); - } - - private class PopupMenuListener implements OnMenuItemClickListener { - @Override - public boolean onMenuItemClick(MenuItem item) { - TextView text = (TextView) findViewById(R.id.text_menu_result); - text.setText(item.getTitle()); - return true; - } - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ScrollActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ScrollActivity.java deleted file mode 100644 index 864fb23..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ScrollActivity.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.os.Bundle; - -/** - * An activity displaying various scroll views. - */ -public class ScrollActivity extends Activity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.scroll_activity); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SendActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SendActivity.java deleted file mode 100644 index fe472e7..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SendActivity.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.MenuInflater; -import android.view.View; -import android.view.View.OnKeyListener; -import android.view.ViewGroup.LayoutParams; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; -import android.widget.EditText; -import android.widget.PopupMenu; -import android.widget.PopupWindow; -import android.widget.TextView; - -/** - * Simple activity used for validating intent sending and UI behavior. - */ -public class SendActivity extends Activity { - - private static final int PICK_CONTACT_REQUEST = 1; // The request code - static final String EXTRA_DATA = "com.google.android.apps.common.testing.ui.testapp.DATA"; - static final int PICK_CONTACT = 100; - private PopupWindow popupWindow; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.send_activity); - - EditText editText = (EditText) findViewById(R.id.enter_data_edit_text); - editText.setOnKeyListener(new OnKeyListener() { - - @Override - public boolean onKey(View view, int keyCode, KeyEvent event) { - if ((event.getAction() == KeyEvent.ACTION_DOWN) && - (keyCode == KeyEvent.KEYCODE_ENTER)) { - EditText editText = (EditText) view; - TextView responseText = (TextView) findViewById(R.id.enter_data_response_text); - responseText.setText(editText.getText()); - return true; - } else { - return false; - } - } - }); - - final EditText searchBox = (EditText) findViewById(R.id.search_box); - searchBox.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_SEARCH) { - TextView result = (TextView) findViewById(R.id.search_result); - result.setText(getString(R.string.searching_for_label) + " " + v.getText()); - result.setVisibility(View.VISIBLE); - InputMethodManager imm = - (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(searchBox.getWindowToken(), 0); - return true; - } - return false; - } - }); - AutoCompleteTextView autoComplete = (AutoCompleteTextView) findViewById( - R.id.auto_complete_text_view); - String [] completions = new String[] { - "Pacific Ocean", "Atlantic Ocean", "Indian Ocean", "Southern Ocean", "Artic Ocean", - "Mediterranean Sea", "Caribbean Sea", "South China Sea", "Bering Sea", - "Gulf of Mexico", "Okhotsk Sea", "East China Sea", "Hudson Bay", "Japan Sea", - "Andaman Sea", "North Sea", "Red Sea", "Baltic Sea" }; - ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, - android.R.layout.simple_dropdown_item_1line, - completions); - autoComplete.setAdapter(adapter); - } - - /** Called when user clicks the Send button */ - public void sendData(@SuppressWarnings("unused") View view) { - Intent intent = new Intent(this, DisplayActivity.class); - EditText editText = (EditText) findViewById(R.id.send_data_edit_text); - intent.putExtra(EXTRA_DATA, editText.getText().toString()); - startActivity(intent); - } - - public void sendDataToCall(@SuppressWarnings("unused") View view) { - Intent intentToCall = new Intent(Intent.ACTION_CALL); - EditText editText = (EditText) findViewById(R.id.send_data_to_call_edit_text); - String number = editText.getText().toString(); - intentToCall.setData(Uri.parse("tel:" + number)); - startActivity(intentToCall); - } - - public void sendDataToBrowser(@SuppressWarnings("unused") View view) { - EditText editText = (EditText) findViewById(R.id.send_data_to_browser_edit_text); - String url = editText.getText().toString(); - Intent intentToBrowser = new Intent(Intent.ACTION_VIEW); - intentToBrowser.setData(Uri.parse(url)); - intentToBrowser.addCategory(Intent.CATEGORY_BROWSABLE); - intentToBrowser.putExtra("key1", "value1"); - intentToBrowser.putExtra("key2", "value2"); - startActivity(intentToBrowser); - } - - public void sendMessage(@SuppressWarnings("unused") View view) { - Intent sendIntent = new Intent(); - EditText editText = (EditText) findViewById(R.id.send_data_to_message_edit_text); - sendIntent.setAction(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, editText.getText().toString()); - sendIntent.setType("text/plain"); - startActivity(sendIntent); - } - - public void clickToMarket(@SuppressWarnings("unused") View view) { - Intent marketIntent = new Intent(Intent.ACTION_VIEW); - EditText editText = (EditText) findViewById(R.id.send_to_market_data); - marketIntent.setData(Uri.parse( - "market://details?id=" + editText.getText().toString())); - startActivity(marketIntent); - } - - public void clickToGesture(@SuppressWarnings("unused") View view) { - startActivity(new Intent(this, GestureActivity.class)); - } - - public void clickToScroll(@SuppressWarnings("unused") View view) { - startActivity(new Intent(this, ScrollActivity.class)); - } - - public void clickToList(@SuppressWarnings("unused") View view) { - startActivity(new Intent(this, LongListActivity.class)); - } - - public boolean showDialog(@SuppressWarnings("unused") View view) { - new AlertDialog.Builder(this) - .setTitle(R.string.dialog_title) - .setMessage(R.string.dialog_message) - .setNeutralButton("Fine", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int choice) { - dialog.dismiss(); - } - }) - .show(); - return true; - } - - public boolean showPopupView(View view) { - View content = getLayoutInflater().inflate(R.layout.popup_window, null, false); - popupWindow = new PopupWindow(content, LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT, true); - content.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - popupWindow.dismiss(); - } - }); - - popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0); - - return true; - } - - public boolean showPopupMenu(View view) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - return false; - } - - PopupMenu popup = new PopupMenu(this, view); - MenuInflater inflater = popup.getMenuInflater(); - inflater.inflate(R.menu.popup_menu, popup.getMenu()); - popup.show(); - return true; - } - - public void pickContact(@SuppressWarnings("unused") View view) { - Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")); - pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers - startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == PICK_CONTACT_REQUEST) { - if (resultCode == RESULT_OK) { - // TODO(user): hook this up for real as shown in this example: - // http://developer.android.com/training/basics/intents/result.html - TextView textView = (TextView) findViewById(R.id.phone_number); - textView.setText(data.getExtras().getString("phone")); - } - } - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimpleActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimpleActivity.java deleted file mode 100644 index 8af2747..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimpleActivity.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TextView; - -/** - * Simple activity used to demonstrate a simple Espresso test. - */ -public class SimpleActivity extends Activity implements OnItemSelectedListener{ - - static final String EXTRA_DATA = "com.google.android.apps.common.testing.ui.testapp.DATA"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.simple_activity); - - Spinner spinner = (Spinner) findViewById(R.id.spinner_simple); - ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, - R.array.spinner_array, android.R.layout.simple_spinner_item); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(adapter); - spinner.setOnItemSelectedListener(this); - } - - public void simpleButtonClicked(View view) { - TextView textView = (TextView) findViewById(R.id.text_simple); - String message = "Hello Espresso!"; - textView.setText(message); - } - - /** Called when user clicks the Send button */ - public void sendButtonClicked(@SuppressWarnings("unused") View view) { - Intent intent = new Intent(this, DisplayActivity.class); - EditText editText = (EditText) findViewById(R.id.sendtext_simple); - intent.putExtra(EXTRA_DATA, editText.getText().toString()); - startActivity(intent); - } - - public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { - TextView textView = (TextView) findViewById(R.id.spinnertext_simple); - textView.setText(String.format("One %s a day!", parent.getItemAtPosition(pos))); - } - - public void onNothingSelected(AdapterView<?> parent) { - } -} - diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimplePagerAdapter.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimplePagerAdapter.java deleted file mode 100644 index 42d9cf4..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimplePagerAdapter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.graphics.Color; -import android.support.v4.view.PagerAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -class SimplePagerAdapter extends PagerAdapter { - - private static final int[] COLORS = { - Color.BLUE, - Color.RED, - Color.YELLOW, - }; - - private static final int NUM_PAGES = COLORS.length; - - @Override - public int getCount() { - return NUM_PAGES; - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; - } - - @Override - public int getItemPosition(Object object) { - return ((ViewGroup) ((View) object).getParent()).indexOfChild((View) object); - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - LayoutInflater inflater = LayoutInflater.from(container.getContext()); - View view = inflater.inflate(R.layout.pager_view, null); - ((TextView) view.findViewById(R.id.pager_content)).setText("Position #" + position); - view.setBackgroundColor(COLORS[position]); - container.addView(view); - return view; - } - - @Override - public void destroyItem(ViewGroup container, int position, Object object) { - container.removeView((View) object); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimpleWebViewActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimpleWebViewActivity.java deleted file mode 100644 index 9c844af..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SimpleWebViewActivity.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.os.Bundle; -import android.webkit.WebSettings; -import android.webkit.WebView; - -/** - * One big web view to play with. - */ -public class SimpleWebViewActivity extends Activity { - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - WebView mainWebView = new WebView(this); - setContentView(mainWebView); - mainWebView.loadData( - "<html>" + - "<script>document.was_clicked = false</script>" + - "<body> " + - "<button style='height:1000px;width:1000px;' onclick='document.was_clicked = true'> " + - "I'm a button</button>" + - "</body> " + - "</html>", "text/html", null); - WebSettings settings = mainWebView.getSettings(); - settings.setJavaScriptEnabled(true); - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SwipeActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SwipeActivity.java deleted file mode 100644 index 93d1c18..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SwipeActivity.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.view.ViewPager; - -/** - * Activity to test swipe interactions. - */ -public class SwipeActivity extends Activity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.swipe_activity); - - ((ViewPager) findViewById(R.id.small_pager)).setAdapter(new SimplePagerAdapter()); - ((ViewPager) findViewById(R.id.overlapped_pager)).setAdapter(new SimplePagerAdapter()); - } - -} - diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SyncActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SyncActivity.java deleted file mode 100644 index 6702390..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/SyncActivity.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.VisibleForTesting; - -import android.app.Activity; -import android.os.Bundle; -import android.os.SystemClock; -import android.view.View; -import android.widget.TextView; - -import java.util.Random; - -/** - * Displays "hello world" with a random delay of 2 to 7s after the user clicks on a button. This is - * used to demonstrate how Espresso can synchronize with any part of your application, which may - * cause the application state to be unstable (e.g. a network call). - */ -public class SyncActivity extends Activity { - - /** - * A server that returns a hello world string - */ - public interface HelloWorldServer { - String getHelloWorld(); - } - - private HelloWorldServer helloWorldServer; - private TextView statusTextView; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - setContentView(R.layout.sync_activity); - - statusTextView = checkNotNull(((TextView) findViewById(R.id.status_text))); - - setHelloWorldServer(new HelloWorldServer() { - @Override - public String getHelloWorld() { - Random rand = new Random(); - SystemClock.sleep(rand.nextInt(5000) + 2000); - return getString(R.string.hello_world); - } - }); - } - - public void onRequestButtonClick(@SuppressWarnings("unused") View view) { - Thread t = new Thread() { - @Override - public void run() { - final String helloworld = helloWorldServer.getHelloWorld(); - runOnUiThread(new Runnable() { - @Override - public void run() { - setStatus(helloworld); - } - }); - } - }; - t.start(); - } - - private void setStatus(String text) { - statusTextView.setText(text); - } - - @VisibleForTesting - public HelloWorldServer getHelloWorldServer() { - return helloWorldServer; - } - - @VisibleForTesting - public void setHelloWorldServer(HelloWorldServer helloWorldServer) { - this.helloWorldServer = helloWorldServer; - } -} diff --git a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ViewPagerActivity.java b/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ViewPagerActivity.java deleted file mode 100644 index ec92db8..0000000 --- a/espresso/espresso-sample/src/main/java/com/google/android/apps/common/testing/ui/testapp/ViewPagerActivity.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.testapp; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.view.ViewPager; - -/** - * Activity to demonstrate actions on a {@link ViewPager}. - */ -public class ViewPagerActivity extends Activity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.pager_activity); - - final ViewPager pager = (ViewPager) findViewById(R.id.pager_layout); - pager.setAdapter(new SimplePagerAdapter()); - } - -} - diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_calendar.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_calendar.png Binary files differdeleted file mode 100644 index c7bd88b..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_calendar.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_key.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_key.png Binary files differdeleted file mode 100644 index ff876a0..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_key.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_lock.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_lock.png Binary files differdeleted file mode 100644 index 1c80686..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_lock.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_save.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_save.png Binary files differdeleted file mode 100644 index 827355d..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_save.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_search.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_search.png Binary files differdeleted file mode 100644 index b826566..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_search.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_world.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_world.png Binary files differdeleted file mode 100644 index 612a5f2..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_action_world.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_drawer.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_drawer.png Binary files differdeleted file mode 100644 index 9691a6c..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_drawer.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_launcher.png b/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_launcher.png Binary files differdeleted file mode 100644 index c1615e0..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-hdpi/ic_launcher.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_calendar.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_calendar.png Binary files differdeleted file mode 100644 index 37a9d7a..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_calendar.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_key.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_key.png Binary files differdeleted file mode 100644 index 8628a15..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_key.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_lock.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_lock.png Binary files differdeleted file mode 100644 index a29abbb..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_lock.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_save.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_save.png Binary files differdeleted file mode 100644 index a51c100..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_save.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_search.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_search.png Binary files differdeleted file mode 100644 index 1b4aac6..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_search.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_world.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_world.png Binary files differdeleted file mode 100644 index c27143c..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_action_world.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_drawer.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_drawer.png Binary files differdeleted file mode 100644 index 9691a6c..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_drawer.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_launcher.png b/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_launcher.png Binary files differdeleted file mode 100644 index 110987a..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-ldpi/ic_launcher.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_calendar.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_calendar.png Binary files differdeleted file mode 100644 index 7cb5f27..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_calendar.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_key.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_key.png Binary files differdeleted file mode 100644 index 6bb6ff3..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_key.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_lock.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_lock.png Binary files differdeleted file mode 100644 index ee9dea0..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_lock.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_save.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_save.png Binary files differdeleted file mode 100644 index eebcf21..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_save.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_search.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_search.png Binary files differdeleted file mode 100644 index 3516c9e..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_search.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_world.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_world.png Binary files differdeleted file mode 100644 index f7e8dcf..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_action_world.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_drawer.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_drawer.png Binary files differdeleted file mode 100644 index 2190a93..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_drawer.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_launcher.png b/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_launcher.png Binary files differdeleted file mode 100644 index 90f091c..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-mdpi/ic_launcher.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_calendar.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_calendar.png Binary files differdeleted file mode 100644 index d34b110..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_calendar.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_key.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_key.png Binary files differdeleted file mode 100644 index 31c6756..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_key.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_lock.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_lock.png Binary files differdeleted file mode 100644 index 63797e2..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_lock.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_save.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_save.png Binary files differdeleted file mode 100644 index 2e7c579..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_save.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_search.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_search.png Binary files differdeleted file mode 100644 index 3539eab..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_search.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_world.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_world.png Binary files differdeleted file mode 100644 index e1b21d3..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_action_world.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_drawer.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_drawer.png Binary files differdeleted file mode 100644 index e2dd13a..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_drawer.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_launcher.png b/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differdeleted file mode 100644 index 0f6604b..0000000 --- a/espresso/espresso-sample/src/main/res/drawable-xhdpi/ic_launcher.png +++ /dev/null diff --git a/espresso/espresso-sample/src/main/res/layout/actionbar_activity.xml b/espresso/espresso-sample/src/main/res/layout/actionbar_activity.xml deleted file mode 100644 index 41fa6fa..0000000 --- a/espresso/espresso-sample/src/main/res/layout/actionbar_activity.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:orientation="vertical" - android:padding="20dip" > - - <Button - android:id="@+id/show_contextual_action_bar" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/text_show" /> - - <Button - android:id="@+id/hide_contextual_action_bar" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/text_hide" /> - - <TextView - android:id="@+id/text_action_bar_result" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginTop="20dp" - android:text="@string/text_empty" - android:textAppearance="?android:attr/textAppearanceSmall" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/delegating_edit_text.xml b/espresso/espresso-sample/src/main/res/layout/delegating_edit_text.xml deleted file mode 100644 index 8d4cb33..0000000 --- a/espresso/espresso-sample/src/main/res/layout/delegating_edit_text.xml +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<merge xmlns:android="http://schemas.android.com/apk/res/android" > - - <EditText - android:id="@+id/delegate_edit_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="text" - android:singleLine="true" /> - - <TextView - android:id="@+id/edit_text_message" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:singleLine="false" - android:visibility="gone" /> - -</merge> diff --git a/espresso/espresso-sample/src/main/res/layout/display_activity.xml b/espresso/espresso-sample/src/main/res/layout/display_activity.xml deleted file mode 100644 index 5781524..0000000 --- a/espresso/espresso-sample/src/main/res/layout/display_activity.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- XML for screen for displaying data received from another activity. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentRight="true" - android:layout_alignParentTop="true" - android:orientation="vertical" > - - <TextView - android:id="@+id/display_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/display_title" - android:textAppearance="?android:attr/textAppearanceMedium" /> - - <TextView - android:id="@+id/display_data" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/display_data" - android:textAppearance="?android:attr/textAppearanceSmall" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/drawer_activity.xml b/espresso/espresso-sample/src/main/res/layout/drawer_activity.xml deleted file mode 100644 index ea5532d..0000000 --- a/espresso/espresso-sample/src/main/res/layout/drawer_activity.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<android.support.v4.widget.DrawerLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/drawer_layout" - android:layout_width="fill_parent" - android:layout_height="fill_parent" > - - <!-- The main content view --> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="match_parent" > - <TextView - android:id="@+id/drawer_text_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - </FrameLayout> - - <ListView - android:id="@+id/drawer_list" - android:layout_width="240dp" - android:layout_height="match_parent" - android:layout_gravity="start" - android:choiceMode="singleChoice" - android:divider="@android:color/transparent" - android:dividerHeight="0dp" - android:background="#111" /> - -</android.support.v4.widget.DrawerLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/drawer_row.xml b/espresso/espresso-sample/src/main/res/layout/drawer_row.xml deleted file mode 100644 index f56a688..0000000 --- a/espresso/espresso-sample/src/main/res/layout/drawer_row.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="fill_horizontal|center_vertical" - android:gravity="fill_horizontal" - android:minHeight="70dip" - android:orientation="horizontal" > - - <TextView android:id="@+id/drawer_row_name" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_alignParentLeft="true" - android:gravity="left|center_vertical"/> -</RelativeLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/fragment_stack.xml b/espresso/espresso-sample/src/main/res/layout/fragment_stack.xml deleted file mode 100644 index 0861f87..0000000 --- a/espresso/espresso-sample/src/main/res/layout/fragment_stack.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center_horizontal" - android:orientation="vertical" - android:padding="4dip" > - - <FrameLayout - android:id="@+id/simple_fragment" - android:layout_width="match_parent" - android:layout_height="0px" - android:layout_weight="1" > - </FrameLayout> - - <Button - android:id="@+id/new_fragment" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="0" - android:text="Create New Fragment" > - - <requestFocus /> - </Button> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/gesture_activity.xml b/espresso/espresso-sample/src/main/res/layout/gesture_activity.xml deleted file mode 100644 index d2bf3f7..0000000 --- a/espresso/espresso-sample/src/main/res/layout/gesture_activity.xml +++ /dev/null @@ -1,80 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- XML for screen providing ability to test different clicks and gestures. --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:fillViewport="true" - android:orientation="vertical" > - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" > - - <TextView - android:id="@+id/text_click" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:gravity="center" - android:text="@string/text_click" - android:textAppearance="?android:attr/textAppearanceMedium" - android:visibility="gone" /> - - <TextView - android:id="@+id/text_long_click" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:gravity="center" - android:text="@string/text_long_click" - android:textAppearance="?android:attr/textAppearanceMedium" - android:visibility="gone" /> - - <TextView - android:id="@+id/text_swipe" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:gravity="center" - android:text="@string/text_swipe" - android:textAppearance="?android:attr/textAppearanceMedium" - android:visibility="gone" /> - - <TextView - android:id="@+id/text_double_click" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:gravity="center" - android:text="@string/text_double_click" - android:textAppearance="?android:attr/textAppearanceMedium" - android:visibility="gone" /> - </LinearLayout> - - <View - android:id="@+id/gesture_area" - android:layout_width="fill_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:clickable="true" - android:gravity="top" - android:onClick="areaClicked" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/list_activity.xml b/espresso/espresso-sample/src/main/res/layout/list_activity.xml deleted file mode 100644 index 20dfc5c..0000000 --- a/espresso/espresso-sample/src/main/res/layout/list_activity.xml +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- XML for a screen with a list view. --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingBottom="48dp" - android:paddingTop="48dp" > - - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="24dp" > - - <TextView - android:id="@+id/selection_row" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/row_label" /> - - <TextView - android:id="@+id/selection_row_value" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dp" /> - </LinearLayout> - - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="24dp" > - - <TextView - android:id="@+id/selection_column" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/column_label" /> - - <TextView - android:id="@+id/selection_column_value" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dp" /> - </LinearLayout> - - <ListView - android:id="@+id/list" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/list_item.xml b/espresso/espresso-sample/src/main/res/layout/list_item.xml deleted file mode 100644 index d1cf1d9..0000000 --- a/espresso/espresso-sample/src/main/res/layout/list_item.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" > - - <TextView - android:id="@+id/item_content" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <TextView - android:id="@+id/item_size" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="50dp" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/menu_activity.xml b/espresso/espresso-sample/src/main/res/layout/menu_activity.xml deleted file mode 100644 index f47e76b..0000000 --- a/espresso/espresso-sample/src/main/res/layout/menu_activity.xml +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:orientation="vertical" - android:padding="20dip" > - - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:gravity="center_horizontal" - android:orientation="horizontal" > - - <Button - android:id="@+id/popup_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginRight="10dp" - android:onClick="showPopup" - android:text="Click here for popup menu!" /> - </LinearLayout> - - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:gravity="center_horizontal" - android:orientation="horizontal" > - - <TextView - android:id="@+id/text_context_menu" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="long-click here for context menu!" - android:textAppearance="?android:attr/textAppearanceMedium" /> - </LinearLayout> - - <TextView - android:id="@+id/text_menu_result" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginTop="20dp" - android:gravity="center" - android:text="@string/text_empty" - android:textAppearance="?android:attr/textAppearanceSmall" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/pager_activity.xml b/espresso/espresso-sample/src/main/res/layout/pager_activity.xml deleted file mode 100644 index 015b2fb..0000000 --- a/espresso/espresso-sample/src/main/res/layout/pager_activity.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/pager_layout" - android:layout_width="fill_parent" - android:layout_height="fill_parent" > - -</android.support.v4.view.ViewPager> diff --git a/espresso/espresso-sample/src/main/res/layout/pager_view.xml b/espresso/espresso-sample/src/main/res/layout/pager_view.xml deleted file mode 100644 index 0e8a802..0000000 --- a/espresso/espresso-sample/src/main/res/layout/pager_view.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" > - - <TextView - android:id="@+id/pager_content" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:gravity="center" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/popup_window.xml b/espresso/espresso-sample/src/main/res/layout/popup_window.xml deleted file mode 100644 index f596ecb..0000000 --- a/espresso/espresso-sample/src/main/res/layout/popup_window.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- XML for screen providing ability to enter text and send some intents. --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical" > - - <TextView - android:id="@+id/popup_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/popup_title" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/popup_window_text" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/scroll_activity.xml b/espresso/espresso-sample/src/main/res/layout/scroll_activity.xml deleted file mode 100644 index ecfee52..0000000 --- a/espresso/espresso-sample/src/main/res/layout/scroll_activity.xml +++ /dev/null @@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- XML for screen that holds various scroll views. --> - -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:fillViewport="true" - android:orientation="vertical" > - - <LinearLayout - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical" > - - <TextView - android:id="@+id/top_left" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="top_left" /> - - <ScrollView - android:layout_width="fill_parent" - android:layout_height="50dp" - android:layout_marginTop="10dp" - android:background="#FFDDDDDD" - android:fillViewport="true" - android:orientation="vertical" > - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical" > - - <TextView - android:id="@+id/double_scroll" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="200dp" - android:text="double_scroll" - android:textColor="#000000" /> - </LinearLayout> - </ScrollView> - - <!-- Keep this on bottom to test scrolling to views that are not showing. --> - <!-- Huge top margin to guarantee this being out of view on large screen layout. --> - - <HorizontalScrollView - android:layout_width="fill_parent" - android:layout_height="50dp" - android:layout_marginTop="3000dp" - android:background="#FFDDDDDD" > - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" > - - <TextView - android:id="@+id/bottom_left" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="bottom_left" - android:textColor="#000000" /> - - <TextView - android:id="@+id/bottom_right" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="3000dp" - android:text="bottom_right" - android:textColor="#000000" /> - </LinearLayout> - </HorizontalScrollView> - </LinearLayout> - -</ScrollView> diff --git a/espresso/espresso-sample/src/main/res/layout/send_activity.xml b/espresso/espresso-sample/src/main/res/layout/send_activity.xml deleted file mode 100644 index 2e67143..0000000 --- a/espresso/espresso-sample/src/main/res/layout/send_activity.xml +++ /dev/null @@ -1,313 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- - XML for screen providing ability to enter text, send some intents, - switch to gesture activity and test scroll down action. ---> - -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:fillViewport="true" - android:orientation="vertical" > - - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="vertical" > - - <TextView - android:id="@+id/send_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:clickable="true" - android:onClick="sendData" - android:text="@string/send_title" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <EditText - android:id="@+id/send_data_edit_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:ems="10" - android:hint="@string/send_hint" /> - - <Button - android:id="@+id/send_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="sendData" - android:text="@string/button_send" /> - - <EditText - android:id="@+id/enter_data_edit_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:ems="10" - android:hint="@string/enter_hint" /> - - <TextView - android:id="@+id/enter_data_response_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <TextView - android:id="@+id/call" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/send_intent_to_call" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <EditText - android:id="@+id/send_data_to_call_edit_text" - android:layout_width="229dp" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:ems="10" - android:hint="@string/send_hint_for_call" /> - - <Button - android:id="@+id/send_to_call_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="sendDataToCall" - android:text="@string/button_call" /> - - <TextView - android:id="@+id/send_data_message" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/send_message" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <EditText - android:id="@+id/send_data_to_message_edit_text" - android:layout_width="290dp" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:ems="10" - android:hint="@string/send_hint" - android:text="@string/send_data_to_message_edit_text" /> - - <Button - android:id="@+id/send_message_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="sendMessage" - android:text="@string/button_to_message" /> - - <TextView - android:id="@+id/goto_browser" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/send_intent_to_browser" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <EditText - android:id="@+id/send_data_to_browser_edit_text" - android:layout_width="290dp" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:ems="10" - android:hint="@string/send_hint" /> - - <Button - android:id="@+id/send_to_browser_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="sendDataToBrowser" - android:text="@string/button_to_browser" /> - - <TextView - android:id="@+id/pick_contact_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/pick_title" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <Button - android:id="@+id/pick_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="pickContact" - android:text="@string/button_pick" /> - - <TextView - android:id="@+id/phone_number" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" /> - - <TextView - android:id="@+id/market" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/send_intent_to_market" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <EditText - android:id="@+id/send_to_market_data" - android:layout_width="229dp" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:ems="10" - android:hint="@string/send_hint_to_market" /> - - <Button - android:id="@+id/send_to_market_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="clickToMarket" - android:text="@string/button_market" /> - - <EditText - android:id="@+id/search_box" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:ems="10" - android:hint="search box" - android:imeOptions="actionSearch" - android:inputType="text" /> - - <TextView - android:id="@+id/search_result" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:visibility="invisible" /> - - <TextView - android:id="@+id/weird_text_title" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="Delegating Edit Text" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <com.google.android.apps.common.testing.ui.testapp.DelegatingEditText - android:id="@+id/delegating_edit_text" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" /> - - <TextView - android:id="@+id/gesture_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:text="@string/gesture_title" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <Button - android:id="@+id/go_to_gesture_activity" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="clickToGesture" - android:text="@string/button_gesture" /> - - <Button - android:id="@+id/scroll_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="clickToScroll" - android:text="@string/launch_scroll_activity" /> - - <Button - android:id="@+id/list_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="clickToList" - android:text="@string/launch_list_activity" /> - - <Button - android:id="@+id/make_alert_dialog" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="showDialog" - android:text="@string/make_alert_dialog_button" /> - - <Button - android:id="@+id/make_popup_menu_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="showPopupMenu" - android:text="@string/make_popup_menu_button" /> - - <Button - android:id="@+id/make_popup_view_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:onClick="showPopupView" - android:text="@string/make_popup_view_button" /> - - <AutoCompleteTextView - android:id="@+id/auto_complete_text_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:completionThreshold="1" - android:hint="@string/pick_water" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - - <!-- Keep this on bottom to test scrolling to views that are not showing. --> - <!-- Huge top margin to guarantee this being out of view on large screen layout. --> - - <Button - android:id="@+id/bottom_send_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="1000dp" - android:onClick="sendData" - android:text="@string/button_send_bottom" /> - - <TextView - android:id="@+id/bottom_send_text_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="1000dp" - android:clickable="true" - android:onClick="sendData" - android:text="@string/send_title" /> - </LinearLayout> - -</ScrollView> diff --git a/espresso/espresso-sample/src/main/res/layout/simple_activity.xml b/espresso/espresso-sample/src/main/res/layout/simple_activity.xml deleted file mode 100644 index 31aa760..0000000 --- a/espresso/espresso-sample/src/main/res/layout/simple_activity.xml +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<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" > - - <Spinner - android:id="@+id/spinner_simple" - android:layout_width="fill_parent" - android:layout_height="wrap_content" /> - - <TextView - android:id="@+id/spinnertext_simple" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <View - android:layout_width="1dp" - android:layout_height="30dp" /> - - <Button - android:id="@+id/button_simple" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:onClick="simpleButtonClicked" - android:text="@string/button_simple" /> - - <TextView - android:id="@+id/text_simple" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/text_simple" - android:textAppearance="?android:attr/textAppearanceLarge" /> - - <View - android:layout_width="1dp" - android:layout_height="30dp" /> - - <EditText - android:id="@+id/sendtext_simple" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:ems="10" - android:hint="@string/send_hint" /> - - <Button - android:id="@+id/send_simple" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:onClick="sendButtonClicked" - android:text="@string/button_send" /> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/swipe_activity.xml b/espresso/espresso-sample/src/main/res/layout/swipe_activity.xml deleted file mode 100644 index e7bfa76..0000000 --- a/espresso/espresso-sample/src/main/res/layout/swipe_activity.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<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" > - - <!-- With update to rev 19, swipe does not consistently work on small pagers - b/12113054 opened to investigate why this regressed .--> - <android.support.v4.view.ViewPager - android:id="@+id/small_pager" - android:layout_width="120dp" - android:layout_height="48dp" /> - - <RelativeLayout - android:layout_width="fill_parent" - android:layout_height="200dp"> - <android.support.v4.view.ViewPager - android:id="@+id/overlapped_pager" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:layout_alignParentTop="true" - android:layout_alignParentLeft="true"/> - <TextView - android:layout_width="50dp" - android:layout_height="fill_parent" - android:background="#CCCCCC" - android:layout_alignParentTop="true" - android:layout_alignParentLeft="true"/> - </RelativeLayout> - - <TextView - android:id="@+id/text_simple" - android:text="@string/text_simple" - android:layout_width="fill_parent" - android:layout_height="wrap_content"/> - -</LinearLayout> diff --git a/espresso/espresso-sample/src/main/res/layout/sync_activity.xml b/espresso/espresso-sample/src/main/res/layout/sync_activity.xml deleted file mode 100644 index 5642eee..0000000 --- a/espresso/espresso-sample/src/main/res/layout/sync_activity.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" > - - <Button - android:id="@+id/request_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:onClick="onRequestButtonClick" - android:text="@string/request_hello_world" /> - - <TextView - android:id="@+id/status_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:textAppearance="?android:attr/textAppearanceMedium" /> - -</LinearLayout> - diff --git a/espresso/espresso-sample/src/main/res/menu/actionbar_activity_actions.xml b/espresso/espresso-sample/src/main/res/menu/actionbar_activity_actions.xml deleted file mode 100644 index 0358ffe..0000000 --- a/espresso/espresso-sample/src/main/res/menu/actionbar_activity_actions.xml +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:yourapp="http://schemas.android.com/apk/res-auto" > - - <item - android:id="@+id/action_lock" - android:icon="@drawable/ic_action_lock" - android:title="Lock" - yourapp:showAsAction="ifRoom|withText"/> - <item - android:id="@+id/action_key" - android:icon="@drawable/ic_action_key" - android:title="Key" - yourapp:showAsAction="never"/> - <item - android:id="@+id/action_calendar" - android:icon="@drawable/ic_action_calendar" - android:title="Calendar" - yourapp:showAsAction="never"/> - -</menu> diff --git a/espresso/espresso-sample/src/main/res/menu/actionbar_context_actions.xml b/espresso/espresso-sample/src/main/res/menu/actionbar_context_actions.xml deleted file mode 100644 index 59233bb..0000000 --- a/espresso/espresso-sample/src/main/res/menu/actionbar_context_actions.xml +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:yourapp="http://schemas.android.com/apk/res-auto" > - - <item - android:id="@+id/action_save" - android:icon="@drawable/ic_action_save" - android:title="Save" - yourapp:showAsAction="ifRoom|withText"/> - <item - android:id="@+id/action_search" - android:icon="@drawable/ic_action_search" - android:title="Search" - yourapp:showAsAction="never"/> - <item - android:id="@+id/action_world" - android:icon="@drawable/ic_action_world" - android:title="World" - yourapp:showAsAction="never"/> - -</menu> diff --git a/espresso/espresso-sample/src/main/res/menu/contextmenu.xml b/espresso/espresso-sample/src/main/res/menu/contextmenu.xml deleted file mode 100644 index 5d4137d..0000000 --- a/espresso/espresso-sample/src/main/res/menu/contextmenu.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" > - - <item - android:id="@+id/context_item1" - android:title="@string/context_item_1_text"> - </item> - <item - android:id="@+id/context_item2" - android:title="@string/context_item_2_text"> - </item> - <item - android:id="@+id/context_item3" - android:title="@string/context_item_3_text"> - </item> - -</menu> diff --git a/espresso/espresso-sample/src/main/res/menu/optionsmenu.xml b/espresso/espresso-sample/src/main/res/menu/optionsmenu.xml deleted file mode 100644 index 66ed1b2..0000000 --- a/espresso/espresso-sample/src/main/res/menu/optionsmenu.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" > - - <item - android:id="@+id/option_item1" - android:title="@string/options_item_1_text"> - </item> - <item - android:id="@+id/option_item2" - android:title="@string/options_item_2_text"> - </item> - <item - android:id="@+id/option_item3" - android:title="@string/options_item_3_text"> - </item> - -</menu> diff --git a/espresso/espresso-sample/src/main/res/menu/popup_menu.xml b/espresso/espresso-sample/src/main/res/menu/popup_menu.xml deleted file mode 100644 index 9bfb67f..0000000 --- a/espresso/espresso-sample/src/main/res/menu/popup_menu.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" > - - <item - android:id="@+id/menu_item_1" - android:title="@string/item_1_text"/> - <item - android:id="@+id/menu_item_2" - android:title="@string/item_2_text"/> - -</menu> diff --git a/espresso/espresso-sample/src/main/res/menu/popupmenu.xml b/espresso/espresso-sample/src/main/res/menu/popupmenu.xml deleted file mode 100644 index 0dae632..0000000 --- a/espresso/espresso-sample/src/main/res/menu/popupmenu.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<menu xmlns:android="http://schemas.android.com/apk/res/android" > - - <item - android:id="@+id/popup_item1" - android:title="@string/popup_item_1_text"> - </item> - <item - android:id="@+id/popup_item2" - android:title="@string/popup_item_2_text"> - </item> - <item - android:id="@+id/popup_item3" - android:title="@string/popup_item_3_text"> - </item> - -</menu> diff --git a/espresso/espresso-sample/src/main/res/values/strings.xml b/espresso/espresso-sample/src/main/res/values/strings.xml deleted file mode 100644 index e9d9ec5..0000000 --- a/espresso/espresso-sample/src/main/res/values/strings.xml +++ /dev/null @@ -1,90 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources> - - <string name="button_send">Send</string> - <string name="button_send_bottom">Send Bottom</string> - <string name="button_call">Call</string> - <string name="button_to_message">SMS</string> - <string name="button_to_browser">Go To Browser</string> - <string name="button_pick">Pick</string> - <string name="button_market">Goto Market</string> - <string name="button_gesture">Go To Gesture Activity</string> - <string name="button_simple">Click Me!</string> - <string name="display_data" /> - <string name="display_title">Data from sender</string> - <string name="dialog_title">An emergency alert</string> - <string name="dialog_message">A really important message</string> - <string name="enter_hint">Type text and press Enter</string> - <string name="launch_list_activity">Launch list_activity</string> - <string name="launch_scroll_activity">Launch scroll_activity</string> - <string name="send_data_to_message_edit_text">send_data_to_message_edit_text</string> - <string name="send_hint">Enter text here</string> - <string name="send_hint_for_call">Enter number here</string> - <string name="send_title">Send internal intent with data</string> - <string name="send_intent_to_call">Enter Number To Call</string> - <string name="send_intent_to_market">Enter App Id From Market</string> - <string name="send_intent_to_browser">Enter URL you wanted to go.</string> - <string name="send_hint_to_market">Enter App id</string> - <string name="send_message">Enter Message</string> - <string name="pick_title">Pick a Contact</string> - <string name="item_1_text">Menu Item 1</string> - <string name="item_2_text">Goodbye</string> - <string name="make_alert_dialog_button">Make an alert dialog</string> - <string name="make_popup_menu_button">Make a Popup Window</string> - <string name="make_popup_view_button">Make a Popup Window</string> - <string name="popup_window_text">I am in a popup window</string> - <string name="popup_title">A popup window</string> - <string name="gesture_title">Show Gesture Activity</string> - <string name="text_click">Click</string> - <string name="text_long_click">Long Click</string> - <string name="text_swipe">Swipe</string> - <string name="text_double_click">Double Click</string> - <string name="text_empty"></string> - <string name="text_show">Show context actionbar</string> - <string name="text_hide">Hide context actionbar</string> - <string name="text_simple">Message</string> - <string name="popup_item_1_text">Popup Item 1</string> - <string name="popup_item_2_text">Popup Item 2</string> - <string name="popup_item_3_text">Popup Item 3</string> - <string name="context_item_1_text">Context Item 1</string> - <string name="context_item_2_text">Context Item 2</string> - <string name="context_item_3_text">Context Item 3</string> - <string name="options_item_1_text">Options Item 1</string> - <string name="options_item_2_text">Options Item 2</string> - <string name="options_item_3_text">Options Item 3</string> - <string name="searching_for_label">Searching for:</string> - <string name="row_label">clicked on row:</string> - <string name="column_label">clicked on column:</string> - <string name="hello_world">hello world!</string> - <string name="request_hello_world">Request hello world</string> - <string name="nav_drawer_open">Open navigation drawer</string> - <string name="pick_water">Pick a body of water</string> - <string name="nav_drawer_close">Close navigation drawer</string> - - <string-array name="spinner_array"> - <item>Espresso</item> - <item>Doppio</item> - <item>Macchiato</item> - <item>Cappuccino</item> - <item>Americano</item> - <item>Mocha</item> - <item>Late</item> - </string-array> - -</resources> diff --git a/espresso/gradle.properties b/espresso/gradle.properties deleted file mode 100644 index bd11c51..0000000 --- a/espresso/gradle.properties +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Settings specified in this file will override any Gradle settings -# configured through the IDE. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - -# Specifies custom SDK location -#androidCustomSdkPath=/path/to/sdk - -##SNPSHOT?? -VERSION=1.2 -GROUP_ID=com.google.android.apps.common.testing //just espresso-lib? - -POM_DESCRIPTION=A simple API for writing reliable UI tests -POM_URL= -POM_SCM_URL= -POM_SCM_CONNECTION= -POM_SCM_DEV_CONNECTION= -POM_LICENCE_NAME=The Apache Software License, Version 2.0 -POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt -POM_LICENCE_DIST=repo -POM_DEVELOPER_ID= -POM_DEVELOPER_NAME=The Android Open Source Project
\ No newline at end of file diff --git a/espresso/gradle/wrapper/gradle-wrapper.jar b/espresso/gradle/wrapper/gradle-wrapper.jar Binary files differdeleted file mode 100644 index d5c591c..0000000 --- a/espresso/gradle/wrapper/gradle-wrapper.jar +++ /dev/null diff --git a/espresso/gradle/wrapper/gradle-wrapper.properties b/espresso/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index f057df0..0000000 --- a/espresso/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jan 24 18:15:27 SGT 2014 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip diff --git a/espresso/gradlew b/espresso/gradlew deleted file mode 100755 index 91a7e26..0000000 --- a/espresso/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/espresso/gradlew.bat b/espresso/gradlew.bat deleted file mode 100644 index aec9973..0000000 --- a/espresso/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/espresso/idling-resource-interface/Android.mk b/espresso/idling-resource-interface/Android.mk deleted file mode 100644 index 5e1bd42..0000000 --- a/espresso/idling-resource-interface/Android.mk +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := espresso-idling-resource - -LOCAL_SDK_VERSION := 9 - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/espresso/idling-resource-interface/build.gradle b/espresso/idling-resource-interface/build.gradle deleted file mode 100644 index 5952351..0000000 --- a/espresso/idling-resource-interface/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'java' - -task androidJavadocs(type: Javadoc) { - source = sourceSets.main.allJava -} - -task androidSourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allSource -} diff --git a/espresso/idling-resource-interface/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingResource.java b/espresso/idling-resource-interface/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingResource.java deleted file mode 100644 index 0f5e839..0000000 --- a/espresso/idling-resource-interface/src/main/java/com/google/android/apps/common/testing/ui/espresso/IdlingResource.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.apps.common.testing.ui.espresso; - -/** - * Represents a resource of an application under test which can cause asynchronous background work - * to happen during test execution (e.g. an intent service that processes a button click). By - * default, {@link Espresso} synchronizes all view operations with the UI thread as well as - * AsyncTasks; however, it has no way of doing so with "hand-made" resources. In such cases, test - * authors can register the custom resource and {@link Espresso} will wait for the resource to - * become idle prior to executing a view operation. - * <br><br> - * <b>Important Note:</b> it is assumed that the resource stays idle most of the time. - */ -public interface IdlingResource { - - /** - * Returns the name of the resources (used for logging and idempotency of registration). - */ - public String getName(); - - /** - * Returns {@code true} if resource is currently idle. Espresso will <b>always</b> call this - * method from the main thread, therefore it should be non-blocking and return immediately. - */ - public boolean isIdleNow(); - - /** - * Registers the given {@link ResourceCallback} with the resource. Espresso will call this method: - * <ul> - * <li>with its implementation of {@link ResourceCallback} so it can be notified asynchronously - * that your resource is idle - * <li>from the main thread, but you are free to execute the callback's onTransitionToIdle from - * any thread - * <li>once (when it is initially given a reference to your IdlingResource) - * </ul> - * <br> - * You only need to call this upon transition from busy to idle - if the resource is already idle - * when the method is called invoking the call back is optional and has no significant impact. - */ - public void registerIdleTransitionCallback(ResourceCallback callback); - - /** - * Registered by an {@link IdlingResource} to notify Espresso of a transition to idle. - */ - public interface ResourceCallback { - /** - * Called when the resource goes from busy to idle. - */ - public void onTransitionToIdle(); - } -} diff --git a/espresso/javadoc.gradle b/espresso/javadoc.gradle deleted file mode 100644 index e947fb8..0000000 --- a/espresso/javadoc.gradle +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -task androidJavadocs(type: Javadoc) { - source = android.sourceSets.main.allJava -} - -task androidSourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.allSource -} diff --git a/espresso/libs/README b/espresso/libs/README deleted file mode 100644 index b829d43..0000000 --- a/espresso/libs/README +++ /dev/null @@ -1,18 +0,0 @@ -The following outlines the license and the download location of the binary files -present in this "libs" folder. - -dagger-1.2.1: -jar: http://mvnrepository.com/artifact/com.squareup.dagger/dagger/1.2.1 -license: Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -dagger-compiler-1.2.1: -jar: http://mvnrepository.com/artifact/com.squareup.dagger/dagger-compiler/1.2.1 -license: Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -guava-14.0.1 -jar: http://mvnrepository.com/artifact/com.google.guava/guava/14.0.1 -license: Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - -jarjar-1.4 -jar: https://code.google.com/p/jarjar -license: Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
\ No newline at end of file diff --git a/espresso/libs/dagger-1.2.1.jar b/espresso/libs/dagger-1.2.1.jar Binary files differdeleted file mode 100644 index 90d9509..0000000 --- a/espresso/libs/dagger-1.2.1.jar +++ /dev/null diff --git a/espresso/libs/dagger-compiler-1.2.1.jar b/espresso/libs/dagger-compiler-1.2.1.jar Binary files differdeleted file mode 100644 index f2aa56d..0000000 --- a/espresso/libs/dagger-compiler-1.2.1.jar +++ /dev/null diff --git a/espresso/libs/guava-14.0.1.jar b/espresso/libs/guava-14.0.1.jar Binary files differdeleted file mode 100644 index 3a3d925..0000000 --- a/espresso/libs/guava-14.0.1.jar +++ /dev/null diff --git a/espresso/libs/jarjar-1.4.jar b/espresso/libs/jarjar-1.4.jar Binary files differdeleted file mode 100644 index 68b9db9..0000000 --- a/espresso/libs/jarjar-1.4.jar +++ /dev/null diff --git a/espresso/libs/testrunner-1.1.jar b/espresso/libs/testrunner-1.1.jar Binary files differdeleted file mode 100644 index 5abc79f..0000000 --- a/espresso/libs/testrunner-1.1.jar +++ /dev/null diff --git a/espresso/libs/testrunner-runtime-1.1.jar b/espresso/libs/testrunner-runtime-1.1.jar Binary files differdeleted file mode 100644 index 17b20d5..0000000 --- a/espresso/libs/testrunner-runtime-1.1.jar +++ /dev/null diff --git a/espresso/publishLocal.gradle b/espresso/publishLocal.gradle deleted file mode 100644 index 91596fa..0000000 --- a/espresso/publishLocal.gradle +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'maven' - -def getReleaseRepositoryUrl() { - if (hasProperty('androidSdkPath')) { - return "file:/$project.androidCustomSdkPath/extras/$project.POM_ARTIFACT_ID/m2repository" - } else { - println "No Android SDK path set. Using default m2 location, " + - "defined Maven settings.xml. Set ANDROID_HOME or set SDK location " + - "via ANDROID_SDK in gradle.properties" - } -} - -task publishLocal(type: Upload) { -//task publishLocal { -// configuration = configurations.archives -// -// repositories { -// mavenCentral() -// } - - uploadArchives { - repositories { - mavenDeployer { - - println "***** ${getReleaseRepositoryUrl()}" - repository(url: getReleaseRepositoryUrl()) - - println "***** versoin $VERSION" - pom.project { - pom.version = VERSION - pom.groupId = GROUP_ID - pom.artifactId = POM_ARTIFACT_ID - -// licenses { -// license { -// name POM_LICENCE_NAME -// url POM_LICENCE_URL -// distribution POM_LICENCE_DIST -// } -// } -// -// developers { -// developer { -// //id POM_DEVELOPER_ID -// name POM_DEVELOPER_NAME -// } -// } - } - } - } - } - -// def isReleaseBuild() { -// return VERSION.contains("SNAPSHOT") == false -// } -// signing { -// required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } -// sign configurations.archives -// } -// -// task androidJavadocs(type: Javadoc) { -// source = android.sourceSets.main.allJava -// classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) -// } -// -// task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { -// classifier = 'javadoc' -// from androidJavadocs.destinationDir -// } -// -// task androidSourcesJar(type: Jar) { -// classifier = 'sources' -// from android.sourceSets.main.allSource -// } -// -// artifacts { -// archives androidSourcesJar -// archives androidJavadocsJar -// } -} diff --git a/espresso/settings.gradle b/espresso/settings.gradle deleted file mode 100644 index 2a8f5f0..0000000 --- a/espresso/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -include ':espresso-lib' -include ':espresso-lib-tests' - -include ':espresso-contrib' -include ':espresso-contrib-tests' - -include ':espresso-sample' - -include ':idling-resource-interface' |