IntegrationTestUtils.java revision 953bf02036ae9880db8f5f5e1046c0530ccdfe9d
1fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng/* 2fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Copyright (C) 2011 The Android Open Source Project 3fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * 4fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 5fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * you may not use this file except in compliance with the License. 6fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * You may obtain a copy of the License at 7fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * 8fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 9fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * 10fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Unless required by applicable law or agreed to in writing, software 11fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 12fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * See the License for the specific language governing permissions and 14fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * limitations under the License. 15fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng */ 16fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 17fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengpackage com.android.contacts.common.test; 18fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 19fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport static android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP; 20fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport static android.os.PowerManager.FULL_WAKE_LOCK; 21fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport static android.os.PowerManager.ON_AFTER_RELEASE; 22fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 23fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport android.app.Activity; 24fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport android.app.Instrumentation; 25fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport android.content.Context; 26fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport android.os.PowerManager; 27fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport android.view.View; 28fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport android.view.ViewGroup; 29fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport android.widget.TextView; 30fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 31fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport com.google.common.base.Preconditions; 32fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 33fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport junit.framework.Assert; 34fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 35fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport java.util.ArrayList; 36fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport java.util.List; 37fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport java.util.concurrent.Callable; 38fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport java.util.concurrent.ExecutionException; 39fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport java.util.concurrent.FutureTask; 40fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 41fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport javax.annotation.concurrent.GuardedBy; 42fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengimport javax.annotation.concurrent.ThreadSafe; 43fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 44fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng/** Some utility methods for making integration testing smoother. */ 45fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng@ThreadSafe 46fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Chengpublic class IntegrationTestUtils { 47fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng private static final String TAG = "IntegrationTestUtils"; 48fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 49fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng private final Instrumentation mInstrumentation; 50fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng private final Object mLock = new Object(); 51fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng @GuardedBy("mLock") private PowerManager.WakeLock mWakeLock; 52fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 53fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public IntegrationTestUtils(Instrumentation instrumentation) { 54fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng mInstrumentation = instrumentation; 55fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 56fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 57fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** 58fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Find a view by a given resource id, from the given activity, and click it, iff it is 59fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * enabled according to {@link View#isEnabled()}. 60fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng */ 61fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public void clickButton(final Activity activity, final int buttonResourceId) throws Throwable { 62fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng runOnUiThreadAndGetTheResult(new Callable<Void>() { 63fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng @Override 64fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public Void call() throws Exception { 65fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng View view = activity.findViewById(buttonResourceId); 66fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng Assert.assertNotNull(view); 67fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng if (view.isEnabled()) { 68fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng view.performClick(); 69fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 70fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return null; 71fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 72fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng }); 73fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 74fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 75fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** Returns the result of running {@link TextView#getText()} on the ui thread. */ 76fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public CharSequence getText(final TextView view) throws Throwable { 77fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return runOnUiThreadAndGetTheResult(new Callable<CharSequence>() { 78fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng @Override 79fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public CharSequence call() { 80fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return view.getText(); 81fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 82fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng }); 83fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 84fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 85fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // TODO: Move this class and the appropriate documentation into a test library, having checked 86fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // first to see if exactly this code already exists or not. 87fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** 88fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Execute a callable on the ui thread, returning its result synchronously. 89fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * <p> 90fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Waits for an idle sync on the main thread (see {@link Instrumentation#waitForIdle(Runnable)}) 91fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * before executing this callable. 92fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng */ 93fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public <T> T runOnUiThreadAndGetTheResult(Callable<T> callable) throws Throwable { 94fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng FutureTask<T> future = new FutureTask<T>(callable); 95fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng mInstrumentation.waitForIdle(future); 96fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng try { 97fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return future.get(); 98fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } catch (ExecutionException e) { 99fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // Unwrap the cause of the exception and re-throw it. 100fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng throw e.getCause(); 101fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 102fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 103fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 104fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** 105fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Wake up the screen, useful in tests that want or need the screen to be on. 106fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * <p> 107fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * This is usually called from setUp() for tests that require it. After calling this method, 108fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * {@link #releaseScreenWakeLock()} must be called, this is usually done from tearDown(). 109fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng */ 110fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public void acquireScreenWakeLock(Context context) { 111fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng synchronized (mLock) { 112fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng Preconditions.checkState(mWakeLock == null, "mWakeLock was already held"); 113fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)) 114fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng .newWakeLock( 115fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE | PowerManager.FULL_WAKE_LOCK, TAG); 116fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng mWakeLock.acquire(); 117fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 118fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 119fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 120fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** Release the wake lock previously acquired with {@link #acquireScreenWakeLock(Context)}. */ 121fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public void releaseScreenWakeLock() { 122fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng synchronized (mLock) { 123fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // We don't use Preconditions to force you to have acquired before release. 124fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // This is because we don't want unnecessary exceptions in tearDown() since they'll 125fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // typically mask the actual exception that happened during the test. 126fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // The other reason is that this method is most likely to be called from tearDown(), 127fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // which is invoked within a finally block, so it's not infrequently the case that 128fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // the setUp() method fails before getting the lock, at which point we don't want 129fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng // to fail in tearDown(). 130fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng if (mWakeLock != null) { 131fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng mWakeLock.release(); 132fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng mWakeLock = null; 133fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 134fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 135fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 136fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 137fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** 138fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Gets all {@link TextView} objects whose {@link TextView#getText()} contains the given text as 139fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * a substring. 140fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng */ 141fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public List<TextView> getTextViewsWithString(final Activity activity, final String text) 142fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng throws Throwable { 143953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee return getTextViewsWithString(getRootView(activity), text); 144953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee } 145953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee 146953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee /** 147953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee * Gets all {@link TextView} objects whose {@link TextView#getText()} contains the given text as 148953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee * a substring for the given root view. 149953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee */ 150953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee public List<TextView> getTextViewsWithString(final View rootView, final String text) 151953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee throws Throwable { 152fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return runOnUiThreadAndGetTheResult(new Callable<List<TextView>>() { 153fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng @Override 154fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public List<TextView> call() throws Exception { 155fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng List<TextView> matchingViews = new ArrayList<TextView>(); 156953bf02036ae9880db8f5f5e1046c0530ccdfe9dAndrew Lee for (TextView textView : getAllViews(TextView.class, rootView)) { 157fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng if (textView.getText().toString().contains(text)) { 158fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng matchingViews.add(textView); 159fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 160fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 161fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return matchingViews; 162fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 163fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng }); 164fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 165fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 166fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** Find the root view for a given activity. */ 167fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng public static View getRootView(Activity activity) { 168fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return activity.findViewById(android.R.id.content).getRootView(); 169fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 170fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng 171fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng /** 172fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * Gets a list of all views of a given type, rooted at the given parent. 173fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * <p> 174fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * This method will recurse down through all {@link ViewGroup} instances looking for 175fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * {@link View} instances of the supplied class type. Specifically it will use the 176fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * {@link Class#isAssignableFrom(Class)} method as the test for which views to add to the list, 177fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * so if you provide {@code View.class} as your type, you will get every view. The parent itself 178fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * will be included also, should it be of the right type. 179fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * <p> 180fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * This call manipulates the ui, and as such should only be called from the application's main 181fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng * thread. 182fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng */ 183fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng private static <T extends View> List<T> getAllViews(final Class<T> clazz, final View parent) { 184fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng List<T> results = new ArrayList<T>(); 185fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng if (parent.getClass().equals(clazz)) { 186fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng results.add(clazz.cast(parent)); 187fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 188fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng if (parent instanceof ViewGroup) { 189fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng ViewGroup viewGroup = (ViewGroup) parent; 190fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng for (int i = 0; i < viewGroup.getChildCount(); ++i) { 191fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng results.addAll(getAllViews(clazz, viewGroup.getChildAt(i))); 192fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 193fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 194fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng return results; 195fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng } 196fbecde24e96a5d95adc0e50c5ff5418346e37298Chiao Cheng} 197