summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
commitf013e1afd1e68af5e3b868c26a653bbfb39538f8 (patch)
tree7ad6c8fd9c7b55f4b4017171dec1cb760bbd26bf /core/jni
parente70cfafe580c6f2994c4827cd8a534aabf3eb05c (diff)
downloadframeworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.zip
frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.gz
frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/Android.mk18
-rw-r--r--core/jni/AndroidRuntime.cpp75
-rw-r--r--core/jni/android/graphics/Bitmap.cpp1134
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp93
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp109
-rw-r--r--core/jni/android/graphics/Graphics.cpp4
-rw-r--r--core/jni/android/graphics/Movie.cpp2
-rw-r--r--core/jni/android/graphics/NinePatch.cpp47
-rw-r--r--core/jni/android/graphics/NinePatchImpl.cpp4
-rw-r--r--core/jni/android/graphics/Paint.cpp39
-rw-r--r--core/jni/android/graphics/Shader.cpp70
-rw-r--r--core/jni/android_bluetooth_common.h9
-rw-r--r--core/jni/android_database_SQLiteProgram.cpp2
-rw-r--r--core/jni/android_database_SQLiteQuery.cpp18
-rw-r--r--core/jni/android_hardware_Camera.cpp86
-rw-r--r--core/jni/android_hardware_SensorManager.cpp127
-rw-r--r--core/jni/android_media_AudioRecord.cpp566
-rw-r--r--core/jni/android_media_AudioTrack.cpp832
-rw-r--r--core/jni/android_media_ToneGenerator.cpp2
-rw-r--r--core/jni/android_net_LocalSocketImpl.cpp4
-rw-r--r--core/jni/android_net_NetUtils.cpp14
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp30
-rw-r--r--core/jni/android_server_BluetoothA2dpService.cpp417
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp161
-rw-r--r--core/jni/android_text_AndroidCharacter.cpp4
-rw-r--r--core/jni/android_text_format_Time.cpp (renamed from core/jni/android_pim_Time.cpp)263
-rw-r--r--core/jni/android_util_AssetManager.cpp15
-rw-r--r--core/jni/android_util_Process.cpp6
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp11
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp26
-rw-r--r--core/jni/server/Android.mk2
-rw-r--r--core/jni/server/com_android_server_AlarmManagerService.cpp18
-rw-r--r--core/jni/server/com_android_server_SensorService.cpp30
33 files changed, 3224 insertions, 1014 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index e9009e6..2c74ab7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -11,6 +11,10 @@ else
LOCAL_CFLAGS += -DPACKED=""
endif
+ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),)
+ LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX)
+endif
+
LOCAL_SRC_FILES:= \
ActivityManager.cpp \
AndroidRuntime.cpp \
@@ -45,7 +49,7 @@ LOCAL_SRC_FILES:= \
android_net_wifi_Wifi.cpp \
android_nio_utils.cpp \
android_pim_EventRecurrence.cpp \
- android_pim_Time.cpp \
+ android_text_format_Time.cpp \
android_security_Md5MessageDigest.cpp \
android_util_AssetManager.cpp \
android_util_Binder.cpp \
@@ -84,7 +88,9 @@ LOCAL_SRC_FILES:= \
android/graphics/Shader.cpp \
android/graphics/Typeface.cpp \
android/graphics/Xfermode.cpp \
+ android_media_AudioRecord.cpp \
android_media_AudioSystem.cpp \
+ android_media_AudioTrack.cpp \
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
@@ -100,6 +106,7 @@ LOCAL_SRC_FILES:= \
android_bluetooth_ScoSocket.cpp \
android_server_BluetoothDeviceService.cpp \
android_server_BluetoothEventLoop.cpp \
+ android_server_BluetoothA2dpService.cpp \
android_message_digest_sha1.cpp \
android_ddm_DdmHandleNativeHeap.cpp \
android_location_GpsLocationProvider.cpp \
@@ -109,7 +116,7 @@ LOCAL_SRC_FILES:= \
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
$(LOCAL_PATH)/android/graphics \
- $(call include-path-for, corecg graphics) \
+ $(call include-path-for, bluedroid corecg graphics) \
$(call include-path-for, libhardware)/hardware \
$(LOCAL_PATH)/../../include/ui \
$(LOCAL_PATH)/../../include/utils \
@@ -128,6 +135,7 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libnetutils \
libui \
+ libskiagl \
libsgl \
libcorecg \
libsqlite \
@@ -151,15 +159,15 @@ LOCAL_CFLAGS += -DHAVE_BLUETOOTH
LOCAL_SHARED_LIBRARIES += libbluedroid libdbus
endif
-ifeq ($(TARGET_ARCH),arm)
+ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += \
libdl
endif
LOCAL_LDLIBS += -lpthread -ldl
-ifeq ($(TARGET_OS),linux)
-ifeq ($(TARGET_ARCH),x86)
+ifeq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
LOCAL_LDLIBS += -lrt
endif
endif
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 2a1184f..f85f7d5 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -71,7 +71,9 @@ extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
+extern int register_android_media_AudioRecord(JNIEnv *env);
extern int register_android_media_AudioSystem(JNIEnv *env);
+extern int register_android_media_AudioTrack(JNIEnv *env);
extern int register_android_media_ToneGenerator(JNIEnv *env);
extern int register_android_message_digest_sha1(JNIEnv *env);
@@ -114,7 +116,7 @@ extern int register_android_database_SQLiteStatement(JNIEnv* env);
extern int register_android_debug_JNITest(JNIEnv* env);
extern int register_android_nio_utils(JNIEnv* env);
extern int register_android_pim_EventRecurrence(JNIEnv* env);
-extern int register_android_pim_Time(JNIEnv* env);
+extern int register_android_text_format_Time(JNIEnv* env);
extern int register_android_os_Debug(JNIEnv* env);
extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
extern int register_android_os_Power(JNIEnv *env);
@@ -142,6 +144,7 @@ extern int register_android_bluetooth_RfcommSocket(JNIEnv *env);
extern int register_android_bluetooth_ScoSocket(JNIEnv *env);
extern int register_android_server_BluetoothDeviceService(JNIEnv* env);
extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
+extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
extern int register_android_util_Base64(JNIEnv* env);
@@ -471,42 +474,21 @@ static void blockSigpipe()
}
/*
- * Read the persistent locale from file.
+ * Read the persistent locale.
*/
static void readLocale(char* language, char* region)
{
- char path[512];
char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
- char *dataDir = getenv("ANDROID_DATA");
- bool found = false;
- if (dataDir && strlen(dataDir) < 500) {
- strcpy(path, dataDir);
- } else {
- strcpy(path, "/data");
- }
- strcat(path, "/locale");
- FILE* localeFile = fopen(path, "r");
- if (localeFile) {
- char line[10];
- char *got = fgets(line, 10, localeFile);
- /* Locale code is ll_rr */
- if (got != NULL && strlen(line) >= 5) {
- strncat(language, line, 2);
- strncat(region, line + 3, 2);
- found = true;
- }
- fclose(localeFile);
- }
-
- if (!found) {
+ property_get("persist.sys.language", propLang, "");
+ property_get("persist.sys.country", propRegn, "");
+ if (*propLang == 0 && *propRegn == 0) {
/* Set to ro properties, default is en_US */
property_get("ro.product.locale.language", propLang, "en");
property_get("ro.product.locale.region", propRegn, "US");
- strncat(language, propLang, 2);
- strncat(region, propRegn, 2);
}
-
+ strncat(language, propLang, 2);
+ strncat(region, propRegn, 2);
//LOGD("language=%s region=%s\n", language, region);
}
@@ -518,8 +500,9 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
JavaVMInitArgs initArgs;
JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
- char enableAssertBuf[4 + PROPERTY_VALUE_MAX];
char stackTraceFileBuf[PROPERTY_VALUE_MAX];
+ char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
+ char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
char* slashClassName = NULL;
char* cp;
@@ -578,6 +561,9 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
strcpy(enableAssertBuf, "-ea:");
property_get("dalvik.vm.enableassertions", enableAssertBuf+4, "");
+ strcpy(jniOptsBuf, "-Xjniopts:");
+ property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");
+
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
@@ -609,20 +595,23 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
mOptions.add(opt);
//options[curOpt++].optionString = "-verbose:class";
+#ifdef CUSTOM_RUNTIME_HEAP_MAX
+#define __make_max_heap_opt(val) #val
+#define _make_max_heap_opt(val) "-Xmx" __make_max_heap_opt(val)
+ opt.optionString = _make_max_heap_opt(CUSTOM_RUNTIME_HEAP_MAX);
+#undef __make_max_heap_opt
+#undef _make_max_heap_opt
+#else
/* limit memory use to 16MB */
opt.optionString = "-Xmx16m";
+#endif
mOptions.add(opt);
- /* enable Java "assert" statements in all non-system code */
- //options[curOpt++].optionString = "-ea";
-
/*
- * Enable or disable bytecode verification. We currently force optimization
- * to be enabled when the verifier is off; this is a bad idea, but
- * useful while we fiddle with the verifier.
+ * Enable or disable bytecode verification.
*
- * This should be coordinated with:
- * //device/dalvik/libcore/android/src/main/native/dalvik_system_TouchDex.cpp
+ * We don't optimize classes that haven't been verified, but that only
+ * matters if we do "just-in-time" DEX optimization.
*/
if (verifyJava) {
opt.optionString = "-Xverify:all";
@@ -632,7 +621,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
} else {
opt.optionString = "-Xverify:none";
mOptions.add(opt);
- //opt.optionString = "-Xdexopt:all";
opt.optionString = "-Xdexopt:verified";
mOptions.add(opt);
}
@@ -697,6 +685,12 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
LOGV("Assertions disabled\n");
}
+ if (jniOptsBuf[10] != '\0') {
+ LOGI("JNI options: '%s'\n", jniOptsBuf);
+ opt.optionString = jniOptsBuf;
+ mOptions.add(opt);
+ }
+
if (stackTraceFileBuf[0] != '\0') {
static const char* stfOptName = "-Xstacktracefile:";
@@ -1008,7 +1002,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_FloatMath),
- REG_JNI(register_android_pim_Time),
+ REG_JNI(register_android_text_format_Time),
REG_JNI(register_android_pim_EventRecurrence),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
@@ -1076,7 +1070,9 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_SensorManager),
+ REG_JNI(register_android_media_AudioRecord),
REG_JNI(register_android_media_AudioSystem),
+ REG_JNI(register_android_media_AudioTrack),
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
@@ -1087,6 +1083,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_bluetooth_ScoSocket),
REG_JNI(register_android_server_BluetoothDeviceService),
REG_JNI(register_android_server_BluetoothEventLoop),
+ REG_JNI(register_android_server_BluetoothA2dpService),
REG_JNI(register_android_message_digest_sha1),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
REG_JNI(register_android_util_Base64),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 8628ec0..27a6349 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,573 +1,561 @@
-#include "SkBitmap.h"
-#include "SkImageDecoder.h"
-#include "SkColorPriv.h"
-#include "GraphicsJNI.h"
-#include "SkDither.h"
-
-#include "Parcel.h"
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <jni.h>
-
-#if 0
- #define TRACE_BITMAP(code) code
-#else
- #define TRACE_BITMAP(code)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Conversions to/from SkColor, for get/setPixels, and the create method, which
-// is basically like setPixels
-
-typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
- int x, int y);
-
-static void FromColor_D32(void* dst, const SkColor src[], int width,
- int, int) {
- SkPMColor* d = (SkPMColor*)dst;
-
- for (int i = 0; i < width; i++) {
- *d++ = SkPreMultiplyColor(*src++);
- }
-}
-
-static void FromColor_D565(void* dst, const SkColor src[], int width,
- int x, int y) {
- uint16_t* d = (uint16_t*)dst;
-
- DITHER_565_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkColor c = *src++;
- *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
- DITHER_VALUE(x));
- }
-}
-
-static void FromColor_D4444(void* dst, const SkColor src[], int width,
- int x, int y) {
- SkPMColor16* d = (SkPMColor16*)dst;
-
- DITHER_4444_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkPMColor c = SkPreMultiplyColor(*src++);
- *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));
-// *d++ = SkPixel32ToPixel4444(c);
- }
-}
-
-// can return NULL
-static FromColorProc ChooseFromColorProc(SkBitmap::Config config) {
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- return FromColor_D32;
- case SkBitmap::kARGB_4444_Config:
- return FromColor_D4444;
- case SkBitmap::kRGB_565_Config:
- return FromColor_D565;
- default:
- break;
- }
- return NULL;
-}
-
-bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors,
- int srcOffset, int srcStride,
- int x, int y, int width, int height,
- const SkBitmap& dstBitmap) {
- SkAutoLockPixels alp(dstBitmap);
- void* dst = dstBitmap.getPixels();
- FromColorProc proc = ChooseFromColorProc(dstBitmap.config());
-
- if (NULL == dst || NULL == proc) {
- return false;
- }
-
- jint* array = env->GetIntArrayElements(srcColors, NULL);
- const SkColor* src = (const SkColor*)array + srcOffset;
-
- // reset to to actual choice from caller
- dst = dstBitmap.getAddr(x, y);
- // now copy/convert each scanline
- for (int y = 0; y < height; y++) {
- proc(dst, src, width, x, y);
- src += srcStride;
- dst = (char*)dst + dstBitmap.rowBytes();
- }
-
- env->ReleaseIntArrayElements(srcColors, array, 0);
- return true;
-}
-
-//////////////////// ToColor procs
-
-typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
- SkColorTable*);
-
-static inline SkColor pmcolorToColor(SkPMColor c) {
- if (0 == c) {
- return 0;
- }
-
- unsigned a = SkGetPackedA32(c);
- unsigned r = SkGetPackedR32(c);
- unsigned g = SkGetPackedG32(c);
- unsigned b = SkGetPackedB32(c);
-
- if (a < 255) {
- SkFixed scale = SK_Fixed1 / a;
- r = SkFixedRound(r * scale);
- g = SkFixedRound(g * scale);
- b = SkFixedRound(b * scale);
- SkASSERT(r <= 0xFF);
- SkASSERT(g <= 0xFF);
- SkASSERT(b <= 0xFF);
- }
-
- return SkColorSetARGB(a, r, g, b);
-}
-
-static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- *dst++ = pmcolorToColor(*s++);
- } while (--width != 0);
-}
-
-static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- SkPMColor c = *s++;
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor16* s = (const SkPMColor16*)src;
- do {
- *dst++ = pmcolorToColor(SkPixel4444ToPixel32(*s++));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- SkPMColor c = SkPixel4444ToPixel32(*s++);
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S565(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const uint16_t* s = (const uint16_t*)src;
- do {
- uint16_t c = *s++;
- *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
- SkPacked16ToB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- *dst++ = pmcolorToColor(colors[*s++]);
- } while (--width != 0);
- ctable->unlockColors(false);
-}
-
-static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- SkPMColor c = colors[*s++];
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
- ctable->unlockColors(false);
-}
-
-// can return NULL
-static ToColorProc ChooseToColorProc(const SkBitmap& src) {
- switch (src.config()) {
- case SkBitmap::kARGB_8888_Config:
- return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;
- case SkBitmap::kARGB_4444_Config:
- return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;
- case SkBitmap::kRGB_565_Config:
- return ToColor_S565;
- case SkBitmap::kIndex8_Config:
- if (src.getColorTable() == NULL) {
- return NULL;
- }
- return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;
- default:
- break;
- }
- return NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
- int offset, int stride, int width, int height,
- SkBitmap::Config config, jboolean isMutable) {
- if (width <= 0 || height <= 0) {
- doThrowIAE(env, "width and height must be > 0");
- return NULL;
- }
-
- if (NULL != jColors) {
- size_t n = env->GetArrayLength(jColors);
- if (n < SkAbs32(stride) * (size_t)height) {
- doThrowAIOOBE(env);
- return NULL;
- }
- }
-
- SkBitmap bitmap;
-
- bitmap.setConfig(config, width, height);
- if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) {
- return NULL;
- }
-
- if (jColors != NULL) {
- GraphicsJNI::SetPixels(env, jColors, offset, stride,
- 0, 0, width, height, bitmap);
- }
-
- return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable,
- NULL);
-}
-
-static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
- SkBitmap::Config dstConfig, jboolean isMutable) {
- SkBitmap result;
- JavaPixelAllocator allocator(env);
-
- if (!src->copyTo(&result, dstConfig, &allocator)) {
- return NULL;
- }
-
- return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable,
- NULL);
-}
-
-static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
- delete bitmap;
-}
-
-static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
- bitmap->setPixels(NULL, NULL);
-}
-
-// These must match the int values in Bitmap.java
-enum JavaEncodeFormat {
- kJPEG_JavaEncodeFormat = 0,
- kPNG_JavaEncodeFormat = 1
-};
-
-static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
- int format, int quality,
- jobject jstream, jbyteArray jstorage) {
- SkImageEncoder::Type fm;
-
- switch (format) {
- case kJPEG_JavaEncodeFormat:
- fm = SkImageEncoder::kJPEG_Type;
- break;
- case kPNG_JavaEncodeFormat:
- fm = SkImageEncoder::kPNG_Type;
- break;
- default:
- return false;
- }
-
- bool success = false;
- SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
- if (NULL != strm) {
- SkImageEncoder* encoder = SkImageEncoder::Create(fm);
- if (NULL != encoder) {
- success = encoder->encodeStream(strm, *bitmap, quality);
- delete encoder;
- }
- delete strm;
- }
- return success;
-}
-
-static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
- bitmap->eraseColor(color);
-}
-
-static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {
- return bitmap->width();
-}
-
-static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {
- return bitmap->height();
-}
-
-static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
- return bitmap->rowBytes();
-}
-
-static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
- return bitmap->config();
-}
-
-static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
- return !bitmap->isOpaque();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
- if (parcel == NULL) {
- SkDebugf("-------- unparcel parcel is NULL\n");
- return NULL;
- }
-
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
- const bool isMutable = p->readInt32() != 0;
- const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
- const int width = p->readInt32();
- const int height = p->readInt32();
- const int rowBytes = p->readInt32();
-
- if (SkBitmap::kARGB_8888_Config != config &&
- SkBitmap::kRGB_565_Config != config &&
- SkBitmap::kARGB_4444_Config != config &&
- SkBitmap::kIndex8_Config != config &&
- SkBitmap::kA8_Config != config) {
- SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
- return NULL;
- }
-
- SkBitmap* bitmap = new SkBitmap;
-
- bitmap->setConfig(config, width, height, rowBytes);
-
- SkColorTable* ctable = NULL;
- if (config == SkBitmap::kIndex8_Config) {
- int count = p->readInt32();
- if (count > 0) {
- size_t size = count * sizeof(SkPMColor);
- const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
- ctable = new SkColorTable(src, count);
- }
- }
-
- if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) {
- ctable->safeUnref();
- delete bitmap;
- return NULL;
- }
-
- ctable->safeUnref();
-
- size_t size = bitmap->getSize();
- bitmap->lockPixels();
- memcpy(bitmap->getPixels(), p->readInplace(size), size);
- bitmap->unlockPixels();
-
- return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL);
-}
-
-static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
- const SkBitmap* bitmap,
- jboolean isMutable, jobject parcel) {
- if (parcel == NULL) {
- SkDebugf("------- writeToParcel null parcel\n");
- return false;
- }
-
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
- p->writeInt32(isMutable);
- p->writeInt32(bitmap->config());
- p->writeInt32(bitmap->width());
- p->writeInt32(bitmap->height());
- p->writeInt32(bitmap->rowBytes());
-
- if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
- SkColorTable* ctable = bitmap->getColorTable();
- if (ctable != NULL) {
- int count = ctable->count();
- p->writeInt32(count);
- memcpy(p->writeInplace(count * sizeof(SkPMColor)),
- ctable->lockColors(), count * sizeof(SkPMColor));
- ctable->unlockColors(false);
- } else {
- p->writeInt32(0); // indicate no ctable
- }
- }
-
- size_t size = bitmap->getSize();
- bitmap->lockPixels();
- memcpy(p->writeInplace(size), bitmap->getPixels(), size);
- bitmap->unlockPixels();
- return true;
-}
-
-static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
- const SkBitmap* src, const SkPaint* paint,
- jintArray offsetXY) {
- SkIPoint offset;
- SkBitmap* dst = new SkBitmap;
-
- src->extractAlpha(dst, paint, &offset);
- if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
- int* array = env->GetIntArrayElements(offsetXY, NULL);
- array[0] = offset.fX;
- array[1] = offset.fY;
- env->ReleaseIntArrayElements(offsetXY, array, 0);
- }
-
- return GraphicsJNI::createBitmap(env, dst, true, NULL);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
- int x, int y) {
- SkAutoLockPixels alp(*bitmap);
-
- ToColorProc proc = ChooseToColorProc(*bitmap);
- if (NULL == proc) {
- return 0;
- }
- const void* src = bitmap->getAddr(x, y);
- if (NULL == src) {
- return 0;
- }
-
- SkColor dst[1];
- proc(dst, src, 1, bitmap->getColorTable());
- return dst[0];
-}
-
-static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
- jintArray pixelArray, int offset, int stride,
- int x, int y, int width, int height) {
- SkAutoLockPixels alp(*bitmap);
-
- ToColorProc proc = ChooseToColorProc(*bitmap);
- if (NULL == proc) {
- return;
- }
- const void* src = bitmap->getAddr(x, y);
- if (NULL == src) {
- return;
- }
-
- SkColorTable* ctable = bitmap->getColorTable();
- jint* dst = env->GetIntArrayElements(pixelArray, NULL);
- SkColor* d = (SkColor*)dst + offset;
- while (--height >= 0) {
- proc(d, src, width, ctable);
- d += stride;
- src = (void*)((const char*)src + bitmap->rowBytes());
- }
- env->ReleaseIntArrayElements(pixelArray, dst, 0);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
- int x, int y, SkColor color) {
- SkAutoLockPixels alp(*bitmap);
- if (NULL == bitmap->getPixels()) {
- return;
- }
-
- FromColorProc proc = ChooseFromColorProc(bitmap->config());
- if (NULL == proc) {
- return;
- }
-
- proc(bitmap->getAddr(x, y), &color, 1, x, y);
-}
-
-static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
- jintArray pixelArray, int offset, int stride,
- int x, int y, int width, int height) {
- GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
- x, y, width, height, *bitmap);
-}
-
-static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
- const SkBitmap* bitmap, jobject jbuffer) {
- SkAutoLockPixels alp(*bitmap);
- const void* src = bitmap->getPixels();
-
- if (NULL != src) {
- android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
-
- // the java side has already checked that buffer is large enough
- memcpy(abp.pointer(), src, bitmap->getSize());
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gBitmapMethods[] = {
- { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_creator },
- { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_copy },
- { "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
- { "nativeRecycle", "(I)V", (void*)Bitmap_recycle },
- { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
- (void*)Bitmap_compress },
- { "nativeErase", "(II)V", (void*)Bitmap_erase },
- { "nativeWidth", "(I)I", (void*)Bitmap_width },
- { "nativeHeight", "(I)I", (void*)Bitmap_height },
- { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes },
- { "nativeConfig", "(I)I", (void*)Bitmap_config },
- { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha },
- { "nativeCreateFromParcel",
- "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
- (void*)Bitmap_createFromParcel },
- { "nativeWriteToParcel", "(IZLandroid/os/Parcel;)Z",
- (void*)Bitmap_writeToParcel },
- { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
- (void*)Bitmap_extractAlpha },
- { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel },
- { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels },
- { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel },
- { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels },
- { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
- (void*)Bitmap_copyPixelsToBuffer }
-};
-
-#define kClassPathName "android/graphics/Bitmap"
-
-int register_android_graphics_Bitmap(JNIEnv* env);
-int register_android_graphics_Bitmap(JNIEnv* env)
-{
- return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
- gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
-}
-
+#include "SkBitmap.h"
+#include "SkImageDecoder.h"
+#include "SkColorPriv.h"
+#include "GraphicsJNI.h"
+#include "SkDither.h"
+#include "SkUnPreMultiply.h"
+
+#include "Parcel.h"
+#include "android_util_Binder.h"
+#include "android_nio_utils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <jni.h>
+
+#if 0
+ #define TRACE_BITMAP(code) code
+#else
+ #define TRACE_BITMAP(code)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Conversions to/from SkColor, for get/setPixels, and the create method, which
+// is basically like setPixels
+
+typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
+ int x, int y);
+
+static void FromColor_D32(void* dst, const SkColor src[], int width,
+ int, int) {
+ SkPMColor* d = (SkPMColor*)dst;
+
+ for (int i = 0; i < width; i++) {
+ *d++ = SkPreMultiplyColor(*src++);
+ }
+}
+
+static void FromColor_D565(void* dst, const SkColor src[], int width,
+ int x, int y) {
+ uint16_t* d = (uint16_t*)dst;
+
+ DITHER_565_SCAN(y);
+ for (int stop = x + width; x < stop; x++) {
+ SkColor c = *src++;
+ *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
+ DITHER_VALUE(x));
+ }
+}
+
+static void FromColor_D4444(void* dst, const SkColor src[], int width,
+ int x, int y) {
+ SkPMColor16* d = (SkPMColor16*)dst;
+
+ DITHER_4444_SCAN(y);
+ for (int stop = x + width; x < stop; x++) {
+ SkPMColor c = SkPreMultiplyColor(*src++);
+ *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));
+// *d++ = SkPixel32ToPixel4444(c);
+ }
+}
+
+// can return NULL
+static FromColorProc ChooseFromColorProc(SkBitmap::Config config) {
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ return FromColor_D32;
+ case SkBitmap::kARGB_4444_Config:
+ return FromColor_D4444;
+ case SkBitmap::kRGB_565_Config:
+ return FromColor_D565;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors,
+ int srcOffset, int srcStride,
+ int x, int y, int width, int height,
+ const SkBitmap& dstBitmap) {
+ SkAutoLockPixels alp(dstBitmap);
+ void* dst = dstBitmap.getPixels();
+ FromColorProc proc = ChooseFromColorProc(dstBitmap.config());
+
+ if (NULL == dst || NULL == proc) {
+ return false;
+ }
+
+ const jint* array = env->GetIntArrayElements(srcColors, NULL);
+ const SkColor* src = (const SkColor*)array + srcOffset;
+
+ // reset to to actual choice from caller
+ dst = dstBitmap.getAddr(x, y);
+ // now copy/convert each scanline
+ for (int y = 0; y < height; y++) {
+ proc(dst, src, width, x, y);
+ src += srcStride;
+ dst = (char*)dst + dstBitmap.rowBytes();
+ }
+
+ env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
+ JNI_ABORT);
+ return true;
+}
+
+//////////////////// ToColor procs
+
+typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
+ SkColorTable*);
+
+static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor* s = (const SkPMColor*)src;
+ do {
+ *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
+ } while (--width != 0);
+}
+
+static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor* s = (const SkPMColor*)src;
+ do {
+ SkPMColor c = *s++;
+ *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+ SkGetPackedB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor16* s = (const SkPMColor16*)src;
+ do {
+ *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
+ } while (--width != 0);
+}
+
+static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor* s = (const SkPMColor*)src;
+ do {
+ SkPMColor c = SkPixel4444ToPixel32(*s++);
+ *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+ SkGetPackedB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_S565(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const uint16_t* s = (const uint16_t*)src;
+ do {
+ uint16_t c = *s++;
+ *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
+ SkPacked16ToB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
+ SkColorTable* ctable) {
+ SkASSERT(width > 0);
+ const uint8_t* s = (const uint8_t*)src;
+ const SkPMColor* colors = ctable->lockColors();
+ do {
+ *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
+ } while (--width != 0);
+ ctable->unlockColors(false);
+}
+
+static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
+ SkColorTable* ctable) {
+ SkASSERT(width > 0);
+ const uint8_t* s = (const uint8_t*)src;
+ const SkPMColor* colors = ctable->lockColors();
+ do {
+ SkPMColor c = colors[*s++];
+ *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+ SkGetPackedB32(c));
+ } while (--width != 0);
+ ctable->unlockColors(false);
+}
+
+// can return NULL
+static ToColorProc ChooseToColorProc(const SkBitmap& src) {
+ switch (src.config()) {
+ case SkBitmap::kARGB_8888_Config:
+ return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;
+ case SkBitmap::kARGB_4444_Config:
+ return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;
+ case SkBitmap::kRGB_565_Config:
+ return ToColor_S565;
+ case SkBitmap::kIndex8_Config:
+ if (src.getColorTable() == NULL) {
+ return NULL;
+ }
+ return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
+ int offset, int stride, int width, int height,
+ SkBitmap::Config config, jboolean isMutable) {
+ if (width <= 0 || height <= 0) {
+ doThrowIAE(env, "width and height must be > 0");
+ return NULL;
+ }
+
+ if (NULL != jColors) {
+ size_t n = env->GetArrayLength(jColors);
+ if (n < SkAbs32(stride) * (size_t)height) {
+ doThrowAIOOBE(env);
+ return NULL;
+ }
+ }
+
+ SkBitmap bitmap;
+
+ bitmap.setConfig(config, width, height);
+ if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) {
+ return NULL;
+ }
+
+ if (jColors != NULL) {
+ GraphicsJNI::SetPixels(env, jColors, offset, stride,
+ 0, 0, width, height, bitmap);
+ }
+
+ return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable,
+ NULL);
+}
+
+static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
+ SkBitmap::Config dstConfig, jboolean isMutable) {
+ SkBitmap result;
+ JavaPixelAllocator allocator(env);
+
+ if (!src->copyTo(&result, dstConfig, &allocator)) {
+ return NULL;
+ }
+
+ return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable,
+ NULL);
+}
+
+static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ delete bitmap;
+}
+
+static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ bitmap->setPixels(NULL, NULL);
+}
+
+// These must match the int values in Bitmap.java
+enum JavaEncodeFormat {
+ kJPEG_JavaEncodeFormat = 0,
+ kPNG_JavaEncodeFormat = 1
+};
+
+static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
+ int format, int quality,
+ jobject jstream, jbyteArray jstorage) {
+ SkImageEncoder::Type fm;
+
+ switch (format) {
+ case kJPEG_JavaEncodeFormat:
+ fm = SkImageEncoder::kJPEG_Type;
+ break;
+ case kPNG_JavaEncodeFormat:
+ fm = SkImageEncoder::kPNG_Type;
+ break;
+ default:
+ return false;
+ }
+
+ bool success = false;
+ SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
+ if (NULL != strm) {
+ SkImageEncoder* encoder = SkImageEncoder::Create(fm);
+ if (NULL != encoder) {
+ success = encoder->encodeStream(strm, *bitmap, quality);
+ delete encoder;
+ }
+ delete strm;
+ }
+ return success;
+}
+
+static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
+ bitmap->eraseColor(color);
+}
+
+static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ return bitmap->width();
+}
+
+static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ return bitmap->height();
+}
+
+static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ return bitmap->rowBytes();
+}
+
+static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ return bitmap->config();
+}
+
+static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ return !bitmap->isOpaque();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
+ if (parcel == NULL) {
+ SkDebugf("-------- unparcel parcel is NULL\n");
+ return NULL;
+ }
+
+ android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+ const bool isMutable = p->readInt32() != 0;
+ const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
+ const int width = p->readInt32();
+ const int height = p->readInt32();
+ const int rowBytes = p->readInt32();
+
+ if (SkBitmap::kARGB_8888_Config != config &&
+ SkBitmap::kRGB_565_Config != config &&
+ SkBitmap::kARGB_4444_Config != config &&
+ SkBitmap::kIndex8_Config != config &&
+ SkBitmap::kA8_Config != config) {
+ SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
+ return NULL;
+ }
+
+ SkBitmap* bitmap = new SkBitmap;
+
+ bitmap->setConfig(config, width, height, rowBytes);
+
+ SkColorTable* ctable = NULL;
+ if (config == SkBitmap::kIndex8_Config) {
+ int count = p->readInt32();
+ if (count > 0) {
+ size_t size = count * sizeof(SkPMColor);
+ const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
+ ctable = new SkColorTable(src, count);
+ }
+ }
+
+ if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) {
+ ctable->safeUnref();
+ delete bitmap;
+ return NULL;
+ }
+
+ ctable->safeUnref();
+
+ size_t size = bitmap->getSize();
+ bitmap->lockPixels();
+ memcpy(bitmap->getPixels(), p->readInplace(size), size);
+ bitmap->unlockPixels();
+
+ return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL);
+}
+
+static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
+ const SkBitmap* bitmap,
+ jboolean isMutable, jobject parcel) {
+ if (parcel == NULL) {
+ SkDebugf("------- writeToParcel null parcel\n");
+ return false;
+ }
+
+ android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+ p->writeInt32(isMutable);
+ p->writeInt32(bitmap->config());
+ p->writeInt32(bitmap->width());
+ p->writeInt32(bitmap->height());
+ p->writeInt32(bitmap->rowBytes());
+
+ if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
+ SkColorTable* ctable = bitmap->getColorTable();
+ if (ctable != NULL) {
+ int count = ctable->count();
+ p->writeInt32(count);
+ memcpy(p->writeInplace(count * sizeof(SkPMColor)),
+ ctable->lockColors(), count * sizeof(SkPMColor));
+ ctable->unlockColors(false);
+ } else {
+ p->writeInt32(0); // indicate no ctable
+ }
+ }
+
+ size_t size = bitmap->getSize();
+ bitmap->lockPixels();
+ memcpy(p->writeInplace(size), bitmap->getPixels(), size);
+ bitmap->unlockPixels();
+ return true;
+}
+
+static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
+ const SkBitmap* src, const SkPaint* paint,
+ jintArray offsetXY) {
+ SkIPoint offset;
+ SkBitmap* dst = new SkBitmap;
+
+ src->extractAlpha(dst, paint, &offset);
+ if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
+ int* array = env->GetIntArrayElements(offsetXY, NULL);
+ array[0] = offset.fX;
+ array[1] = offset.fY;
+ env->ReleaseIntArrayElements(offsetXY, array, 0);
+ }
+
+ return GraphicsJNI::createBitmap(env, dst, true, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
+ int x, int y) {
+ SkAutoLockPixels alp(*bitmap);
+
+ ToColorProc proc = ChooseToColorProc(*bitmap);
+ if (NULL == proc) {
+ return 0;
+ }
+ const void* src = bitmap->getAddr(x, y);
+ if (NULL == src) {
+ return 0;
+ }
+
+ SkColor dst[1];
+ proc(dst, src, 1, bitmap->getColorTable());
+ return dst[0];
+}
+
+static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
+ jintArray pixelArray, int offset, int stride,
+ int x, int y, int width, int height) {
+ SkAutoLockPixels alp(*bitmap);
+
+ ToColorProc proc = ChooseToColorProc(*bitmap);
+ if (NULL == proc) {
+ return;
+ }
+ const void* src = bitmap->getAddr(x, y);
+ if (NULL == src) {
+ return;
+ }
+
+ SkColorTable* ctable = bitmap->getColorTable();
+ jint* dst = env->GetIntArrayElements(pixelArray, NULL);
+ SkColor* d = (SkColor*)dst + offset;
+ while (--height >= 0) {
+ proc(d, src, width, ctable);
+ d += stride;
+ src = (void*)((const char*)src + bitmap->rowBytes());
+ }
+ env->ReleaseIntArrayElements(pixelArray, dst, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
+ int x, int y, SkColor color) {
+ SkAutoLockPixels alp(*bitmap);
+ if (NULL == bitmap->getPixels()) {
+ return;
+ }
+
+ FromColorProc proc = ChooseFromColorProc(bitmap->config());
+ if (NULL == proc) {
+ return;
+ }
+
+ proc(bitmap->getAddr(x, y), &color, 1, x, y);
+}
+
+static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
+ jintArray pixelArray, int offset, int stride,
+ int x, int y, int width, int height) {
+ GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
+ x, y, width, height, *bitmap);
+}
+
+static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
+ const SkBitmap* bitmap, jobject jbuffer) {
+ SkAutoLockPixels alp(*bitmap);
+ const void* src = bitmap->getPixels();
+
+ if (NULL != src) {
+ android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
+
+ // the java side has already checked that buffer is large enough
+ memcpy(abp.pointer(), src, bitmap->getSize());
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gBitmapMethods[] = {
+ { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_creator },
+ { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_copy },
+ { "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
+ { "nativeRecycle", "(I)V", (void*)Bitmap_recycle },
+ { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
+ (void*)Bitmap_compress },
+ { "nativeErase", "(II)V", (void*)Bitmap_erase },
+ { "nativeWidth", "(I)I", (void*)Bitmap_width },
+ { "nativeHeight", "(I)I", (void*)Bitmap_height },
+ { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes },
+ { "nativeConfig", "(I)I", (void*)Bitmap_config },
+ { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha },
+ { "nativeCreateFromParcel",
+ "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_createFromParcel },
+ { "nativeWriteToParcel", "(IZLandroid/os/Parcel;)Z",
+ (void*)Bitmap_writeToParcel },
+ { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_extractAlpha },
+ { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel },
+ { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels },
+ { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel },
+ { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels },
+ { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
+ (void*)Bitmap_copyPixelsToBuffer }
+};
+
+#define kClassPathName "android/graphics/Bitmap"
+
+int register_android_graphics_Bitmap(JNIEnv* env);
+int register_android_graphics_Bitmap(JNIEnv* env)
+{
+#if 1
+ return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+ gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
+#else
+ short n = 0;
+ int limit = (char*)env - (char*)0;
+ for (int i = 0; i < limit; i++) {
+ n += i*i;
+ }
+ return n;
+#endif
+}
+
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 90822a1..be8526d 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -43,57 +43,74 @@ public:
private:
AutoDecoderCancel* fNext;
+ AutoDecoderCancel* fPrev;
jobject fJOptions; // java options object
SkImageDecoder* fDecoder;
+
+#ifdef SK_DEBUG
+ static void Validate();
+#else
+ static void Validate() {}
+#endif
};
static SkMutex gAutoDecoderCancelMutex;
static AutoDecoderCancel* gAutoDecoderCancel;
+#ifdef SK_DEBUG
+ static int gAutoDecoderCancelCount;
+#endif
AutoDecoderCancel::AutoDecoderCancel(jobject joptions,
SkImageDecoder* decoder) {
fJOptions = joptions;
fDecoder = decoder;
- // only need to be in the list if we have options
if (NULL != joptions) {
SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
-
+
+ // Add us as the head of the list
+ fPrev = NULL;
fNext = gAutoDecoderCancel;
+ if (gAutoDecoderCancel) {
+ gAutoDecoderCancel->fPrev = this;
+ }
gAutoDecoderCancel = this;
+
+ SkDEBUGCODE(gAutoDecoderCancelCount += 1;)
+ Validate();
}
}
AutoDecoderCancel::~AutoDecoderCancel() {
- const jobject joptions = fJOptions;
-
- if (NULL != joptions) {
+ if (NULL != fJOptions) {
SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
- // remove us
- AutoDecoderCancel* pair = gAutoDecoderCancel;
- AutoDecoderCancel* prev = NULL;
- while (pair != NULL) {
- AutoDecoderCancel* next = pair->fNext;
- if (pair->fJOptions == joptions) {
- SkASSERT(pair->fDecoder == fDecoder);
- if (prev) {
- prev->fNext = next;
- } else {
- gAutoDecoderCancel = next;
- }
- return;
- }
- pair = next;
+ // take us out of the dllist
+ AutoDecoderCancel* prev = fPrev;
+ AutoDecoderCancel* next = fNext;
+
+ if (prev) {
+ SkASSERT(prev->fNext == this);
+ prev->fNext = next;
+ } else {
+ SkASSERT(gAutoDecoderCancel == this);
+ gAutoDecoderCancel = next;
}
- SkDebugf("xxxxxxxxxxxxxxxxxxxxxxx not found in pair list %p %p\n",
- fJOptions, fDecoder);
+ if (next) {
+ SkASSERT(next->fPrev == this);
+ next->fPrev = prev;
+ }
+
+ SkDEBUGCODE(gAutoDecoderCancelCount -= 1;)
+ Validate();
}
}
bool AutoDecoderCancel::RequestCancel(jobject joptions) {
SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
+ Validate();
+
AutoDecoderCancel* pair = gAutoDecoderCancel;
while (pair != NULL) {
if (pair->fJOptions == joptions) {
@@ -105,6 +122,37 @@ bool AutoDecoderCancel::RequestCancel(jobject joptions) {
return false;
}
+#ifdef SK_DEBUG
+// can only call this inside a lock on gAutoDecoderCancelMutex
+void AutoDecoderCancel::Validate() {
+ const int gCount = gAutoDecoderCancelCount;
+
+ if (gCount == 0) {
+ SkASSERT(gAutoDecoderCancel == NULL);
+ } else {
+ SkASSERT(gCount > 0);
+
+ AutoDecoderCancel* curr = gAutoDecoderCancel;
+ SkASSERT(curr);
+ SkASSERT(curr->fPrev == NULL);
+
+ int count = 0;
+ while (curr) {
+ count += 1;
+ SkASSERT(count <= gCount);
+ if (curr->fPrev) {
+ SkASSERT(curr->fPrev->fNext == curr);
+ }
+ if (curr->fNext) {
+ SkASSERT(curr->fNext->fPrev == curr);
+ }
+ curr = curr->fNext;
+ }
+ SkASSERT(count == gCount);
+ }
+}
+#endif
+
///////////////////////////////////////////////////////////////////////////////
using namespace android;
@@ -132,6 +180,7 @@ public:
// You have to copy the data because it is owned by the png reader
Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize);
memcpy(patchNew, patch, patchSize);
+ // this relies on deserialization being done in place
Res_png_9patch::deserialize(patchNew);
patchNew->fileToDevice();
if (fPatchIsValid) {
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 002fdf9..65c2326 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -28,66 +28,39 @@ public:
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
- printf("------- reset threw an exception\n");
+ SkDebugf("------- reset threw an exception\n");
return false;
}
return true;
}
- virtual size_t read(void* buffer, size_t size) {
+ size_t doRead(void* buffer, size_t size) {
JNIEnv* env = fEnv;
-
- if (buffer == NULL && size == 0) {
- jint avail = env->CallIntMethod(fJavaInputStream,
- gInputStream_availableMethodID);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- printf("------- available threw an exception\n");
- avail = 0;
- }
- return avail;
- }
-
size_t bytesRead = 0;
-
- if (buffer == NULL) { // skip
- jlong skipped = env->CallLongMethod(fJavaInputStream,
- gInputStream_skipMethodID, (jlong)size);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- printf("------- available threw an exception\n");
- return 0;
- }
- if (skipped < 0) {
- return 0;
- }
- return (size_t)skipped;
- }
-
// read the bytes
do {
size_t requested = size;
if (requested > fCapacity)
requested = fCapacity;
-
+
jint n = env->CallIntMethod(fJavaInputStream,
- gInputStream_readMethodID, fJavaByteArray, 0, requested);
+ gInputStream_readMethodID, fJavaByteArray, 0, requested);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
- printf("---- read threw an exception\n");
+ SkDebugf("---- read threw an exception\n");
return 0;
}
-
+
if (n <= 0) {
break; // eof
}
-
- jbyte* array = env->GetByteArrayElements(fJavaByteArray, NULL);
+
+ const jbyte* array = env->GetByteArrayElements(fJavaByteArray,
+ NULL);
memcpy(buffer, array, n);
- env->ReleaseByteArrayElements(fJavaByteArray, array, 0);
+ env->ReleaseByteArrayElements(fJavaByteArray,
+ const_cast<jbyte*>(array), JNI_ABORT);
buffer = (void*)((char*)buffer + n);
bytesRead += n;
@@ -98,6 +71,64 @@ public:
return bytesRead;
}
+ size_t doSkip(size_t size) {
+ JNIEnv* env = fEnv;
+ jlong skipped = env->CallLongMethod(fJavaInputStream,
+ gInputStream_skipMethodID, (jlong)size);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ SkDebugf("------- available threw an exception\n");
+ return 0;
+ }
+ if (skipped < 0) {
+ skipped = 0;
+ }
+ return (size_t)skipped;
+ }
+
+ size_t doSize() {
+ JNIEnv* env = fEnv;
+ jint avail = env->CallIntMethod(fJavaInputStream,
+ gInputStream_availableMethodID);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ SkDebugf("------- available threw an exception\n");
+ avail = 0;
+ }
+ return avail;
+ }
+
+ virtual size_t read(void* buffer, size_t size) {
+ JNIEnv* env = fEnv;
+ if (NULL == buffer) {
+ if (0 == size) {
+ return this->doSize();
+ } else {
+ /* InputStream.skip(n) can return <=0 but still not be at EOF
+ If we see that value, we need to call read(), which will
+ block if waiting for more data, or return -1 at EOF
+ */
+ size_t amountSkipped = 0;
+ do {
+ size_t amount = this->doSkip(size);
+ if (0 == amount) {
+ char tmp;
+ amount = this->doRead(&tmp, 1);
+ if (0 == amount) {
+ // if read returned 0, we're at EOF
+ break;
+ }
+ }
+ amountSkipped += amount;
+ } while (amountSkipped < size);
+ return amountSkipped;
+ }
+ }
+ return this->doRead(buffer, size);
+ }
+
private:
JNIEnv* fEnv;
jobject fJavaInputStream; // the caller owns this object
@@ -167,7 +198,7 @@ public:
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
- printf("------- write threw an exception\n");
+ SkDebugf("------- write threw an exception\n");
return false;
}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index f8ccf72..44113e5 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -265,8 +265,8 @@ void GraphicsJNI::ipoint_to_jpoint(const SkIPoint& ir, JNIEnv* env, jobject obj)
{
SkASSERT(env->IsInstanceOf(obj, gPoint_class));
- env->SetIntField(obj, gPointF_xFieldID, ir.fX);
- env->SetIntField(obj, gPointF_yFieldID, ir.fY);
+ env->SetIntField(obj, gPoint_xFieldID, ir.fX);
+ env->SetIntField(obj, gPoint_yFieldID, ir.fY);
}
SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point)
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 5c48077..de18f9f 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -106,7 +106,7 @@ static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
int totalLength = env->GetArrayLength(byteArray);
if ((offset | length) < 0 || offset + length > totalLength) {
- doThrow(env, "java/lang/ArrayIndexException");
+ doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
return 0;
}
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index a098d89..9e943f3 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -21,13 +21,14 @@ public:
if (env->GetArrayLength(obj) < (int)sizeof(Res_png_9patch)) {
return false;
}
- jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(obj, 0);
- if (array != NULL)
- {
- Res_png_9patch* chunk = (Res_png_9patch*)array;
- int8_t numXDivs = chunk->numXDivs;
- env->ReleasePrimitiveArrayCritical(obj, array, 0);
- return array[0] != -1;
+ const jbyte* array = env->GetByteArrayElements(obj, 0);
+ if (array != NULL) {
+ const Res_png_9patch* chunk =
+ reinterpret_cast<const Res_png_9patch*>(array);
+ int8_t wasDeserialized = chunk->wasDeserialized;
+ env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array),
+ JNI_ABORT);
+ return wasDeserialized != -1;
}
return false;
}
@@ -46,17 +47,19 @@ public:
static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
{
- jbyte* array = env->GetByteArrayElements(chunkObj, 0);
- if (array != NULL)
- {
+ const jbyte* array = env->GetByteArrayElements(chunkObj, 0);
+ if (array != NULL) {
size_t chunkSize = env->GetArrayLength(chunkObj);
- void* deserializedArray = alloca(chunkSize);
- Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray;
- assert(chunkSize == ((Res_png_9patch*) array)->serializedSize());
+ // need to deserialize the chunk
+ void* storage = alloca(chunkSize);
+ Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
memcpy(chunk, array, chunkSize);
+ assert(chunkSize == chunk->serializedSize());
+ // this relies on deserialization being done in place
Res_png_9patch::deserialize(chunk);
NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
- env->ReleaseByteArrayElements(chunkObj, array, 0);
+ env->ReleaseByteArrayElements(chunkObj, const_cast<jbyte*>(array),
+ JNI_ABORT);
}
}
@@ -99,18 +102,20 @@ public:
SkRect bounds;
GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
- jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0);
- if (array != NULL)
- {
+ const jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0);
+ if (array != NULL) {
size_t chunkSize = env->GetArrayLength(chunkObj);
- void* deserializedArray = alloca(chunkSize);
- Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray;
- assert(chunkSize == ((Res_png_9patch*) array)->serializedSize());
+ // need to deserialize the chunk
+ void* storage = alloca(chunkSize);
+ Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
memcpy(chunk, array, chunkSize);
+ assert(chunkSize == chunk->serializedSize());
+ // this relies on deserialization being done in place
Res_png_9patch::deserialize(chunk);
SkRegion* region = NULL;
NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
- env->ReleaseByteArrayElements(chunkObj, array, 0);
+ env->ReleaseByteArrayElements(chunkObj, const_cast<jbyte*>(array),
+ JNI_ABORT);
return (jint)region;
}
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index ba63ae4..f82053c 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -103,6 +103,10 @@ SkScalar calculateStretch(SkScalar boundsLimit, SkScalar startingPoint,
void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
const SkPaint* paint, SkRegion** outRegion) {
+ if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
+ return;
+ }
+
// if our canvas is GL, draw this as a mesh, which will be faster than
// in parts (which is faster for raster)
if (canvas && canvas->getViewport(NULL)) {
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 05830de..76e6f02 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -313,18 +313,21 @@ public:
NPE_CHECK_RETURN_ZERO(env, jpaint);
NPE_CHECK_RETURN_ZERO(env, text);
- SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
- jchar* textArray = env->GetCharArrayElements(text, NULL);
size_t textLength = env->GetArrayLength(text);
-
+
if ((index | count) < 0 || (size_t)(index + count) > textLength) {
- doThrow(env, "ArrayIndexOutOfBoundsException");
+ doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
return 0;
}
- jfloat width = SkScalarToFloat(paint->measureText(textArray + index, count << 1));
- env->ReleaseCharArrayElements(text, textArray, 0);
- return width;
+ const SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+ const jchar* textArray = env->GetCharArrayElements(text, NULL);
+ // we double count, since measureText wants a byteLength
+ SkScalar width = paint->measureText(textArray + index, count << 1);
+ env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+ JNI_ABORT);
+
+ return SkScalarToFloat(width);
}
static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) {
@@ -337,7 +340,7 @@ public:
int count = end - start;
if ((start | count) < 0 || (size_t)count > textLength) {
- doThrow(env, "IndexOutOfBoundsException");
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
return 0;
}
@@ -372,9 +375,10 @@ public:
}
static int getTextWidths___CII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloatArray widths) {
- jchar* textArray = env->GetCharArrayElements(text, NULL);
+ const jchar* textArray = env->GetCharArrayElements(text, NULL);
count = dotextwidths(env, paint, textArray + index, count, widths);
- env->ReleaseCharArrayElements(text, textArray, 0);
+ env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+ JNI_ABORT);
return count;
}
@@ -386,9 +390,10 @@ public:
}
static void getTextPath___CIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
- jchar* textArray = env->GetCharArrayElements(text, NULL);
+ const jchar* textArray = env->GetCharArrayElements(text, NULL);
paint->getTextPath(textArray + index, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), path);
- env->ReleaseCharArrayElements(text, textArray, 0);
+ env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+ JNI_ABORT);
}
static void getTextPath__StringIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
@@ -451,10 +456,11 @@ public:
}
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
- jchar* text = env->GetCharArrayElements(jtext, NULL);
+ const jchar* text = env->GetCharArrayElements(jtext, NULL);
count = breakText(env, *paint, text + index, count, maxWidth,
jmeasuredWidth, tbd);
- env->ReleaseCharArrayElements(jtext, text, 0);
+ env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
+ JNI_ABORT);
return count;
}
@@ -498,9 +504,10 @@ public:
static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint,
jcharArray text, int index, int count, jobject bounds)
{
- jchar* textArray = env->GetCharArrayElements(text, NULL);
+ const jchar* textArray = env->GetCharArrayElements(text, NULL);
doTextBounds(env, textArray + index, count, bounds, *paint);
- env->ReleaseCharArrayElements(text, textArray, 0);
+ env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
+ JNI_ABORT);
}
};
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 71dc875..eef8bb2 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -8,6 +8,12 @@
#include "SkTemplates.h"
#include "SkXfermode.h"
+static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
+ if (NULL == ptr) {
+ doThrowIAE(env);
+ }
+}
+
static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, jfloatArray hsvArray)
{
SkScalar hsv[3];
@@ -64,9 +70,11 @@ static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const
static SkShader* BitmapShader_constructor(JNIEnv* env, jobject, const SkBitmap* bitmap,
int tileModeX, int tileModeY)
{
- return SkShader::CreateBitmapShader(*bitmap,
+ SkShader* s = SkShader::CreateBitmapShader(*bitmap,
(SkShader::TileMode)tileModeX,
(SkShader::TileMode)tileModeY);
+ ThrowIAE_IfNull(env, s);
+ return s;
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -79,8 +87,8 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject,
pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
- size_t count = env->GetArrayLength(colorArray);
- int* colorValues = env->GetIntArrayElements(colorArray, NULL);
+ size_t count = env->GetArrayLength(colorArray);
+ const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
SkScalar* pos = NULL;
@@ -93,9 +101,13 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject,
pos[i] = SkFloatToScalar(posValues[i]);
}
- SkShader* shader = SkGradientShader::CreateLinear(pts, (const SkColor*)colorValues,
- pos, count, (SkShader::TileMode)tileMode);
- env->ReleaseIntArrayElements(colorArray, colorValues, 0);
+ SkShader* shader = SkGradientShader::CreateLinear(pts,
+ reinterpret_cast<const SkColor*>(colorValues),
+ pos, count,
+ static_cast<SkShader::TileMode>(tileMode));
+ env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
+ JNI_ABORT);
+ ThrowIAE_IfNull(env, shader);
return shader;
}
@@ -111,7 +123,9 @@ static SkShader* LinearGradient_create2(JNIEnv* env, jobject,
colors[0] = color0;
colors[1] = color1;
- return SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
+ ThrowIAE_IfNull(env, s);
+ return s;
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -123,8 +137,8 @@ static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
SkPoint center;
center.set(SkFloatToScalar(x), SkFloatToScalar(y));
- size_t count = env->GetArrayLength(colorArray);
- int* colorValues = env->GetIntArrayElements(colorArray, NULL);
+ size_t count = env->GetArrayLength(colorArray);
+ const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
SkScalar* pos = NULL;
@@ -137,10 +151,15 @@ static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
pos[i] = SkFloatToScalar(posValues[i]);
}
- SkShader* shader = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius),
- (const SkColor*)colorValues, pos,
- count, (SkShader::TileMode)tileMode);
- env->ReleaseIntArrayElements(colorArray, colorValues, 0);
+ SkShader* shader = SkGradientShader::CreateRadial(center,
+ SkFloatToScalar(radius),
+ reinterpret_cast<const SkColor*>(colorValues),
+ pos, count,
+ static_cast<SkShader::TileMode>(tileMode));
+ env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
+ JNI_ABORT);
+
+ ThrowIAE_IfNull(env, shader);
return shader;
}
@@ -155,8 +174,10 @@ static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
colors[0] = color0;
colors[1] = color1;
- return SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
+ SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
2, (SkShader::TileMode)tileMode);
+ ThrowIAE_IfNull(env, s);
+ return s;
}
///////////////////////////////////////////////////////////////////////////////
@@ -164,8 +185,8 @@ static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
jintArray jcolors, jfloatArray jpositions)
{
- size_t count = env->GetArrayLength(jcolors);
- int* colors = env->GetIntArrayElements(jcolors, NULL);
+ size_t count = env->GetArrayLength(jcolors);
+ const jint* colors = env->GetIntArrayElements(jcolors, NULL);
SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
SkScalar* pos = NULL;
@@ -174,15 +195,18 @@ static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
AutoJavaFloatArray autoPos(env, jpositions, count);
const float* posValues = autoPos.ptr();
pos = (SkScalar*)storage.get();
- for (size_t i = 0; i < count; i++)
+ for (size_t i = 0; i < count; i++) {
pos[i] = SkFloatToScalar(posValues[i]);
+ }
}
SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x),
- SkFloatToScalar(y),
- (const SkColor*)colors,
- pos, count);
- env->ReleaseIntArrayElements(jcolors, colors, 0);
+ SkFloatToScalar(y),
+ reinterpret_cast<const SkColor*>(colors),
+ pos, count);
+ env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
+ JNI_ABORT);
+ ThrowIAE_IfNull(env, shader);
return shader;
}
@@ -192,8 +216,10 @@ static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
SkColor colors[2];
colors[0] = color0;
colors[1] = color1;
- return SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
+ SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
colors, NULL, 2);
+ ThrowIAE_IfNull(env, s);
+ return s;
}
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index e77cd30..c30ba22 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -61,6 +61,15 @@ jfieldID get_field(JNIEnv *env,
(err)->name, (err)->message); \
dbus_error_free((err)); }
+struct event_loop_native_data_t {
+ DBusConnection *conn;
+ /* These variables are set in waitForAndDispatchEventNative() and are
+ valid only within the scope of this function. At any other time, they
+ are NULL. */
+ jobject me;
+ JNIEnv *env;
+};
+
dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
DBusConnection *conn,
int timeout_ms,
diff --git a/core/jni/android_database_SQLiteProgram.cpp b/core/jni/android_database_SQLiteProgram.cpp
index 54e7de2..7bda004 100644
--- a/core/jni/android_database_SQLiteProgram.cpp
+++ b/core/jni/android_database_SQLiteProgram.cpp
@@ -172,7 +172,7 @@ static void native_bind_blob(JNIEnv* env, jobject object,
if (err != SQLITE_OK) {
char buf[32];
- sprintf(buf, "handle %p", statement);
+ sprintf(buf, "statement %p", statement);
throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
return;
}
diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp
index 9458433..4427168 100644
--- a/core/jni/android_database_SQLiteQuery.cpp
+++ b/core/jni/android_database_SQLiteQuery.cpp
@@ -106,11 +106,12 @@ static int finish_program_and_get_row_count(sqlite3_stmt *statement) {
}
static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
- jint startPos, jint offsetParam)
+ jint startPos, jint offsetParam, jint maxRead, jint lastPos)
{
int err;
sqlite3_stmt * statement = GET_STATEMENT(env, object);
- int numRows = 0;
+ int numRows = lastPos;
+ maxRead += lastPos;
int numColumns;
int retryCount;
int boundParams;
@@ -168,7 +169,7 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
}
}
- while(true) {
+ while(startPos != 0 || numRows < maxRead) {
err = sqlite3_step(statement);
if (err == SQLITE_ROW) {
LOG_WINDOW("\nStepped statement %p to row %d", statement, startPos + numRows);
@@ -274,6 +275,7 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
if (i < numColumns) {
// Not all the fields fit in the window
+ // Unknown data error happened
break;
}
@@ -305,8 +307,12 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
LOG_WINDOW("Resetting statement %p after fetching %d rows in %d bytes\n\n\n\n", statement,
numRows, window->size() - window->freeSpace());
// LOGI("Filled window with %d rows in %d bytes", numRows, window->size() - window->freeSpace());
- sqlite3_reset(statement);
- return startPos + numRows;
+ if (err == SQLITE_ROW) {
+ return -1;
+ } else {
+ sqlite3_reset(statement);
+ return startPos + numRows;
+ }
}
static jint native_column_count(JNIEnv* env, jobject object)
@@ -330,7 +336,7 @@ static jstring native_column_name(JNIEnv* env, jobject object, jint columnIndex)
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
- {"native_fill_window", "(Landroid/database/CursorWindow;II)I", (void *)native_fill_window},
+ {"native_fill_window", "(Landroid/database/CursorWindow;IIII)I", (void *)native_fill_window},
{"native_column_count", "()I", (void*)native_column_count},
{"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name},
};
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index a29c27b..4b126a6 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2008, 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
+** 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
+** 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
+** 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.
*/
@@ -50,15 +50,17 @@ struct fields_t {
};
static fields_t fields;
+static Mutex sLock;
struct callback_cookie {
jclass camera_class;
jobject camera_ref;
};
-static Camera *get_native_camera(JNIEnv *env, jobject thiz)
+sp<Camera> get_native_camera(JNIEnv *env, jobject thiz)
{
- Camera *c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
+ Mutex::Autolock _l(sLock);
+ sp<Camera> c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
if (c == 0)
jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
@@ -80,7 +82,7 @@ static void err_callback(status_t err, void *cookie)
break;
}
LOGV("err_callback: camera_ref=%x, cookie=%x", (int)c->camera_ref, (int)cookie);
-
+
env->CallStaticVoidMethod(c->camera_class, fields.post_event,
c->camera_ref, kErrorCallback, error, 0, NULL);
}
@@ -117,34 +119,38 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj
env->SetIntField(thiz, fields.listener_context, (int)cookie);
LOGV("native_setup: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie);
-
+
// save camera object in opaque field
env->SetIntField(thiz, fields.context, reinterpret_cast<int>(c.get()));
c->setErrorCallback(err_callback, cookie);
-
- // hold a strong reference so this doesn't go away while the app is still running
+
+ // hold a strong reference so the camera doesn't go away while the app is still running
c->incStrong(thiz);
}
// disconnect from camera service
static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
{
+ Mutex::Autolock _l(sLock);
sp<Camera> c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
// It's okay to call this when the native camera context is already null.
// This handles the case where the user has called release() and the
// finalizer is invoked later.
if (c != 0) {
+ // Make sure that we do not attempt to deliver an eror callback on a deleted
+ // Java object.
+ c->setErrorCallback(NULL, NULL);
c->disconnect();
// remove our strong reference created in native setup
c->decStrong(thiz);
env->SetIntField(thiz, fields.context, 0);
-
+
callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
LOGV("release: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie);
-
+
if (cookie) {
env->DeleteGlobalRef(cookie->camera_ref);
env->DeleteGlobalRef(cookie->camera_class);
@@ -156,7 +162,7 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject surface)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return;
@@ -183,6 +189,7 @@ static void preview_callback(const sp<IMemory>& mem, void *cookie)
jbyteArray array = env->NewByteArray(size);
if (array == NULL) {
LOGE("Couldn't allocate byte array for YUV data");
+ env->ExceptionClear();
return;
}
@@ -199,10 +206,10 @@ static void preview_callback(const sp<IMemory>& mem, void *cookie)
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return;
-
+
if (c->startPreview() != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "startPreview failed");
return;
@@ -211,7 +218,7 @@ static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return;
@@ -220,7 +227,7 @@ static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return;
@@ -228,7 +235,10 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
// setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
// each preview frame for nothing.
callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
- c->setFrameCallback(installed ? preview_callback : NULL, cookie);
+
+ c->setFrameCallback(installed ? preview_callback : NULL,
+ cookie,
+ installed ? FRAME_CALLBACK_FLAG_CAMERA: FRAME_CALLBACK_FLAG_NOOP);
}
static void autofocus_callback_impl(bool success, void *cookie)
@@ -236,7 +246,7 @@ static void autofocus_callback_impl(bool success, void *cookie)
JNIEnv *env = AndroidRuntime::getJNIEnv();
callback_cookie *c = (callback_cookie *)cookie;
env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kAutoFocusCallback,
+ c->camera_ref, kAutoFocusCallback,
success, 0, NULL);
}
@@ -244,7 +254,7 @@ static void autofocus_callback_impl(bool success, void *cookie)
static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return;
callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
@@ -282,6 +292,7 @@ static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
jbyteArray array = env->NewByteArray(size);
if (array == NULL) {
LOGE("Couldn't allocate byte array for JPEG data");
+ env->ExceptionClear();
return;
}
@@ -315,7 +326,7 @@ static void raw_callback(const sp<IMemory>& mem __attribute__((unused)),
static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return;
@@ -334,7 +345,7 @@ static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return;
@@ -345,20 +356,32 @@ static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jst
env->ReleaseStringCritical(params, str);
}
if (c->setParameters(params8) != NO_ERROR) {
- jniThrowException(env, "java/io/IllegalArgumentException", "setParameters failed");
+ jniThrowException(env, "java/lang/IllegalArgumentException", "setParameters failed");
return;
}
}
static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz)
{
- Camera *c = get_native_camera(env, thiz);
+ sp<Camera> c = get_native_camera(env, thiz);
if (c == 0)
return 0;
return env->NewStringUTF(c->getParameters().string());
}
+static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
+{
+ sp<Camera> c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+
+ if (c->reconnect() != NO_ERROR) {
+ jniThrowException(env, "java/io/IOException", "reconnect failed");
+ return;
+ }
+}
+
//-------------------------------------------------
static JNINativeMethod camMethods[] = {
@@ -391,7 +414,10 @@ static JNINativeMethod camMethods[] = {
(void *)android_hardware_Camera_setParameters },
{ "native_getParameters",
"()Ljava/lang/String;",
- (void *)android_hardware_Camera_getParameters }
+ (void *)android_hardware_Camera_getParameters },
+ { "reconnect",
+ "()V",
+ (void*)android_hardware_Camera_reconnect },
};
struct field {
@@ -442,7 +468,7 @@ int register_android_hardware_Camera(JNIEnv *env)
LOGE("Can't find android/hardware/Camera.postEventFromNative");
return -1;
}
-
+
// Register native functions
return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e8dcd71..75aa458 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -24,51 +24,142 @@
namespace android {
+struct SensorOffsets
+{
+ jfieldID name;
+ jfieldID vendor;
+ jfieldID version;
+ jfieldID handle;
+ jfieldID type;
+ jfieldID range;
+ jfieldID resolution;
+ jfieldID power;
+} gSensorOffsets;
+
/*
* The method below are not thread-safe and not intended to be
*/
+static sensors_module_t* sSensorModule = 0;
+static sensors_data_device_t* sSensorDevice = 0;
+
+static jint
+sensors_module_init(JNIEnv *env, jclass clazz)
+{
+ int err = 0;
+ sensors_module_t const* module;
+ err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t **)&module);
+ if (err == 0)
+ sSensorModule = (sensors_module_t*)module;
+ return err;
+}
+
static jint
-android_data_open(JNIEnv *env, jclass clazz, jobject fdo)
+sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint next)
+{
+ if (sSensorModule == NULL)
+ return 0;
+
+ SensorOffsets& sensorOffsets = gSensorOffsets;
+ const struct sensor_t* list;
+ int count = sSensorModule->get_sensors_list(sSensorModule, &list);
+ if (next >= count)
+ return -1;
+
+ list += next;
+
+ jstring name = env->NewStringUTF(list->name);
+ jstring vendor = env->NewStringUTF(list->vendor);
+ env->SetObjectField(sensor, sensorOffsets.name, name);
+ env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
+ env->SetIntField(sensor, sensorOffsets.version, list->version);
+ env->SetIntField(sensor, sensorOffsets.handle, list->handle);
+ env->SetIntField(sensor, sensorOffsets.type, list->type);
+ env->SetFloatField(sensor, sensorOffsets.range, list->maxRange);
+ env->SetFloatField(sensor, sensorOffsets.resolution, list->resolution);
+ env->SetFloatField(sensor, sensorOffsets.power, list->power);
+
+ next++;
+ return next<count ? next : 0;
+}
+
+//----------------------------------------------------------------------------
+static jint
+sensors_data_init(JNIEnv *env, jclass clazz)
+{
+ if (sSensorModule == NULL)
+ return -1;
+ int err = sensors_data_open(&sSensorModule->common, &sSensorDevice);
+ return err;
+}
+
+static jint
+sensors_data_uninit(JNIEnv *env, jclass clazz)
+{
+ int err = 0;
+ if (sSensorDevice) {
+ err = sensors_data_close(sSensorDevice);
+ if (err == 0)
+ sSensorDevice = 0;
+ }
+ return err;
+}
+
+static jint
+sensors_data_open(JNIEnv *env, jclass clazz, jobject fdo)
{
jclass FileDescriptor = env->FindClass("java/io/FileDescriptor");
jfieldID offset = env->GetFieldID(FileDescriptor, "descriptor", "I");
int fd = env->GetIntField(fdo, offset);
- return sensors_data_open(fd); // doesn't take ownership of fd
+ return sSensorDevice->data_open(sSensorDevice, fd); // doesn't take ownership of fd
}
static jint
-android_data_close(JNIEnv *env, jclass clazz)
+sensors_data_close(JNIEnv *env, jclass clazz)
{
- return sensors_data_close();
+ return sSensorDevice->data_close(sSensorDevice);
}
static jint
-android_data_poll(JNIEnv *env, jclass clazz, jfloatArray values, jint sensors)
+sensors_data_poll(JNIEnv *env, jclass clazz,
+ jfloatArray values, jintArray status, jlongArray timestamp)
{
sensors_data_t data;
- int res = sensors_data_poll(&data, sensors);
- if (res) {
+ int res = sSensorDevice->poll(sSensorDevice, &data);
+ if (res >= 0) {
+ jint accuracy = data.vector.status;
env->SetFloatArrayRegion(values, 0, 3, data.vector.v);
- // return the sensor's number
- res = 31 - __builtin_clz(res);
- // and its status in the top 4 bits
- res |= data.vector.status << 28;
+ env->SetIntArrayRegion(status, 0, 1, &accuracy);
+ env->SetLongArrayRegion(timestamp, 0, 1, &data.time);
}
return res;
}
-static jint
-android_data_get_sensors(JNIEnv *env, jclass clazz)
+static void
+nativeClassInit (JNIEnv *_env, jclass _this)
{
- return sensors_data_get_sensors();
+ jclass sensorClass = _env->FindClass("android/hardware/Sensor");
+ SensorOffsets& sensorOffsets = gSensorOffsets;
+ sensorOffsets.name = _env->GetFieldID(sensorClass, "mName", "Ljava/lang/String;");
+ sensorOffsets.vendor = _env->GetFieldID(sensorClass, "mVendor", "Ljava/lang/String;");
+ sensorOffsets.version = _env->GetFieldID(sensorClass, "mVersion", "I");
+ sensorOffsets.handle = _env->GetFieldID(sensorClass, "mHandle", "I");
+ sensorOffsets.type = _env->GetFieldID(sensorClass, "mType", "I");
+ sensorOffsets.range = _env->GetFieldID(sensorClass, "mMaxRange", "F");
+ sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F");
+ sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F");
}
static JNINativeMethod gMethods[] = {
- {"_sensors_data_open", "(Ljava/io/FileDescriptor;)I", (void*) android_data_open },
- {"_sensors_data_close", "()I", (void*) android_data_close },
- {"_sensors_data_poll", "([FI)I", (void*) android_data_poll },
- {"_sensors_data_get_sensors","()I", (void*) android_data_get_sensors },
+ {"nativeClassInit", "()V", (void*)nativeClassInit },
+ {"sensors_module_init","()I", (void*)sensors_module_init },
+ {"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I",
+ (void*)sensors_module_get_next_sensor },
+ {"sensors_data_init", "()I", (void*)sensors_data_init },
+ {"sensors_data_uninit", "()I", (void*)sensors_data_uninit },
+ {"sensors_data_open", "(Ljava/io/FileDescriptor;)I", (void*)sensors_data_open },
+ {"sensors_data_close", "()I", (void*)sensors_data_close },
+ {"sensors_data_poll", "([F[I[J)I", (void*)sensors_data_poll },
};
}; // namespace android
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
new file mode 100644
index 0000000..e4586d9
--- /dev/null
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2008 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_NDEBUG 0
+
+#define LOG_TAG "AudioRecord-JNI"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "utils/Log.h"
+#include "media/AudioSystem.h"
+#include "media/AudioRecord.h"
+
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioRecord";
+
+struct fields_t {
+ // these fields provide access from C++ to the...
+ jclass audioRecordClass; //... AudioRecord class
+ jmethodID postNativeEventInJava; //... event post callback method
+ int PCM16; //... format constants
+ int PCM8; //... format constants
+ int SOURCE_DEFAULT; //... record source constants
+ int SOURCE_MIC; //... record source constants
+ jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
+ jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data
+};
+static fields_t javaAudioRecordFields;
+
+struct audiorecord_callback_cookie {
+ jclass audioRecord_class;
+ jobject audioRecord_ref;
+ };
+
+// ----------------------------------------------------------------------------
+
+#define AUDIORECORD_SUCCESS 0
+#define AUDIORECORD_ERROR -1
+#define AUDIORECORD_ERROR_BAD_VALUE -2
+#define AUDIORECORD_ERROR_INVALID_OPERATION -3
+#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -4
+#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -5
+#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -6
+#define AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE -7
+#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -8
+
+jint android_media_translateRecorderErrorCode(int code) {
+ switch(code) {
+ case NO_ERROR:
+ return AUDIORECORD_SUCCESS;
+ case BAD_VALUE:
+ return AUDIORECORD_ERROR_BAD_VALUE;
+ case INVALID_OPERATION:
+ return AUDIORECORD_ERROR_INVALID_OPERATION;
+ default:
+ return AUDIORECORD_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static void recorderCallback(int event, void* user, void *info) {
+ if (event == AudioRecord::EVENT_MORE_DATA) {
+ // set size to 0 to signal we're not using the callback to read more data
+ AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info;
+ pBuff->size = 0;
+
+ } else if (event == AudioRecord::EVENT_MARKER) {
+ audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (user && env) {
+ env->CallStaticVoidMethod(
+ callbackInfo->audioRecord_class,
+ javaAudioRecordFields.postNativeEventInJava,
+ callbackInfo->audioRecord_ref, event, 0,0, NULL);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ }
+
+ } else if (event == AudioRecord::EVENT_NEW_POS) {
+ audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (user && env) {
+ env->CallStaticVoidMethod(
+ callbackInfo->audioRecord_class,
+ javaAudioRecordFields.postNativeEventInJava,
+ callbackInfo->audioRecord_ref, event, 0,0, NULL);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static int
+android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+ jint source, jint sampleRateInHertz, jint nbChannels,
+ jint audioFormat, jint buffSizeInBytes)
+{
+ //LOGV(">> Entering android_media_AudioRecord_setup");
+ //LOGV("sampleRate=%d, audioFormat=%d, nbChannels=%d, buffSizeInBytes=%d",
+ // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+
+ if ((nbChannels == 0) || (nbChannels > 2)) {
+ LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
+ return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ }
+
+ // compare the format against the Java constants
+ if ((audioFormat != javaAudioRecordFields.PCM16)
+ && (audioFormat != javaAudioRecordFields.PCM8)) {
+ LOGE("Error creating AudioRecord: unsupported audio format.");
+ return AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
+ }
+
+ int bytesPerSample = audioFormat==javaAudioRecordFields.PCM16 ? 2 : 1;
+ int format = audioFormat==javaAudioRecordFields.PCM16 ?
+ AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
+
+ if (buffSizeInBytes == 0) {
+ LOGE("Error creating AudioRecord: frameCount is 0.");
+ return AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
+ }
+ int frameSize = nbChannels * bytesPerSample;
+ size_t frameCount = buffSizeInBytes / frameSize;
+
+ // compare the source against the Java constants
+ AudioRecord::stream_type arSource;
+ if (source == javaAudioRecordFields.SOURCE_DEFAULT) {
+ arSource = AudioRecord::DEFAULT_INPUT;
+ } else if (source == javaAudioRecordFields.SOURCE_MIC) {
+ arSource = AudioRecord::MIC_INPUT;
+ } else {
+ LOGE("Error creating AudioRecord: unknown source.");
+ return AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE;
+ }
+
+ audiorecord_callback_cookie *lpCallbackData = NULL;
+ AudioRecord* lpRecorder = NULL;
+
+ // create an uninitialized AudioRecord object
+ lpRecorder = new AudioRecord();
+ if(lpRecorder == NULL) {
+ LOGE("Error creating AudioRecord instance.");
+ return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
+ }
+
+ // create the callback information:
+ // this data will be passed with every AudioRecord callback
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ LOGE("Can't find %s when setting up callback.", kClassPathName);
+ goto native_track_failure;
+ }
+ lpCallbackData = new audiorecord_callback_cookie;
+ lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
+ // we use a weak reference so the AudioRecord object can be garbage collected.
+ lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
+
+ lpRecorder->set(arSource,
+ sampleRateInHertz,
+ format, // word length, PCM
+ nbChannels,
+ frameCount,
+ 0, // flags
+ recorderCallback,// callback_t
+ lpCallbackData,// void* user
+ 0, // notificationFrames,
+ true); // threadCanCallJava)
+
+ if(lpRecorder->initCheck() != NO_ERROR) {
+ LOGE("Error creating AudioRecord instance: initialization check failed.");
+ goto native_init_failure;
+ }
+
+ // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
+ // of the Java object
+ env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)lpRecorder);
+
+ // save our newly created callback information in the "nativeCallbackCookie" field
+ // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
+ env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, (int)lpCallbackData);
+
+ return AUDIORECORD_SUCCESS;
+
+ // failure:
+native_init_failure:
+ delete lpCallbackData;
+
+native_track_failure:
+ delete lpRecorder;
+
+ env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
+ env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+
+ return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
+}
+
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioRecord_start(JNIEnv *env, jobject thiz)
+{
+ AudioRecord *lpRecorder =
+ (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ if (lpRecorder == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ lpRecorder->start();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
+{
+ AudioRecord *lpRecorder =
+ (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ if (lpRecorder == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ lpRecorder->stop();
+ //LOGV("Called lpRecorder->stop()");
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) {
+
+ // delete the AudioRecord object
+ AudioRecord *lpRecorder =
+ (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+
+ if (lpRecorder) {
+ //LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
+ lpRecorder->stop();
+ delete lpRecorder;
+ }
+
+ // delete the callback information
+ audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField(
+ thiz, javaAudioRecordFields.nativeCallbackCookie);
+ if (lpCookie) {
+ LOGV("deleting lpCookie: %x\n", (int)lpCookie);
+ delete lpCookie;
+ }
+
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) {
+
+ // do everything a call to finalize would
+ android_media_AudioRecord_finalize(env, thiz);
+ // + reset the native resources in the Java object so any attempt to access
+ // them after a call to release fails.
+ env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0);
+ env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_readInByteArray(JNIEnv *env, jobject thiz,
+ jbyteArray javaAudioData,
+ jint offsetInBytes, jint sizeInBytes) {
+ jbyte* recordBuff = NULL;
+ AudioRecord *lpRecorder = NULL;
+
+ // get the audio recorder from which we'll read new audio samples
+ lpRecorder =
+ (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ if (lpRecorder == NULL) {
+ LOGE("Unable to retrieve AudioRecord object, can't record");
+ return 0;
+ }
+
+ if (!javaAudioData) {
+ LOGE("Invalid Java array to store recorded audio, can't record");
+ return 0;
+ }
+
+ // get the pointer to where we'll record the audio
+ recordBuff = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+
+ if (recordBuff == NULL) {
+ LOGE("Error retrieving destination for recorded audio data, can't record");
+ return 0;
+ }
+
+ // read the new audio data from the native AudioRecord object
+ ssize_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
+ ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes,
+ sizeInBytes > (jint)recorderBuffSize ?
+ (jint)recorderBuffSize : sizeInBytes );
+ env->ReleasePrimitiveArrayCritical(javaAudioData, recordBuff, 0);
+
+ return (jint) readSize;
+}
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thiz,
+ jshortArray javaAudioData,
+ jint offsetInShorts, jint sizeInShorts) {
+
+ return (android_media_AudioRecord_readInByteArray(env, thiz,
+ (jbyteArray) javaAudioData,
+ offsetInShorts*2, sizeInShorts*2)
+ / 2);
+}
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz,
+ jobject jBuffer, jint sizeInBytes) {
+ AudioRecord *lpRecorder = NULL;
+ //LOGV("Entering android_media_AudioRecord_readInBuffer");
+
+ // get the audio recorder from which we'll read new audio samples
+ lpRecorder =
+ (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ if(lpRecorder==NULL)
+ return 0;
+
+ // direct buffer and direct access supported?
+ long capacity = env->GetDirectBufferCapacity(jBuffer);
+ if(capacity == -1) {
+ // buffer direct access is not supported
+ LOGE("Buffer direct access is not supported, can't record");
+ return 0;
+ }
+ //LOGV("capacity = %ld", capacity);
+ jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
+ if(nativeFromJavaBuf==NULL) {
+ LOGE("Buffer direct access is not supported, can't record");
+ return 0;
+ }
+
+ // read new data from the recorder
+ return (jint) lpRecorder->read(nativeFromJavaBuf,
+ capacity < sizeInBytes ? capacity : sizeInBytes);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz,
+ jint markerPos) {
+
+ AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+ thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+
+ if (lpRecorder) {
+ return
+ android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
+ return AUDIORECORD_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) {
+
+ AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+ thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ uint32_t markerPos = 0;
+
+ if (lpRecorder) {
+ lpRecorder->getMarkerPosition(&markerPos);
+ return (jint)markerPos;
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
+ return AUDIORECORD_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz,
+ jint period) {
+
+ AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+ thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+
+ if (lpRecorder) {
+ return
+ android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
+ return AUDIORECORD_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) {
+
+ AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField(
+ thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
+ uint32_t period = 0;
+
+ if (lpRecorder) {
+ lpRecorder->getPositionUpdatePeriod(&period);
+ return (jint)period;
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
+ return AUDIORECORD_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+static JNINativeMethod gMethods[] = {
+ // name, signature, funcPtr
+ {"native_start", "()V", (void *)android_media_AudioRecord_start},
+ {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
+ {"native_setup", "(Ljava/lang/Object;IIIII)I",
+ (void *)android_media_AudioRecord_setup},
+ {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
+ {"native_release", "()V", (void *)android_media_AudioRecord_release},
+ {"native_read_in_byte_array",
+ "([BII)I", (void *)android_media_AudioRecord_readInByteArray},
+ {"native_read_in_short_array",
+ "([SII)I", (void *)android_media_AudioRecord_readInShortArray},
+ {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I",
+ (void *)android_media_AudioRecord_readInDirectBuffer},
+ {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos},
+ {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos},
+ {"native_set_pos_update_period",
+ "(I)I", (void *)android_media_AudioRecord_set_pos_update_period},
+ {"native_get_pos_update_period",
+ "()I", (void *)android_media_AudioRecord_get_pos_update_period},
+};
+
+// field names found in android/media/AudioRecord.java
+#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
+#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT"
+#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT"
+#define JAVA_CONST_SOURCEDEFAULT_NAME "SOURCE_DEFAULT"
+#define JAVA_CONST_SOURCEMIC_NAME "SOURCE_MIC"
+#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj"
+#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie"
+
+#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
+
+// ----------------------------------------------------------------------------
+
+extern bool android_media_getIntConstantFromClass(JNIEnv* pEnv,
+ jclass theClass, const char* className, const char* constName, int* constVal);
+
+// ----------------------------------------------------------------------------
+int register_android_media_AudioRecord(JNIEnv *env)
+{
+ javaAudioRecordFields.audioRecordClass = NULL;
+ javaAudioRecordFields.postNativeEventInJava = NULL;
+ javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
+ javaAudioRecordFields.nativeCallbackCookie = NULL;
+
+
+ // Get the AudioRecord class
+ javaAudioRecordFields.audioRecordClass = env->FindClass(kClassPathName);
+ if (javaAudioRecordFields.audioRecordClass == NULL) {
+ LOGE("Can't find %s", kClassPathName);
+ return -1;
+ }
+
+ // Get the postEvent method
+ javaAudioRecordFields.postNativeEventInJava = env->GetStaticMethodID(
+ javaAudioRecordFields.audioRecordClass,
+ JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (javaAudioRecordFields.postNativeEventInJava == NULL) {
+ LOGE("Can't find AudioRecord.%s", JAVA_POSTEVENT_CALLBACK_NAME);
+ return -1;
+ }
+
+ // Get the variables
+ // mNativeRecorderInJavaObj
+ javaAudioRecordFields.nativeRecorderInJavaObj =
+ env->GetFieldID(javaAudioRecordFields.audioRecordClass,
+ JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "I");
+ if (javaAudioRecordFields.nativeRecorderInJavaObj == NULL) {
+ LOGE("Can't find AudioRecord.%s", JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME);
+ return -1;
+ }
+ // mNativeCallbackCookie
+ javaAudioRecordFields.nativeCallbackCookie = env->GetFieldID(
+ javaAudioRecordFields.audioRecordClass,
+ JAVA_NATIVECALLBACKINFO_FIELD_NAME, "I");
+ if (javaAudioRecordFields.nativeCallbackCookie == NULL) {
+ LOGE("Can't find AudioRecord.%s", JAVA_NATIVECALLBACKINFO_FIELD_NAME);
+ return -1;
+ }
+
+ // Get the format constants from the AudioFormat class
+ jclass audioFormatClass = NULL;
+ audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
+ if (audioFormatClass == NULL) {
+ LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
+ return -1;
+ }
+ if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
+ JAVA_AUDIOFORMAT_CLASS_NAME,
+ JAVA_CONST_PCM16_NAME, &(javaAudioRecordFields.PCM16))
+ || !android_media_getIntConstantFromClass(env, audioFormatClass,
+ JAVA_AUDIOFORMAT_CLASS_NAME,
+ JAVA_CONST_PCM8_NAME, &(javaAudioRecordFields.PCM8)) ) {
+ // error log performed in getIntConstantFromClass()
+ return -1;
+ }
+
+ // Get the recording source constants from the AudioRecord class
+ if ( !android_media_getIntConstantFromClass(env, javaAudioRecordFields.audioRecordClass,
+ kClassPathName,
+ JAVA_CONST_SOURCEDEFAULT_NAME, &(javaAudioRecordFields.SOURCE_DEFAULT))
+ || !android_media_getIntConstantFromClass(env, javaAudioRecordFields.audioRecordClass,
+ kClassPathName,
+ JAVA_CONST_SOURCEMIC_NAME, &(javaAudioRecordFields.SOURCE_MIC)) ) {
+ // error log performed in getIntConstantFromClass()
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ kClassPathName, gMethods, NELEM(gMethods));
+}
+
+// ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
new file mode 100644
index 0000000..4a98fcc
--- /dev/null
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2008 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_NDEBUG 0
+
+#define LOG_TAG "AudioTrack-JNI"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "utils/Log.h"
+#include "media/AudioSystem.h"
+#include "media/AudioTrack.h"
+
+#include <utils/MemoryHeapBase.h>
+#include <utils/MemoryBase.h>
+
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioTrack";
+
+struct fields_t {
+ // these fields provide access from C++ to the...
+ jclass audioTrackClass; //... AudioTrack class
+ jmethodID postNativeEventInJava; //... event post callback method
+ int PCM16; //... format constants
+ int PCM8; //... format constants
+ int STREAM_VOICE_CALL; //... stream type constants
+ int STREAM_SYSTEM; //... stream type constants
+ int STREAM_RING; //... stream type constants
+ int STREAM_MUSIC; //... stream type constants
+ int STREAM_ALARM; //... stream type constants
+ int MODE_STREAM; //... memory mode
+ int MODE_STATIC; //... memory mode
+ jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
+ jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
+};
+static fields_t javaAudioTrackFields;
+
+struct audiotrack_callback_cookie {
+ jclass audioTrack_class;
+ jobject audioTrack_ref;
+ };
+
+// ----------------------------------------------------------------------------
+class AudioTrackJniStorage {
+ public:
+ sp<MemoryHeapBase> mMemHeap;
+ sp<MemoryBase> mMemBase;
+ audiotrack_callback_cookie mCallbackData;
+
+ AudioTrackJniStorage() {
+ }
+
+ ~AudioTrackJniStorage() {
+ mMemBase.clear();
+ mMemHeap.clear();
+ }
+
+ bool allocSharedMem(int sizeInBytes) {
+ mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
+ if (mMemHeap->getHeapID() < 0) {
+ return false;
+ }
+ mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
+ return true;
+ }
+};
+
+// ----------------------------------------------------------------------------
+#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
+
+#define AUDIOTRACK_SUCCESS 0
+#define AUDIOTRACK_ERROR -1
+#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -2
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -3
+#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -4
+#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -5
+#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -6
+#define AUDIOTRACK_ERROR_BAD_VALUE -7
+#define AUDIOTRACK_ERROR_INVALID_OPERATION -8
+
+
+jint android_media_translateErrorCode(int code) {
+ switch(code) {
+ case NO_ERROR:
+ return AUDIOTRACK_SUCCESS;
+ case BAD_VALUE:
+ return AUDIOTRACK_ERROR_BAD_VALUE;
+ case INVALID_OPERATION:
+ return AUDIOTRACK_ERROR_INVALID_OPERATION;
+ default:
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static void audioCallback(int event, void* user, void *info) {
+ if (event == AudioTrack::EVENT_MORE_DATA) {
+ // set size to 0 to signal we're not using the callback to write more data
+ AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;
+ pBuff->size = 0;
+
+ } else if (event == AudioTrack::EVENT_MARKER) {
+ audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (user && env) {
+ env->CallStaticVoidMethod(
+ callbackInfo->audioTrack_class,
+ javaAudioTrackFields.postNativeEventInJava,
+ callbackInfo->audioTrack_ref, event, 0,0, NULL);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ }
+
+ } else if (event == AudioTrack::EVENT_NEW_POS) {
+ audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (user && env) {
+ env->CallStaticVoidMethod(
+ callbackInfo->audioTrack_class,
+ javaAudioTrackFields.postNativeEventInJava,
+ callbackInfo->audioTrack_ref, event, 0,0, NULL);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static int
+android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+ jint streamType, jint sampleRateInHertz, jint nbChannels,
+ jint audioFormat, jint buffSizeInBytes, jint memoryMode)
+{
+ //LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d",
+ // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ int afSampleRate;
+ int afFrameCount;
+
+ if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+ LOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
+ return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
+ }
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+ LOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
+ return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
+ }
+
+ if ((nbChannels == 0) || (nbChannels > 2)) {
+ LOGE("Error creating AudioTrack: channel count is not 1 or 2.");
+ return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ }
+
+ // check the stream type
+ AudioTrack::stream_type atStreamType;
+ if (streamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
+ atStreamType = AudioTrack::VOICE_CALL;
+ } else if (streamType == javaAudioTrackFields.STREAM_SYSTEM) {
+ atStreamType = AudioTrack::SYSTEM;
+ } else if (streamType == javaAudioTrackFields.STREAM_RING) {
+ atStreamType = AudioTrack::RING;
+ } else if (streamType == javaAudioTrackFields.STREAM_MUSIC) {
+ atStreamType = AudioTrack::MUSIC;
+ } else if (streamType == javaAudioTrackFields.STREAM_ALARM) {
+ atStreamType = AudioTrack::ALARM;
+ } else {
+ LOGE("Error creating AudioTrack: unknown stream type.");
+ return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
+ }
+
+ // check the format.
+ // This function was called from Java, so we compare the format against the Java constants
+ if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) {
+ LOGE("Error creating AudioTrack: unsupported audio format.");
+ return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
+ }
+
+ // compute the frame count
+ int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
+ int format = audioFormat == javaAudioTrackFields.PCM16 ?
+ AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
+ int frameCount;
+ if (buffSizeInBytes == -1) {
+ // compute the frame count based on the system's output frame count
+ // and the native sample rate
+ frameCount = (sampleRateInHertz*afFrameCount)/afSampleRate;
+ } else {
+ // compute the frame count based on the specified buffer size
+ frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
+ }
+
+ AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
+
+ // initialize the callback information:
+ // this data will be passed with every AudioTrack callback
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ LOGE("Can't find %s when setting up callback.", kClassPathName);
+ delete lpJniStorage;
+ return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
+ }
+ lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
+ // we use a weak reference so the AudioTrack object can be garbage collected.
+ lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+
+ // create the native AudioTrack object
+ AudioTrack* lpTrack = new AudioTrack();
+ if (lpTrack == NULL) {
+ LOGE("Error creating uninitialized AudioTrack");
+ goto native_track_failure;
+ }
+
+ // initialize the native AudioTrack object
+ if (memoryMode == javaAudioTrackFields.MODE_STREAM) {
+
+ lpTrack->set(
+ atStreamType,// stream type
+ sampleRateInHertz,
+ format,// word length, PCM
+ nbChannels,
+ frameCount,
+ 0,// flags
+ audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
+ 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
+ 0,// shared mem
+ true);// thread can call Java
+
+ } else if (memoryMode == javaAudioTrackFields.MODE_STATIC) {
+ // AudioTrack is using shared memory
+
+ if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
+ LOGE("Error creating AudioTrack in static mode: error creating mem heap base");
+ goto native_init_failure;
+ }
+
+ lpTrack->set(
+ atStreamType,// stream type
+ sampleRateInHertz,
+ format,// word length, PCM
+ nbChannels,
+ frameCount,
+ 0,// flags
+ audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
+ 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
+ lpJniStorage->mMemBase,// shared mem
+ true);// thread can call Java
+ }
+
+ if (lpTrack->initCheck() != NO_ERROR) {
+ LOGE("Error initializing AudioTrack");
+ goto native_init_failure;
+ }
+
+ // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
+ // of the Java object (in mNativeTrackInJavaObj)
+ env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack);
+
+ // save the JNI resources so we can free them later
+ //LOGV("storing lpJniStorage: %x\n", (int)lpJniStorage);
+ env->SetIntField(thiz, javaAudioTrackFields.jniData, (int)lpJniStorage);
+
+ return AUDIOTRACK_SUCCESS;
+
+ // failures:
+native_init_failure:
+ delete lpTrack;
+ env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
+
+native_track_failure:
+ delete lpJniStorage;
+ env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
+ return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
+
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
+{
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for start()");
+ }
+
+ lpTrack->start();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
+{
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for stop()");
+ }
+
+ lpTrack->stop();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
+{
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for pause()");
+ }
+
+ lpTrack->pause();
+}
+
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
+{
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for flush()");
+ }
+
+ lpTrack->flush();
+}
+
+// ----------------------------------------------------------------------------
+static void
+android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
+{
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for setVolume()");
+ }
+
+ lpTrack->setVolume(leftVol, rightVol);
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
+ LOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
+
+ // delete the AudioTrack object
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack) {
+ LOGV("deleting lpTrack: %x\n", (int)lpTrack);
+ lpTrack->stop();
+ delete lpTrack;
+ }
+
+ // delete the JNI data
+ AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetIntField(
+ thiz, javaAudioTrackFields.jniData);
+ if (pJniStorage) {
+ LOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
+ delete pJniStorage;
+ }
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) {
+
+ // do everything a call to finalize would
+ android_media_AudioTrack_native_finalize(env, thiz);
+ // + reset the native resources in the Java object so any attempt to access
+ // them after a call to release fails.
+ env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
+ env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz,
+ jbyteArray javaAudioData,
+ jint offsetInBytes, jint sizeInBytes) {
+ jbyte* cAudioData = NULL;
+ AudioTrack *lpTrack = NULL;
+ //LOGV("android_media_AudioTrack_native_write(offset=%d, sizeInBytes=%d) called",
+ // offsetInBytes, sizeInBytes);
+
+ // get the audio track to load with samples
+ lpTrack = (AudioTrack *)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for write()");
+ }
+
+ // get the pointer for the audio data from the java array
+ if (javaAudioData) {
+ cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+ if (cAudioData == NULL) {
+ LOGE("Error retrieving source of audio data to play, can't play");
+ return 0; // out of memory or no data to load
+ }
+ } else {
+ LOGE("NULL java array of audio data to play, can't play");
+ return 0;
+ }
+
+ // give the data to the native AudioTrack object (the data starts at the offset)
+ ssize_t written = 0;
+ // regular write() or copy the data to the AudioTrack's shared memory?
+ if (lpTrack->sharedBuffer() == 0) {
+ written = lpTrack->write(cAudioData + offsetInBytes, sizeInBytes);
+ } else {
+ memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes);
+ written = sizeInBytes;
+ }
+
+ env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
+
+ //LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
+ // (int)written, (int)(sizeInBytes), (int)offsetInBytes);
+ return (int)written;
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz,
+ jshortArray javaAudioData,
+ jint offsetInShorts, jint sizeInShorts) {
+ return (android_media_AudioTrack_native_write(env, thiz,
+ (jbyteArray) javaAudioData,
+ offsetInShorts*2, sizeInShorts*2)
+ / 2);
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+ if (lpTrack) {
+ return lpTrack->frameCount();
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for frameCount()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
+ jint sampleRateInHz) {
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+ if (lpTrack) {
+ lpTrack->setSampleRate(sampleRateInHz);
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for setSampleRate()");
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+ if (lpTrack) {
+ return (jint) lpTrack->getSampleRate();
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for getSampleRate()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
+ jint markerPos) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+ if (lpTrack) {
+ return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ uint32_t markerPos = 0;
+
+ if (lpTrack) {
+ lpTrack->getMarkerPosition(&markerPos);
+ return (jint)markerPos;
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
+ jint period) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+ if (lpTrack) {
+ return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ uint32_t period = 0;
+
+ if (lpTrack) {
+ lpTrack->getPositionUpdatePeriod(&period);
+ return (jint)period;
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
+ jint position) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+
+ if (lpTrack) {
+ return android_media_translateErrorCode( lpTrack->setPosition(position) );
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for setPosition()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ uint32_t position = 0;
+
+ if (lpTrack) {
+ lpTrack->getPosition(&position);
+ return (jint)position;
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for getPosition()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
+ jint loopStart, jint loopEnd, jint loopCount) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack) {
+ return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for setLoop()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
+
+ AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
+ thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+ if (lpTrack) {
+ return android_media_translateErrorCode( lpTrack->reload() );
+ } else {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for reload()");
+ return AUDIOTRACK_ERROR;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz) {
+ int afSamplingRate;
+ if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+ return DEFAULT_OUTPUT_SAMPLE_RATE;
+ } else {
+ return afSamplingRate;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+static JNINativeMethod gMethods[] = {
+ // name, signature, funcPtr
+ {"native_start", "()V", (void *)android_media_AudioTrack_start},
+ {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
+ {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
+ {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
+ {"native_setup", "(Ljava/lang/Object;IIIIII)I",
+ (void *)android_media_AudioTrack_native_setup},
+ {"native_finalize", "()V", (void *)android_media_AudioTrack_native_finalize},
+ {"native_release", "()V", (void *)android_media_AudioTrack_native_release},
+ {"native_write_byte", "([BII)I", (void *)android_media_AudioTrack_native_write},
+ {"native_write_short", "([SII)I", (void *)android_media_AudioTrack_native_write_short},
+ {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
+ {"native_get_native_frame_count",
+ "()I", (void *)android_media_AudioTrack_get_native_frame_count},
+ {"native_set_playback_rate",
+ "(I)V", (void *)android_media_AudioTrack_set_playback_rate},
+ {"native_get_playback_rate",
+ "()I", (void *)android_media_AudioTrack_get_playback_rate},
+ {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
+ {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
+ {"native_set_pos_update_period",
+ "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
+ {"native_get_pos_update_period",
+ "()I", (void *)android_media_AudioTrack_get_pos_update_period},
+ {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
+ {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
+ {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
+ {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
+ {"native_get_output_sample_rate",
+ "()I", (void *)android_media_AudioTrack_get_output_sample_rate},
+};
+
+
+// field names found in android/media/AudioTrack.java
+#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
+#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT"
+#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT"
+#define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT"
+#define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL"
+#define JAVA_CONST_STREAM_SYSTEM_NAME "STREAM_SYSTEM"
+#define JAVA_CONST_STREAM_RING_NAME "STREAM_RING"
+#define JAVA_CONST_STREAM_MUSIC_NAME "STREAM_MUSIC"
+#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
+#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
+#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
+#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
+#define JAVA_JNIDATA_FIELD_NAME "mJniData"
+
+#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
+#define JAVA_AUDIOMANAGER_CLASS_NAME "android/media/AudioManager"
+
+// ----------------------------------------------------------------------------
+// preconditions:
+// theClass is valid
+bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
+ const char* constName, int* constVal) {
+ jfieldID javaConst = NULL;
+ javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
+ if (javaConst != NULL) {
+ *constVal = pEnv->GetStaticIntField(theClass, javaConst);
+ return true;
+ } else {
+ LOGE("Can't find %s.%s", className, constName);
+ return false;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+int register_android_media_AudioTrack(JNIEnv *env)
+{
+ javaAudioTrackFields.audioTrackClass = NULL;
+ javaAudioTrackFields.nativeTrackInJavaObj = NULL;
+ javaAudioTrackFields.postNativeEventInJava = NULL;
+
+ // Get the AudioTrack class
+ javaAudioTrackFields.audioTrackClass = env->FindClass(kClassPathName);
+ if (javaAudioTrackFields.audioTrackClass == NULL) {
+ LOGE("Can't find %s", kClassPathName);
+ return -1;
+ }
+
+ // Get the postEvent method
+ javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID(
+ javaAudioTrackFields.audioTrackClass,
+ JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (javaAudioTrackFields.postNativeEventInJava == NULL) {
+ LOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME);
+ return -1;
+ }
+
+ // Get the variables fields
+ // nativeTrackInJavaObj
+ javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID(
+ javaAudioTrackFields.audioTrackClass,
+ JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "I");
+ if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) {
+ LOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME);
+ return -1;
+ }
+ // jniData;
+ javaAudioTrackFields.jniData = env->GetFieldID(
+ javaAudioTrackFields.audioTrackClass,
+ JAVA_JNIDATA_FIELD_NAME, "I");
+ if (javaAudioTrackFields.jniData == NULL) {
+ LOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME);
+ return -1;
+ }
+
+ // Get the memory mode constants
+ if ( !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass,
+ kClassPathName,
+ JAVA_CONST_MODE_STATIC_NAME, &(javaAudioTrackFields.MODE_STATIC))
+ || !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass,
+ kClassPathName,
+ JAVA_CONST_MODE_STREAM_NAME, &(javaAudioTrackFields.MODE_STREAM)) ) {
+ // error log performed in android_media_getIntConstantFromClass()
+ return -1;
+ }
+
+ // Get the format constants from the AudioFormat class
+ jclass audioFormatClass = NULL;
+ audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
+ if (audioFormatClass == NULL) {
+ LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
+ return -1;
+ }
+ if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
+ JAVA_AUDIOFORMAT_CLASS_NAME,
+ JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16))
+ || !android_media_getIntConstantFromClass(env, audioFormatClass,
+ JAVA_AUDIOFORMAT_CLASS_NAME,
+ JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) {
+ // error log performed in android_media_getIntConstantFromClass()
+ return -1;
+ }
+
+ // Get the stream types from the AudioManager class
+ jclass audioManagerClass = NULL;
+ audioManagerClass = env->FindClass(JAVA_AUDIOMANAGER_CLASS_NAME);
+ if (audioManagerClass == NULL) {
+ LOGE("Can't find %s", JAVA_AUDIOMANAGER_CLASS_NAME);
+ return -1;
+ }
+ if ( !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_VOICE_CALL_NAME, &(javaAudioTrackFields.STREAM_VOICE_CALL))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_MUSIC_NAME, &(javaAudioTrackFields.STREAM_MUSIC))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_SYSTEM_NAME, &(javaAudioTrackFields.STREAM_SYSTEM))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_RING_NAME, &(javaAudioTrackFields.STREAM_RING))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_ALARM_NAME, &(javaAudioTrackFields.STREAM_ALARM)) ) {
+ // error log performed in android_media_getIntConstantFromClass()
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+
+// ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 73c1283..a4388de 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -87,7 +87,7 @@ static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
if (lpToneGen == NULL) {
LOGE("ToneGenerator creation failed \n");
- jniThrowException(env, "java/lang/OutOfMemoryException", NULL);
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
LOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index abd0961..f14b9fa 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -700,7 +700,7 @@ static jint socket_readba (JNIEnv *env, jobject object,
}
if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
- jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL);
+ jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
return (jint)-1;
}
@@ -767,7 +767,7 @@ static void socket_writeba (JNIEnv *env, jobject object,
}
if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
- jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL);
+ jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
return;
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 417ce54..8383deb 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -41,6 +41,7 @@ int dhcp_do_request(const char *ifname,
in_addr_t *server,
uint32_t *lease);
int dhcp_stop(const char *ifname);
+int dhcp_release_lease(const char *ifname);
char *dhcp_get_errmsg();
}
@@ -157,7 +158,7 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if
return (jboolean)(result == 0);
}
-static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -167,6 +168,16 @@ static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring i
return (jboolean)(result == 0);
}
+static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::dhcp_release_lease(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jboolean)(result == 0);
+}
+
static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
{
return env->NewStringUTF(::dhcp_get_errmsg());
@@ -207,6 +218,7 @@ static JNINativeMethod gNetworkUtilMethods[] = {
{ "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections },
{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
+ { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
};
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 48af99e..722b5b8 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -343,6 +343,32 @@ static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz,
return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
}
+static jboolean android_net_wifi_setNumAllowedChannelsCommand(JNIEnv* env, jobject clazz, jint numChannels)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER SCAN-CHANNELS %u", numChannels);
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jint android_net_wifi_getNumAllowedChannelsCommand(JNIEnv* env, jobject clazz)
+{
+ char reply[256];
+ int numChannels;
+
+ if (doCommand("DRIVER SCAN-CHANNELS", reply, sizeof(reply)) != 0) {
+ return -1;
+ }
+ // reply comes back in the form "Scan-Channels = X" where X is the
+ // number of channels
+ if (sscanf(reply, "%*s = %u", &numChannels) == 1)
+ return numChannels;
+ else
+ return -1;
+}
+
static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode)
{
char cmdstr[256];
@@ -382,7 +408,7 @@ static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject claz
const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
- int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= sizeof(cmdstr);
+ int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= (int)sizeof(cmdstr);
env->ReleaseStringUTFChars(bssid, bssidStr);
@@ -453,6 +479,8 @@ static JNINativeMethod gWifiMethods[] = {
{ "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand },
{ "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand },
{ "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },
+ { "setNumAllowedChannelsCommand", "(I)Z", (void*) android_net_wifi_setNumAllowedChannelsCommand },
+ { "getNumAllowedChannelsCommand", "()I", (void*) android_net_wifi_getNumAllowedChannelsCommand },
{ "setBluetoothCoexistenceModeCommand", "(I)Z",
(void*) android_net_wifi_setBluetoothCoexistenceModeCommand },
{ "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand },
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
new file mode 100644
index 0000000..19ed39f
--- /dev/null
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -0,0 +1,417 @@
+/*
+** Copyright 2008, 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 "BluetoothA2dpService.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jmethodID method_onHeadsetCreated;
+static jmethodID method_onHeadsetRemoved;
+static jmethodID method_onSinkConnected;
+static jmethodID method_onSinkDisconnected;
+static jmethodID method_onSinkPlaying;
+static jmethodID method_onSinkStopped;
+
+typedef struct {
+ JNIEnv *env;
+ DBusConnection *conn;
+ jobject me; // for callbacks to java
+} native_data_t;
+
+static native_data_t *nat = NULL; // global native data
+
+extern event_loop_native_data_t *event_loop_nat; // for the event loop JNIEnv
+#endif
+
+#ifdef HAVE_BLUETOOTH
+static void onConnectSinkResult(DBusMessage *msg, void *user);
+static void onDisconnectSinkResult(DBusMessage *msg, void *user);
+#endif
+
+/* Returns true on success (even if adapter is present but disabled).
+ * Return false if dbus is down, or another serious error (out of memory)
+*/
+static bool initNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return false;
+ }
+ nat->env = env;
+ nat->me = env->NewGlobalRef(object);
+
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_threads_init_default();
+ nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ LOGE("Could not get onto the system bus: %s", err.message);
+ dbus_error_free(&err);
+ return false;
+ }
+#endif /*HAVE_BLUETOOTH*/
+ return true;
+}
+
+static void cleanupNative(JNIEnv* env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ dbus_connection_close(nat->conn);
+ env->DeleteGlobalRef(nat->me);
+ free(nat);
+ nat = NULL;
+ }
+#endif
+}
+static jobjectArray listHeadsetsNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, "/org/bluez/audio",
+ "org.bluez.audio.Manager", "ListHeadsets",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jstring createHeadsetNative(JNIEnv *env, jobject object,
+ jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s\n", c_address);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, "/org/bluez/audio",
+ "org.bluez.audio.Manager", "CreateHeadset",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return reply ? dbus_returns_string(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jstring removeHeadsetNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, "/org/bluez/audio",
+ "org.bluez.audio.Manager", "RemoveHeadset",
+ DBUS_TYPE_STRING, &c_path,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+ return reply ? dbus_returns_string(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jstring getAddressNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, c_path,
+ "org.bluez.audio.Device", "GetAddress",
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+ return reply ? dbus_returns_string(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ size_t path_sz = env->GetStringUTFLength(path) + 1;
+ char *c_path_copy = (char *)malloc(path_sz); // callback data
+ strncpy(c_path_copy, c_path, path_sz);
+
+ bool ret =
+ dbus_func_args_async(env, nat->conn, -1,
+ onConnectSinkResult, (void *)c_path_copy, c_path,
+ "org.bluez.audio.Sink", "Connect",
+ DBUS_TYPE_INVALID);
+
+ env->ReleaseStringUTFChars(path, c_path);
+ if (!ret) {
+ free(c_path_copy);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
+ jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ size_t path_sz = env->GetStringUTFLength(path) + 1;
+ char *c_path_copy = (char *)malloc(path_sz); // callback data
+ strncpy(c_path_copy, c_path, path_sz);
+
+ bool ret =
+ dbus_func_args_async(env, nat->conn, -1,
+ onDisconnectSinkResult, (void *)c_path_copy, c_path,
+ "org.bluez.audio.Sink", "Disconnect",
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+ if (!ret) {
+ free(c_path_copy);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ if (nat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, c_path,
+ "org.bluez.audio.Sink", "IsConnected",
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+ return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+#ifdef HAVE_BLUETOOTH
+static void onConnectSinkResult(DBusMessage *msg, void *user) {
+ LOGV(__FUNCTION__);
+
+ char *c_path = (char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env = event_loop_nat->env;
+
+ LOGV("... path = %s", c_path);
+ if (dbus_set_error_from_message(&err, msg)) {
+ /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ dbus_error_free(&err);
+ env->CallVoidMethod(nat->me,
+ method_onSinkDisconnected,
+ env->NewStringUTF(c_path));
+ if (env->ExceptionCheck()) {
+ LOGE("VM Exception occurred in native function %s (%s:%d)",
+ __FUNCTION__, __FILE__, __LINE__);
+ }
+ } // else Java callback is triggered by signal in a2dp_event_filter
+
+ free(c_path);
+}
+
+static void onDisconnectSinkResult(DBusMessage *msg, void *user) {
+ LOGV(__FUNCTION__);
+
+ char *c_path = (char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env = event_loop_nat->env;
+
+ LOGV("... path = %s", c_path);
+ if (dbus_set_error_from_message(&err, msg)) {
+ /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ dbus_error_free(&err);
+ // Assume it is still connected
+ env->CallVoidMethod(nat->me,
+ method_onSinkConnected,
+ env->NewStringUTF(c_path));
+ if (env->ExceptionCheck()) {
+ LOGE("VM Exception occurred in native function %s (%s:%d)",
+ __FUNCTION__, __FILE__, __LINE__);
+ }
+ } // else Java callback is triggered by signal in a2dp_event_filter
+
+ free(c_path);
+}
+
+DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
+ DBusError err;
+
+ if (!nat) {
+ LOGV("... skipping %s\n", __FUNCTION__);
+ LOGV("... ignored\n");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ dbus_error_init(&err);
+
+ if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_is_signal(msg,
+ "org.bluez.audio.Manager",
+ "HeadsetCreated")) {
+ char *c_path;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_path,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... path = %s", c_path);
+ env->CallVoidMethod(nat->me,
+ method_onHeadsetCreated,
+ env->NewStringUTF(c_path));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.audio.Manager",
+ "HeadsetRemoved")) {
+ char *c_path;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_path,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... path = %s", c_path);
+ env->CallVoidMethod(nat->me,
+ method_onHeadsetRemoved,
+ env->NewStringUTF(c_path));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.audio.Sink",
+ "Connected")) {
+ const char *c_path = dbus_message_get_path(msg);
+ LOGV("... path = %s", c_path);
+ env->CallVoidMethod(nat->me,
+ method_onSinkConnected,
+ env->NewStringUTF(c_path));
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.audio.Sink",
+ "Disconnected")) {
+ const char *c_path = dbus_message_get_path(msg);
+ LOGV("... path = %s", c_path);
+ env->CallVoidMethod(nat->me,
+ method_onSinkDisconnected,
+ env->NewStringUTF(c_path));
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.audio.Sink",
+ "Playing")) {
+ const char *c_path = dbus_message_get_path(msg);
+ LOGV("... path = %s", c_path);
+ env->CallVoidMethod(nat->me,
+ method_onSinkPlaying,
+ env->NewStringUTF(c_path));
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.audio.Sink",
+ "Stopped")) {
+ const char *c_path = dbus_message_get_path(msg);
+ LOGV("... path = %s", c_path);
+ env->CallVoidMethod(nat->me,
+ method_onSinkStopped,
+ env->NewStringUTF(c_path));
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) {
+ LOGV("... ignored");
+ }
+ if (env->ExceptionCheck()) {
+ LOGE("VM Exception occurred while handling %s.%s (%s) in %s,"
+ " leaving for VM",
+ dbus_message_get_interface(msg), dbus_message_get_member(msg),
+ dbus_message_get_path(msg), __FUNCTION__);
+ }
+
+ return result;
+}
+#endif
+
+
+static JNINativeMethod sMethods[] = {
+ {"initNative", "()Z", (void *)initNative},
+ {"cleanupNative", "()V", (void *)cleanupNative},
+
+ /* Bluez audio 3.36 API */
+ {"listHeadsetsNative", "()[Ljava/lang/String;", (void*)listHeadsetsNative},
+ {"createHeadsetNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)createHeadsetNative},
+ {"removeHeadsetNative", "(Ljava/lang/String;)Z", (void*)removeHeadsetNative},
+ {"getAddressNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAddressNative},
+ {"connectSinkNative", "(Ljava/lang/String;)Z", (void*)connectSinkNative},
+ {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void*)disconnectSinkNative},
+ {"isSinkConnectedNative", "(Ljava/lang/String;)Z", (void*)isSinkConnectedNative},
+};
+
+int register_android_server_BluetoothA2dpService(JNIEnv *env) {
+ jclass clazz = env->FindClass("android/server/BluetoothA2dpService");
+ if (clazz == NULL) {
+ LOGE("Can't find android/server/BluetoothA2dpService");
+ return -1;
+ }
+
+#ifdef HAVE_BLUETOOTH
+ method_onHeadsetCreated = env->GetMethodID(clazz, "onHeadsetCreated", "(Ljava/lang/String;)V");
+ method_onHeadsetRemoved = env->GetMethodID(clazz, "onHeadsetRemoved", "(Ljava/lang/String;)V");
+ method_onSinkConnected = env->GetMethodID(clazz, "onSinkConnected", "(Ljava/lang/String;)V");
+ method_onSinkDisconnected = env->GetMethodID(clazz, "onSinkDisconnected", "(Ljava/lang/String;)V");
+ method_onSinkPlaying = env->GetMethodID(clazz, "onSinkPlaying", "(Ljava/lang/String;)V");
+ method_onSinkStopped = env->GetMethodID(clazz, "onSinkStopped", "(Ljava/lang/String;)V");
+#endif
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothA2dpService", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 395a45c..1aef138 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -39,6 +39,7 @@ namespace android {
static jfieldID field_mNativeData;
static jmethodID method_onModeChanged;
+static jmethodID method_onNameChanged;
static jmethodID method_onDiscoveryStarted;
static jmethodID method_onDiscoveryCompleted;
static jmethodID method_onRemoteDeviceFound;
@@ -60,17 +61,10 @@ static jmethodID method_onGetRemoteServiceChannelResult;
static jmethodID method_onPasskeyAgentRequest;
static jmethodID method_onPasskeyAgentCancel;
-struct native_data_t {
- DBusConnection *conn;
- /* These variables are set in waitForAndDispatchEventNative() and are
- valid only within the scope of this function. At any other time, they
- are NULL. */
- jobject me;
- JNIEnv *env;
-};
+typedef event_loop_native_data_t native_data_t;
// Only valid during waitForAndDispatchEventNative()
-static native_data_t *event_loop_nat;
+native_data_t *event_loop_nat;
static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
return (native_data_t *)(env->GetIntField(object,
@@ -83,6 +77,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
#ifdef HAVE_BLUETOOTH
method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(Ljava/lang/String;)V");
+ method_onNameChanged = env->GetMethodID(clazz, "onNameChanged", "(Ljava/lang/String;)V");
method_onDiscoveryStarted = env->GetMethodID(clazz, "onDiscoveryStarted", "()V");
method_onDiscoveryCompleted = env->GetMethodID(clazz, "onDiscoveryCompleted", "()V");
method_onRemoteDeviceFound = env->GetMethodID(clazz, "onRemoteDeviceFound", "(Ljava/lang/String;IS)V");
@@ -142,8 +137,6 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
}
#ifdef HAVE_BLUETOOTH
-static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat);
-static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat);
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
void *data);
static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
@@ -160,15 +153,46 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
LOGV(__FUNCTION__);
dbus_threads_init_default();
native_data_t *nat = get_native_data(env, object);
+ DBusError err;
+ dbus_error_init(&err);
+
if (nat != NULL && nat->conn != NULL) {
+ // Add a filter for all incoming messages
if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
return JNI_FALSE;
}
- if (add_adapter_event_match(env, nat) != JNI_TRUE) {
+ // Set which messages will be processed by this dbus connection
+ dbus_bus_add_match(nat->conn,
+ "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+ dbus_bus_add_match(nat->conn,
+ "type='signal',interface='org.bluez.audio.Manager'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+ dbus_bus_add_match(nat->conn,
+ "type='signal',interface='org.bluez.audio.Device'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+ dbus_bus_add_match(nat->conn,
+ "type='signal',interface='org.bluez.audio.Sink'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
return JNI_FALSE;
}
+ // Add an object handler for passkey agent method calls
const char *path = "/android/bluetooth/PasskeyAgent";
if (!dbus_connection_register_object_path(nat->conn, path,
&passkey_agent_vtable, NULL)) {
@@ -177,9 +201,6 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
return JNI_FALSE;
}
- DBusError err;
- dbus_error_init(&err);
-
// RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep
// trying for 10 seconds.
int attempt;
@@ -219,6 +240,9 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) {
native_data_t *nat = get_native_data(env, object);
if (nat != NULL && nat->conn != NULL) {
+ DBusError err;
+ dbus_error_init(&err);
+
const char *path = "/android/bluetooth/PasskeyAgent";
DBusMessage *reply =
dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH,
@@ -227,50 +251,40 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) {
DBUS_TYPE_INVALID);
if (reply) dbus_message_unref(reply);
- DBusError err;
- dbus_error_init(&err);
- (void)dbus_connection_remove_filter(nat->conn,
- event_filter,
- nat);
-
dbus_connection_unregister_object_path(nat->conn, path);
- remove_adapter_event_match(env, nat);
+ dbus_bus_remove_match(nat->conn,
+ "type='signal',interface='org.bluez.audio.Sink'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ dbus_bus_remove_match(nat->conn,
+ "type='signal',interface='org.bluez.audio.Device'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ dbus_bus_remove_match(nat->conn,
+ "type='signal',interface='org.bluez.audio.Manager'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ dbus_bus_remove_match(nat->conn,
+ "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+
+ dbus_connection_remove_filter(nat->conn, event_filter, nat);
}
#endif
}
#ifdef HAVE_BLUETOOTH
-static const char *const adapter_event_match =
- "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'";
-
-static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat) {
- if (nat == NULL || nat->conn == NULL) {
- LOGE("%s: Not connected to d-bus!", __FUNCTION__);
- return JNI_FALSE;
- }
- DBusError err;
- dbus_error_init(&err);
- dbus_bus_add_match(nat->conn, adapter_event_match, &err);
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return JNI_FALSE;
- }
- return JNI_TRUE;
-}
-
-static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat) {
- if (nat->conn == NULL) {
- LOGE("%s: Not connected to d-bus!", __FUNCTION__);
- return;
- }
- DBusError err;
- dbus_error_init(&err);
- dbus_bus_remove_match(nat->conn, adapter_event_match, &err);
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- }
-}
+extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env);
// Called by dbus during WaitForAndDispatchEventNative()
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
@@ -288,8 +302,9 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- LOGV("%s: Received signal %s:%s", __FUNCTION__,
- dbus_message_get_interface(msg), dbus_message_get_member(msg));
+ LOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg),
+ dbus_message_get_path(msg));
if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
@@ -471,11 +486,35 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
env->NewStringUTF(c_address));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
return DBUS_HANDLER_RESULT_HANDLED;
- } else {
- LOGV("... ignored");
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "ModeChanged")) {
+ char *c_mode;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_mode,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... mode = %s", c_mode);
+ env->CallVoidMethod(nat->me,
+ method_onModeChanged,
+ env->NewStringUTF(c_mode));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "NameChanged")) {
+ char *c_name;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_name,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... name = %s", c_name);
+ env->CallVoidMethod(nat->me,
+ method_onNameChanged,
+ env->NewStringUTF(c_name));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
}
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return a2dp_event_filter(msg, env);
}
// Called by dbus during WaitForAndDispatchEventNative()
@@ -557,9 +596,9 @@ static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object,
nat->me = object;
nat->env = env;
event_loop_nat = nat;
- ret = dbus_connection_read_write_dispatch(nat->conn,
- timeout_ms) == TRUE ?
- JNI_TRUE : JNI_FALSE;
+ ret = dbus_connection_read_write_dispatch_greedy(nat->conn,
+ timeout_ms) == TRUE ?
+ JNI_TRUE : JNI_FALSE;
event_loop_nat = NULL;
nat->me = NULL;
nat->env = NULL;
@@ -604,7 +643,7 @@ void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) {
JNIEnv *env = event_loop_nat->env;
jint channel = -2;
- LOGV("... address = %s", context->address);
+ LOGV("... address = %s", address);
if (dbus_set_error_from_message(&err, msg) ||
!dbus_message_get_args(msg, &err,
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 97daed3..450cee2 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -43,7 +43,7 @@ static void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, j
}
if (env->GetArrayLength(srcArray) < count || env->GetArrayLength(destArray) < count) {
- jniThrowException(env, "java/lang/ArrayIndexException", NULL);
+ jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
goto DIRECTION_END;
}
@@ -81,7 +81,7 @@ static jboolean mirror(JNIEnv* env, jobject obj, jcharArray charArray, int start
}
if (start > start + count || env->GetArrayLength(charArray) < count) {
- jniThrowException(env, "java/lang/ArrayIndexException", NULL);
+ jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
goto MIRROR_END;
}
diff --git a/core/jni/android_pim_Time.cpp b/core/jni/android_text_format_Time.cpp
index c1dd499..8e41ec7 100644
--- a/core/jni/android_pim_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -25,6 +25,7 @@
#include "android_runtime/AndroidRuntime.h"
#include <utils/TimeUtils.h>
#include <nativehelper/JNIHelp.h>
+#include <cutils/tztime.h>
namespace android {
@@ -41,6 +42,17 @@ static jfieldID g_isdstField = 0;
static jfieldID g_gmtoffField = 0;
static jfieldID g_timezoneField = 0;
+static jfieldID g_shortMonthsField = 0;
+static jfieldID g_longMonthsField = 0;
+static jfieldID g_shortWeekdaysField = 0;
+static jfieldID g_longWeekdaysField = 0;
+static jfieldID g_timeOnlyFormatField = 0;
+static jfieldID g_dateOnlyFormatField = 0;
+static jfieldID g_dateTimeFormatField = 0;
+static jfieldID g_amField = 0;
+static jfieldID g_pmField = 0;
+static jfieldID g_dateCommandField = 0;
+
static inline bool java2time(JNIEnv* env, Time* t, jobject o)
{
t->t.tm_sec = env->GetIntField(o, g_secField);
@@ -89,7 +101,7 @@ static inline void time2java(JNIEnv* env, jobject o, const Time &t)
// ============================================================================
-static jlong android_pim_Time_normalize(JNIEnv* env, jobject This,
+static jlong android_text_format_Time_normalize(JNIEnv* env, jobject This,
jboolean ignoreDst)
{
Time t;
@@ -104,7 +116,7 @@ static jlong android_pim_Time_normalize(JNIEnv* env, jobject This,
return result;
}
-static void android_pim_Time_switchTimezone(JNIEnv* env, jobject This,
+static void android_text_format_Time_switchTimezone(JNIEnv* env, jobject This,
jstring timezoneObject)
{
Time t;
@@ -123,7 +135,7 @@ static void android_pim_Time_switchTimezone(JNIEnv* env, jobject This,
env->SetObjectField(This, g_timezoneField, timezoneObject);
}
-static jint android_pim_Time_compare(JNIEnv* env, jobject clazz,
+static jint android_text_format_Time_compare(JNIEnv* env, jobject clazz,
jobject aObject, jobject bObject)
{
Time a, b;
@@ -142,7 +154,7 @@ static jint android_pim_Time_compare(JNIEnv* env, jobject clazz,
return result;
}
-static jstring android_pim_Time_format2445(JNIEnv* env, jobject This)
+static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This)
{
Time t;
if (!java2time(env, &t, This)) return env->NewStringUTF("");
@@ -168,25 +180,91 @@ static jstring android_pim_Time_format2445(JNIEnv* env, jobject This)
}
}
-static jstring android_pim_Time_format(JNIEnv* env, jobject This,
+static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
jstring formatObject)
{
Time t;
+ struct strftime_locale locale;
+ jclass timeClass = env->FindClass("android/text/format/Time");
+ jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7];
+ jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt;
+ jobjectArray ja;
+
if (!java2time(env, &t, This)) return env->NewStringUTF("");
+
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField);
+ for (int i = 0; i < 12; i++) {
+ js_mon[i] = (jstring) env->GetObjectArrayElement(ja, i);
+ locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL);
+ }
+
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField);
+ for (int i = 0; i < 12; i++) {
+ js_month[i] = (jstring) env->GetObjectArrayElement(ja, i);
+ locale.month[i] = env->GetStringUTFChars(js_month[i], NULL);
+ }
+
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField);
+ for (int i = 0; i < 7; i++) {
+ js_wday[i] = (jstring) env->GetObjectArrayElement(ja, i);
+ locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL);
+ }
+
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField);
+ for (int i = 0; i < 7; i++) {
+ js_weekday[i] = (jstring) env->GetObjectArrayElement(ja, i);
+ locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL);
+ }
+
+ js_X_fmt = (jstring) env->GetStaticObjectField(timeClass, g_timeOnlyFormatField);
+ locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL);
+
+ js_x_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateOnlyFormatField);
+ locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL);
+
+ js_c_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateTimeFormatField);
+ locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL);
+
+ js_am = (jstring) env->GetStaticObjectField(timeClass, g_amField);
+ locale.am = env->GetStringUTFChars(js_am, NULL);
+
+ js_pm = (jstring) env->GetStaticObjectField(timeClass, g_pmField);
+ locale.pm = env->GetStringUTFChars(js_pm, NULL);
+
+ js_date_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateCommandField);
+ locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL);
+
ACQUIRE_TIMEZONE(This, t)
const char* format = env->GetStringUTFChars(formatObject, NULL);
- String8 r = t.format(format);
+ String8 r = t.format(format, &locale);
env->ReleaseStringUTFChars(formatObject, format);
RELEASE_TIMEZONE(This, t)
+ for (int i = 0; i < 12; i++) {
+ env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]);
+ env->ReleaseStringUTFChars(js_month[i], locale.month[i]);
+ }
+
+ for (int i = 0; i < 7; i++) {
+ env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]);
+ env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]);
+ }
+
+ env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt);
+ env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt);
+ env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt);
+ env->ReleaseStringUTFChars(js_am, locale.am);
+ env->ReleaseStringUTFChars(js_pm, locale.pm);
+ env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt);
+
return env->NewStringUTF(r.string());
}
-static jstring android_pim_Time_toString(JNIEnv* env, jobject This)
+static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
{
Time t;
if (!java2time(env, &t, This)) return env->NewStringUTF("");;
@@ -199,7 +277,7 @@ static jstring android_pim_Time_toString(JNIEnv* env, jobject This)
return env->NewStringUTF(r.string());
}
-static void android_pim_Time_setToNow(JNIEnv* env, jobject This)
+static void android_text_format_Time_setToNow(JNIEnv* env, jobject This)
{
env->SetBooleanField(This, g_allDayField, JNI_FALSE);
Time t;
@@ -211,7 +289,7 @@ static void android_pim_Time_setToNow(JNIEnv* env, jobject This)
RELEASE_TIMEZONE(This, t)
}
-static jlong android_pim_Time_toMillis(JNIEnv* env, jobject This,
+static jlong android_text_format_Time_toMillis(JNIEnv* env, jobject This,
jboolean ignoreDst)
{
Time t;
@@ -225,7 +303,7 @@ static jlong android_pim_Time_toMillis(JNIEnv* env, jobject This,
return result;
}
-static void android_pim_Time_set(JNIEnv* env, jobject This, jlong millis)
+static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis)
{
env->SetBooleanField(This, g_allDayField, JNI_FALSE);
Time t;
@@ -271,48 +349,71 @@ static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
}
-static void android_pim_Time_parse(JNIEnv* env, jobject This, jstring strObj)
+static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
{
jsize len = env->GetStringLength(strObj);
const jchar *s = env->GetStringChars(strObj, NULL);
bool thrown = false;
int n;
+ jboolean inUtc = false;
+ if (len < 8) {
+ char msg[100];
+ sprintf(msg, "String too short -- expected at least 8 characters.");
+ jniThrowException(env, "android/util/TimeFormatException", msg);
+ return false;
+ }
+
+ // year
n = get_char(env, s, 0, 1000, &thrown);
n += get_char(env, s, 1, 100, &thrown);
n += get_char(env, s, 2, 10, &thrown);
n += get_char(env, s, 3, 1, &thrown);
- if (thrown) return;
+ if (thrown) return false;
env->SetIntField(This, g_yearField, n);
+ // month
n = get_char(env, s, 4, 10, &thrown);
n += get_char(env, s, 5, 1, &thrown);
n--;
- if (thrown) return;
+ if (thrown) return false;
env->SetIntField(This, g_monField, n);
+ // day of month
n = get_char(env, s, 6, 10, &thrown);
n += get_char(env, s, 7, 1, &thrown);
- if (thrown) return;
+ if (thrown) return false;
env->SetIntField(This, g_mdayField, n);
- if (len >= 15) {
+ if (len > 8) {
+ // T
+ if (!check_char(env, s, 8, 'T')) return false;
env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+
+ // hour
n = get_char(env, s, 9, 10, &thrown);
n += get_char(env, s, 10, 1, &thrown);
- if (thrown) return;
+ if (thrown) return false;
env->SetIntField(This, g_hourField, n);
+ // min
n = get_char(env, s, 11, 10, &thrown);
n += get_char(env, s, 12, 1, &thrown);
- if (thrown) return;
+ if (thrown) return false;
env->SetIntField(This, g_minField, n);
+ // sec
n = get_char(env, s, 13, 10, &thrown);
n += get_char(env, s, 14, 1, &thrown);
- if (thrown) return;
+ if (thrown) return false;
env->SetIntField(This, g_secField, n);
+
+ if (len > 15) {
+ // Z
+ if (!check_char(env, s, 15, 'Z')) return false;
+ inUtc = true;
+ }
} else {
env->SetBooleanField(This, g_allDayField, JNI_TRUE);
env->SetIntField(This, g_hourField, 0);
@@ -326,92 +427,10 @@ static void android_pim_Time_parse(JNIEnv* env, jobject This, jstring strObj)
env->SetLongField(This, g_gmtoffField, 0);
env->ReleaseStringChars(strObj, s);
-}
-
-static jboolean android_pim_Time_parse2445(JNIEnv* env, jobject This,
- jstring strObj)
-{
- jsize len = env->GetStringLength(strObj);
- const jchar *s = env->GetStringChars(strObj, NULL);
-
- bool thrown = false;
- int n;
- jboolean inUtc = false;
-
- if (len < 8) {
- char msg[100];
- sprintf(msg, "String too short -- expected at least 8 characters.");
- jniThrowException(env, "android/util/TimeFormatException", msg);
- return false;
- }
-
- // year
- n = get_char(env, s, 0, 1000, &thrown);
- n += get_char(env, s, 1, 100, &thrown);
- n += get_char(env, s, 2, 10, &thrown);
- n += get_char(env, s, 3, 1, &thrown);
- if (thrown) return false;
- env->SetIntField(This, g_yearField, n);
-
- // month
- n = get_char(env, s, 4, 10, &thrown);
- n += get_char(env, s, 5, 1, &thrown);
- n--;
- if (thrown) return false;
- env->SetIntField(This, g_monField, n);
-
- // day of month
- n = get_char(env, s, 6, 10, &thrown);
- n += get_char(env, s, 7, 1, &thrown);
- if (thrown) return false;
- env->SetIntField(This, g_mdayField, n);
-
- if (len > 8) {
- // T
- if (!check_char(env, s, 8, 'T')) return false;
- env->SetBooleanField(This, g_allDayField, JNI_FALSE);
-
- // hour
- n = get_char(env, s, 9, 10, &thrown);
- n += get_char(env, s, 10, 1, &thrown);
- if (thrown) return false;
- env->SetIntField(This, g_hourField, n);
-
- // min
- n = get_char(env, s, 11, 10, &thrown);
- n += get_char(env, s, 12, 1, &thrown);
- if (thrown) return false;
- env->SetIntField(This, g_minField, n);
-
- // sec
- n = get_char(env, s, 13, 10, &thrown);
- n += get_char(env, s, 14, 1, &thrown);
- if (thrown) return false;
- env->SetIntField(This, g_secField, n);
-
- if (len > 15) {
- // Z
- if (!check_char(env, s, 15, 'Z')) return false;
- inUtc = true;
- }
- } else {
- // all day
- env->SetBooleanField(This, g_allDayField, JNI_TRUE);
- env->SetIntField(This, g_hourField, 0);
- env->SetIntField(This, g_minField, 0);
- env->SetIntField(This, g_secField, 0);
- }
-
- env->SetIntField(This, g_wdayField, 0);
- env->SetIntField(This, g_ydayField, 0);
- env->SetIntField(This, g_isdstField, -1);
- env->SetLongField(This, g_gmtoffField, 0);
-
- env->ReleaseStringChars(strObj, s);
return inUtc;
}
-static jboolean android_pim_Time_parse3339(JNIEnv* env,
+static jboolean android_text_format_Time_parse3339(JNIEnv* env,
jobject This,
jstring strObj)
{
@@ -531,7 +550,7 @@ static jboolean android_pim_Time_parse3339(JNIEnv* env,
if (offset != 0) {
// we need to normalize after applying the hour and minute offsets
- android_pim_Time_normalize(env, This, false /* use isdst */);
+ android_text_format_Time_normalize(env, This, false /* use isdst */);
// The timezone is set to UTC in the calling Java code.
}
} else {
@@ -556,23 +575,22 @@ static jboolean android_pim_Time_parse3339(JNIEnv* env,
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "normalize", "(Z)J", (void*)android_pim_Time_normalize },
- { "switchTimezone", "(Ljava/lang/String;)V", (void*)android_pim_Time_switchTimezone },
- { "compare", "(Landroid/pim/Time;Landroid/pim/Time;)I", (void*)android_pim_Time_compare },
- { "format", "(Ljava/lang/String;)Ljava/lang/String;", (void*)android_pim_Time_format },
- { "format2445", "()Ljava/lang/String;", (void*)android_pim_Time_format2445 },
- { "toString", "()Ljava/lang/String;", (void*)android_pim_Time_toString },
- { "parse", "(Ljava/lang/String;)V", (void*)android_pim_Time_parse },
- { "nativeParse2445", "(Ljava/lang/String;)Z", (void*)android_pim_Time_parse2445 },
- { "nativeParse3339", "(Ljava/lang/String;)Z", (void*)android_pim_Time_parse3339 },
- { "setToNow", "()V", (void*)android_pim_Time_setToNow },
- { "toMillis", "(Z)J", (void*)android_pim_Time_toMillis },
- { "set", "(J)V", (void*)android_pim_Time_set }
+ { "normalize", "(Z)J", (void*)android_text_format_Time_normalize },
+ { "switchTimezone", "(Ljava/lang/String;)V", (void*)android_text_format_Time_switchTimezone },
+ { "compare", "(Landroid/text/format/Time;Landroid/text/format/Time;)I", (void*)android_text_format_Time_compare },
+ { "format1", "(Ljava/lang/String;)Ljava/lang/String;", (void*)android_text_format_Time_format },
+ { "format2445", "()Ljava/lang/String;", (void*)android_text_format_Time_format2445 },
+ { "toString", "()Ljava/lang/String;", (void*)android_text_format_Time_toString },
+ { "nativeParse", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse },
+ { "nativeParse3339", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse3339 },
+ { "setToNow", "()V", (void*)android_text_format_Time_setToNow },
+ { "toMillis", "(Z)J", (void*)android_text_format_Time_toMillis },
+ { "set", "(J)V", (void*)android_text_format_Time_set }
};
-int register_android_pim_Time(JNIEnv* env)
+int register_android_text_format_Time(JNIEnv* env)
{
- jclass timeClass = env->FindClass("android/pim/Time");
+ jclass timeClass = env->FindClass("android/text/format/Time");
g_allDayField = env->GetFieldID(timeClass, "allDay", "Z");
g_secField = env->GetFieldID(timeClass, "second", "I");
@@ -587,7 +605,18 @@ int register_android_pim_Time(JNIEnv* env)
g_gmtoffField = env->GetFieldID(timeClass, "gmtoff", "J");
g_timezoneField = env->GetFieldID(timeClass, "timezone", "Ljava/lang/String;");
- return AndroidRuntime::registerNativeMethods(env, "android/pim/Time", gMethods, NELEM(gMethods));
+ g_shortMonthsField = env->GetStaticFieldID(timeClass, "sShortMonths", "[Ljava/lang/String;");
+ g_longMonthsField = env->GetStaticFieldID(timeClass, "sLongMonths", "[Ljava/lang/String;");
+ g_shortWeekdaysField = env->GetStaticFieldID(timeClass, "sShortWeekdays", "[Ljava/lang/String;");
+ g_longWeekdaysField = env->GetStaticFieldID(timeClass, "sLongWeekdays", "[Ljava/lang/String;");
+ g_timeOnlyFormatField = env->GetStaticFieldID(timeClass, "sTimeOnlyFormat", "Ljava/lang/String;");
+ g_dateOnlyFormatField = env->GetStaticFieldID(timeClass, "sDateOnlyFormat", "Ljava/lang/String;");
+ g_dateTimeFormatField = env->GetStaticFieldID(timeClass, "sDateTimeFormat", "Ljava/lang/String;");
+ g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;");
+ g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;");
+ g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;");
+
+ return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods));
}
}; // namespace android
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 8a62159..add1080 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -901,7 +901,8 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
return JNI_FALSE;
}
- jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ jint* dest = baseDest;
if (dest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
doThrow(env, "java/lang/OutOfMemoryError");
@@ -1074,7 +1075,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla
indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
- env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+ env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_TRUE;
@@ -1112,7 +1113,8 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
return JNI_FALSE;
}
- jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ jint* dest = baseDest;
if (dest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
doThrow(env, "java/lang/OutOfMemoryError");
@@ -1201,7 +1203,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
- env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+ env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_TRUE;
@@ -1243,7 +1245,8 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
const jsize NV = env->GetArrayLength(outValues);
- jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ jint* dest = baseDest;
if (dest == NULL) {
doThrow(env, "java/lang/OutOfMemoryError");
return JNI_FALSE;
@@ -1295,7 +1298,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz
res.unlock();
- env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+ env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
return i;
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 08c4f1c..3feccde 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -88,6 +88,11 @@ jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
return getpid();
}
+jint android_os_Process_myUid(JNIEnv* env, jobject clazz)
+{
+ return getuid();
+}
+
jint android_os_Process_myTid(JNIEnv* env, jobject clazz)
{
#ifdef HAVE_GETTID
@@ -707,6 +712,7 @@ static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
static const JNINativeMethod methods[] = {
{"myPid", "()I", (void*)android_os_Process_myPid},
{"myTid", "()I", (void*)android_os_Process_myTid},
+ {"myUid", "()I", (void*)android_os_Process_myUid},
{"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
{"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
{"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority},
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index af03016..a985c24 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -332,12 +332,8 @@ jboolean jni_eglGetConfigs(JNIEnv *_env, jobject _this, jobject display,
if (success && configs) {
for (int i=0 ; i<num ; i++) {
- jobject obj = _env->GetObjectArrayElement(configs, i);
- if (obj == NULL) {
- doThrow(_env, "java/lang/NullPointerException");
- break;
- }
- _env->SetIntField(obj, gConfig_EGLConfigFieldID, (jint)nativeConfigs[i]);
+ jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]);
+ _env->SetObjectArrayElement(configs, i, obj);
}
}
return success;
@@ -396,8 +392,7 @@ jboolean jni_eglMakeCurrent(JNIEnv *_env, jobject _this, jobject display, jobjec
jstring jni_eglQueryString(JNIEnv *_env, jobject _this, jobject display, jint name) {
EGLDisplay dpy = getDisplay(_env, display);
const char* chars = eglQueryString(dpy, name);
- return _env->NewString((const jchar *)chars,
- (jsize)strlen((const char *)chars));
+ return _env->NewStringUTF(chars);
}
jboolean jni_eglSwapBuffers(JNIEnv *_env, jobject _this, jobject display, jobject surface) {
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index 1cd23b0..9b09c9b 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -35,6 +35,7 @@ static jclass bufferClass;
static jclass OOMEClass;
static jclass UOEClass;
static jclass IAEClass;
+static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -78,10 +79,13 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass)
_env->FindClass("java/lang/OutOfMemoryError");
jclass UOEClassLocal =
_env->FindClass("java/lang/UnsupportedOperationException");
+ jclass AIOOBEClassLocal =
+ _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
+ AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
}
static void *
@@ -526,12 +530,18 @@ android_glDrawElements__IIILjava_nio_Buffer_2
GLvoid *indices = (GLvoid *) 0;
indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
+ if (_remaining < count) {
+ _env->ThrowNew(AIOOBEClass, "remaining() < count");
+ goto exit;
+ }
glDrawElements(
(GLenum)mode,
(GLsizei)count,
(GLenum)type,
(GLvoid *)indices
);
+
+exit:
if (_array) {
releasePointer(_env, _array, indices, JNI_FALSE);
}
@@ -1647,20 +1657,8 @@ exit:
jstring
android_glGetString
(JNIEnv *_env, jobject _this, jint name) {
- const GLubyte * chars = glGetString((GLenum)name);
-
- int len = strlen((const char *)chars);
- jchar * wchars = (jchar *)malloc(len * sizeof(jchar));
- if (wchars == (jchar*) 0) {
- _env->ThrowNew(OOMEClass, "No space for glGetString output");
- return (jstring) 0;
- }
- // Copy bytes -> chars, including trailing '\0'
- for (int i = 0; i <= len; i++) {
- wchars[i] = (jchar) chars[i];
- }
- jstring output = _env->NewString(wchars, (jsize) len);
- free(wchars);
+ const char * chars = (const char *)glGetString((GLenum)name);
+ jstring output = _env->NewStringUTF(chars);
return output;
}
/* void glHint ( GLenum target, GLenum mode ) */
diff --git a/core/jni/server/Android.mk b/core/jni/server/Android.mk
index d108330..bd08da3 100644
--- a/core/jni/server/Android.mk
+++ b/core/jni/server/Android.mk
@@ -21,11 +21,13 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libui
+ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS),linux)
ifeq ($(TARGET_ARCH),x86)
LOCAL_LDLIBS += -lpthread -ldl -lrt
endif
endif
+endif
ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
diff --git a/core/jni/server/com_android_server_AlarmManagerService.cpp b/core/jni/server/com_android_server_AlarmManagerService.cpp
index a81a0ff..0f37921 100644
--- a/core/jni/server/com_android_server_AlarmManagerService.cpp
+++ b/core/jni/server/com_android_server_AlarmManagerService.cpp
@@ -44,6 +44,23 @@
namespace android {
+static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
+{
+#if HAVE_ANDROID_OS
+ struct timezone tz;
+
+ tz.tz_minuteswest = minswest;
+ tz.tz_dsttime = 0;
+
+ int result = ioctl(fd, ANDROID_ALARM_SET_TIMEZONE, &tz);
+ if (result < 0) {
+ LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
+ return -1;
+ }
+ return 0;
+#endif
+}
+
static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
{
#if HAVE_ANDROID_OS
@@ -101,6 +118,7 @@ static JNINativeMethod sMethods[] = {
{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
{"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set},
{"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
+ {"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
};
int register_android_server_AlarmManagerService(JNIEnv* env)
diff --git a/core/jni/server/com_android_server_SensorService.cpp b/core/jni/server/com_android_server_SensorService.cpp
index 37f6231..695a8a3 100644
--- a/core/jni/server/com_android_server_SensorService.cpp
+++ b/core/jni/server/com_android_server_SensorService.cpp
@@ -23,7 +23,6 @@
namespace android {
-
static struct file_descriptor_offsets_t
{
jclass mClass;
@@ -41,16 +40,26 @@ static struct parcel_file_descriptor_offsets_t
* The method below are not thread-safe and not intended to be
*/
+static sensors_control_device_t* sSensorDevice = 0;
+
static jint
android_init(JNIEnv *env, jclass clazz)
{
- return sensors_control_init();
+ sensors_module_t* module;
+ if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
+ if (sensors_control_open(&module->common, &sSensorDevice) == 0) {
+ const struct sensor_t* list;
+ int count = module->get_sensors_list(module, &list);
+ return count;
+ }
+ }
+ return 0;
}
static jobject
android_open(JNIEnv *env, jclass clazz)
{
- int fd = sensors_control_open();
+ int fd = sSensorDevice->open_data_source(sSensorDevice);
// new FileDescriptor()
jobject filedescriptor = env->NewObject(
gFileDescriptorOffsets.mClass,
@@ -70,20 +79,29 @@ android_open(JNIEnv *env, jclass clazz)
static jboolean
android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
{
- uint32_t active = sensors_control_activate(activate ? sensor : 0, sensor);
- return (activate && !active) ? false : true;
+ int active = sSensorDevice->activate(sSensorDevice, sensor, activate);
+ return (active<0) ? false : true;
}
static jint
android_set_delay(JNIEnv *env, jclass clazz, jint ms)
{
- return sensors_control_delay(ms);
+ return sSensorDevice->set_delay(sSensorDevice, ms);
+}
+
+static jint
+android_data_wake(JNIEnv *env, jclass clazz)
+{
+ int res = sSensorDevice->wake(sSensorDevice);
+ return res;
}
+
static JNINativeMethod gMethods[] = {
{"_sensors_control_init", "()I", (void*) android_init },
{"_sensors_control_open", "()Landroid/os/ParcelFileDescriptor;", (void*) android_open },
{"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
+ {"_sensors_control_wake", "()I", (void*) android_data_wake },
{"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
};