1cddda72410c992a12db61cef26713b498e31fea4Thanh Le/*
2cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Copyright (C) 2013 DroidDriver committers
3cddda72410c992a12db61cef26713b498e31fea4Thanh Le *
4cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Licensed under the Apache License, Version 2.0 (the "License");
5cddda72410c992a12db61cef26713b498e31fea4Thanh Le * you may not use this file except in compliance with the License.
6cddda72410c992a12db61cef26713b498e31fea4Thanh Le * You may obtain a copy of the License at
7cddda72410c992a12db61cef26713b498e31fea4Thanh Le *
8cddda72410c992a12db61cef26713b498e31fea4Thanh Le *      http://www.apache.org/licenses/LICENSE-2.0
9cddda72410c992a12db61cef26713b498e31fea4Thanh Le *
10cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Unless required by applicable law or agreed to in writing, software
11cddda72410c992a12db61cef26713b498e31fea4Thanh Le * distributed under the License is distributed on an "AS IS" BASIS,
12cddda72410c992a12db61cef26713b498e31fea4Thanh Le * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cddda72410c992a12db61cef26713b498e31fea4Thanh Le * See the License for the specific language governing permissions and
14cddda72410c992a12db61cef26713b498e31fea4Thanh Le * limitations under the License.
15cddda72410c992a12db61cef26713b498e31fea4Thanh Le */
16cddda72410c992a12db61cef26713b498e31fea4Thanh Le
17cddda72410c992a12db61cef26713b498e31fea4Thanh Lepackage com.google.android.droiddriver.instrumentation;
18cddda72410c992a12db61cef26713b498e31fea4Thanh Le
19115eb39036a7a4e500dc94b57975a5693861f654Tony Wickhamimport android.app.Activity;
20cddda72410c992a12db61cef26713b498e31fea4Thanh Leimport android.app.Instrumentation;
21e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jinimport android.graphics.Bitmap;
225838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jinimport android.os.SystemClock;
23cddda72410c992a12db61cef26713b498e31fea4Thanh Leimport android.view.View;
24cddda72410c992a12db61cef26713b498e31fea4Thanh Le
250d7b67b43f83536708a6ae0330e739744049a48eKevin Jinimport com.google.android.droiddriver.base.AbstractDroidDriver;
265838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jinimport com.google.android.droiddriver.exceptions.TimeoutException;
27115eb39036a7a4e500dc94b57975a5693861f654Tony Wickhamimport com.google.android.droiddriver.util.ActivityUtils;
285838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jinimport com.google.common.primitives.Longs;
290d7b67b43f83536708a6ae0330e739744049a48eKevin Jin
30cddda72410c992a12db61cef26713b498e31fea4Thanh Le/**
31cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Implementation of a UiDriver that is driven via instrumentation.
32cddda72410c992a12db61cef26713b498e31fea4Thanh Le */
33cddda72410c992a12db61cef26713b498e31fea4Thanh Lepublic class InstrumentationDriver extends AbstractDroidDriver {
3452107c27b6b0f2b0fdfec995784c73746bb95c4eKevin Jin  private final InstrumentationContext context;
35cddda72410c992a12db61cef26713b498e31fea4Thanh Le
36cddda72410c992a12db61cef26713b498e31fea4Thanh Le  public InstrumentationDriver(Instrumentation instrumentation) {
3721a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin    super(instrumentation);
3852107c27b6b0f2b0fdfec995784c73746bb95c4eKevin Jin    this.context = new InstrumentationContext(instrumentation);
39cddda72410c992a12db61cef26713b498e31fea4Thanh Le  }
40cddda72410c992a12db61cef26713b498e31fea4Thanh Le
41cddda72410c992a12db61cef26713b498e31fea4Thanh Le  @Override
4221a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin  protected ViewElement getNewRootElement() {
43c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin    return context.getUiElement(findRootView());
44c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin  }
45115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham
4621a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin  @Override
4721a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin  protected InstrumentationContext getContext() {
4821a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin    return context;
4921a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin  }
5021a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin
51c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin  private View findRootView() {
52c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin    Activity runningActivity = getRunningActivity();
53cddda72410c992a12db61cef26713b498e31fea4Thanh Le    View[] views = RootFinder.getRootViews();
54115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham    if (views.length > 1) {
55c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin      for (View view : views) {
56c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin        if (view.hasWindowFocus()) {
57c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin          return view;
58c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin        }
59c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin      }
60115eb39036a7a4e500dc94b57975a5693861f654Tony Wickham    }
61c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin    return runningActivity.getWindow().getDecorView();
62cddda72410c992a12db61cef26713b498e31fea4Thanh Le  }
63cddda72410c992a12db61cef26713b498e31fea4Thanh Le
645838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin  private Activity getRunningActivity() {
655838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin    long timeoutMillis = getPoller().getTimeoutMillis();
665838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin    long end = SystemClock.uptimeMillis() + timeoutMillis;
675838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin    while (true) {
6821a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin      instrumentation.waitForIdleSync();
695838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin      Activity runningActivity = ActivityUtils.getRunningActivity();
705838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin      if (runningActivity != null) {
715838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin        return runningActivity;
725838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin      }
735838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin      long remainingMillis = end - SystemClock.uptimeMillis();
745838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin      if (remainingMillis < 0) {
755838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin        throw new TimeoutException(String.format(
765838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin            "Timed out after %d milliseconds waiting for foreground activity", timeoutMillis));
775838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin      }
785838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin      SystemClock.sleep(Longs.min(250, remainingMillis));
795838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin    }
805838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin  }
815838b1a067427865c3ec8cc33a5dfa64ba05407fKevin Jin
82e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin  private static class ScreenshotRunnable implements Runnable {
83e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    private final View rootView;
84e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    private Bitmap screenshot;
85e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin
86e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    private ScreenshotRunnable(View rootView) {
87e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin      this.rootView = rootView;
88e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    }
89e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin
90e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    @Override
91e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    public void run() {
92e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin      rootView.destroyDrawingCache();
93e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin      rootView.buildDrawingCache(false);
946b3044b3bb260efec4b9c4cfe0fd8920841a6e7dKevin Jin      screenshot = Bitmap.createBitmap(rootView.getDrawingCache());
95e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin      rootView.destroyDrawingCache();
96e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    }
97e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin  }
98e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin
99e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin  @Override
100e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin  protected Bitmap takeScreenshot() {
101c91cb19438c6ef8ecd794664bf1f879725866bb9Kevin Jin    ScreenshotRunnable screenshotRunnable = new ScreenshotRunnable(findRootView());
10221a0001e2426644dd68e6140b5873ebaeafcc3dcKevin Jin    instrumentation.runOnMainSync(screenshotRunnable);
103e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin    return screenshotRunnable.screenshot;
104e2660726a43b1a68729d736f6ffa0332ab152498Kevin Jin  }
105cddda72410c992a12db61cef26713b498e31fea4Thanh Le}
106