1 /* 2 * Copyright (C) 2013 DroidDriver committers 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 17 package com.google.android.droiddriver.instrumentation; 18 19 import android.app.Activity; 20 import android.app.Instrumentation; 21 import android.graphics.Bitmap; 22 import android.os.SystemClock; 23 import android.view.View; 24 25 import com.google.android.droiddriver.base.AbstractDroidDriver; 26 import com.google.android.droiddriver.exceptions.TimeoutException; 27 import com.google.android.droiddriver.util.ActivityUtils; 28 import com.google.common.primitives.Longs; 29 30 /** 31 * Implementation of a UiDriver that is driven via instrumentation. 32 */ 33 public class InstrumentationDriver extends AbstractDroidDriver { 34 private final InstrumentationContext context; 35 36 public InstrumentationDriver(Instrumentation instrumentation) { 37 super(instrumentation); 38 this.context = new InstrumentationContext(instrumentation); 39 } 40 41 @Override 42 protected ViewElement getNewRootElement() { 43 return context.getUiElement(findRootView()); 44 } 45 46 @Override 47 protected InstrumentationContext getContext() { 48 return context; 49 } 50 51 private View findRootView() { 52 Activity runningActivity = getRunningActivity(); 53 View[] views = RootFinder.getRootViews(); 54 if (views.length > 1) { 55 for (View view : views) { 56 if (view.hasWindowFocus()) { 57 return view; 58 } 59 } 60 } 61 return runningActivity.getWindow().getDecorView(); 62 } 63 64 private Activity getRunningActivity() { 65 long timeoutMillis = getPoller().getTimeoutMillis(); 66 long end = SystemClock.uptimeMillis() + timeoutMillis; 67 while (true) { 68 instrumentation.waitForIdleSync(); 69 Activity runningActivity = ActivityUtils.getRunningActivity(); 70 if (runningActivity != null) { 71 return runningActivity; 72 } 73 long remainingMillis = end - SystemClock.uptimeMillis(); 74 if (remainingMillis < 0) { 75 throw new TimeoutException(String.format( 76 "Timed out after %d milliseconds waiting for foreground activity", timeoutMillis)); 77 } 78 SystemClock.sleep(Longs.min(250, remainingMillis)); 79 } 80 } 81 82 private static class ScreenshotRunnable implements Runnable { 83 private final View rootView; 84 private Bitmap screenshot; 85 86 private ScreenshotRunnable(View rootView) { 87 this.rootView = rootView; 88 } 89 90 @Override 91 public void run() { 92 rootView.destroyDrawingCache(); 93 rootView.buildDrawingCache(false); 94 screenshot = Bitmap.createBitmap(rootView.getDrawingCache()); 95 rootView.destroyDrawingCache(); 96 } 97 } 98 99 @Override 100 protected Bitmap takeScreenshot() { 101 ScreenshotRunnable screenshotRunnable = new ScreenshotRunnable(findRootView()); 102 instrumentation.runOnMainSync(screenshotRunnable); 103 return screenshotRunnable.screenshot; 104 } 105 } 106