IntegrationTestUtils.java revision 149fb7fd82554d5b02c335a3f9b8c60be4d083ec
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.contacts.util; 18 19import static android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP; 20import static android.os.PowerManager.FULL_WAKE_LOCK; 21import static android.os.PowerManager.ON_AFTER_RELEASE; 22 23import com.google.common.base.Preconditions; 24 25import android.app.Activity; 26import android.app.Instrumentation; 27import android.content.Context; 28import android.os.PowerManager; 29import android.view.View; 30 31import junit.framework.Assert; 32 33import java.util.concurrent.Callable; 34import java.util.concurrent.ExecutionException; 35import java.util.concurrent.FutureTask; 36 37import javax.annotation.concurrent.GuardedBy; 38import javax.annotation.concurrent.ThreadSafe; 39 40/** Some utility methods for making integration testing smoother. */ 41@ThreadSafe 42public class IntegrationTestUtils { 43 private static final String TAG = "IntegrationTestUtils"; 44 45 private final Instrumentation mInstrumentation; 46 private final Object mLock = new Object(); 47 @GuardedBy("mLock") private PowerManager.WakeLock mWakeLock; 48 49 public IntegrationTestUtils(Instrumentation instrumentation) { 50 mInstrumentation = instrumentation; 51 } 52 53 /** 54 * Find a view by a given resource id, from the given activity, and click it, iff it is 55 * enabled according to {@link View#isEnabled()}. 56 */ 57 public void clickButton(final Activity activity, final int buttonResourceId) throws Throwable { 58 runOnUiThreadAndGetTheResult(new Callable<Void>() { 59 @Override 60 public Void call() throws Exception { 61 View view = activity.findViewById(buttonResourceId); 62 Assert.assertNotNull(view); 63 if (view.isEnabled()) { 64 view.performClick(); 65 } 66 return null; 67 } 68 }); 69 } 70 71 // TODO: Move this class and the appropriate documentation into a test library, having checked 72 // first to see if exactly this code already exists or not. 73 /** 74 * Execute a callable on the ui thread, returning its result synchronously. 75 * <p> 76 * Waits for an idle sync on the main thread (see {@link Instrumentation#waitForIdle(Runnable)}) 77 * before executing this callable. 78 */ 79 private <T> T runOnUiThreadAndGetTheResult(Callable<T> callable) throws Throwable { 80 FutureTask<T> future = new FutureTask<T>(callable); 81 mInstrumentation.waitForIdle(future); 82 try { 83 return future.get(); 84 } catch (ExecutionException e) { 85 // Unwrap the cause of the exception and re-throw it. 86 throw e.getCause(); 87 } 88 } 89 90 /** 91 * Wake up the screen, useful in tests that want or need the screen to be on. 92 * <p> 93 * This is usually called from setUp() for tests that require it. After calling this method, 94 * {@link #releaseScreenWakeLock()} must be called, this is usually done from tearDown(). 95 */ 96 public void acquireScreenWakeLock(Context context) { 97 synchronized (mLock) { 98 Preconditions.checkState(mWakeLock == null, "mWakeLock was already held"); 99 mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)) 100 .newWakeLock(ACQUIRE_CAUSES_WAKEUP | ON_AFTER_RELEASE | FULL_WAKE_LOCK, TAG); 101 mWakeLock.acquire(); 102 } 103 } 104 105 /** Release the wake lock previously acquired with {@link #acquireScreenWakeLock(Context)}. */ 106 public void releaseScreenWakeLock() { 107 synchronized (mLock) { 108 // We don't use Preconditions to force you to have acquired before release. 109 // This is because we don't want unnecessary exceptions in tearDown() since they'll 110 // typically mask the actual exception that happened during the test. 111 // The other reason is that this method is most likely to be called from tearDown(), 112 // which is invoked within a finally block, so it's not infrequently the case that 113 // the setUp() method fails before getting the lock, at which point we don't want 114 // to fail in tearDown(). 115 if (mWakeLock != null) { 116 mWakeLock.release(); 117 mWakeLock = null; 118 } 119 } 120 } 121} 122