Merge "API tweaks to PixelCopy and make it public" into nyc-dev
am: 7f209d3 * commit '7f209d37f17d4df09475137c38b84a3338c84023': API tweaks to PixelCopy and make it public Change-Id: I3642b7c915213f9c9bcc5ede1710335d56eb9d75
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
150
graphics/java/android/view/PixelCopy.java
Normal file
150
graphics/java/android/view/PixelCopy.java
Normal file
@@ -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() {}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user