square / spoon

Distributing instrumentation tests to all your Androids.
https://square.github.io/spoon/
Apache License 2.0
2.7k stars 477 forks source link

Screenshot does not have elevation on views. #542

Closed jacksierkstra closed 6 years ago

jacksierkstra commented 6 years ago

Spoon client version: 1.6.4. Spoon runner version: spoon-runner-1.7.1-jar-with-dependencies.jar.

I have been playing around with Spoon for some time and I discovered a problem with the created screenshots. They do not incorporate the elevation that is present on CardView for example. This is because of the way how Spoon creates it's screenshots.

At first I didn't know if it was related to Spoon or my views, so I copied the Spoon implementation of taking screenshots and started experimenting. This is the implementation I took:

private static void takeScreenshot(File file, final Activity activity) throws IOException {
    View view = activity.getWindow().getDecorView();
    final Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), ARGB_8888);

    if (Looper.myLooper() == Looper.getMainLooper()) {
      // On main thread already, Just Do It™.
      drawDecorViewToBitmap(activity, bitmap);
    } else {
      // On a background thread, post to main.
      final CountDownLatch latch = new CountDownLatch(1);
      activity.runOnUiThread(new Runnable() {
        @Override public void run() {
          try {
            drawDecorViewToBitmap(activity, bitmap);
          } finally {
            latch.countDown();
          }
        }
      });
      try {
        latch.await();
      } catch (InterruptedException e) {
        String msg = "Unable to get screenshot " + file.getAbsolutePath();
        Log.e(TAG, msg, e);
        throw new RuntimeException(msg, e);
      }
    }

    OutputStream fos = null;
    try {
      fos = new BufferedOutputStream(new FileOutputStream(file));
      bitmap.compress(PNG, 100 /* quality */, fos);

      chmodPlusR(file);
    } finally {
      bitmap.recycle();
      if (fos != null) {
        fos.close();
      }
    }
  }

Because it was me giving odd results, I went searching for a solution and stumbled upon this post: https://stackoverflow.com/questions/34795786/how-to-capture-screenshot-with-shadow-using-getdrawingcache

I quickly tried to make a screenshot with the following implementation, which worked as expected (it is in kotlin).

@Throws(IOException::class)
    private fun takeScreenshot(file: File) {
        val bitmap = InstrumentationRegistry.getInstrumentation().uiAutomation.takeScreenshot()

        var fos: OutputStream? = null
        try {
            fos = BufferedOutputStream(FileOutputStream(file))
            bitmap.compress(android.graphics.Bitmap.CompressFormat.PNG, 100, fos)

        chmodPlusR(file)
        } finally {
            bitmap.recycle()
            fos?.close()
        }
    }
JakeWharton commented 6 years ago

Yes this is a known limitation. A better means of screenshot is tracked by #4