OSDN Git Service

Use SurfaceControl.screenshot() instead of screencap for screenshots.
authorFelipe Leme <felipeal@google.com>
Fri, 29 Jul 2016 00:04:04 +0000 (17:04 -0700)
committerFelipe Leme <felipeal@google.com>
Fri, 29 Jul 2016 00:31:45 +0000 (17:31 -0700)
Change-Id: I5a9e7bbc5f3ae176ac5ae7209a133526992e92d4
Fixes: 30429392

packages/Shell/src/com/android/shell/BugreportProgressService.java
packages/Shell/src/com/android/shell/Screenshooter.java [new file with mode: 0644]

index f04df4b..5a75f40 100644 (file)
@@ -60,6 +60,8 @@ import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.hardware.display.DisplayManagerGlobal;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -78,6 +80,8 @@ import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Patterns;
 import android.util.SparseArray;
+import android.view.Display;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.View.OnFocusChangeListener;
@@ -771,7 +775,6 @@ public class BugreportProgressService extends Service {
             }
             msg = mContext.getString(R.string.bugreport_screenshot_taken);
         } else {
-            // TODO: try again using Framework APIs instead of relying on screencap.
             msg = mContext.getString(R.string.bugreport_screenshot_failed);
             Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
         }
@@ -1350,22 +1353,24 @@ public class BugreportProgressService extends Service {
     /**
      * Takes a screenshot and save it to the given location.
      */
-    private static boolean takeScreenshot(Context context, String screenshotFile) {
-        final ProcessBuilder screencap = new ProcessBuilder()
-                .command("/system/bin/screencap", "-p", screenshotFile);
-        Log.d(TAG, "Taking screenshot using " + screencap.command());
-        try {
-            final int exitValue = screencap.start().waitFor();
-            if (exitValue == 0) {
+    private static boolean takeScreenshot(Context context, String path) {
+        final Bitmap bitmap = Screenshooter.takeScreenshot();
+        if (bitmap == null) {
+            return false;
+        }
+        boolean status;
+        try (final FileOutputStream fos = new FileOutputStream(path)) {
+            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) {
                 ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150);
                 return true;
+            } else {
+                Log.e(TAG, "Failed to save screenshot on " + path);
             }
-            Log.e(TAG, "screencap (" + screencap.command() + ") failed: " + exitValue);
-        } catch (IOException e) {
-            Log.e(TAG, "screencap (" + screencap.command() + ") failed", e);
-        } catch (InterruptedException e) {
-            Log.w(TAG, "Thread interrupted while screencap still running");
-            Thread.currentThread().interrupt();
+        } catch (IOException e ) {
+            Log.e(TAG, "Failed to save screenshot on " + path, e);
+            return false;
+        } finally {
+            bitmap.recycle();
         }
         return false;
     }
diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java
new file mode 100644 (file)
index 0000000..3f4895b
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+/**
+ * Helper class used to take screenshots.
+ *
+ * TODO: logic below was copied and pasted from UiAutomation; it should be refactored into a common
+ * component that could be used by both (Shell and UiAutomation).
+ */
+final class Screenshooter {
+
+    private static final String TAG = "Screenshooter";
+
+    /** Rotation constant: Freeze rotation to 0 degrees (natural orientation) */
+    public static final int ROTATION_FREEZE_0 = Surface.ROTATION_0;
+
+    /** Rotation constant: Freeze rotation to 90 degrees . */
+    public static final int ROTATION_FREEZE_90 = Surface.ROTATION_90;
+
+    /** Rotation constant: Freeze rotation to 180 degrees . */
+    public static final int ROTATION_FREEZE_180 = Surface.ROTATION_180;
+
+    /** Rotation constant: Freeze rotation to 270 degrees . */
+    public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
+
+    /**
+     * Takes a screenshot.
+     *
+     * @return The screenshot bitmap on success, null otherwise.
+     */
+    static Bitmap takeScreenshot() {
+        Display display = DisplayManagerGlobal.getInstance()
+                .getRealDisplay(Display.DEFAULT_DISPLAY);
+        Point displaySize = new Point();
+        display.getRealSize(displaySize);
+        final int displayWidth = displaySize.x;
+        final int displayHeight = displaySize.y;
+
+        final float screenshotWidth;
+        final float screenshotHeight;
+
+        final int rotation = display.getRotation();
+        switch (rotation) {
+            case ROTATION_FREEZE_0: {
+                screenshotWidth = displayWidth;
+                screenshotHeight = displayHeight;
+            } break;
+            case ROTATION_FREEZE_90: {
+                screenshotWidth = displayHeight;
+                screenshotHeight = displayWidth;
+            } break;
+            case ROTATION_FREEZE_180: {
+                screenshotWidth = displayWidth;
+                screenshotHeight = displayHeight;
+            } break;
+            case ROTATION_FREEZE_270: {
+                screenshotWidth = displayHeight;
+                screenshotHeight = displayWidth;
+            } break;
+            default: {
+                throw new IllegalArgumentException("Invalid rotation: "
+                        + rotation);
+            }
+        }
+
+        Log.d(TAG, "Taking screenshot of dimensions " + displayWidth + " x " + displayHeight);
+        // Take the screenshot
+        Bitmap screenShot =
+                SurfaceControl.screenshot((int) screenshotWidth, (int) screenshotHeight);
+        if (screenShot == null) {
+            Log.e(TAG, "Failed to take screenshot of dimensions " + screenshotWidth + " x "
+                    + screenshotHeight);
+            return null;
+        }
+
+        // Rotate the screenshot to the current orientation
+        if (rotation != ROTATION_FREEZE_0) {
+            Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
+                    Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(unrotatedScreenShot);
+            canvas.translate(unrotatedScreenShot.getWidth() / 2,
+                    unrotatedScreenShot.getHeight() / 2);
+            canvas.rotate(getDegreesForRotation(rotation));
+            canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2);
+            canvas.drawBitmap(screenShot, 0, 0, null);
+            canvas.setBitmap(null);
+            screenShot.recycle();
+            screenShot = unrotatedScreenShot;
+        }
+
+        // Optimization
+        screenShot.setHasAlpha(false);
+
+        return screenShot;
+    }
+
+    private static float getDegreesForRotation(int value) {
+        switch (value) {
+            case Surface.ROTATION_90: {
+                return 360f - 90f;
+            }
+            case Surface.ROTATION_180: {
+                return 360f - 180f;
+            }
+            case Surface.ROTATION_270: {
+                return 360f - 270f;
+            } default: {
+                return 0;
+            }
+        }
+    }
+
+}