diff options
author | John Reck <jreck@google.com> | 2016-04-27 14:36:51 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-04-27 14:36:53 +0000 |
commit | 7f209d37f17d4df09475137c38b84a3338c84023 (patch) | |
tree | 07856ff96c1e32df08aef9ad73b7b8216d16f9c0 | |
parent | 9fa8b54589b68dc6da3a7201cad1fc43e01e59e3 (diff) | |
parent | e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1 (diff) |
Merge "API tweaks to PixelCopy and make it public" into nyc-dev
-rw-r--r-- | api/current.txt | 15 | ||||
-rw-r--r-- | api/system-current.txt | 15 | ||||
-rw-r--r-- | api/test-current.txt | 15 | ||||
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 4 | ||||
-rw-r--r-- | core/jni/android_view_ThreadedRenderer.cpp | 4 | ||||
-rw-r--r-- | graphics/java/android/graphics/PixelCopy.java | 104 | ||||
-rw-r--r-- | graphics/java/android/view/PixelCopy.java | 150 | ||||
-rw-r--r-- | libs/hwui/Readback.cpp | 22 | ||||
-rw-r--r-- | libs/hwui/Readback.h | 12 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 5 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 2 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java | 47 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java | 48 |
13 files changed, 265 insertions, 178 deletions
diff --git a/api/current.txt b/api/current.txt index f267789600e6..1810d7802e4f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -42049,6 +42049,21 @@ package android.view { 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 f9d8d34de88c..3fe962efff7c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -45039,6 +45039,21 @@ package android.view { 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 25e58e2780c2..e5e84e7b3373 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -42127,6 +42127,21 @@ package android.view { 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 34110df5767a..9c6e6b7ee77c 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -909,7 +909,7 @@ public final class ThreadedRenderer { 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 @@ public final class ThreadedRenderer { 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 68c818e92e5c..650a0fc82a7b 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -669,7 +669,7 @@ static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env, 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 @@ static const JNINativeMethod gMethods[] = { { "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 c5991264e555..000000000000 --- 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 000000000000..95c930c5264d --- /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 4a325897d4ec..49596e143ebf 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 @@ bool Readback::copySurfaceInto(renderthread::RenderThread& renderThread, || 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 @@ bool Readback::copySurfaceInto(renderthread::RenderThread& renderThread, 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 @@ bool Readback::copySurfaceInto(renderthread::RenderThread& renderThread, 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 @@ bool Readback::copySurfaceInto(renderthread::RenderThread& renderThread, 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 @@ bool Readback::copySurfaceInto(renderthread::RenderThread& renderThread, GL_CHECKPOINT(MODERATE); - return true; + return CopyResult::Success; } } // namespace uirenderer diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index ea03c829f492..a112c42988c0 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 5e37856ecce9..54af2829cf40 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -623,12 +623,13 @@ CREATE_BRIDGE3(copySurfaceInto, RenderThread* thread, *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 c39319da4b39..898b31421aad 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -127,7 +127,7 @@ public: 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 d3cd7db7d46a..f658b7c05e66 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 @@ package com.android.test.hwui; 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.Button; import android.widget.FrameLayout; import android.widget.Toast; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -52,12 +49,25 @@ public class GetBitmapSurfaceViewActivity extends Activity implements SurfaceHol 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 @@ public class GetBitmapSurfaceViewActivity extends Activity implements SurfaceHol 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 5c30faba3d18..086a8f0126b3 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.app.Activity; 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.FrameLayout; 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 @@ public class HardwareCanvasSurfaceViewActivity extends Activity implements Callb 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 @@ public class HardwareCanvasSurfaceViewActivity extends Activity implements Callb 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()); |