diff options
author | Svet Ganov <svetoslavganov@google.com> | 2014-09-03 23:33:29 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-09-03 23:33:30 +0000 |
commit | def58cbffc32d12445b60ed1a0d8bb81d8dc6625 (patch) | |
tree | d5e45acfc13e34c6dab739d6a0a09a94ebbba680 | |
parent | b541f09be309f5f314760ff832bda245e6ec9cdd (diff) | |
parent | df6444931b030d3cdd9769e23f16f0a16fe9c654 (diff) | |
download | frameworks_base-def58cbffc32d12445b60ed1a0d8bb81d8dc6625.zip frameworks_base-def58cbffc32d12445b60ed1a0d8bb81d8dc6625.tar.gz frameworks_base-def58cbffc32d12445b60ed1a0d8bb81d8dc6625.tar.bz2 |
Merge "Switching to raw byte copy of bitmaps for print preview." into lmp-dev
7 files changed, 279 insertions, 13 deletions
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk index 4948a02..6e1402c 100644 --- a/packages/PrintSpooler/Android.mk +++ b/packages/PrintSpooler/Android.mk @@ -26,3 +26,5 @@ LOCAL_PACKAGE_NAME := PrintSpooler LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview include $(BUILD_PACKAGE) + +include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file diff --git a/packages/PrintSpooler/jni/Android.mk b/packages/PrintSpooler/jni/Android.mk new file mode 100644 index 0000000..fbf56be --- /dev/null +++ b/packages/PrintSpooler/jni/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + com_android_printspooler_util_BitmapSerializeUtils.cpp \ + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper + +LOCAL_LDLIBS := -lm -llog -ljnigraphics + +LOCAL_MODULE := libprintspooler_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp new file mode 100644 index 0000000..57281c8 --- /dev/null +++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2014 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. + */ + +#define LOG_TAG "BitmapSerializeUtils" + +#include <jni.h> +#include <JNIHelp.h> + +#include <android/bitmap.h> +#include <android/log.h> + +namespace android { + +#define RGBA_8888_COLOR_DEPTH 4 + +static bool writeAllBytes(const int fd, void* buffer, const size_t byteCount) { + char* writeBuffer = static_cast<char*>(buffer); + size_t remainingBytes = byteCount; + while (remainingBytes > 0) { + ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes); + if (writtenByteCount == -1) { + if (errno == EINTR) { + continue; + } + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, + "Error writing to buffer: %d", errno); + return false; + } + remainingBytes -= writtenByteCount; + writeBuffer += writtenByteCount; + } + return true; +} + +static bool readAllBytes(const int fd, void* buffer, const size_t byteCount) { + char* readBuffer = static_cast<char*>(buffer); + size_t remainingBytes = byteCount; + while (remainingBytes > 0) { + ssize_t readByteCount = read(fd, readBuffer, remainingBytes); + if (readByteCount == -1) { + if (errno == EINTR) { + continue; + } + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, + "Error reading from buffer: %d", errno); + return false; + } + remainingBytes -= readByteCount; + readBuffer += readByteCount; + } + return true; +} + +static void throwException(JNIEnv* env, const char* className, const char* message) { + jclass exceptionClass = env->FindClass(className); + env->ThrowNew(exceptionClass, message); +} + +static void throwIllegalStateException(JNIEnv* env, char *message) { + const char* className = "java/lang/IllegalStateException"; + throwException(env, className, message); +} + +static void throwIllegalArgumentException(JNIEnv* env, char* message) { + const char* className = "java/lang/IllegalArgumentException"; + throwException(env, className, message); +} + +static void readBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) { + // Read the info. + AndroidBitmapInfo readInfo; + bool read = readAllBytes(fd, (void*) &readInfo, sizeof(AndroidBitmapInfo)); + if (!read) { + throwIllegalStateException(env, (char*) "Cannot read bitmap info"); + return; + } + + // Get the info of the target bitmap. + AndroidBitmapInfo targetInfo; + int result = AndroidBitmap_getInfo(env, jbitmap, &targetInfo); + if (result < 0) { + throwIllegalStateException(env, (char*) "Cannot get bitmap info"); + return; + } + + // Enforce we can reuse the bitmap. + if (readInfo.width != targetInfo.width || readInfo.height != targetInfo.height + || readInfo.stride != targetInfo.stride || readInfo.format != targetInfo.format + || readInfo.flags != targetInfo.flags) { + throwIllegalArgumentException(env, (char*) "Cannot reuse bitmap"); + return; + } + + // Lock the pixels. + void* pixels; + result = AndroidBitmap_lockPixels(env, jbitmap, &pixels); + if (result < 0) { + throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels"); + return; + } + + // Read the pixels. + size_t byteCount = readInfo.stride * readInfo.height; + read = readAllBytes(fd, (void*) pixels, byteCount); + if (!read) { + throwIllegalStateException(env, (char*) "Cannot read bitmap pixels"); + return; + } + + // Unlock the pixels. + result = AndroidBitmap_unlockPixels(env, jbitmap); + if (result < 0) { + throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels"); + } +} + +static void writeBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) { + // Get the info. + AndroidBitmapInfo info; + int result = AndroidBitmap_getInfo(env, jbitmap, &info); + if (result < 0) { + throwIllegalStateException(env, (char*) "Cannot get bitmap info"); + return; + } + + // Write the info. + bool written = writeAllBytes(fd, (void*) &info, sizeof(AndroidBitmapInfo)); + if (!written) { + throwIllegalStateException(env, (char*) "Cannot write bitmap info"); + return; + } + + // Lock the pixels. + void* pixels; + result = AndroidBitmap_lockPixels(env, jbitmap, &pixels); + if (result < 0) { + throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels"); + return; + } + + // Write the pixels. + size_t byteCount = info.stride * info.height; + written = writeAllBytes(fd, (void*) pixels, byteCount); + if (!written) { + throwIllegalStateException(env, (char*) "Cannot write bitmap pixels"); + return; + } + + // Unlock the pixels. + result = AndroidBitmap_unlockPixels(env, jbitmap); + if (result < 0) { + throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels"); + } +} + +static JNINativeMethod sMethods[] = { + {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels}, + {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels}, +}; + +int register_com_android_printspooler_util_BitmapSerializeUtils(JNIEnv* env) { + return jniRegisterNativeMethods(env, "com/android/printspooler/util/BitmapSerializeUtils", + sMethods, NELEM(sMethods)); +} + +} + +jint JNI_OnLoad(JavaVM* jvm, void*) { + JNIEnv *env = NULL; + if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6)) { + return JNI_ERR; + } + + if (android::register_com_android_printspooler_util_BitmapSerializeUtils(env) == -1) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java index 1382f55..a581e8a 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.os.AsyncTask; @@ -39,6 +38,7 @@ import android.view.View; import com.android.internal.annotations.GuardedBy; import com.android.printspooler.renderer.IPdfRenderer; import com.android.printspooler.renderer.PdfRendererService; +import com.android.printspooler.util.BitmapSerializeUtils; import dalvik.system.CloseGuard; import libcore.io.IoUtils; @@ -815,9 +815,7 @@ public final class PageContentRepository { // ownership, so close our copy for the write to complete. destination.close(); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inBitmap = bitmap; - BitmapFactory.decodeFileDescriptor(source.getFileDescriptor(), null, options); + BitmapSerializeUtils.readBitmapPixels(bitmap, source); } catch (IOException|RemoteException e) { Log.e(LOG_TAG, "Error rendering page:" + mPageIndex, e); } finally { diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java index 5012cad..4d02c01 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java @@ -33,8 +33,7 @@ import android.print.PrintAttributes.Margins; import android.util.Log; import android.view.View; import libcore.io.IoUtils; - -import java.io.FileOutputStream; +import com.android.printspooler.util.BitmapSerializeUtils; import java.io.IOException; /** @@ -77,7 +76,6 @@ public final class PdfRendererService extends Service { @Override public void renderPage(int pageIndex, int bitmapWidth, int bitmapHeight, PrintAttributes attributes, ParcelFileDescriptor destination) { - FileOutputStream out = null; synchronized (mLock) { try { throwIfNotOpened(); @@ -137,10 +135,8 @@ public final class PdfRendererService extends Service { page.close(); - out = new FileOutputStream(destination.getFileDescriptor()); - bitmap.compress(Bitmap.CompressFormat.PNG, 0, out); + BitmapSerializeUtils.writeBitmapPixels(bitmap, destination); } finally { - IoUtils.closeQuietly(out); IoUtils.closeQuietly(destination); } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java new file mode 100644 index 0000000..a1845f6 --- /dev/null +++ b/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 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.printspooler.util; + +import android.graphics.Bitmap; +import android.os.ParcelFileDescriptor; + +/** + * Helper for serialization of bitmaps in the very specific + * use case of having the same bitmap on both ends and just + * marshaling the pixels from one side to the other. + */ +public final class BitmapSerializeUtils { + + static { + System.loadLibrary("printspooler_jni"); + } + + private BitmapSerializeUtils() { + /* do nothing */ + } + + /** + * Reads a bitmap pixels from a file descriptor. + * + * @param bitmap A bitmap whose pixels to populate. + * @param source The source file descriptor. + */ + public static void readBitmapPixels(Bitmap bitmap, ParcelFileDescriptor source) { + nativeReadBitmapPixels(bitmap, source.getFd()); + } + + /** + * Writes a bitmap pixels to a file descriptor. + * + * @param bitmap The bitmap. + * @param destination The destination file descriptor. + */ + public static void writeBitmapPixels(Bitmap bitmap, ParcelFileDescriptor destination) { + nativeWriteBitmapPixels(bitmap, destination.getFd()); + } + + private static native void nativeReadBitmapPixels(Bitmap bitmap, int fd); + + private static native void nativeWriteBitmapPixels(Bitmap bitmap, int fd); +} diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java index d935f58..23a01bd 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java +++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java @@ -77,9 +77,8 @@ public class PageContentView extends View @Override public void onPageContentAvailable(BitmapDrawable content) { - if (getBackground() != content) { - setBackground(content); - } + assert (getBackground() != content); + setBackground(content); } public PageContentProvider getPageContentProvider() { |