API tweaks to PixelCopy and make it public
Bug: 27708453
Change-Id: I81667ce42f9ca1c1a13e1e61299927900845fc84
diff --git a/api/current.txt b/api/current.txt
index 15fc149..a0d5a7f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -42046,6 +42046,21 @@
field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
}
+ public final class PixelCopy {
+ method public static void request(android.view.SurfaceView, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+ method public static void request(android.view.Surface, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+ field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
+ field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
+ field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
+ field public static final int ERROR_TIMEOUT = 2; // 0x2
+ field public static final int ERROR_UNKNOWN = 1; // 0x1
+ field public static final int SUCCESS = 0; // 0x0
+ }
+
+ public static abstract interface PixelCopy.OnPixelCopyFinishedListener {
+ method public abstract void onPixelCopyFinished(int);
+ }
+
public final class PointerIcon implements android.os.Parcelable {
method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float);
method public int describeContents();
diff --git a/api/system-current.txt b/api/system-current.txt
index c489435..1acb466 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -45059,6 +45059,21 @@
field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
}
+ public final class PixelCopy {
+ method public static void request(android.view.SurfaceView, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+ method public static void request(android.view.Surface, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+ field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
+ field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
+ field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
+ field public static final int ERROR_TIMEOUT = 2; // 0x2
+ field public static final int ERROR_UNKNOWN = 1; // 0x1
+ field public static final int SUCCESS = 0; // 0x0
+ }
+
+ public static abstract interface PixelCopy.OnPixelCopyFinishedListener {
+ method public abstract void onPixelCopyFinished(int);
+ }
+
public final class PointerIcon implements android.os.Parcelable {
method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float);
method public int describeContents();
diff --git a/api/test-current.txt b/api/test-current.txt
index f6340b2..18319dc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -42123,6 +42123,21 @@
field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
}
+ public final class PixelCopy {
+ method public static void request(android.view.SurfaceView, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+ method public static void request(android.view.Surface, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+ field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
+ field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
+ field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
+ field public static final int ERROR_TIMEOUT = 2; // 0x2
+ field public static final int ERROR_UNKNOWN = 1; // 0x1
+ field public static final int SUCCESS = 0; // 0x0
+ }
+
+ public static abstract interface PixelCopy.OnPixelCopyFinishedListener {
+ method public abstract void onPixelCopyFinished(int);
+ }
+
public final class PointerIcon implements android.os.Parcelable {
method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float);
method public int describeContents();
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 34110df..9c6e6b7 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -909,7 +909,7 @@
nSerializeDisplayListTree(mNativeProxy);
}
- public static boolean copySurfaceInto(Surface surface, Bitmap bitmap) {
+ public static int copySurfaceInto(Surface surface, Bitmap bitmap) {
return nCopySurfaceInto(surface, bitmap);
}
@@ -1051,5 +1051,5 @@
private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
- private static native boolean nCopySurfaceInto(Surface surface, Bitmap bitmap);
+ private static native int nCopySurfaceInto(Surface surface, Bitmap bitmap);
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 68c818e..650a0fc 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -669,7 +669,7 @@
proxy->setContentDrawBounds(left, top, right, bottom);
}
-static jboolean android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
+static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
jobject clazz, jobject jsurface, jobject jbitmap) {
SkBitmap bitmap;
GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
@@ -783,7 +783,7 @@
{ "nRemoveFrameMetricsObserver",
"(JJ)V",
(void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
- { "nCopySurfaceInto", "(Landroid/view/Surface;Landroid/graphics/Bitmap;)Z",
+ { "nCopySurfaceInto", "(Landroid/view/Surface;Landroid/graphics/Bitmap;)I",
(void*)android_view_ThreadedRenderer_copySurfaceInto },
};
diff --git a/graphics/java/android/graphics/PixelCopy.java b/graphics/java/android/graphics/PixelCopy.java
deleted file mode 100644
index c599126..0000000
--- a/graphics/java/android/graphics/PixelCopy.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package android.graphics;
-
-import android.annotation.NonNull;
-import android.os.Handler;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.ThreadedRenderer;
-
-/**
- * Provides a mechanisms to issue pixel copy requests to allow for copy
- * operations from {@link Surface} to {@link Bitmap}
- *
- * @hide
- */
-public final class PixelCopy {
- /**
- * Contains the result of a pixel copy request
- */
- public static final class Response {
- /**
- * Indicates whether or not the copy request completed successfully.
- * If this is true, then {@link #bitmap} contains the result of the copy.
- * If this is false, {@link #bitmap} is unmodified from the originally
- * passed destination.
- *
- * For example a request might fail if the source is protected content
- * so copies are not allowed. Similarly if the source has nothing to
- * copy from, because either no frames have been produced yet or because
- * it has already been destroyed, then this will be false.
- */
- public boolean success;
-
- /**
- * The output bitmap. This is always the same object that was passed
- * to request() as the 'dest' bitmap. If {@link #success} is true this
- * contains a copy of the pixels of the source object. If {@link #success}
- * is false then this is unmodified.
- */
- @NonNull
- public Bitmap bitmap;
- }
-
- public interface OnPixelCopyFinished {
- /**
- * Callback for when a pixel copy request has completed. This will be called
- * regardless of whether the copy succeeded or failed.
- *
- * @param response Contains the result of the copy request which includes
- * whether or not the copy was successful.
- */
- void onPixelCopyFinished(PixelCopy.Response response);
- }
-
- /**
- * Requests for the display content of a {@link SurfaceView} to be copied
- * into a provided {@link Bitmap}.
- *
- * The contents of the source will be scaled to fit exactly inside the bitmap.
- * The pixel format of the source buffer will be converted, as part of the copy,
- * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
- * in the SurfaceView's Surface will be used as the source of the copy.
- *
- * @param source The source from which to copy
- * @param dest The destination of the copy. The source will be scaled to
- * match the width, height, and format of this bitmap.
- * @param listener Callback for when the pixel copy request completes
- * @param listenerThread The callback will be invoked on this Handler when
- * the copy is finished.
- */
- public static void request(@NonNull SurfaceView source, @NonNull Bitmap dest,
- @NonNull OnPixelCopyFinished listener, @NonNull Handler listenerThread) {
- request(source.getHolder().getSurface(), dest, listener, listenerThread);
- }
-
- /**
- * Requests a copy of the pixels from a {@link Surface} to be copied into
- * a provided {@link Bitmap}.
- *
- * The contents of the source will be scaled to fit exactly inside the bitmap.
- * The pixel format of the source buffer will be converted, as part of the copy,
- * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
- * in the Surface will be used as the source of the copy.
- *
- * @param source The source from which to copy
- * @param dest The destination of the copy. The source will be scaled to
- * match the width, height, and format of this bitmap.
- * @param listener Callback for when the pixel copy request completes
- * @param listenerThread The callback will be invoked on this Handler when
- * the copy is finished.
- */
- public static void request(@NonNull Surface source, @NonNull Bitmap dest,
- @NonNull OnPixelCopyFinished listener, @NonNull Handler listenerThread) {
- // TODO: Make this actually async and fast and cool and stuff
- final PixelCopy.Response response = new PixelCopy.Response();
- response.success = ThreadedRenderer.copySurfaceInto(source, dest);
- response.bitmap = dest;
- listenerThread.post(new Runnable() {
- @Override
- public void run() {
- listener.onPixelCopyFinished(response);
- }
- });
- }
-}
diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java
new file mode 100644
index 0000000..95c930c
--- /dev/null
+++ b/graphics/java/android/view/PixelCopy.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016 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 android.view;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.graphics.Bitmap;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Provides a mechanisms to issue pixel copy requests to allow for copy
+ * operations from {@link Surface} to {@link Bitmap}
+ */
+public final class PixelCopy {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SUCCESS, ERROR_UNKNOWN, ERROR_TIMEOUT, ERROR_SOURCE_NO_DATA,
+ ERROR_SOURCE_INVALID, ERROR_DESTINATION_INVALID})
+ public @interface CopyResultStatus {}
+
+ /** The pixel copy request succeeded */
+ public static final int SUCCESS = 0;
+
+ /** The pixel copy request failed with an unknown error. */
+ public static final int ERROR_UNKNOWN = 1;
+
+ /**
+ * A timeout occurred while trying to acquire a buffer from the source to
+ * copy from.
+ */
+ public static final int ERROR_TIMEOUT = 2;
+
+ /**
+ * The source has nothing to copy from. When the source is a {@link Surface}
+ * this means that no buffers have been queued yet. Wait for the source
+ * to produce a frame and try again.
+ */
+ public static final int ERROR_SOURCE_NO_DATA = 3;
+
+ /**
+ * It is not possible to copy from the source. This can happen if the source
+ * is hardware-protected or destroyed.
+ */
+ public static final int ERROR_SOURCE_INVALID = 4;
+
+ /**
+ * The destination isn't a valid copy target. If the destination is a bitmap
+ * this can occur if the bitmap is too large for the hardware to copy to.
+ * It can also occur if the destination has been destroyed.
+ */
+ public static final int ERROR_DESTINATION_INVALID = 5;
+
+ /**
+ * Listener for observing the completion of a PixelCopy request.
+ */
+ public interface OnPixelCopyFinishedListener {
+ /**
+ * Callback for when a pixel copy request has completed. This will be called
+ * regardless of whether the copy succeeded or failed.
+ *
+ * @param copyResult Contains the resulting status of the copy request.
+ * This will either be {@link PixelCopy#SUCCESS} or one of the
+ * <code>PixelCopy.ERROR_*</code> values.
+ */
+ void onPixelCopyFinished(@CopyResultStatus int copyResult);
+ }
+
+ /**
+ * Requests for the display content of a {@link SurfaceView} to be copied
+ * into a provided {@link Bitmap}.
+ *
+ * The contents of the source will be scaled to fit exactly inside the bitmap.
+ * The pixel format of the source buffer will be converted, as part of the copy,
+ * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+ * in the SurfaceView's Surface will be used as the source of the copy.
+ *
+ * @param source The source from which to copy
+ * @param dest The destination of the copy. The source will be scaled to
+ * match the width, height, and format of this bitmap.
+ * @param listener Callback for when the pixel copy request completes
+ * @param listenerThread The callback will be invoked on this Handler when
+ * the copy is finished.
+ */
+ public static void request(@NonNull SurfaceView source, @NonNull Bitmap dest,
+ @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
+ request(source.getHolder().getSurface(), dest, listener, listenerThread);
+ }
+
+ /**
+ * Requests a copy of the pixels from a {@link Surface} to be copied into
+ * a provided {@link Bitmap}.
+ *
+ * The contents of the source will be scaled to fit exactly inside the bitmap.
+ * The pixel format of the source buffer will be converted, as part of the copy,
+ * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+ * in the Surface will be used as the source of the copy.
+ *
+ * @param source The source from which to copy
+ * @param dest The destination of the copy. The source will be scaled to
+ * match the width, height, and format of this bitmap.
+ * @param listener Callback for when the pixel copy request completes
+ * @param listenerThread The callback will be invoked on this Handler when
+ * the copy is finished.
+ */
+ public static void request(@NonNull Surface source, @NonNull Bitmap dest,
+ @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
+ validateBitmapDest(dest);
+ // TODO: Make this actually async and fast and cool and stuff
+ int result = ThreadedRenderer.copySurfaceInto(source, dest);
+ listenerThread.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onPixelCopyFinished(result);
+ }
+ });
+ }
+
+ private static void validateBitmapDest(Bitmap bitmap) {
+ // TODO: Pre-check max texture dimens if we can
+ if (bitmap == null) {
+ throw new IllegalArgumentException("Bitmap cannot be null");
+ }
+ if (bitmap.isRecycled()) {
+ throw new IllegalArgumentException("Bitmap is recycled");
+ }
+ if (!bitmap.isMutable()) {
+ throw new IllegalArgumentException("Bitmap is immutable");
+ }
+ }
+
+ private PixelCopy() {}
+}
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 4a32589..49596e1 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -30,7 +30,7 @@
namespace android {
namespace uirenderer {
-bool Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
+CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
Surface& surface, SkBitmap* bitmap) {
// TODO: Clean this up and unify it with LayerRenderer::copyLayer,
// of which most of this is copied from.
@@ -44,12 +44,12 @@
|| destHeight > caches.maxTextureSize) {
ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d",
destWidth, destHeight, caches.maxTextureSize);
- return false;
+ return CopyResult::DestinationInvalid;
}
GLuint fbo = renderState.createFramebuffer();
if (!fbo) {
ALOGW("Could not obtain an FBO");
- return false;
+ return CopyResult::UnknownError;
}
SkAutoLockPixels alp(*bitmap);
@@ -104,16 +104,20 @@
status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence);
if (err != NO_ERROR) {
ALOGW("Failed to get last queued buffer, error = %d", err);
- return false;
+ return CopyResult::UnknownError;
}
if (!sourceBuffer.get()) {
ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
- return false;
+ return CopyResult::SourceEmpty;
+ }
+ if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
+ ALOGW("Surface is protected, unable to copy from it");
+ return CopyResult::SourceInvalid;
}
err = sourceFence->wait(500 /* ms */);
if (err != NO_ERROR) {
ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
- return false;
+ return CopyResult::Timeout;
}
// TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
@@ -130,7 +134,7 @@
if (sourceImage == EGL_NO_IMAGE_KHR) {
ALOGW("Error creating image (%#x)", eglGetError());
- return false;
+ return CopyResult::UnknownError;
}
GLuint sourceTexId;
// Create a 2D texture to sample from the EGLImage
@@ -141,7 +145,7 @@
GLenum status = GL_NO_ERROR;
while ((status = glGetError()) != GL_NO_ERROR) {
ALOGW("Error creating image (%#x)", status);
- return false;
+ return CopyResult::UnknownError;
}
Texture sourceTexture(caches);
@@ -178,7 +182,7 @@
GL_CHECKPOINT(MODERATE);
- return true;
+ return CopyResult::Success;
}
} // namespace uirenderer
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index ea03c82..a112c42 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -24,9 +24,19 @@
namespace android {
namespace uirenderer {
+// Keep in sync with PixelCopy.java codes
+enum class CopyResult {
+ Success = 0,
+ UnknownError = 1,
+ Timeout = 2,
+ SourceEmpty = 3,
+ SourceInvalid = 4,
+ DestinationInvalid = 5,
+};
+
class Readback {
public:
- static bool copySurfaceInto(renderthread::RenderThread& renderThread,
+ static CopyResult copySurfaceInto(renderthread::RenderThread& renderThread,
Surface& surface, SkBitmap* bitmap);
};
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 5e37856..54af282 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -623,12 +623,13 @@
*args->surface, args->bitmap);
}
-bool RenderProxy::copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap) {
+int RenderProxy::copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap) {
SETUP_TASK(copySurfaceInto);
args->bitmap = bitmap;
args->surface = surface.get();
args->thread = &RenderThread::getInstance();
- return (bool) staticPostAndWait(task);
+ return static_cast<int>(
+ reinterpret_cast<intptr_t>( staticPostAndWait(task) ));
}
void RenderProxy::post(RenderTask* task) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c39319d..898b314 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -127,7 +127,7 @@
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API long getDroppedFrameReportCount();
- ANDROID_API static bool copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap);
+ ANDROID_API static int copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap);
private:
RenderThread& mRenderThread;
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
index d3cd7db..f658b7c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
@@ -18,13 +18,11 @@
import android.app.Activity;
import android.graphics.Bitmap;
-import android.graphics.PixelCopy;
-import android.graphics.PixelCopy.OnPixelCopyFinished;
-import android.graphics.PixelCopy.Response;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Environment;
import android.view.Gravity;
+import android.view.PixelCopy;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
@@ -32,7 +30,6 @@
import android.widget.FrameLayout;
import android.widget.Toast;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -52,12 +49,25 @@
Button button = new Button(this);
button.setText("Copy bitmap to /sdcard/surfaceview.png");
button.setOnClickListener((View v) -> {
- Bitmap b = Bitmap.createBitmap(
- mSurfaceView.getWidth(),
- mSurfaceView.getHeight(),
- Bitmap.Config.ARGB_8888);
+ final Bitmap b = Bitmap.createBitmap(
+ mSurfaceView.getWidth(), mSurfaceView.getHeight(),
+ Bitmap.Config.ARGB_8888);
PixelCopy.request(mSurfaceView, b,
- mOnCopyFinished, mSurfaceView.getHandler());
+ (int result) -> {
+ if (result != PixelCopy.SUCCESS) {
+ Toast.makeText(GetBitmapSurfaceViewActivity.this,
+ "Failed to copy", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ try {
+ try (FileOutputStream out = new FileOutputStream(
+ Environment.getExternalStorageDirectory() + "/surfaceview.png");) {
+ b.compress(Bitmap.CompressFormat.PNG, 100, out);
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ }, mSurfaceView.getHandler());
});
content.addView(mSurfaceView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
@@ -67,25 +77,6 @@
setContentView(content);
}
- private final OnPixelCopyFinished mOnCopyFinished = new OnPixelCopyFinished() {
- @Override
- public void onPixelCopyFinished(Response response) {
- if (!response.success) {
- Toast.makeText(GetBitmapSurfaceViewActivity.this,
- "Failed to copy", Toast.LENGTH_SHORT).show();
- return;
- }
- try {
- try (FileOutputStream out = new FileOutputStream(
- Environment.getExternalStorageDirectory() + "/surfaceview.png");) {
- response.bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- }
- } catch (Exception e) {
- // Ignore
- }
- }
- };
-
@Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java
index 5c30fab..086a8f0 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java
@@ -20,12 +20,10 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.PixelCopy;
-import android.graphics.PixelCopy.OnPixelCopyFinished;
-import android.graphics.PixelCopy.Response;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.os.Environment;
+import android.view.PixelCopy;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
@@ -36,9 +34,7 @@
import android.widget.LinearLayout;
import android.widget.Toast;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.IOException;
public class HardwareCanvasSurfaceViewActivity extends Activity implements Callback {
private SurfaceView mSurfaceView;
@@ -56,12 +52,25 @@
Button button = new Button(this);
button.setText("Copy bitmap to /sdcard/surfaceview.png");
button.setOnClickListener((View v) -> {
- Bitmap b = Bitmap.createBitmap(
- mSurfaceView.getWidth(),
- mSurfaceView.getHeight(),
- Bitmap.Config.ARGB_8888);
+ final Bitmap b = Bitmap.createBitmap(
+ mSurfaceView.getWidth(), mSurfaceView.getHeight(),
+ Bitmap.Config.ARGB_8888);
PixelCopy.request(mSurfaceView, b,
- mOnCopyFinished, mSurfaceView.getHandler());
+ (int result) -> {
+ if (result != PixelCopy.SUCCESS) {
+ Toast.makeText(HardwareCanvasSurfaceViewActivity.this,
+ "Failed to copy", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ try {
+ try (FileOutputStream out = new FileOutputStream(
+ Environment.getExternalStorageDirectory() + "/surfaceview.png");) {
+ b.compress(Bitmap.CompressFormat.PNG, 100, out);
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ }, mSurfaceView.getHandler());
});
LinearLayout layout = new LinearLayout(this);
@@ -77,25 +86,6 @@
setContentView(content);
}
- private final OnPixelCopyFinished mOnCopyFinished = new OnPixelCopyFinished() {
- @Override
- public void onPixelCopyFinished(Response response) {
- if (!response.success) {
- Toast.makeText(HardwareCanvasSurfaceViewActivity.this,
- "Failed to copy", Toast.LENGTH_SHORT).show();
- return;
- }
- try {
- try (FileOutputStream out = new FileOutputStream(
- Environment.getExternalStorageDirectory() + "/surfaceview.png");) {
- response.bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- }
- } catch (Exception e) {
- // Ignore
- }
- }
- };
-
@Override
public void surfaceCreated(SurfaceHolder holder) {
mThread = new RenderingThread(holder.getSurface());