summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/ActivityManager.cpp60
-rw-r--r--core/jni/Android.mk176
-rw-r--r--core/jni/AndroidRuntime.cpp1151
-rw-r--r--core/jni/BindTest.cpp289
-rw-r--r--core/jni/CursorWindow.cpp412
-rw-r--r--core/jni/CursorWindow.h203
-rw-r--r--core/jni/GraphicsExternGlue.h25
-rw-r--r--core/jni/GraphicsRegisterGlue.h25
-rw-r--r--core/jni/MODULE_LICENSE_APACHE20
-rw-r--r--core/jni/NOTICE190
-rw-r--r--core/jni/android/graphics/Bitmap.cpp573
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp505
-rw-r--r--core/jni/android/graphics/Camera.cpp102
-rw-r--r--core/jni/android/graphics/Canvas.cpp934
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp98
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp212
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h13
-rw-r--r--core/jni/android/graphics/DrawFilter.cpp76
-rw-r--r--core/jni/android/graphics/Graphics.cpp578
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h156
-rw-r--r--core/jni/android/graphics/Interpolator.cpp97
-rw-r--r--core/jni/android/graphics/LayerRasterizer.cpp34
-rw-r--r--core/jni/android/graphics/MaskFilter.cpp61
-rw-r--r--core/jni/android/graphics/Matrix.cpp412
-rw-r--r--core/jni/android/graphics/Movie.cpp155
-rw-r--r--core/jni/android/graphics/NIOBuffer.cpp143
-rw-r--r--core/jni/android/graphics/NIOBuffer.h27
-rw-r--r--core/jni/android/graphics/NinePatch.cpp142
-rw-r--r--core/jni/android/graphics/NinePatchImpl.cpp320
-rw-r--r--core/jni/android/graphics/Paint.cpp605
-rw-r--r--core/jni/android/graphics/Path.cpp306
-rw-r--r--core/jni/android/graphics/PathEffect.cpp113
-rw-r--r--core/jni/android/graphics/PathMeasure.cpp138
-rw-r--r--core/jni/android/graphics/Picture.cpp128
-rw-r--r--core/jni/android/graphics/PorterDuff.cpp52
-rw-r--r--core/jni/android/graphics/Rasterizer.cpp50
-rw-r--r--core/jni/android/graphics/Region.cpp231
-rw-r--r--core/jni/android/graphics/Shader.cpp273
-rw-r--r--core/jni/android/graphics/Typeface.cpp156
-rw-r--r--core/jni/android/graphics/Xfermode.cpp77
-rw-r--r--core/jni/android/opengl/poly.h51
-rw-r--r--core/jni/android/opengl/poly_clip.cpp155
-rw-r--r--core/jni/android/opengl/util.cpp730
-rwxr-xr-xcore/jni/android_bluetooth_BluetoothAudioGateway.cpp553
-rw-r--r--core/jni/android_bluetooth_Database.cpp183
-rw-r--r--core/jni/android_bluetooth_HeadsetBase.cpp548
-rw-r--r--core/jni/android_bluetooth_RfcommSocket.cpp621
-rw-r--r--core/jni/android_bluetooth_ScoSocket.cpp506
-rw-r--r--core/jni/android_bluetooth_common.cpp423
-rw-r--r--core/jni/android_bluetooth_common.h137
-rw-r--r--core/jni/android_database_CursorWindow.cpp674
-rw-r--r--core/jni/android_database_SQLiteDatabase.cpp464
-rw-r--r--core/jni/android_database_SQLiteDebug.cpp244
-rw-r--r--core/jni/android_database_SQLiteProgram.cpp240
-rw-r--r--core/jni/android_database_SQLiteQuery.cpp360
-rw-r--r--core/jni/android_database_SQLiteStatement.cpp149
-rw-r--r--core/jni/android_ddm_DdmHandleNativeHeap.cpp144
-rw-r--r--core/jni/android_debug_JNITest.cpp119
-rw-r--r--core/jni/android_graphics_PixelFormat.cpp85
-rw-r--r--core/jni/android_hardware_Camera.cpp451
-rw-r--r--core/jni/android_hardware_SensorManager.cpp82
-rw-r--r--core/jni/android_location_GpsLocationProvider.cpp293
-rw-r--r--core/jni/android_media_AudioSystem.cpp186
-rw-r--r--core/jni/android_media_ToneGenerator.cpp149
-rw-r--r--core/jni/android_message_digest_sha1.cpp146
-rw-r--r--core/jni/android_net_LocalSocketImpl.cpp966
-rw-r--r--core/jni/android_net_NetUtils.cpp235
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp492
-rw-r--r--core/jni/android_nio_utils.cpp114
-rw-r--r--core/jni/android_nio_utils.h74
-rw-r--r--core/jni/android_os_Debug.cpp307
-rw-r--r--core/jni/android_os_Exec.cpp215
-rw-r--r--core/jni/android_os_FileUtils.cpp208
-rw-r--r--core/jni/android_os_Hardware.cpp91
-rw-r--r--core/jni/android_os_MemoryFile.cpp129
-rw-r--r--core/jni/android_os_NetStat.cpp158
-rw-r--r--core/jni/android_os_ParcelFileDescriptor.cpp102
-rw-r--r--core/jni/android_os_Power.cpp123
-rw-r--r--core/jni/android_os_StatFs.cpp163
-rw-r--r--core/jni/android_os_SystemClock.cpp103
-rw-r--r--core/jni/android_os_SystemProperties.cpp108
-rw-r--r--core/jni/android_os_UEventObserver.cpp70
-rw-r--r--core/jni/android_pim_EventRecurrence.cpp199
-rw-r--r--core/jni/android_pim_Time.cpp594
-rw-r--r--core/jni/android_security_Md5MessageDigest.cpp126
-rw-r--r--core/jni/android_server_BluetoothDeviceService.cpp1144
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp642
-rw-r--r--core/jni/android_text_AndroidCharacter.cpp128
-rw-r--r--core/jni/android_text_KeyCharacterMap.cpp173
-rw-r--r--core/jni/android_util_AssetManager.cpp1673
-rw-r--r--core/jni/android_util_Base64.cpp160
-rw-r--r--core/jni/android_util_Binder.cpp1510
-rw-r--r--core/jni/android_util_Binder.h35
-rw-r--r--core/jni/android_util_EventLog.cpp353
-rw-r--r--core/jni/android_util_FileObserver.cpp157
-rw-r--r--core/jni/android_util_FloatMath.cpp46
-rw-r--r--core/jni/android_util_Log.cpp161
-rw-r--r--core/jni/android_util_Process.cpp743
-rw-r--r--core/jni/android_util_StringBlock.cpp204
-rw-r--r--core/jni/android_util_XmlBlock.cpp426
-rw-r--r--core/jni/android_view_Display.cpp133
-rw-r--r--core/jni/android_view_Surface.cpp619
-rw-r--r--core/jni/android_view_ViewRoot.cpp98
-rw-r--r--core/jni/com_android_internal_graphics_NativeUtils.cpp65
-rw-r--r--core/jni/com_android_internal_os_ZygoteInit.cpp367
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp475
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp6571
-rw-r--r--core/jni/server/Android.mk37
-rw-r--r--core/jni/server/com_android_server_AlarmManagerService.cpp120
-rw-r--r--core/jni/server/com_android_server_BatteryService.cpp274
-rw-r--r--core/jni/server/com_android_server_HardwareService.cpp54
-rw-r--r--core/jni/server/com_android_server_KeyInputQueue.cpp299
-rw-r--r--core/jni/server/com_android_server_SensorService.cpp107
-rw-r--r--core/jni/server/com_android_server_SystemServer.cpp47
-rw-r--r--core/jni/server/onload.cpp36
-rw-r--r--core/jni/sqlite3_exception.h47
116 files changed, 38472 insertions, 0 deletions
diff --git a/core/jni/ActivityManager.cpp b/core/jni/ActivityManager.cpp
new file mode 100644
index 0000000..9017827
--- /dev/null
+++ b/core/jni/ActivityManager.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#include <unistd.h>
+#include <android_runtime/ActivityManager.h>
+#include <utils/IBinder.h>
+#include <utils/IServiceManager.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+
+namespace android {
+
+const uint32_t OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4;
+
+// Perform ContentProvider.openFile() on the given URI, returning
+// the resulting native file descriptor. Returns < 0 on error.
+int openContentProviderFile(const String16& uri)
+{
+ int fd = -1;
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> am = sm->getService(String16("activity"));
+ if (am != NULL) {
+ Parcel data, reply;
+ data.writeInterfaceToken(String16("android.app.IActivityManager"));
+ data.writeString16(uri);
+ status_t ret = am->transact(OPEN_CONTENT_URI_TRANSACTION, data, &reply);
+ if (ret == NO_ERROR) {
+ int32_t exceptionCode = reply.readInt32();
+ if (!exceptionCode) {
+ // Success is indicated here by a nonzero int followed by the fd;
+ // failure by a zero int with no data following.
+ if (reply.readInt32() != 0) {
+ fd = dup(reply.readFileDescriptor());
+ }
+ } else {
+ // An exception was thrown back; fall through to return failure
+ LOGD("openContentUri(%s) caught exception %d\n",
+ String8(uri).string(), exceptionCode);
+ }
+ }
+ }
+
+ return fd;
+}
+
+} /* namespace android */
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
new file mode 100644
index 0000000..e9009e6
--- /dev/null
+++ b/core/jni/Android.mk
@@ -0,0 +1,176 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
+LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
+LOCAL_CFLAGS += -U__APPLE__
+
+ifeq ($(TARGET_ARCH), arm)
+ LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
+else
+ LOCAL_CFLAGS += -DPACKED=""
+endif
+
+LOCAL_SRC_FILES:= \
+ ActivityManager.cpp \
+ AndroidRuntime.cpp \
+ CursorWindow.cpp \
+ com_google_android_gles_jni_EGLImpl.cpp \
+ com_google_android_gles_jni_GLImpl.cpp.arm \
+ android_database_CursorWindow.cpp \
+ android_database_SQLiteDebug.cpp \
+ android_database_SQLiteDatabase.cpp \
+ android_database_SQLiteProgram.cpp \
+ android_database_SQLiteQuery.cpp \
+ android_database_SQLiteStatement.cpp \
+ android_view_Display.cpp \
+ android_view_Surface.cpp \
+ android_view_ViewRoot.cpp \
+ android_text_AndroidCharacter.cpp \
+ android_text_KeyCharacterMap.cpp \
+ android_os_Debug.cpp \
+ android_os_Exec.cpp \
+ android_os_FileUtils.cpp \
+ android_os_MemoryFile.cpp \
+ android_os_ParcelFileDescriptor.cpp \
+ android_os_Power.cpp \
+ android_os_StatFs.cpp \
+ android_os_SystemClock.cpp \
+ android_os_SystemProperties.cpp \
+ android_os_UEventObserver.cpp \
+ android_os_NetStat.cpp \
+ android_os_Hardware.cpp \
+ android_net_LocalSocketImpl.cpp \
+ android_net_NetUtils.cpp \
+ android_net_wifi_Wifi.cpp \
+ android_nio_utils.cpp \
+ android_pim_EventRecurrence.cpp \
+ android_pim_Time.cpp \
+ android_security_Md5MessageDigest.cpp \
+ android_util_AssetManager.cpp \
+ android_util_Binder.cpp \
+ android_util_EventLog.cpp \
+ android_util_Log.cpp \
+ android_util_FloatMath.cpp \
+ android_util_Process.cpp \
+ android_util_StringBlock.cpp \
+ android_util_XmlBlock.cpp \
+ android_util_Base64.cpp \
+ android/graphics/Bitmap.cpp \
+ android/graphics/BitmapFactory.cpp \
+ android/graphics/Camera.cpp \
+ android/graphics/Canvas.cpp \
+ android/graphics/ColorFilter.cpp \
+ android/graphics/DrawFilter.cpp \
+ android/graphics/CreateJavaOutputStreamAdaptor.cpp \
+ android/graphics/Graphics.cpp \
+ android/graphics/Interpolator.cpp \
+ android/graphics/LayerRasterizer.cpp \
+ android/graphics/MaskFilter.cpp \
+ android/graphics/Matrix.cpp \
+ android/graphics/Movie.cpp \
+ android/graphics/NIOBuffer.cpp \
+ android/graphics/NinePatch.cpp \
+ android/graphics/NinePatchImpl.cpp \
+ android/graphics/Paint.cpp \
+ android/graphics/Path.cpp \
+ android/graphics/PathMeasure.cpp \
+ android/graphics/PathEffect.cpp \
+ android_graphics_PixelFormat.cpp \
+ android/graphics/Picture.cpp \
+ android/graphics/PorterDuff.cpp \
+ android/graphics/Rasterizer.cpp \
+ android/graphics/Region.cpp \
+ android/graphics/Shader.cpp \
+ android/graphics/Typeface.cpp \
+ android/graphics/Xfermode.cpp \
+ android_media_AudioSystem.cpp \
+ android_media_ToneGenerator.cpp \
+ android_hardware_Camera.cpp \
+ android_hardware_SensorManager.cpp \
+ android_debug_JNITest.cpp \
+ android_util_FileObserver.cpp \
+ android/opengl/poly_clip.cpp.arm \
+ android/opengl/util.cpp.arm \
+ android_bluetooth_Database.cpp \
+ android_bluetooth_HeadsetBase.cpp \
+ android_bluetooth_common.cpp \
+ android_bluetooth_BluetoothAudioGateway.cpp \
+ android_bluetooth_RfcommSocket.cpp \
+ android_bluetooth_ScoSocket.cpp \
+ android_server_BluetoothDeviceService.cpp \
+ android_server_BluetoothEventLoop.cpp \
+ android_message_digest_sha1.cpp \
+ android_ddm_DdmHandleNativeHeap.cpp \
+ android_location_GpsLocationProvider.cpp \
+ com_android_internal_os_ZygoteInit.cpp \
+ com_android_internal_graphics_NativeUtils.cpp
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ $(LOCAL_PATH)/android/graphics \
+ $(call include-path-for, corecg graphics) \
+ $(call include-path-for, libhardware)/hardware \
+ $(LOCAL_PATH)/../../include/ui \
+ $(LOCAL_PATH)/../../include/utils \
+ external/sqlite/dist \
+ external/sqlite/android \
+ external/expat/lib \
+ external/openssl/include \
+ external/tremor/Tremor \
+ external/icu4c/i18n \
+ external/icu4c/common \
+
+LOCAL_SHARED_LIBRARIES := \
+ libexpat \
+ libnativehelper \
+ libcutils \
+ libutils \
+ libnetutils \
+ libui \
+ libsgl \
+ libcorecg \
+ libsqlite \
+ libdvm \
+ libGLES_CM \
+ libhardware \
+ libsonivox \
+ libcrypto \
+ libssl \
+ libicuuc \
+ libicui18n \
+ libicudata \
+ libmedia \
+ libwpa_client
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+LOCAL_C_INCLUDES += \
+ external/dbus \
+ external/bluez/libs/include
+LOCAL_CFLAGS += -DHAVE_BLUETOOTH
+LOCAL_SHARED_LIBRARIES += libbluedroid libdbus
+endif
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SHARED_LIBRARIES += \
+ libdl
+endif
+
+LOCAL_LDLIBS += -lpthread -ldl
+
+ifeq ($(TARGET_OS),linux)
+ifeq ($(TARGET_ARCH),x86)
+LOCAL_LDLIBS += -lrt
+endif
+endif
+
+ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
+ LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
+endif
+
+LOCAL_MODULE:= libandroid_runtime
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
new file mode 100644
index 0000000..2a1184f
--- /dev/null
+++ b/core/jni/AndroidRuntime.cpp
@@ -0,0 +1,1151 @@
+/* //device/libs/android_runtime/AndroidRuntime.cpp
+**
+** Copyright 2006, 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 "AndroidRuntime"
+//#define LOG_NDEBUG 0
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/IBinder.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <utils/Parcel.h>
+#include <utils/string_array.h>
+#include <utils/threads.h>
+#include <cutils/properties.h>
+
+#include <SkGraphics.h>
+#include <SkImageDecoder.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_util_Binder.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <dirent.h>
+#include <assert.h>
+
+
+using namespace android;
+
+extern void register_BindTest();
+
+extern int register_android_os_Binder(JNIEnv* env);
+extern int register_android_os_Process(JNIEnv* env);
+extern int register_android_graphics_Bitmap(JNIEnv*);
+extern int register_android_graphics_BitmapFactory(JNIEnv*);
+extern int register_android_graphics_Camera(JNIEnv* env);
+extern int register_android_graphics_Graphics(JNIEnv* env);
+extern int register_android_graphics_Interpolator(JNIEnv* env);
+extern int register_android_graphics_LayerRasterizer(JNIEnv*);
+extern int register_android_graphics_MaskFilter(JNIEnv* env);
+extern int register_android_graphics_Movie(JNIEnv* env);
+extern int register_android_graphics_NinePatch(JNIEnv*);
+extern int register_android_graphics_PathEffect(JNIEnv* env);
+extern int register_android_graphics_Region(JNIEnv* env);
+extern int register_android_graphics_Shader(JNIEnv* env);
+extern int register_android_graphics_Typeface(JNIEnv* env);
+
+extern int register_com_google_android_gles_jni_EGLImpl(JNIEnv* env);
+extern int register_com_google_android_gles_jni_GLImpl(JNIEnv* env);
+
+extern int register_android_hardware_Camera(JNIEnv *env);
+
+extern int register_android_hardware_SensorManager(JNIEnv *env);
+
+extern int register_android_media_AudioSystem(JNIEnv *env);
+extern int register_android_media_ToneGenerator(JNIEnv *env);
+
+extern int register_android_message_digest_sha1(JNIEnv *env);
+
+extern int register_android_util_FloatMath(JNIEnv* env);
+
+namespace android {
+
+/*
+ * JNI-based registration functions. Note these are properly contained in
+ * namespace android.
+ */
+extern int register_android_content_AssetManager(JNIEnv* env);
+extern int register_android_util_EventLog(JNIEnv* env);
+extern int register_android_util_Log(JNIEnv* env);
+extern int register_android_content_StringBlock(JNIEnv* env);
+extern int register_android_content_XmlBlock(JNIEnv* env);
+extern int register_android_graphics_Canvas(JNIEnv* env);
+extern int register_android_graphics_ColorFilter(JNIEnv* env);
+extern int register_android_graphics_DrawFilter(JNIEnv* env);
+extern int register_android_graphics_Matrix(JNIEnv* env);
+extern int register_android_graphics_Paint(JNIEnv* env);
+extern int register_android_graphics_Path(JNIEnv* env);
+extern int register_android_graphics_PathMeasure(JNIEnv* env);
+extern int register_android_graphics_Picture(JNIEnv*);
+extern int register_android_graphics_PorterDuff(JNIEnv* env);
+extern int register_android_graphics_Rasterizer(JNIEnv* env);
+extern int register_android_graphics_Xfermode(JNIEnv* env);
+extern int register_android_graphics_PixelFormat(JNIEnv* env);
+extern int register_com_android_internal_graphics_NativeUtils(JNIEnv *env);
+extern int register_android_view_Display(JNIEnv* env);
+extern int register_android_view_Surface(JNIEnv* env);
+extern int register_android_view_ViewRoot(JNIEnv* env);
+extern int register_android_database_CursorWindow(JNIEnv* env);
+extern int register_android_database_SQLiteDatabase(JNIEnv* env);
+extern int register_android_database_SQLiteDebug(JNIEnv* env);
+extern int register_android_database_SQLiteProgram(JNIEnv* env);
+extern int register_android_database_SQLiteQuery(JNIEnv* env);
+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_os_Debug(JNIEnv* env);
+extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
+extern int register_android_os_Power(JNIEnv *env);
+extern int register_android_os_StatFs(JNIEnv *env);
+extern int register_android_os_SystemProperties(JNIEnv *env);
+extern int register_android_os_Hardware(JNIEnv* env);
+extern int register_android_os_Exec(JNIEnv *env);
+extern int register_android_os_SystemClock(JNIEnv* env);
+extern int register_android_os_FileObserver(JNIEnv *env);
+extern int register_android_os_FileUtils(JNIEnv *env);
+extern int register_android_os_UEventObserver(JNIEnv* env);
+extern int register_android_os_NetStat(JNIEnv* env);
+extern int register_android_os_MemoryFile(JNIEnv* env);
+extern int register_android_net_LocalSocketImpl(JNIEnv* env);
+extern int register_android_net_NetworkUtils(JNIEnv* env);
+extern int register_android_net_wifi_WifiManager(JNIEnv* env);
+extern int register_android_security_Md5MessageDigest(JNIEnv *env);
+extern int register_android_text_AndroidCharacter(JNIEnv *env);
+extern int register_android_text_KeyCharacterMap(JNIEnv *env);
+extern int register_android_opengl_classes(JNIEnv *env);
+extern int register_android_bluetooth_Database(JNIEnv* env);
+extern int register_android_bluetooth_HeadsetBase(JNIEnv* env);
+extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env);
+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_ddm_DdmHandleNativeHeap(JNIEnv *env);
+extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
+extern int register_android_util_Base64(JNIEnv* env);
+extern int register_android_location_GpsLocationProvider(JNIEnv* env);
+
+static AndroidRuntime* gCurRuntime = NULL;
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ if (jniThrowException(env, exc, msg) != 0)
+ assert(false);
+}
+
+/*
+ * Code written in the Java Programming Language calls here from main().
+ */
+static void com_android_internal_os_RuntimeInit_finishInit(JNIEnv* env, jobject clazz)
+{
+ gCurRuntime->onStarted();
+}
+
+static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
+{
+ gCurRuntime->onZygoteInit();
+}
+
+static jint com_android_internal_os_RuntimeInit_isComputerOn(JNIEnv* env, jobject clazz)
+{
+ return 1;
+}
+
+static void com_android_internal_os_RuntimeInit_turnComputerOn(JNIEnv* env, jobject clazz)
+{
+}
+
+static jint com_android_internal_os_RuntimeInit_getQwertyKeyboard(JNIEnv* env, jobject clazz)
+{
+ char* value = getenv("qwerty");
+ if (value != NULL && strcmp(value, "true") == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ { "finishInit", "()V",
+ (void*) com_android_internal_os_RuntimeInit_finishInit },
+ { "zygoteInitNative", "()V",
+ (void*) com_android_internal_os_RuntimeInit_zygoteInit },
+ { "isComputerOn", "()I",
+ (void*) com_android_internal_os_RuntimeInit_isComputerOn },
+ { "turnComputerOn", "()V",
+ (void*) com_android_internal_os_RuntimeInit_turnComputerOn },
+ { "getQwertyKeyboard", "()I",
+ (void*) com_android_internal_os_RuntimeInit_getQwertyKeyboard },
+};
+
+int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
+ gMethods, NELEM(gMethods));
+}
+
+// ----------------------------------------------------------------------
+
+/*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;
+
+
+AndroidRuntime::AndroidRuntime()
+{
+ SkGraphics::Init(false); // true means run unittests (slow)
+ // this sets our preference for 16bit images during decode
+ // in case the src is opaque and 24bit
+ SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config);
+
+ // Pre-allocate enough space to hold a fair number of options.
+ mOptions.setCapacity(20);
+
+ assert(gCurRuntime == NULL); // one per process
+ gCurRuntime = this;
+}
+
+AndroidRuntime::~AndroidRuntime()
+{
+ SkGraphics::Term();
+}
+
+/*
+ * Register native methods using JNI.
+ */
+/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
+ const char* className, const JNINativeMethod* gMethods, int numMethods)
+{
+ return jniRegisterNativeMethods(env, className, gMethods, numMethods);
+}
+
+/*
+ * Call a static Java Programming Language function that takes no arguments and returns void.
+ */
+status_t AndroidRuntime::callStatic(const char* className, const char* methodName)
+{
+ JNIEnv* env;
+ jclass clazz;
+ jmethodID methodId;
+
+ env = getJNIEnv();
+ if (env == NULL)
+ return UNKNOWN_ERROR;
+
+ clazz = findClass(env, className);
+ if (clazz == NULL) {
+ LOGE("ERROR: could not find class '%s'\n", className);
+ return UNKNOWN_ERROR;
+ }
+ methodId = env->GetStaticMethodID(clazz, methodName, "()V");
+ if (methodId == NULL) {
+ LOGE("ERROR: could not find method %s.%s\n", className, methodName);
+ return UNKNOWN_ERROR;
+ }
+
+ env->CallStaticVoidMethod(clazz, methodId);
+
+ return NO_ERROR;
+}
+
+status_t AndroidRuntime::callMain(
+ const char* className, int argc, const char* const argv[])
+{
+ JNIEnv* env;
+ jclass clazz;
+ jmethodID methodId;
+
+ env = getJNIEnv();
+ if (env == NULL)
+ return UNKNOWN_ERROR;
+
+ clazz = findClass(env, className);
+ if (clazz == NULL) {
+ LOGE("ERROR: could not find class '%s'\n", className);
+ return UNKNOWN_ERROR;
+ }
+
+ methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
+ if (methodId == NULL) {
+ LOGE("ERROR: could not find method %s.main(String[])\n", className);
+ return UNKNOWN_ERROR;
+ }
+
+ /*
+ * We want to call main() with a String array with our arguments in it.
+ * Create an array and populate it.
+ */
+ jclass stringClass;
+ jobjectArray strArray;
+
+ stringClass = env->FindClass("java/lang/String");
+ strArray = env->NewObjectArray(argc, stringClass, NULL);
+
+ for (int i = 0; i < argc; i++) {
+ jstring argStr = env->NewStringUTF(argv[i]);
+ env->SetObjectArrayElement(strArray, i, argStr);
+ }
+
+ env->CallStaticVoidMethod(clazz, methodId, strArray);
+ return NO_ERROR;
+}
+
+/*
+ * Find the named class.
+ */
+jclass AndroidRuntime::findClass(JNIEnv* env, const char* className)
+{
+ char* convName = NULL;
+
+ if (env->ExceptionCheck()) {
+ LOGE("ERROR: exception pending on entry to findClass()\n");
+ return NULL;
+ }
+
+ /*
+ * JNI FindClass uses class names with slashes, but ClassLoader.loadClass
+ * uses the dotted "binary name" format. We don't need to convert the
+ * name with the new approach.
+ */
+#if 0
+ /* (convName only created if necessary -- use className) */
+ for (char* cp = const_cast<char*>(className); *cp != '\0'; cp++) {
+ if (*cp == '.') {
+ if (convName == NULL) {
+ convName = strdup(className);
+ cp = convName + (cp-className);
+ className = convName;
+ }
+ *cp = '/';
+ }
+ }
+#endif
+
+ /*
+ * This is a little awkward because the JNI FindClass call uses the
+ * class loader associated with the native method we're executing in.
+ * Because this native method is part of a "boot" class, JNI doesn't
+ * look for the class in CLASSPATH, which unfortunately is a likely
+ * location for it. (Had we issued the FindClass call before calling
+ * into the VM -- at which point there isn't a native method frame on
+ * the stack -- the VM would have checked CLASSPATH. We have to do
+ * this because we call into Java Programming Language code and
+ * bounce back out.)
+ *
+ * JNI lacks a "find class in a specific class loader" operation, so we
+ * have to do things the hard way.
+ */
+ jclass cls = NULL;
+ //cls = env->FindClass(className);
+
+ jclass javaLangClassLoader;
+ jmethodID getSystemClassLoader, loadClass;
+ jobject systemClassLoader;
+ jstring strClassName;
+
+ /* find the "system" class loader; none of this is expected to fail */
+ javaLangClassLoader = env->FindClass("java/lang/ClassLoader");
+ assert(javaLangClassLoader != NULL);
+ getSystemClassLoader = env->GetStaticMethodID(javaLangClassLoader,
+ "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
+ loadClass = env->GetMethodID(javaLangClassLoader,
+ "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ assert(getSystemClassLoader != NULL && loadClass != NULL);
+ systemClassLoader = env->CallStaticObjectMethod(javaLangClassLoader,
+ getSystemClassLoader);
+ assert(systemClassLoader != NULL);
+
+ /* create an object for the class name string; alloc could fail */
+ strClassName = env->NewStringUTF(className);
+ if (env->ExceptionCheck()) {
+ LOGE("ERROR: unable to convert '%s' to string\n", className);
+ goto bail;
+ }
+ LOGV("system class loader is %p, loading %p (%s)\n",
+ systemClassLoader, strClassName, className);
+
+ /* try to find the named class */
+ cls = (jclass) env->CallObjectMethod(systemClassLoader, loadClass,
+ strClassName);
+ if (env->ExceptionCheck()) {
+ LOGE("ERROR: unable to load class '%s' from %p\n",
+ className, systemClassLoader);
+ cls = NULL;
+ goto bail;
+ }
+
+bail:
+ free(convName);
+ return cls;
+}
+
+/*
+ * The VM calls this through the "exit" hook.
+ */
+static void runtime_exit(int code)
+{
+ gCurRuntime->onExit(code);
+ exit(code);
+}
+
+/*
+ * The VM calls this through the "vfprintf" hook.
+ *
+ * We ignore "fp" and just write the results to the log file.
+ */
+static void runtime_vfprintf(FILE* fp, const char* format, va_list ap)
+{
+ LOG_PRI_VA(ANDROID_LOG_INFO, "vm-printf", format, ap);
+}
+
+
+/**
+ * Add VM arguments to the to-be-executed VM
+ * Stops at first non '-' argument (also stops at an argument of '--')
+ * Returns the number of args consumed
+ */
+int AndroidRuntime::addVmArguments(int argc, const char* const argv[])
+{
+ int i;
+
+ for (i = 0; i<argc; i++) {
+ if (argv[i][0] != '-') {
+ return i;
+ }
+ if (argv[i][1] == '-' && argv[i][2] == 0) {
+ return i+1;
+ }
+
+ JavaVMOption opt;
+ memset(&opt, 0, sizeof(opt));
+ opt.optionString = (char*)argv[i];
+ mOptions.add(opt);
+ }
+ return i;
+}
+
+static int hasDir(const char* dir)
+{
+ struct stat s;
+ int res = stat(dir, &s);
+ if (res == 0) {
+ return S_ISDIR(s.st_mode);
+ }
+ return 0;
+}
+
+/*
+ * We just want failed write() calls to just return with an error.
+ */
+static void blockSigpipe()
+{
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGPIPE);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
+ LOGW("WARNING: SIGPIPE not blocked\n");
+}
+
+/*
+ * Read the persistent locale from file.
+ */
+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) {
+ /* 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);
+ }
+
+ //LOGD("language=%s region=%s\n", language, region);
+}
+
+void AndroidRuntime::start(const char* className, const bool startSystemServer)
+{
+ LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
+
+ JNIEnv* env;
+ JavaVMInitArgs initArgs;
+ JavaVMOption opt;
+ char propBuf[PROPERTY_VALUE_MAX];
+ char enableAssertBuf[4 + PROPERTY_VALUE_MAX];
+ char stackTraceFileBuf[PROPERTY_VALUE_MAX];
+ char* stackTraceFile = NULL;
+ char* slashClassName = NULL;
+ char* cp;
+ bool checkJni = false;
+ bool logStdio = false;
+ bool verifyJava = true;
+ enum { kEMDefault, kEMIntPortable, kEMIntFast } executionMode = kEMDefault;
+
+ blockSigpipe();
+
+ /*
+ * 'startSystemServer == true' means runtime is obslete and not run from
+ * init.rc anymore, so we print out the boot start event here.
+ */
+ if (startSystemServer) {
+ /* track our progress through the boot sequence */
+ const int LOG_BOOT_PROGRESS_START = 3000;
+ LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
+ ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+ }
+
+ property_get("dalvik.vm.checkjni", propBuf, "");
+ if (strcmp(propBuf, "true") == 0) {
+ checkJni = true;
+ } else if (strcmp(propBuf, "false") != 0) {
+ /* property is neither true nor false; fall back on kernel parameter */
+ property_get("ro.kernel.android.checkjni", propBuf, "");
+ if (propBuf[0] == '1') {
+ checkJni = true;
+ }
+ }
+
+ property_get("dalvik.vm.verify-bytecode", propBuf, "");
+ if (strcmp(propBuf, "true") == 0) {
+ verifyJava = true;
+ } else if (strcmp(propBuf, "false") == 0) {
+ verifyJava = false;
+ } else {
+ /* bad value or not defined; use default */
+ }
+
+ property_get("dalvik.vm.execution-mode", propBuf, "");
+ if (strcmp(propBuf, "int:portable") == 0) {
+ executionMode = kEMIntPortable;
+ } else if (strcmp(propBuf, "int:fast") == 0) {
+ executionMode = kEMIntFast;
+ }
+
+ property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
+
+ property_get("log.redirect-stdio", propBuf, "");
+ if (strcmp(propBuf, "true") == 0) {
+ logStdio = true;
+ }
+
+ strcpy(enableAssertBuf, "-ea:");
+ property_get("dalvik.vm.enableassertions", enableAssertBuf+4, "");
+
+ const char* rootDir = getenv("ANDROID_ROOT");
+ if (rootDir == NULL) {
+ rootDir = "/system";
+ if (!hasDir("/system")) {
+ LOG_FATAL("No root directory specified, and /android does not exist.");
+ return;
+ }
+ setenv("ANDROID_ROOT", rootDir, 1);
+ }
+
+ const char* kernelHack = getenv("LD_ASSUME_KERNEL");
+ //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
+
+ /* route exit() to our handler */
+ opt.extraInfo = (void*) runtime_exit;
+ opt.optionString = "exit";
+ mOptions.add(opt);
+
+ /* route fprintf() to our handler */
+ opt.extraInfo = (void*) runtime_vfprintf;
+ opt.optionString = "vfprintf";
+ mOptions.add(opt);
+
+ opt.extraInfo = NULL;
+
+ /* enable verbose; standard options are { jni, gc, class } */
+ //options[curOpt++].optionString = "-verbose:jni";
+ opt.optionString = "-verbose:gc";
+ mOptions.add(opt);
+ //options[curOpt++].optionString = "-verbose:class";
+
+ /* limit memory use to 16MB */
+ opt.optionString = "-Xmx16m";
+ 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.
+ *
+ * This should be coordinated with:
+ * //device/dalvik/libcore/android/src/main/native/dalvik_system_TouchDex.cpp
+ */
+ if (verifyJava) {
+ opt.optionString = "-Xverify:all";
+ mOptions.add(opt);
+ opt.optionString = "-Xdexopt:verified";
+ mOptions.add(opt);
+ } else {
+ opt.optionString = "-Xverify:none";
+ mOptions.add(opt);
+ //opt.optionString = "-Xdexopt:all";
+ opt.optionString = "-Xdexopt:verified";
+ mOptions.add(opt);
+ }
+
+ /* enable debugging; set suspend=y to pause during VM init */
+#ifdef HAVE_ANDROID_OS
+ /* use android ADB transport */
+ opt.optionString =
+ "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
+#else
+ /* use TCP socket; address=0 means start at port 8000 and probe up */
+ LOGI("Using TCP socket for JDWP\n");
+ opt.optionString =
+ "-agentlib:jdwp=transport=dt_socket,suspend=n,server=y,address=0";
+#endif
+ mOptions.add(opt);
+
+ char enableDPBuf[sizeof("-Xdeadlockpredict:") + PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.deadlock-predict", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ strcpy(enableDPBuf, "-Xdeadlockpredict:");
+ strcat(enableDPBuf, propBuf);
+ opt.optionString = enableDPBuf;
+ mOptions.add(opt);
+ }
+
+ LOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
+ if (checkJni) {
+ /* extended JNI checking */
+ opt.optionString = "-Xcheck:jni";
+ mOptions.add(opt);
+
+ /* set a cap on JNI global references */
+ opt.optionString = "-Xjnigreflimit:2000";
+ mOptions.add(opt);
+
+ /* with -Xcheck:jni, this provides a JNI function call trace */
+ //opt.optionString = "-verbose:jni";
+ //mOptions.add(opt);
+ }
+ if (executionMode == kEMIntPortable) {
+ opt.optionString = "-Xint:portable";
+ mOptions.add(opt);
+ } else if (executionMode == kEMIntFast) {
+ opt.optionString = "-Xint:fast";
+ mOptions.add(opt);
+ }
+ if (logStdio) {
+ /* convert stdout/stderr to log messages */
+ opt.optionString = "-Xlog-stdio";
+ mOptions.add(opt);
+ }
+
+ if (enableAssertBuf[4] != '\0') {
+ /* accept "all" to mean "all classes and packages" */
+ if (strcmp(enableAssertBuf+4, "all") == 0)
+ enableAssertBuf[3] = '\0';
+ LOGI("Assertions enabled: '%s'\n", enableAssertBuf);
+ opt.optionString = enableAssertBuf;
+ mOptions.add(opt);
+ } else {
+ LOGV("Assertions disabled\n");
+ }
+
+ if (stackTraceFileBuf[0] != '\0') {
+ static const char* stfOptName = "-Xstacktracefile:";
+
+ stackTraceFile = (char*) malloc(strlen(stfOptName) +
+ strlen(stackTraceFileBuf) +1);
+ strcpy(stackTraceFile, stfOptName);
+ strcat(stackTraceFile, stackTraceFileBuf);
+ opt.optionString = stackTraceFile;
+ mOptions.add(opt);
+ }
+
+ /* Set the properties for locale */
+ {
+ char langOption[sizeof("-Duser.language=") + 3];
+ char regionOption[sizeof("-Duser.region=") + 3];
+ strcpy(langOption, "-Duser.language=");
+ strcpy(regionOption, "-Duser.region=");
+ readLocale(langOption, regionOption);
+ opt.extraInfo = NULL;
+ opt.optionString = langOption;
+ mOptions.add(opt);
+ opt.optionString = regionOption;
+ mOptions.add(opt);
+ }
+
+ /*
+ * We don't have /tmp on the device, but we often have an SD card. Apps
+ * shouldn't use this, but some test suites might want to exercise it.
+ */
+ opt.optionString = "-Djava.io.tmpdir=/sdcard";
+ mOptions.add(opt);
+
+ initArgs.version = JNI_VERSION_1_4;
+ initArgs.options = mOptions.editArray();
+ initArgs.nOptions = mOptions.size();
+ initArgs.ignoreUnrecognized = JNI_FALSE;
+
+ /*
+ * Initialize the VM.
+ *
+ * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
+ * If this call succeeds, the VM is ready, and we can start issuing
+ * JNI calls.
+ */
+ if (JNI_CreateJavaVM(&mJavaVM, &env, &initArgs) < 0) {
+ LOGE("JNI_CreateJavaVM failed\n");
+ goto bail;
+ }
+
+ /*
+ * Register android functions.
+ */
+ if (startReg(env) < 0) {
+ LOGE("Unable to register all android natives\n");
+ goto bail;
+ }
+
+ /*
+ * We want to call main() with a String array with arguments in it.
+ * At present we only have one argument, the class name. Create an
+ * array to hold it.
+ */
+ jclass stringClass;
+ jobjectArray strArray;
+ jstring classNameStr;
+ jstring startSystemServerStr;
+
+ stringClass = env->FindClass("java/lang/String");
+ assert(stringClass != NULL);
+ strArray = env->NewObjectArray(2, stringClass, NULL);
+ assert(strArray != NULL);
+ classNameStr = env->NewStringUTF(className);
+ assert(classNameStr != NULL);
+ env->SetObjectArrayElement(strArray, 0, classNameStr);
+ startSystemServerStr = env->NewStringUTF(startSystemServer ?
+ "true" : "false");
+ env->SetObjectArrayElement(strArray, 1, startSystemServerStr);
+
+ /*
+ * Start VM. This thread becomes the main thread of the VM, and will
+ * not return until the VM exits.
+ */
+ jclass startClass;
+ jmethodID startMeth;
+
+ slashClassName = strdup(className);
+ for (cp = slashClassName; *cp != '\0'; cp++)
+ if (*cp == '.')
+ *cp = '/';
+
+ startClass = env->FindClass(slashClassName);
+ if (startClass == NULL) {
+ LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
+ /* keep going */
+ } else {
+ startMeth = env->GetStaticMethodID(startClass, "main",
+ "([Ljava/lang/String;)V");
+ if (startMeth == NULL) {
+ LOGE("JavaVM unable to find main() in '%s'\n", className);
+ /* keep going */
+ } else {
+ env->CallStaticVoidMethod(startClass, startMeth, strArray);
+
+#if 0
+ if (env->ExceptionCheck())
+ threadExitUncaughtException(env);
+#endif
+ }
+ }
+
+ LOGD("Shutting down VM\n");
+ if (mJavaVM->DetachCurrentThread() != JNI_OK)
+ LOGW("Warning: unable to detach main thread\n");
+ if (mJavaVM->DestroyJavaVM() != 0)
+ LOGW("Warning: VM did not shut down cleanly\n");
+
+bail:
+ free(slashClassName);
+ free(stackTraceFile);
+}
+
+void AndroidRuntime::start()
+{
+ start("com.android.internal.os.RuntimeInit",
+ false /* Don't start the system server */);
+}
+
+void AndroidRuntime::onExit(int code)
+{
+ LOGI("AndroidRuntime onExit calling exit(%d)", code);
+ exit(code);
+}
+
+/*
+ * Get the JNIEnv pointer for this thread.
+ *
+ * Returns NULL if the slot wasn't allocated or populated.
+ */
+/*static*/ JNIEnv* AndroidRuntime::getJNIEnv()
+{
+ JNIEnv* env;
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ assert(vm != NULL);
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
+ return NULL;
+ return env;
+}
+
+/*
+ * Makes the current thread visible to the VM.
+ *
+ * The JNIEnv pointer returned is only valid for the current thread, and
+ * thus must be tucked into thread-local storage.
+ */
+static int javaAttachThread(const char* threadName, JNIEnv** pEnv)
+{
+ JavaVMAttachArgs args;
+ JavaVM* vm;
+ jint result;
+
+ vm = AndroidRuntime::getJavaVM();
+ assert(vm != NULL);
+
+ args.version = JNI_VERSION_1_4;
+ args.name = (char*) threadName;
+ args.group = NULL;
+
+ result = vm->AttachCurrentThread(pEnv, (void*) &args);
+ if (result != JNI_OK)
+ LOGE("ERROR: thread attach failed\n");
+
+ return result;
+}
+
+/*
+ * Detach the current thread from the set visible to the VM.
+ */
+static int javaDetachThread(void)
+{
+ JavaVM* vm;
+ jint result;
+
+ vm = AndroidRuntime::getJavaVM();
+ assert(vm != NULL);
+
+ result = vm->DetachCurrentThread();
+ if (result != JNI_OK)
+ LOGE("ERROR: thread detach failed\n");
+ return result;
+}
+
+/*
+ * When starting a native thread that will be visible from the VM, we
+ * bounce through this to get the right attach/detach action.
+ * Note that this function calls free(args)
+ */
+/*static*/ int AndroidRuntime::javaThreadShell(void* args) {
+ void* start = ((void**)args)[0];
+ void* userData = ((void **)args)[1];
+ char* name = (char*) ((void **)args)[2]; // we own this storage
+ free(args);
+ JNIEnv* env;
+ int result;
+
+ /* hook us into the VM */
+ if (javaAttachThread(name, &env) != JNI_OK)
+ return -1;
+
+ /* start the thread running */
+ result = (*(android_thread_func_t)start)(userData);
+
+ /* unhook us */
+ javaDetachThread();
+ free(name);
+
+ return result;
+}
+
+/*
+ * This is invoked from androidCreateThreadEtc() via the callback
+ * set with androidSetCreateThreadFunc().
+ *
+ * We need to create the new thread in such a way that it gets hooked
+ * into the VM before it really starts executing.
+ */
+/*static*/ int AndroidRuntime::javaCreateThreadEtc(
+ android_thread_func_t entryFunction,
+ void* userData,
+ const char* threadName,
+ int32_t threadPriority,
+ size_t threadStackSize,
+ android_thread_id_t* threadId)
+{
+ void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free
+ int result;
+
+ assert(threadName != NULL);
+
+ args[0] = (void*) entryFunction;
+ args[1] = userData;
+ args[2] = (void*) strdup(threadName); // javaThreadShell must free
+
+ result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args,
+ threadName, threadPriority, threadStackSize, threadId);
+ return result;
+}
+
+/*
+ * Create a thread that is visible from the VM.
+ *
+ * This is called from elsewhere in the library.
+ */
+/*static*/ void AndroidRuntime::createJavaThread(const char* name,
+ void (*start)(void *), void* arg)
+{
+ javaCreateThreadEtc((android_thread_func_t) start, arg, name,
+ ANDROID_PRIORITY_DEFAULT, 0, NULL);
+}
+
+#if 0
+static void quickTest(void* arg)
+{
+ const char* str = (const char*) arg;
+
+ printf("In quickTest: %s\n", str);
+}
+#endif
+
+#ifdef NDEBUG
+ #define REG_JNI(name) { name }
+ struct RegJNIRec {
+ int (*mProc)(JNIEnv*);
+ };
+#else
+ #define REG_JNI(name) { name, #name }
+ struct RegJNIRec {
+ int (*mProc)(JNIEnv*);
+ const char* mName;
+ };
+#endif
+
+typedef void (*RegJAMProc)();
+
+static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
+{
+ for (size_t i = 0; i < count; i++) {
+ if (array[i].mProc(env) < 0) {
+#ifndef NDEBUG
+ LOGD("----------!!! %s failed to load\n", array[i].mName);
+#endif
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void register_jam_procs(const RegJAMProc array[], size_t count)
+{
+ for (size_t i = 0; i < count; i++) {
+ array[i]();
+ }
+}
+
+static const RegJNIRec gRegJNI[] = {
+ REG_JNI(register_android_debug_JNITest),
+ REG_JNI(register_com_android_internal_os_RuntimeInit),
+ REG_JNI(register_android_os_SystemClock),
+ 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_pim_EventRecurrence),
+ REG_JNI(register_android_content_AssetManager),
+ REG_JNI(register_android_content_StringBlock),
+ REG_JNI(register_android_content_XmlBlock),
+ REG_JNI(register_android_security_Md5MessageDigest),
+ REG_JNI(register_android_text_AndroidCharacter),
+ REG_JNI(register_android_text_KeyCharacterMap),
+ REG_JNI(register_android_os_Process),
+ REG_JNI(register_android_os_Binder),
+ REG_JNI(register_android_os_Hardware),
+ REG_JNI(register_android_view_Display),
+ REG_JNI(register_android_nio_utils),
+ REG_JNI(register_android_graphics_PixelFormat),
+ REG_JNI(register_android_graphics_Graphics),
+ REG_JNI(register_android_view_Surface),
+ REG_JNI(register_android_view_ViewRoot),
+ REG_JNI(register_com_google_android_gles_jni_EGLImpl),
+ REG_JNI(register_com_google_android_gles_jni_GLImpl),
+
+ REG_JNI(register_android_graphics_Bitmap),
+ REG_JNI(register_android_graphics_BitmapFactory),
+ REG_JNI(register_android_graphics_Camera),
+ REG_JNI(register_android_graphics_Canvas),
+ REG_JNI(register_android_graphics_ColorFilter),
+ REG_JNI(register_android_graphics_DrawFilter),
+ REG_JNI(register_android_graphics_Interpolator),
+ REG_JNI(register_android_graphics_LayerRasterizer),
+ REG_JNI(register_android_graphics_MaskFilter),
+ REG_JNI(register_android_graphics_Matrix),
+ REG_JNI(register_android_graphics_Movie),
+ REG_JNI(register_android_graphics_NinePatch),
+ REG_JNI(register_android_graphics_Paint),
+ REG_JNI(register_android_graphics_Path),
+ REG_JNI(register_android_graphics_PathMeasure),
+ REG_JNI(register_android_graphics_PathEffect),
+ REG_JNI(register_android_graphics_Picture),
+ REG_JNI(register_android_graphics_PorterDuff),
+ REG_JNI(register_android_graphics_Rasterizer),
+ REG_JNI(register_android_graphics_Region),
+ REG_JNI(register_android_graphics_Shader),
+ REG_JNI(register_android_graphics_Typeface),
+ REG_JNI(register_android_graphics_Xfermode),
+ REG_JNI(register_com_android_internal_graphics_NativeUtils),
+
+ REG_JNI(register_android_database_CursorWindow),
+ REG_JNI(register_android_database_SQLiteDatabase),
+ REG_JNI(register_android_database_SQLiteDebug),
+ REG_JNI(register_android_database_SQLiteProgram),
+ REG_JNI(register_android_database_SQLiteQuery),
+ REG_JNI(register_android_database_SQLiteStatement),
+ REG_JNI(register_android_os_Debug),
+ REG_JNI(register_android_os_Exec),
+ REG_JNI(register_android_os_FileObserver),
+ REG_JNI(register_android_os_FileUtils),
+ REG_JNI(register_android_os_ParcelFileDescriptor),
+ REG_JNI(register_android_os_Power),
+ REG_JNI(register_android_os_StatFs),
+ REG_JNI(register_android_os_SystemProperties),
+ REG_JNI(register_android_os_UEventObserver),
+ REG_JNI(register_android_net_LocalSocketImpl),
+ REG_JNI(register_android_net_NetworkUtils),
+ REG_JNI(register_android_net_wifi_WifiManager),
+ REG_JNI(register_android_os_NetStat),
+ REG_JNI(register_android_os_MemoryFile),
+ 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_AudioSystem),
+ REG_JNI(register_android_media_ToneGenerator),
+
+ REG_JNI(register_android_opengl_classes),
+ REG_JNI(register_android_bluetooth_Database),
+ REG_JNI(register_android_bluetooth_HeadsetBase),
+ REG_JNI(register_android_bluetooth_BluetoothAudioGateway),
+ REG_JNI(register_android_bluetooth_RfcommSocket),
+ REG_JNI(register_android_bluetooth_ScoSocket),
+ REG_JNI(register_android_server_BluetoothDeviceService),
+ REG_JNI(register_android_server_BluetoothEventLoop),
+ REG_JNI(register_android_message_digest_sha1),
+ REG_JNI(register_android_ddm_DdmHandleNativeHeap),
+ REG_JNI(register_android_util_Base64),
+ REG_JNI(register_android_location_GpsLocationProvider),
+};
+
+/*
+ * Register android native functions with the VM.
+ */
+/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
+{
+ /*
+ * This hook causes all future threads created in this process to be
+ * attached to the JavaVM. (This needs to go away in favor of JNI
+ * Attach calls.)
+ */
+ androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
+
+ LOGD("--- registering native functions ---\n");
+
+ /*
+ * Every "register" function calls one or more things that return
+ * a local reference (e.g. FindClass). Because we haven't really
+ * started the VM yet, they're all getting stored in the base frame
+ * and never released. Use Push/Pop to manage the storage.
+ */
+ env->PushLocalFrame(200);
+
+ if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
+ env->PopLocalFrame(NULL);
+ return -1;
+ }
+ env->PopLocalFrame(NULL);
+
+ //createJavaThread("fubar", quickTest, (void*) "hello");
+
+ return 0;
+}
+
+AndroidRuntime* AndroidRuntime::getRuntime()
+{
+ return gCurRuntime;
+}
+
+/**
+ * Used by WithFramework to register native functions.
+ */
+extern "C"
+jint Java_com_android_internal_util_WithFramework_registerNatives(
+ JNIEnv* env, jclass clazz) {
+ return register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
+}
+
+/**
+ * Used by LoadClass to register native functions.
+ */
+extern "C"
+jint Java_LoadClass_registerNatives(JNIEnv* env, jclass clazz) {
+ return register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
+}
+
+} // namespace android
diff --git a/core/jni/BindTest.cpp b/core/jni/BindTest.cpp
new file mode 100644
index 0000000..5fae400
--- /dev/null
+++ b/core/jni/BindTest.cpp
@@ -0,0 +1,289 @@
+/* //device/libs/android_runtime/BindTest.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <jam-public.h>
+
+static u4 offset_instanceString;
+static FieldBlock *fb_classString = NULL;
+static Class *class_ReturnedObject = NULL;
+static MethodBlock *mb_ReturnedObject_setReturnedString = NULL;
+static MethodBlock *mb_Java_Lang_Object_Equals = NULL;
+
+static u4 offset_mObj;
+static u4 offset_mBool;
+static u4 offset_mInt;
+static u4 offset_mString;
+static u4 offset_mDouble;
+static u4 offset_mLong;
+
+
+/* native String getString(); */
+static uintptr_t *
+getString(Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ RETURN_OBJ (createString ("String"));
+}
+
+/* native String getNullString(); */
+static uintptr_t *
+getNullString(Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ RETURN_OBJ (createString (NULL));
+}
+
+/* native String getBooleanTrue(); */
+static uintptr_t *
+getBooleanTrue(Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ RETURN_BOOLEAN (TRUE);
+}
+
+/* native String getBooleanFalse(); */
+static uintptr_t *
+getBooleanFalse(Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ RETURN_BOOLEAN (FALSE);
+}
+
+/* native Object nonvoidThrowsException() */
+static uintptr_t *
+nonvoidThrowsException (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ if (1) {
+ signalException("java/lang/NullPointerException", NULL);
+ goto exception;
+ }
+
+ RETURN_OBJ (NULL);
+exception:
+ RETURN_VOID;
+}
+
+/* native void setInstanceString(String s); */
+static uintptr_t *
+setInstanceString (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ Object *jthis = (Object *) ostack[0];
+
+ JOBJ_set_obj(jthis, offset_instanceString, ostack[1]);
+
+ RETURN_VOID;
+}
+
+/* native void setClassString(String s) */
+static uintptr_t *
+setClassString (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+// Object *jthis = (Object *) ostack[0];
+
+ fb_classString->static_value = ostack[1];
+
+ RETURN_VOID;
+}
+
+/* native String makeStringFromThreeChars(char a, char b, char c); */
+static uintptr_t *
+makeStringFromThreeChars (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ // Object *jthis = ostack[0];
+ char a = (char) ostack[1];
+ char b = (char) ostack[2];
+ char c = (char) ostack[3];
+
+ char str[4];
+
+ str[0] = a;
+ str[1] = b;
+ str[2] = c;
+ str[3] = 0;
+
+ RETURN_OBJ(createString(str));
+}
+
+/* native ReturnedObject makeReturnedObject(String a); */
+static uintptr_t *
+makeReturnedObject (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ //Object *jthis = (Object*)ostack[0];
+ Object *a = (Object*)ostack[1];
+
+ Object *ret;
+
+ ret = allocObject(class_ReturnedObject);
+
+ executeMethod(ret, mb_ReturnedObject_setReturnedString, a);
+
+ RETURN_OBJ (ret);
+}
+
+/* native double addDoubles(double a, double b); */
+static uintptr_t *
+addDoubles (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ //Object *jthis = (Object*)ostack[0];
+ double a = JARG_get_double(1);
+ double b = JARG_get_double(3);
+
+ RETURN_DOUBLE(a+b);
+}
+
+/* native void setAll (Object obj, boolean bool, int i, String str, double d, long l) */
+static uintptr_t *
+setAll (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ Object *jthis = JARG_get_obj(0);
+
+ Object *obj = JARG_get_obj(1);
+ bool b = JARG_get_bool(2);
+ int i = JARG_get_int(3);
+ char *str = JARG_get_cstr_strdup(4);
+ double d = JARG_get_double(5);
+ long long ll = JARG_get_long_long(5+2);
+
+ JOBJ_set_obj(jthis, offset_mObj, obj);
+ JOBJ_set_bool(jthis, offset_mBool, b);
+ JOBJ_set_int(jthis, offset_mInt, i);
+ JOBJ_set_cstr(jthis, offset_mString, str);
+ free(str);
+ str = NULL;
+ JOBJ_set_double(jthis, offset_mDouble, d);
+ JOBJ_set_long_long(jthis, offset_mLong, ll);
+
+ RETURN_VOID;
+}
+
+/* native void compareAll (Object obj, boolean bool, int i, String str, double d, long l) */
+static uintptr_t *
+compareAll (Class *clazz, MethodBlock *mb, uintptr_t *ostack)
+{
+ Object *jthis = JARG_get_obj(0);
+
+ Object *obj = JARG_get_obj(1);
+ bool b = JARG_get_bool(2);
+ int i = JARG_get_int(3);
+ Object *strObj = JARG_get_obj(4);
+ double d = JARG_get_double(5);
+ long long ll = JARG_get_long_long(5+2);
+
+ bool ret;
+
+ void *result;
+
+ Object *mStringObj = JOBJ_get_obj(jthis, offset_mString);
+
+ char *s = JARG_get_cstr_strdup(4);
+
+ result = executeMethod (strObj, lookupVirtualMethod(strObj,mb_Java_Lang_Object_Equals),
+ JOBJ_get_obj(jthis, offset_mString));
+
+ if (exceptionOccurred()) {
+ RETURN_VOID;
+ }
+
+ ret = (*(uintptr_t *)result != 0)
+ && (obj == JOBJ_get_obj(jthis, offset_mObj))
+ && (b == JOBJ_get_bool(jthis, offset_mBool))
+ && (i == JOBJ_get_int(jthis, offset_mInt))
+ && (d == JOBJ_get_double(jthis, offset_mDouble))
+ && (ll == JOBJ_get_long_long(jthis, offset_mLong));
+
+
+ RETURN_BOOLEAN(ret);
+}
+
+static VMMethod methods[] = {
+ {"getString", getString},
+ {"getNullString", getNullString},
+ {"getBooleanTrue", getBooleanTrue},
+ {"getBooleanFalse", getBooleanFalse},
+ {"nonvoidThrowsException", nonvoidThrowsException},
+ {"setInstanceString", setInstanceString},
+ {"setClassString", setClassString},
+ {"makeStringFromThreeChars", makeStringFromThreeChars},
+ {"makeReturnedObject", makeReturnedObject},
+ {"addDoubles", addDoubles},
+ {"setAll", setAll},
+ {"compareAll", compareAll},
+ {NULL, NULL}
+};
+
+
+void register_BindTest()
+{
+ jamvm_registerClass("BindTest", methods);
+
+ Class *clazz = NULL;
+
+ clazz = findClassFromClassLoader("BindTest", getSystemClassLoader());
+
+ if (clazz == NULL) {
+ fprintf(stderr, "Error: BindTest not found\n");
+ clearException();
+ return;
+ }
+
+ FieldBlock *fb;
+
+ fb = findField(clazz, "instanceString", "Ljava/lang/String;");
+
+ if (fb == NULL || ((fb->access_flags & ACC_STATIC) == ACC_STATIC)) {
+ fprintf(stderr, "Error: BindTest.instanceString not found or error\n");
+ return;
+ }
+
+ offset_instanceString = fb->offset;
+
+ fb_classString = findField(clazz, "classString", "Ljava/lang/String;");
+
+ if (fb_classString == NULL || ((fb_classString->access_flags & ACC_STATIC) != ACC_STATIC)) {
+ fprintf(stderr, "Error: BindTest.classString not found or error\n");
+ return;
+ }
+
+
+ class_ReturnedObject = findClassFromClassLoader("ReturnedObject", getSystemClassLoader());
+
+ if (class_ReturnedObject == NULL) {
+ fprintf(stderr, "Error: ReturnedObject class not found or error\n");
+ return;
+ }
+
+ mb_ReturnedObject_setReturnedString=
+ findMethod (class_ReturnedObject, "setReturnedString", "(Ljava/lang/String;)V");
+
+ if (mb_ReturnedObject_setReturnedString == NULL) {
+ fprintf(stderr, "Error: ReturnedObject.setReturnedString class not found or error\n");
+ return;
+ }
+
+ offset_mObj = findField(clazz, "mObj", "Ljava/lang/Object;")->offset;
+ offset_mBool = findField(clazz, "mBool", "Z" )->offset;
+ offset_mInt = findField(clazz, "mInt", "I")->offset;
+ offset_mString = findField(clazz, "mString", "Ljava/lang/String;")->offset;
+ offset_mDouble = findField(clazz, "mDouble", "D")->offset;
+ offset_mLong = findField(clazz, "mLong", "J")->offset;
+
+
+ mb_Java_Lang_Object_Equals = findMethod (
+ findClassFromClassLoader("java/lang/Object", getSystemClassLoader()),
+ "equals", "(Ljava/lang/Object;)Z");
+
+}
+
+
diff --git a/core/jni/CursorWindow.cpp b/core/jni/CursorWindow.cpp
new file mode 100644
index 0000000..fb891c9
--- /dev/null
+++ b/core/jni/CursorWindow.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2006-2007 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CursorWindow"
+
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+#include "CursorWindow.h"
+
+
+namespace android {
+
+CursorWindow::CursorWindow(size_t maxSize) :
+ mMaxSize(maxSize)
+{
+}
+
+bool CursorWindow::setMemory(sp<IMemory> memory)
+{
+ mMemory = memory;
+ mData = (uint8_t *) memory->pointer();
+ if (mData == NULL) {
+ return false;
+ }
+ mHeader = (window_header_t *) mData;
+
+ // Make the window read-only
+ mHeap = NULL;
+ ssize_t size = memory->size();
+ mSize = size;
+ mMaxSize = size;
+ mFreeOffset = size;
+LOG_WINDOW("Created CursorWindow from existing IMemory: mFreeOffset = %d, numRows = %d, numColumns = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mHeader->numRows, mHeader->numColumns, mSize, mMaxSize, mData);
+ return true;
+}
+
+bool CursorWindow::initBuffer(bool localOnly)
+{
+ //TODO Use a non-memory dealer mmap region for localOnly
+
+ mHeap = new MemoryDealer(new SharedHeap(mMaxSize, 0, "CursorWindow"));
+ if (mHeap != NULL) {
+ mMemory = mHeap->allocate(mMaxSize);
+ if (mMemory != NULL) {
+ mData = (uint8_t *) mMemory->pointer();
+ if (mData) {
+ mHeader = (window_header_t *) mData;
+ mSize = mMaxSize;
+
+ // Put the window into a clean state
+ clear();
+ LOG_WINDOW("Created CursorWindow with new MemoryDealer: mFreeOffset = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mSize, mMaxSize, mData);
+ return true;
+ }
+ }
+ LOGE("memory dealer allocation failed");
+ return false;
+ } else {
+ LOGE("failed to create the memory dealer");
+ return false;
+ }
+}
+
+CursorWindow::~CursorWindow()
+{
+ // Everything that matters is a smart pointer
+}
+
+void CursorWindow::clear()
+{
+ mHeader->numRows = 0;
+ mHeader->numColumns = 0;
+ mFreeOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE;
+ // Mark the first chunk's next 'pointer' as null
+ *((uint32_t *)(mData + mFreeOffset - sizeof(uint32_t))) = 0;
+}
+
+int32_t CursorWindow::freeSpace()
+{
+ int32_t freeSpace = mSize - mFreeOffset;
+ if (freeSpace < 0) {
+ freeSpace = 0;
+ }
+ return freeSpace;
+}
+
+field_slot_t * CursorWindow::allocRow()
+{
+ // Fill in the row slot
+ row_slot_t * rowSlot = allocRowSlot();
+ if (rowSlot == NULL) {
+ return NULL;
+ }
+
+ // Allocate the slots for the field directory
+ size_t fieldDirSize = mHeader->numColumns * sizeof(field_slot_t);
+ uint32_t fieldDirOffset = alloc(fieldDirSize);
+ if (!fieldDirOffset) {
+ mHeader->numRows--;
+ LOGE("The row failed, so back out the new row accounting from allocRowSlot %d", mHeader->numRows);
+ return NULL;
+ }
+ field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(fieldDirOffset);
+ memset(fieldDir, 0x0, fieldDirSize);
+
+LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", (mHeader->numRows - 1), ((uint8_t *)rowSlot) - mData, fieldDirSize, fieldDirOffset);
+ rowSlot->offset = fieldDirOffset;
+
+ return fieldDir;
+}
+
+uint32_t CursorWindow::alloc(size_t requestedSize, bool aligned)
+{
+ int32_t size;
+ uint32_t padding;
+ if (aligned) {
+ // 4 byte alignment
+ padding = 4 - (mFreeOffset & 0x3);
+ } else {
+ padding = 0;
+ }
+
+ size = requestedSize + padding;
+
+ if (size > freeSpace()) {
+ LOGE("need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d", mSize, size, freeSpace(), mHeader->numRows);
+ // Only grow the window if the first row doesn't fit
+ if (mHeader->numRows > 1) {
+LOGE("not growing since there are already %d row(s), max size %d", mHeader->numRows, mMaxSize);
+ return 0;
+ }
+
+ // Find a new size that will fit the allocation
+ int allocated = mSize - freeSpace();
+ int newSize = mSize + WINDOW_ALLOCATION_SIZE;
+ while (size > (newSize - allocated)) {
+ newSize += WINDOW_ALLOCATION_SIZE;
+ if (newSize > mMaxSize) {
+ LOGE("Attempting to grow window beyond max size (%d)", mMaxSize);
+ return 0;
+ }
+ }
+LOG_WINDOW("found size %d", newSize);
+ mSize = newSize;
+ }
+
+ uint32_t offset = mFreeOffset + padding;
+ mFreeOffset += size;
+ return offset;
+}
+
+row_slot_t * CursorWindow::getRowSlot(int row)
+{
+ LOG_WINDOW("enter getRowSlot current row num %d, this row %d", mHeader->numRows, row);
+ int chunkNum = row / ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPos = row % ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
+ uint8_t * rowChunk = mData + sizeof(window_header_t);
+ for (int i = 0; i < chunkNum; i++) {
+ rowChunk = offsetToPtr(*((uint32_t *)(mData + chunkPtrOffset)));
+ chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
+ }
+ return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
+ LOG_WINDOW("exit getRowSlot current row num %d, this row %d", mHeader->numRows, row);
+}
+
+row_slot_t * CursorWindow::allocRowSlot()
+{
+ int chunkNum = mHeader->numRows / ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPos = mHeader->numRows % ROW_SLOT_CHUNK_NUM_ROWS;
+ int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t);
+ uint8_t * rowChunk = mData + sizeof(window_header_t);
+LOG_WINDOW("Allocating row slot, mHeader->numRows is %d, chunkNum is %d, chunkPos is %d", mHeader->numRows, chunkNum, chunkPos);
+ for (int i = 0; i < chunkNum; i++) {
+ uint32_t nextChunkOffset = *((uint32_t *)(mData + chunkPtrOffset));
+LOG_WINDOW("nextChunkOffset is %d", nextChunkOffset);
+ if (nextChunkOffset == 0) {
+ // Allocate a new row chunk
+ nextChunkOffset = alloc(ROW_SLOT_CHUNK_SIZE, true);
+ if (nextChunkOffset == 0) {
+ return NULL;
+ }
+ rowChunk = offsetToPtr(nextChunkOffset);
+LOG_WINDOW("allocated new chunk at %d, rowChunk = %p", nextChunkOffset, rowChunk);
+ *((uint32_t *)(mData + chunkPtrOffset)) = rowChunk - mData;
+ // Mark the new chunk's next 'pointer' as null
+ *((uint32_t *)(rowChunk + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t))) = 0;
+ } else {
+LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chunkPtrOffset);
+ rowChunk = offsetToPtr(nextChunkOffset);
+ chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t));
+ }
+ }
+ mHeader->numRows++;
+
+ return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t)));
+}
+
+field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column)
+{
+ if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
+ LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
+ return NULL;
+ }
+ row_slot_t * rowSlot = getRowSlot(row);
+ if (!rowSlot) {
+ LOGE("Failed to find rowSlot for row %d", row);
+ return NULL;
+ }
+ if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
+ LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
+ return NULL;
+ }
+ int fieldDirOffset = rowSlot->offset;
+ return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
+}
+
+uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut)
+{
+ if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
+ LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
+ return -1;
+ }
+ row_slot_t * rowSlot = getRowSlot(row);
+ if (!rowSlot) {
+ LOGE("Failed to find rowSlot for row %d", row);
+ return -1;
+ }
+ if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
+ LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
+ return -1;
+ }
+LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset);
+ field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset);
+LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type);
+
+ // Copy the data to the out param
+ slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset;
+ slotOut->data.buffer.size = fieldDir[column].data.buffer.size;
+ slotOut->type = fieldDir[column].type;
+ return 0;
+}
+
+void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size)
+{
+ assert(offset + size <= mSize);
+ memcpy(mData + offset, data, size);
+}
+
+void CursorWindow::copyIn(uint32_t offset, int64_t data)
+{
+ assert(offset + sizeof(int64_t) <= mSize);
+ memcpy(mData + offset, (uint8_t *)&data, sizeof(int64_t));
+}
+
+void CursorWindow::copyIn(uint32_t offset, double data)
+{
+ assert(offset + sizeof(double) <= mSize);
+ memcpy(mData + offset, (uint8_t *)&data, sizeof(double));
+}
+
+void CursorWindow::copyOut(uint32_t offset, uint8_t * data, size_t size)
+{
+ assert(offset + size <= mSize);
+ memcpy(data, mData + offset, size);
+}
+
+int64_t CursorWindow::copyOutLong(uint32_t offset)
+{
+ int64_t value;
+ assert(offset + sizeof(int64_t) <= mSize);
+ memcpy(&value, mData + offset, sizeof(int64_t));
+ return value;
+}
+
+double CursorWindow::copyOutDouble(uint32_t offset)
+{
+ double value;
+ assert(offset + sizeof(double) <= mSize);
+ memcpy(&value, mData + offset, sizeof(double));
+ return value;
+}
+
+bool CursorWindow::putLong(unsigned int row, unsigned int col, int64_t value)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ fieldSlot->data.l = value;
+#else
+ int offset = alloc(sizeof(int64_t));
+ if (!offset) {
+ return false;
+ }
+
+ copyIn(offset, value);
+
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = sizeof(int64_t);
+#endif
+ fieldSlot->type = FIELD_TYPE_INTEGER;
+ return true;
+}
+
+bool CursorWindow::putDouble(unsigned int row, unsigned int col, double value)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ fieldSlot->data.d = value;
+#else
+ int offset = alloc(sizeof(int64_t));
+ if (!offset) {
+ return false;
+ }
+
+ copyIn(offset, value);
+
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = sizeof(double);
+#endif
+ fieldSlot->type = FIELD_TYPE_FLOAT;
+ return true;
+}
+
+bool CursorWindow::putNull(unsigned int row, unsigned int col)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+ fieldSlot->type = FIELD_TYPE_NULL;
+ fieldSlot->data.buffer.offset = 0;
+ fieldSlot->data.buffer.size = 0;
+ return true;
+}
+
+bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ *valueOut = fieldSlot->data.l;
+#else
+ *valueOut = copyOutLong(fieldSlot->data.buffer.offset);
+#endif
+ return true;
+}
+
+bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot || fieldSlot->type != FIELD_TYPE_FLOAT) {
+ return false;
+ }
+
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ *valueOut = fieldSlot->data.d;
+#else
+ *valueOut = copyOutDouble(fieldSlot->data.buffer.offset);
+#endif
+ return true;
+}
+
+bool CursorWindow::getNull(unsigned int row, unsigned int col, bool * valueOut)
+{
+ field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col);
+ if (!fieldSlot) {
+ return false;
+ }
+
+ if (fieldSlot->type != FIELD_TYPE_NULL) {
+ *valueOut = false;
+ } else {
+ *valueOut = true;
+ }
+ return true;
+}
+
+}; // namespace android
diff --git a/core/jni/CursorWindow.h b/core/jni/CursorWindow.h
new file mode 100644
index 0000000..0fb074f
--- /dev/null
+++ b/core/jni/CursorWindow.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef _ANDROID__DATABASE_WINDOW_H
+#define _ANDROID__DATABASE_WINDOW_H
+
+#include <cutils/log.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/RefBase.h>
+
+#include <jni.h>
+
+#define DEFAULT_WINDOW_SIZE 4096
+#define MAX_WINDOW_SIZE (1024 * 1024)
+#define WINDOW_ALLOCATION_SIZE 4096
+
+#define ROW_SLOT_CHUNK_NUM_ROWS 16
+
+// Row slots are allocated in chunks of ROW_SLOT_CHUNK_NUM_ROWS,
+// with an offset after the rows that points to the next chunk
+#define ROW_SLOT_CHUNK_SIZE ((ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)) + sizeof(uint32_t))
+
+
+#if LOG_NDEBUG
+
+#define IF_LOG_WINDOW() if (false)
+#define LOG_WINDOW(...)
+
+#else
+
+#define IF_LOG_WINDOW() IF_LOG(LOG_DEBUG, "CursorWindow")
+#define LOG_WINDOW(...) LOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__)
+
+#endif
+
+
+// When defined to true strings are stored as UTF8, otherwise they're UTF16
+#define WINDOW_STORAGE_UTF8 1
+
+// When defined to true numberic values are stored inline in the field_slot_t, otherwise they're allocated in the window
+#define WINDOW_STORAGE_INLINE_NUMERICS 1
+
+namespace android {
+
+typedef struct
+{
+ uint32_t numRows;
+ uint32_t numColumns;
+} window_header_t;
+
+typedef struct
+{
+ uint32_t offset;
+} row_slot_t;
+
+typedef struct
+{
+ uint8_t type;
+ union {
+ double d;
+ int64_t l;
+ struct {
+ uint32_t offset;
+ uint32_t size;
+ } buffer;
+ } data;
+} __attribute__((packed)) field_slot_t;
+
+#define FIELD_TYPE_INTEGER 1
+#define FIELD_TYPE_FLOAT 2
+#define FIELD_TYPE_STRING 3
+#define FIELD_TYPE_BLOB 4
+#define FIELD_TYPE_NULL 5
+
+/**
+ * This class stores a set of rows from a database in a buffer. The begining of the
+ * window has first chunk of row_slot_ts, which are offsets to the row directory, followed by
+ * an offset to the next chunk in a linked-list of additional chunk of row_slot_ts in case
+ * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
+ * field_slot_t per column, which has the size, offset, and type of the data for that field.
+ * Note that the data types come from sqlite3.h.
+ */
+class CursorWindow
+{
+public:
+ CursorWindow(size_t maxSize);
+ CursorWindow(){}
+ bool setMemory(sp<IMemory>);
+ ~CursorWindow();
+
+ bool initBuffer(bool localOnly);
+ sp<IMemory> getMemory() {return mMemory;}
+
+ size_t size() {return mSize;}
+ uint8_t * data() {return mData;}
+ uint32_t getNumRows() {return mHeader->numRows;}
+ uint32_t getNumColumns() {return mHeader->numColumns;}
+ void freeLastRow() {
+ if (mHeader->numRows > 0) {
+ mHeader->numRows--;
+ }
+ }
+ bool setNumColumns(uint32_t numColumns)
+ {
+ uint32_t cur = mHeader->numColumns;
+ if (cur > 0 && cur != numColumns) {
+ LOGE("Trying to go from %d columns to %d", cur, numColumns);
+ return false;
+ }
+ mHeader->numColumns = numColumns;
+ return true;
+ }
+
+ int32_t freeSpace();
+
+ void clear();
+
+ /**
+ * Allocate a row slot and its directory. The returned
+ * pointer points to the begining of the row's directory
+ * or NULL if there wasn't room. The directory is
+ * initialied with NULL entries for each field.
+ */
+ field_slot_t * allocRow();
+
+ /**
+ * Allocate a portion of the window. Returns the offset
+ * of the allocation, or 0 if there isn't enough space.
+ * If aligned is true, the allocation gets 4 byte alignment.
+ */
+ uint32_t alloc(size_t size, bool aligned = false);
+
+ uint32_t read_field_slot(int row, int column, field_slot_t * slot);
+
+ /**
+ * Copy data into the window at the given offset.
+ */
+ void copyIn(uint32_t offset, uint8_t const * data, size_t size);
+ void copyIn(uint32_t offset, int64_t data);
+ void copyIn(uint32_t offset, double data);
+
+ void copyOut(uint32_t offset, uint8_t * data, size_t size);
+ int64_t copyOutLong(uint32_t offset);
+ double copyOutDouble(uint32_t offset);
+
+ bool putLong(unsigned int row, unsigned int col, int64_t value);
+ bool putDouble(unsigned int row, unsigned int col, double value);
+ bool putNull(unsigned int row, unsigned int col);
+
+ bool getLong(unsigned int row, unsigned int col, int64_t * valueOut);
+ bool getDouble(unsigned int row, unsigned int col, double * valueOut);
+ bool getNull(unsigned int row, unsigned int col, bool * valueOut);
+
+ uint8_t * offsetToPtr(uint32_t offset) {return mData + offset;}
+
+ row_slot_t * allocRowSlot();
+
+ row_slot_t * getRowSlot(int row);
+
+ /**
+ * return NULL if Failed to find rowSlot or
+ * Invalid rowSlot
+ */
+ field_slot_t * getFieldSlotWithCheck(int row, int column);
+ field_slot_t * getFieldSlot(int row, int column)
+ {
+ int fieldDirOffset = getRowSlot(row)->offset;
+ return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
+ }
+
+private:
+ uint8_t * mData;
+ size_t mSize;
+ size_t mMaxSize;
+ window_header_t * mHeader;
+ sp<MemoryDealer> mHeap;
+ sp<IMemory> mMemory;
+
+ /**
+ * Offset of the lowest unused data byte in the array.
+ */
+ uint32_t mFreeOffset;
+};
+
+}; // namespace android
+
+#endif
diff --git a/core/jni/GraphicsExternGlue.h b/core/jni/GraphicsExternGlue.h
new file mode 100644
index 0000000..290dbd5
--- /dev/null
+++ b/core/jni/GraphicsExternGlue.h
@@ -0,0 +1,25 @@
+/* //device/libs/android_runtime/GraphicsExternGlue.h
+**
+** Copyright 2006, 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.
+*/
+
+extern void register_android_Paint();
+extern void register_android_Canvas();
+extern void register_android_ColorFilter();
+extern void register_android_Matrix();
+extern void register_android_Path();
+extern void register_android_PorterDuff();
+extern void register_android_Rasterizer();
+extern void register_android_Xfermode();
diff --git a/core/jni/GraphicsRegisterGlue.h b/core/jni/GraphicsRegisterGlue.h
new file mode 100644
index 0000000..4054e83
--- /dev/null
+++ b/core/jni/GraphicsRegisterGlue.h
@@ -0,0 +1,25 @@
+/* //device/libs/android_runtime/GraphicsRegisterGlue.h
+**
+** Copyright 2006, 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.
+*/
+
+register_android_Paint();
+register_android_Canvas();
+register_android_ColorFilter();
+register_android_Matrix();
+register_android_Path();
+register_android_PorterDuff();
+register_android_Rasterizer();
+register_android_Xfermode();
diff --git a/core/jni/MODULE_LICENSE_APACHE2 b/core/jni/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/jni/MODULE_LICENSE_APACHE2
diff --git a/core/jni/NOTICE b/core/jni/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/core/jni/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
new file mode 100644
index 0000000..8628ec0
--- /dev/null
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -0,0 +1,573 @@
+#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));
+}
+
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
new file mode 100644
index 0000000..90822a1
--- /dev/null
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -0,0 +1,505 @@
+#include "SkImageDecoder.h"
+#include "SkPixelRef.h"
+#include "SkStream.h"
+#include "GraphicsJNI.h"
+#include "SkTemplates.h"
+#include "SkUtils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Asset.h>
+#include <utils/ResourceTypes.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+
+static jclass gOptions_class;
+static jfieldID gOptions_justBoundsFieldID;
+static jfieldID gOptions_sampleSizeFieldID;
+static jfieldID gOptions_configFieldID;
+static jfieldID gOptions_ditherFieldID;
+static jfieldID gOptions_widthFieldID;
+static jfieldID gOptions_heightFieldID;
+static jfieldID gOptions_mimeFieldID;
+
+static jclass gFileDescriptor_class;
+static jfieldID gFileDescriptor_descriptor;
+
+#if 0
+ #define TRACE_BITMAP(code) code
+#else
+ #define TRACE_BITMAP(code)
+#endif
+
+//#define MIN_SIZE_TO_USE_MMAP (4*1024)
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AutoDecoderCancel {
+public:
+ AutoDecoderCancel(jobject options, SkImageDecoder* decoder);
+ ~AutoDecoderCancel();
+
+ static bool RequestCancel(jobject options);
+
+private:
+ AutoDecoderCancel* fNext;
+ jobject fJOptions; // java options object
+ SkImageDecoder* fDecoder;
+};
+
+static SkMutex gAutoDecoderCancelMutex;
+static AutoDecoderCancel* gAutoDecoderCancel;
+
+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);
+
+ fNext = gAutoDecoderCancel;
+ gAutoDecoderCancel = this;
+ }
+}
+
+AutoDecoderCancel::~AutoDecoderCancel() {
+ const jobject joptions = fJOptions;
+
+ if (NULL != joptions) {
+ 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;
+ }
+ SkDebugf("xxxxxxxxxxxxxxxxxxxxxxx not found in pair list %p %p\n",
+ fJOptions, fDecoder);
+ }
+}
+
+bool AutoDecoderCancel::RequestCancel(jobject joptions) {
+ SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
+
+ AutoDecoderCancel* pair = gAutoDecoderCancel;
+ while (pair != NULL) {
+ if (pair->fJOptions == joptions) {
+ pair->fDecoder->cancelDecode();
+ return true;
+ }
+ pair = pair->fNext;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+using namespace android;
+
+class NinePatchPeeker : public SkImageDecoder::Peeker {
+public:
+ NinePatchPeeker() {
+ fPatchIsValid = false;
+ }
+
+ ~NinePatchPeeker() {
+ if (fPatchIsValid) {
+ free(fPatch);
+ }
+ }
+
+ bool fPatchIsValid;
+ Res_png_9patch* fPatch;
+
+ virtual bool peek(const char tag[], const void* data, size_t length) {
+ if (strcmp("npTc", tag) == 0 && length >= sizeof(Res_png_9patch)) {
+ Res_png_9patch* patch = (Res_png_9patch*) data;
+ size_t patchSize = patch->serializedSize();
+ assert(length == patchSize);
+ // 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);
+ Res_png_9patch::deserialize(patchNew);
+ patchNew->fileToDevice();
+ if (fPatchIsValid) {
+ free(fPatch);
+ }
+ fPatch = patchNew;
+ //printf("9patch: (%d,%d)-(%d,%d)\n",
+ // fPatch.sizeLeft, fPatch.sizeTop,
+ // fPatch.sizeRight, fPatch.sizeBottom);
+ fPatchIsValid = true;
+ } else {
+ fPatch = NULL;
+ }
+ return true; // keep on decoding
+ }
+};
+
+class AssetStreamAdaptor : public SkStream {
+public:
+ AssetStreamAdaptor(Asset* a) : fAsset(a) {}
+
+ virtual bool rewind() {
+ off_t pos = fAsset->seek(0, SEEK_SET);
+ return pos != (off_t)-1;
+ }
+
+ virtual size_t read(void* buffer, size_t size) {
+ ssize_t amount;
+
+ if (NULL == buffer) {
+ if (0 == size) { // caller is asking us for our total length
+ return fAsset->getLength();
+ }
+ // asset->seek returns new total offset
+ // we want to return amount that was skipped
+
+ off_t oldOffset = fAsset->seek(0, SEEK_CUR);
+ if (-1 == oldOffset) {
+ return 0;
+ }
+ off_t newOffset = fAsset->seek(size, SEEK_CUR);
+ if (-1 == newOffset) {
+ return 0;
+ }
+ amount = newOffset - oldOffset;
+ } else {
+ amount = fAsset->read(buffer, size);
+ }
+
+ if (amount < 0) {
+ amount = 0;
+ }
+ return amount;
+ }
+
+private:
+ Asset* fAsset;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline int32_t validOrNeg1(bool isValid, int32_t value) {
+// return isValid ? value : -1;
+ SkASSERT((int)isValid == 0 || (int)isValid == 1);
+ return ((int32_t)isValid - 1) | value;
+}
+
+static jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
+ static const struct {
+ SkImageDecoder::Format fFormat;
+ const char* fMimeType;
+ } gMimeTypes[] = {
+ { SkImageDecoder::kBMP_Format, "image/bmp" },
+ { SkImageDecoder::kGIF_Format, "image/gif" },
+ { SkImageDecoder::kICO_Format, "image/x-ico" },
+ { SkImageDecoder::kJPEG_Format, "image/jpeg" },
+ { SkImageDecoder::kPNG_Format, "image/png" },
+ { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
+ };
+
+ const char* cstr = NULL;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
+ if (gMimeTypes[i].fFormat == format) {
+ cstr = gMimeTypes[i].fMimeType;
+ break;
+ }
+ }
+
+ jstring jstr = 0;
+ if (NULL != cstr) {
+ jstr = env->NewStringUTF(cstr);
+ }
+ return jstr;
+}
+
+static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
+ jobject options) {
+
+ int sampleSize = 1;
+ SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
+ SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
+ bool doDither = true;
+
+ if (NULL != options) {
+ sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
+ if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) {
+ mode = SkImageDecoder::kDecodeBounds_Mode;
+ }
+ // initialize these, in case we fail later on
+ env->SetIntField(options, gOptions_widthFieldID, -1);
+ env->SetIntField(options, gOptions_heightFieldID, -1);
+ env->SetObjectField(options, gOptions_mimeFieldID, 0);
+
+ jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
+ prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
+ doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
+ }
+
+ SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
+ if (NULL == decoder) {
+ return NULL;
+ }
+
+ decoder->setSampleSize(sampleSize);
+ decoder->setDitherImage(doDither);
+
+ NinePatchPeeker peeker;
+ JavaPixelAllocator allocator(env);
+ SkBitmap* bitmap = new SkBitmap;
+ Res_png_9patch dummy9Patch;
+
+ SkAutoTDelete<SkImageDecoder> add(decoder);
+ SkAutoTDelete<SkBitmap> adb(bitmap);
+
+ decoder->setPeeker(&peeker);
+ decoder->setAllocator(&allocator);
+
+ AutoDecoderCancel adc(options, decoder);
+
+ if (!decoder->decode(stream, bitmap, prefConfig, mode)) {
+ return NULL;
+ }
+
+ // update options (if any)
+ if (NULL != options) {
+ env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
+ env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
+ // TODO: set the mimeType field with the data from the codec.
+ // but how to reuse a set of strings, rather than allocating new one
+ // each time?
+ env->SetObjectField(options, gOptions_mimeFieldID,
+ getMimeTypeString(env, decoder->getFormat()));
+ }
+
+ // if we're in justBounds mode, return now (skip the java bitmap)
+ if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+ return NULL;
+ }
+
+ jbyteArray ninePatchChunk = NULL;
+ if (peeker.fPatchIsValid) {
+ size_t ninePatchArraySize = peeker.fPatch->serializedSize();
+ ninePatchChunk = env->NewByteArray(ninePatchArraySize);
+ if (NULL == ninePatchChunk) {
+ return NULL;
+ }
+ jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk,
+ NULL);
+ if (NULL == array) {
+ return NULL;
+ }
+ peeker.fPatch->serialize(array);
+ env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
+ }
+
+ // detach bitmap from its autotdeleter, since we want to own it now
+ adb.detach();
+
+ if (padding) {
+ if (peeker.fPatchIsValid) {
+ GraphicsJNI::set_jrect(env, padding,
+ peeker.fPatch->paddingLeft,
+ peeker.fPatch->paddingTop,
+ peeker.fPatch->paddingRight,
+ peeker.fPatch->paddingBottom);
+ } else {
+ GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1);
+ }
+ }
+
+ // promise we will never change our pixels (great for sharing and pictures)
+ SkPixelRef* ref = bitmap->pixelRef();
+ SkASSERT(ref);
+ ref->setImmutable();
+
+ return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk);
+}
+
+static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
+ jobject is, // InputStream
+ jbyteArray storage, // byte[]
+ jobject padding,
+ jobject options) { // BitmapFactory$Options
+ jobject bitmap = NULL;
+ SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage);
+
+ if (stream) {
+ bitmap = doDecode(env, stream, padding, options);
+ stream->unref();
+ }
+ return bitmap;
+}
+
+static ssize_t getFDSize(int fd) {
+ off_t curr = ::lseek(fd, 0, SEEK_CUR);
+ if (curr < 0) {
+ return 0;
+ }
+ size_t size = ::lseek(fd, 0, SEEK_END);
+ ::lseek(fd, curr, SEEK_SET);
+ return size;
+}
+
+/** Restore the file descriptor's offset in our destructor
+ */
+class AutoFDSeek {
+public:
+ AutoFDSeek(int fd) : fFD(fd) {
+ fCurr = ::lseek(fd, 0, SEEK_CUR);
+ }
+ ~AutoFDSeek() {
+ if (fCurr >= 0) {
+ ::lseek(fFD, fCurr, SEEK_SET);
+ }
+ }
+private:
+ int fFD;
+ off_t fCurr;
+};
+
+static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz,
+ jobject fileDescriptor,
+ jobject padding,
+ jobject bitmapFactoryOptions) {
+ NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
+
+ jint descriptor = env->GetIntField(fileDescriptor,
+ gFileDescriptor_descriptor);
+
+#ifdef MIN_SIZE_TO_USE_MMAP
+ // First try to use mmap
+ size_t size = getFDSize(descriptor);
+ if (size >= MIN_SIZE_TO_USE_MMAP) {
+ void* addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, descriptor, 0);
+// SkDebugf("-------- mmap returned %p %d\n", addr, size);
+ if (MAP_FAILED != addr) {
+ SkMemoryStream strm(addr, size);
+ jobject obj = doDecode(env, &strm, padding, bitmapFactoryOptions);
+ munmap(addr, size);
+ return obj;
+ }
+ }
+#endif
+
+ // we pass false for closeWhenDone, since the caller owns the descriptor
+ SkFDStream file(descriptor, false);
+ if (!file.isValid()) {
+ return NULL;
+ }
+
+ /* Restore our offset when we leave, so the caller doesn't have to.
+ This is a real feature, so we can be called more than once with the
+ same descriptor.
+ */
+ AutoFDSeek as(descriptor);
+
+ return doDecode(env, &file, padding, bitmapFactoryOptions);
+}
+
+static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz,
+ jint native_asset, // Asset
+ jobject padding, // Rect
+ jobject options) { // BitmapFactory$Options
+ AssetStreamAdaptor mystream((Asset*)native_asset);
+
+ return doDecode(env, &mystream, padding, options);
+}
+
+static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
+ int offset, int length, jobject options) {
+ AutoJavaByteArray ar(env, byteArray);
+ SkMemoryStream stream(ar.ptr() + offset, length);
+
+ return doDecode(env, &stream, NULL, options);
+}
+
+static void nativeRequestCancel(JNIEnv*, jobject joptions) {
+ (void)AutoDecoderCancel::RequestCancel(joptions);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static JNINativeMethod gMethods[] = {
+ { "nativeDecodeStream",
+ "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+ (void*)nativeDecodeStream
+ },
+
+ { "nativeDecodeFileDescriptor",
+ "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+ (void*)nativeDecodeFileDescriptor
+ },
+
+ { "nativeDecodeAsset",
+ "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+ (void*)nativeDecodeAsset
+ },
+
+ { "nativeDecodeByteArray",
+ "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+ (void*)nativeDecodeByteArray
+ }
+};
+
+static JNINativeMethod gOptionsMethods[] = {
+ { "requestCancel", "()V", (void*)nativeRequestCancel }
+};
+
+static jclass make_globalref(JNIEnv* env, const char classname[]) {
+ jclass c = env->FindClass(classname);
+ SkASSERT(c);
+ return (jclass)env->NewGlobalRef(c);
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+ const char fieldname[], const char type[]) {
+ jfieldID id = env->GetFieldID(clazz, fieldname, type);
+ SkASSERT(id);
+ return id;
+}
+
+#define kClassPathName "android/graphics/BitmapFactory"
+
+#define RETURN_ERR_IF_NULL(value) \
+ do { if (!(value)) { assert(0); return -1; } } while (false)
+
+int register_android_graphics_BitmapFactory(JNIEnv* env);
+int register_android_graphics_BitmapFactory(JNIEnv* env) {
+ gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options");
+ gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z");
+ gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I");
+ gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig",
+ "Landroid/graphics/Bitmap$Config;");
+ gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
+ gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
+ gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
+ gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
+
+ gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
+ gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
+
+ int ret = AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/BitmapFactory$Options",
+ gOptionsMethods,
+ SK_ARRAY_COUNT(gOptionsMethods));
+ if (ret) {
+ return ret;
+ }
+ return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+ gMethods, SK_ARRAY_COUNT(gMethods));
+}
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
new file mode 100644
index 0000000..980003e
--- /dev/null
+++ b/core/jni/android/graphics/Camera.cpp
@@ -0,0 +1,102 @@
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkCamera.h"
+
+static jfieldID gNativeInstanceFieldID;
+
+static void Camera_constructor(JNIEnv* env, jobject obj) {
+ Sk3DView* view = new Sk3DView;
+ env->SetIntField(obj, gNativeInstanceFieldID, (int)view);
+}
+
+static void Camera_destructor(JNIEnv* env, jobject obj) {
+ delete (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+}
+
+static void Camera_save(JNIEnv* env, jobject obj) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->save();
+}
+
+static void Camera_restore(JNIEnv* env, jobject obj) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->restore();
+}
+
+static void Camera_translate(JNIEnv* env, jobject obj,
+ float dx, float dy, float dz) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->translate(SkFloatToScalar(dx), SkFloatToScalar(dy), SkFloatToScalar(dz));
+}
+
+static void Camera_rotateX(JNIEnv* env, jobject obj, float degrees) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->rotateX(SkFloatToScalar(degrees));
+}
+
+static void Camera_rotateY(JNIEnv* env, jobject obj, float degrees) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->rotateY(SkFloatToScalar(degrees));
+}
+
+static void Camera_rotateZ(JNIEnv* env, jobject obj, float degrees) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->rotateZ(SkFloatToScalar(degrees));
+}
+
+static void Camera_getMatrix(JNIEnv* env, jobject obj, int native_matrix) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->getMatrix((SkMatrix*)native_matrix);
+}
+
+static void Camera_applyToCanvas(JNIEnv* env, jobject obj, int native_canvas) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ v->applyToCanvas((SkCanvas*)native_canvas);
+}
+
+static float Camera_dotWithNormal(JNIEnv* env, jobject obj,
+ float x, float y, float z) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ SkScalar dot = v->dotWithNormal(SkFloatToScalar(x), SkFloatToScalar(y),
+ SkFloatToScalar(z));
+ return SkScalarToFloat(dot);
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gCameraMethods[] = {
+ /* name, signature, funcPtr */
+
+ { "nativeConstructor", "()V", (void*)Camera_constructor },
+ { "nativeDestructor", "()V", (void*)Camera_destructor },
+ { "save", "()V", (void*)Camera_save },
+ { "restore", "()V", (void*)Camera_restore },
+ { "translate", "(FFF)V", (void*)Camera_translate },
+ { "rotateX", "(F)V", (void*)Camera_rotateX },
+ { "rotateY", "(F)V", (void*)Camera_rotateY },
+ { "rotateZ", "(F)V", (void*)Camera_rotateZ },
+ { "nativeGetMatrix", "(I)V", (void*)Camera_getMatrix },
+ { "nativeApplyToCanvas", "(I)V", (void*)Camera_applyToCanvas },
+ { "dotWithNormal", "(FFF)F", (void*)Camera_dotWithNormal }
+};
+
+int register_android_graphics_Camera(JNIEnv* env);
+int register_android_graphics_Camera(JNIEnv* env) {
+ jclass clazz = env->FindClass("android/graphics/Camera");
+ if (clazz == 0) {
+ return -1;
+ }
+ gNativeInstanceFieldID = env->GetFieldID(clazz, "native_instance", "I");
+ if (gNativeInstanceFieldID == 0) {
+ return -1;
+ }
+ return android::AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/Camera",
+ gCameraMethods,
+ SK_ARRAY_COUNT(gCameraMethods));
+}
+
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
new file mode 100644
index 0000000..841fe49
--- /dev/null
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -0,0 +1,934 @@
+/*
+ * Copyright (C) 2006-2007 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.
+ */
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkGLCanvas.h"
+#include "SkShader.h"
+#include "SkTemplates.h"
+
+#define TIME_DRAWx
+
+static uint32_t get_thread_msec() {
+#if defined(HAVE_POSIX_CLOCKS)
+ struct timespec tm;
+
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
+
+ return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
+#else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
+#endif
+}
+
+namespace android {
+
+class SkCanvasGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) {
+ canvas->unref();
+ }
+
+ static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
+ }
+
+ static SkCanvas* initGL(JNIEnv* env, jobject) {
+ return new SkGLCanvas;
+ }
+
+ static void freeGlCaches(JNIEnv* env, jobject) {
+ SkGLCanvas::DeleteAllTextures();
+ }
+
+ static jboolean isOpaque(JNIEnv* env, jobject jcanvas) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+
+ /*
+ Currently we cannot support transparency in GL-based canvas' at
+ the view level. Therefore we cannot base our answer on the device's
+ bitmap, but need to hard-code the answer. If we relax this
+ limitation in views, we can simplify the following code as well.
+
+ Use the getViewport() call to find out if we're gl-based...
+ */
+ if (canvas->getViewport(NULL)) {
+ return true;
+ }
+
+ // normal technique, rely on the device's bitmap for the answer
+ return canvas->getDevice()->accessBitmap(false).isOpaque();
+ }
+
+ static int getWidth(JNIEnv* env, jobject jcanvas) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ return canvas->getDevice()->accessBitmap(false).width();
+ }
+
+ static int getHeight(JNIEnv* env, jobject jcanvas) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ return canvas->getDevice()->accessBitmap(false).height();
+ }
+
+ static void setViewport(JNIEnv* env, jobject, SkCanvas* canvas,
+ int width, int height) {
+ canvas->setViewport(width, height);
+ }
+
+ static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkBitmap* bitmap) {
+ canvas->setBitmapDevice(*bitmap);
+ }
+
+ static int saveAll(JNIEnv* env, jobject jcanvas) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
+ }
+
+ static int save(JNIEnv* env, jobject jcanvas, SkCanvas::SaveFlags flags) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ return GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags);
+ }
+
+ static int saveLayer(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds,
+ SkPaint* paint, int flags) {
+ SkRect* bounds_ = NULL;
+ SkRect storage;
+ if (bounds != NULL) {
+ GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
+ bounds_ = &storage;
+ }
+ return canvas->saveLayer(bounds_, paint, (SkCanvas::SaveFlags)flags);
+ }
+
+ static int saveLayer4F(JNIEnv* env, jobject, SkCanvas* canvas,
+ jfloat l, jfloat t, jfloat r, jfloat b,
+ SkPaint* paint, int flags) {
+ SkRect bounds;
+ bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
+ SkFloatToScalar(b));
+ return canvas->saveLayer(&bounds, paint, (SkCanvas::SaveFlags)flags);
+ }
+
+ static int saveLayerAlpha(JNIEnv* env, jobject, SkCanvas* canvas,
+ jobject bounds, int alpha, int flags) {
+ SkRect* bounds_ = NULL;
+ SkRect storage;
+ if (bounds != NULL) {
+ GraphicsJNI::jrectf_to_rect(env, bounds, &storage);
+ bounds_ = &storage;
+ }
+ return canvas->saveLayerAlpha(bounds_, alpha,
+ (SkCanvas::SaveFlags)flags);
+ }
+
+ static int saveLayerAlpha4F(JNIEnv* env, jobject, SkCanvas* canvas,
+ jfloat l, jfloat t, jfloat r, jfloat b,
+ int alpha, int flags) {
+ SkRect bounds;
+ bounds.set(SkFloatToScalar(l), SkFloatToScalar(t), SkFloatToScalar(r),
+ SkFloatToScalar(b));
+ return canvas->saveLayerAlpha(&bounds, alpha,
+ (SkCanvas::SaveFlags)flags);
+ }
+
+ static void restore(JNIEnv* env, jobject jcanvas) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ if (canvas->getSaveCount() <= 1) { // cannot restore anymore
+ doThrowISE(env, "Underflow in restore");
+ return;
+ }
+ canvas->restore();
+ }
+
+ static int getSaveCount(JNIEnv* env, jobject jcanvas) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ return GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount();
+ }
+
+ static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ if (restoreCount < 1) {
+ doThrowIAE(env, "Underflow in restoreToCount");
+ return;
+ }
+ canvas->restoreToCount(restoreCount);
+ }
+
+ static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx_, dy_);
+ }
+
+ static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx_, sy_);
+ }
+
+ static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ SkScalar degrees_ = SkFloatToScalar(degrees);
+ (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees_);
+ }
+
+ static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx_, sy_);
+ }
+
+ static void concat(JNIEnv* env, jobject, SkCanvas* canvas,
+ const SkMatrix* matrix) {
+ canvas->concat(*matrix);
+ }
+
+ static void setMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
+ const SkMatrix* matrix) {
+ if (NULL == matrix) {
+ canvas->resetMatrix();
+ } else {
+ canvas->setMatrix(*matrix);
+ }
+ }
+
+ static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left,
+ jfloat top, jfloat right, jfloat bottom) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ SkRect r;
+ r.set(SkFloatToScalar(left), SkFloatToScalar(top),
+ SkFloatToScalar(right), SkFloatToScalar(bottom));
+ SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ return c->clipRect(r);
+ }
+
+ static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left,
+ jint top, jint right, jint bottom) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ SkRect r;
+ r.set(SkIntToScalar(left), SkIntToScalar(top),
+ SkIntToScalar(right), SkIntToScalar(bottom));
+ return GraphicsJNI::getNativeCanvas(env, jcanvas)->clipRect(r);
+ }
+
+ static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ NPE_CHECK_RETURN_ZERO(env, rectf);
+ SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ SkRect tmp;
+ return c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp));
+ }
+
+ static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) {
+ NPE_CHECK_RETURN_ZERO(env, jcanvas);
+ NPE_CHECK_RETURN_ZERO(env, rect);
+ SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ SkRect tmp;
+ return c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp));
+ }
+
+ static jboolean clipRect(JNIEnv* env, jobject, SkCanvas* canvas,
+ float left, float top, float right, float bottom,
+ int op) {
+ SkRect rect;
+ rect.set(SkFloatToScalar(left), SkFloatToScalar(top),
+ SkFloatToScalar(right), SkFloatToScalar(bottom));
+ return canvas->clipRect(rect, (SkRegion::Op)op);
+ }
+
+ static jboolean clipPath(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkPath* path, int op) {
+ return canvas->clipPath(*path, (SkRegion::Op)op);
+ }
+
+ static jboolean clipRegion(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkRegion* deviceRgn, int op) {
+ return canvas->clipRegion(*deviceRgn, (SkRegion::Op)op);
+ }
+
+ static void setDrawFilter(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkDrawFilter* filter) {
+ canvas->setDrawFilter(filter);
+ }
+
+ static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
+ jobject rect, int edgetype) {
+ SkRect rect_;
+ GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
+ return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
+ }
+
+ static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkPath* path, int edgetype) {
+ return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
+ }
+
+ static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
+ jfloat left, jfloat top, jfloat right,
+ jfloat bottom, int edgetype) {
+ SkRect r;
+ r.set(SkFloatToScalar(left), SkFloatToScalar(top),
+ SkFloatToScalar(right), SkFloatToScalar(bottom));
+ return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
+ }
+
+ static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
+ jint r, jint g, jint b) {
+ canvas->drawARGB(0xFF, r, g, b);
+ }
+
+ static void drawARGB(JNIEnv* env, jobject, SkCanvas* canvas,
+ jint a, jint r, jint g, jint b) {
+ canvas->drawARGB(a, r, g, b);
+ }
+
+ static void drawColor__I(JNIEnv* env, jobject, SkCanvas* canvas,
+ jint color) {
+ canvas->drawColor(color);
+ }
+
+ static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
+ jint color, SkPorterDuff::Mode mode) {
+ canvas->drawColor(color, mode);
+ }
+
+ static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkPaint* paint) {
+ canvas->drawPaint(*paint);
+ }
+
+ static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
+ jint offset, jint count, jobject jpaint,
+ SkCanvas::PointMode mode) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ NPE_CHECK_RETURN_VOID(env, jptsArray);
+ NPE_CHECK_RETURN_VOID(env, jpaint);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
+
+ AutoJavaFloatArray autoPts(env, jptsArray);
+ float* floats = autoPts.ptr();
+ const int length = autoPts.length();
+
+ if ((offset | count) < 0 || offset + count > length) {
+ doThrowAIOOBE(env);
+ return;
+ }
+
+ // now convert the floats into SkPoints
+ count >>= 1; // now it is the number of points
+ SkAutoSTMalloc<32, SkPoint> storage(count);
+ SkPoint* pts = storage.get();
+ const float* src = floats + offset;
+ for (int i = 0; i < count; i++) {
+ pts[i].set(SkFloatToScalar(src[0]), SkFloatToScalar(src[1]));
+ src += 2;
+ }
+ canvas->drawPoints(mode, count, pts, paint);
+ }
+
+ static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
+ jint offset, jint count, jobject jpaint) {
+ doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
+ SkCanvas::kPoints_PointMode);
+ }
+
+ static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray,
+ jint offset, jint count, jobject jpaint) {
+ doPoints(env, jcanvas, jptsArray, offset, count, jpaint,
+ SkCanvas::kLines_PointMode);
+ }
+
+ static void drawPoint(JNIEnv* env, jobject jcanvas, float x, float y,
+ jobject jpaint) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ NPE_CHECK_RETURN_VOID(env, jpaint);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint);
+
+ canvas->drawPoint(SkFloatToScalar(x), SkFloatToScalar(y), paint);
+ }
+
+ static void drawLine__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jfloat startX, jfloat startY, jfloat stopX,
+ jfloat stopY, SkPaint* paint) {
+ canvas->drawLine(SkFloatToScalar(startX), SkFloatToScalar(startY),
+ SkFloatToScalar(stopX), SkFloatToScalar(stopY),
+ *paint);
+ }
+
+ static void drawRect__RectFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jobject rect, SkPaint* paint) {
+ SkRect rect_;
+ GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
+ canvas->drawRect(rect_, *paint);
+ }
+
+ static void drawRect__FFFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jfloat left, jfloat top, jfloat right,
+ jfloat bottom, SkPaint* paint) {
+ SkScalar left_ = SkFloatToScalar(left);
+ SkScalar top_ = SkFloatToScalar(top);
+ SkScalar right_ = SkFloatToScalar(right);
+ SkScalar bottom_ = SkFloatToScalar(bottom);
+ canvas->drawRectCoords(left_, top_, right_, bottom_, *paint);
+ }
+
+ static void drawOval(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
+ SkPaint* paint) {
+ SkRect oval;
+ GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+ canvas->drawOval(oval, *paint);
+ }
+
+ static void drawCircle(JNIEnv* env, jobject, SkCanvas* canvas, jfloat cx,
+ jfloat cy, jfloat radius, SkPaint* paint) {
+ canvas->drawCircle(SkFloatToScalar(cx), SkFloatToScalar(cy),
+ SkFloatToScalar(radius), *paint);
+ }
+
+ static void drawArc(JNIEnv* env, jobject, SkCanvas* canvas, jobject joval,
+ jfloat startAngle, jfloat sweepAngle,
+ jboolean useCenter, SkPaint* paint) {
+ SkRect oval;
+ GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+ canvas->drawArc(oval, SkFloatToScalar(startAngle),
+ SkFloatToScalar(sweepAngle), useCenter, *paint);
+ }
+
+ static void drawRoundRect(JNIEnv* env, jobject, SkCanvas* canvas,
+ jobject jrect, jfloat rx, jfloat ry,
+ SkPaint* paint) {
+ SkRect rect;
+ GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
+ canvas->drawRoundRect(rect, SkFloatToScalar(rx), SkFloatToScalar(ry),
+ *paint);
+ }
+
+ static void drawPath(JNIEnv* env, jobject, SkCanvas* canvas, SkPath* path,
+ SkPaint* paint) {
+ canvas->drawPath(*path, *paint);
+ }
+
+ static void drawPicture(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkPicture* picture) {
+ SkASSERT(canvas);
+ SkASSERT(picture);
+
+#ifdef TIME_DRAW
+ SkMSec now = get_thread_msec(); //SkTime::GetMSecs();
+#endif
+ canvas->drawPicture(*picture);
+#ifdef TIME_DRAW
+ LOGD("---- picture playback %d ms\n", get_thread_msec() - now);
+#endif
+ }
+
+ static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject,
+ SkCanvas* canvas, SkBitmap* bitmap,
+ jfloat left, jfloat top,
+ SkPaint* paint) {
+ SkScalar left_ = SkFloatToScalar(left);
+ SkScalar top_ = SkFloatToScalar(top);
+ canvas->drawBitmap(*bitmap, left_, top_, paint);
+ }
+
+ static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
+ jobject srcIRect, const SkRect& dst, SkPaint* paint) {
+ SkIRect src, *srcPtr = NULL;
+
+ if (NULL != srcIRect) {
+ GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
+ srcPtr = &src;
+ }
+ canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
+ }
+
+ static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkBitmap* bitmap, jobject srcIRect,
+ jobject dstRectF, SkPaint* paint) {
+ SkRect dst;
+ GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
+ doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint);
+ }
+
+ static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkBitmap* bitmap, jobject srcIRect,
+ jobject dstRect, SkPaint* paint) {
+ SkRect dst;
+ GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
+ doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint);
+ }
+
+ static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
+ jintArray jcolors, int offset, int stride,
+ int x, int y, int width, int height,
+ jboolean hasAlpha, SkPaint* paint)
+ {
+ SkBitmap bitmap;
+
+ bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
+ SkBitmap::kRGB_565_Config, width, height);
+ if (!bitmap.allocPixels()) {
+ return;
+ }
+
+ if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride,
+ 0, 0, width, height, bitmap)) {
+ return;
+ }
+
+ canvas->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
+ }
+
+ static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
+ const SkBitmap* bitmap, const SkMatrix* matrix,
+ const SkPaint* paint) {
+ canvas->drawBitmapMatrix(*bitmap, *matrix, paint);
+ }
+
+ static void drawBitmapMesh(JNIEnv* env, jobject, SkCanvas* canvas,
+ const SkBitmap* bitmap, int meshWidth, int meshHeight,
+ jfloatArray jverts, int vertIndex, jintArray jcolors,
+ int colorIndex, const SkPaint* paint) {
+
+ const int ptCount = (meshWidth + 1) * (meshHeight + 1);
+ const int indexCount = meshWidth * meshHeight * 6;
+
+ AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
+ AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
+
+ /* Our temp storage holds 2 or 3 arrays.
+ texture points [ptCount * sizeof(SkPoint)]
+ optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
+ copy to convert from float to fixed
+ indices [ptCount * sizeof(uint16_t)]
+ */
+ ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
+#ifdef SK_SCALAR_IS_FIXED
+ storageSize += ptCount * sizeof(SkPoint); // storage for verts
+#endif
+ storageSize += indexCount * sizeof(uint16_t); // indices[]
+
+ SkAutoMalloc storage(storageSize);
+ SkPoint* texs = (SkPoint*)storage.get();
+ SkPoint* verts;
+ uint16_t* indices;
+#ifdef SK_SCALAR_IS_FLOAT
+ verts = (SkPoint*)(vertA.ptr() + vertIndex);
+ indices = (uint16_t*)(texs + ptCount);
+#else
+ verts = texs + ptCount;
+ indices = (uint16_t*)(verts + ptCount);
+ // convert floats to fixed
+ {
+ const float* src = vertA.ptr() + vertIndex;
+ for (int i = 0; i < ptCount; i++) {
+ verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
+ src += 2;
+ }
+ }
+#endif
+
+ // cons up texture coordinates and indices
+ {
+ const SkScalar w = SkIntToScalar(bitmap->width());
+ const SkScalar h = SkIntToScalar(bitmap->height());
+ const SkScalar dx = w / meshWidth;
+ const SkScalar dy = h / meshHeight;
+
+ SkPoint* texsPtr = texs;
+ SkScalar y = 0;
+ for (int i = 0; i <= meshHeight; i++) {
+ if (i == meshHeight) {
+ y = h; // to ensure numerically we hit h exactly
+ }
+ SkScalar x = 0;
+ for (int j = 0; j < meshWidth; j++) {
+ texsPtr->set(x, y);
+ texsPtr += 1;
+ x += dx;
+ }
+ texsPtr->set(w, y);
+ texsPtr += 1;
+ y += dy;
+ }
+ SkASSERT(texsPtr - texs == ptCount);
+ }
+
+ // cons up indices
+ {
+ uint16_t* indexPtr = indices;
+ int index = 0;
+ for (int i = 0; i < meshHeight; i++) {
+ for (int j = 0; j < meshWidth; j++) {
+ // lower-left triangle
+ *indexPtr++ = index;
+ *indexPtr++ = index + meshWidth + 1;
+ *indexPtr++ = index + meshWidth + 2;
+ // upper-right triangle
+ *indexPtr++ = index;
+ *indexPtr++ = index + meshWidth + 2;
+ *indexPtr++ = index + 1;
+ // bump to the next cell
+ index += 1;
+ }
+ // bump to the next row
+ index += 1;
+ }
+ SkASSERT(indexPtr - indices == indexCount);
+ SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
+ }
+
+ // double-check that we have legal indices
+#ifdef SK_DEBUG
+ {
+ for (int i = 0; i < indexCount; i++) {
+ SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
+ }
+ }
+#endif
+
+ // cons-up a shader for the bitmap
+ SkPaint tmpPaint;
+ if (paint) {
+ tmpPaint = *paint;
+ }
+ SkShader* shader = SkShader::CreateBitmapShader(*bitmap,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ tmpPaint.setShader(shader)->safeUnref();
+
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, verts,
+ texs, (const SkColor*)colorA.ptr(), NULL, indices,
+ indexCount, tmpPaint);
+ }
+
+ static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkCanvas::VertexMode mode, int vertexCount,
+ jfloatArray jverts, int vertIndex,
+ jfloatArray jtexs, int texIndex,
+ jintArray jcolors, int colorIndex,
+ jshortArray jindices, int indexIndex,
+ int indexCount, const SkPaint* paint) {
+
+ AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount);
+ AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount);
+ AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount);
+ AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount);
+
+ const int ptCount = vertexCount >> 1;
+
+ SkPoint* verts;
+ SkPoint* texs = NULL;
+#ifdef SK_SCALAR_IS_FLOAT
+ verts = (SkPoint*)(vertA.ptr() + vertIndex);
+ if (jtexs != NULL) {
+ texs = (SkPoint*)(texA.ptr() + texIndex);
+ }
+#else
+ int count = ptCount; // for verts
+ if (jtexs != NULL) {
+ count += ptCount; // += for texs
+ }
+ SkAutoMalloc storage(count * sizeof(SkPoint));
+ verts = (SkPoint*)storage.get();
+ const float* src = vertA.ptr() + vertIndex;
+ for (int i = 0; i < ptCount; i++) {
+ verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
+ src += 2;
+ }
+ if (jtexs != NULL) {
+ texs = verts + ptCount;
+ src = texA.ptr() + texIndex;
+ for (int i = 0; i < ptCount; i++) {
+ texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1]));
+ src += 2;
+ }
+ }
+#endif
+
+ const SkColor* colors = NULL;
+ const uint16_t* indices = NULL;
+ if (jcolors != NULL) {
+ colors = (const SkColor*)(colorA.ptr() + colorIndex);
+ }
+ if (jindices != NULL) {
+ indices = (const uint16_t*)(indexA.ptr() + indexIndex);
+ }
+
+ canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL,
+ indices, indexCount, *paint);
+ }
+
+ static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jcharArray text, int index, int count,
+ jfloat x, jfloat y, SkPaint* paint) {
+ jchar* textArray = env->GetCharArrayElements(text, NULL);
+ jsize textCount = env->GetArrayLength(text);
+ SkScalar x_ = SkFloatToScalar(x);
+ SkScalar y_ = SkFloatToScalar(y);
+ textArray += index;
+ canvas->drawText(textArray, count << 1, x_, y_, *paint);
+ env->ReleaseCharArrayElements(text, textArray, 0);
+ }
+
+ static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
+ SkCanvas* canvas, jstring text, int start, int end,
+ jfloat x, jfloat y, SkPaint* paint) {
+ const void* text_ = env->GetStringChars(text, NULL);
+ SkScalar x_ = SkFloatToScalar(x);
+ SkScalar y_ = SkFloatToScalar(y);
+ canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1,
+ x_, y_, *paint);
+ env->ReleaseStringChars(text, (const jchar*) text_);
+ }
+
+ static void drawString(JNIEnv* env, jobject canvas, jstring text,
+ jfloat x, jfloat y, jobject paint) {
+ NPE_CHECK_RETURN_VOID(env, canvas);
+ NPE_CHECK_RETURN_VOID(env, paint);
+ NPE_CHECK_RETURN_VOID(env, text);
+ size_t count = env->GetStringLength(text);
+ if (0 == count) {
+ return;
+ }
+ const jchar* text_ = env->GetStringChars(text, NULL);
+ SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
+ c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y),
+ *GraphicsJNI::getNativePaint(env, paint));
+ env->ReleaseStringChars(text, text_);
+ }
+
+ static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jcharArray text, int index, int count,
+ jfloatArray pos, SkPaint* paint) {
+ jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL;
+ jsize textCount = text ? env->GetArrayLength(text) : NULL;
+ float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
+ int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
+ SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
+ int indx;
+ for (indx = 0; indx < posCount; indx++) {
+ posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
+ posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
+ }
+ textArray += index;
+ canvas->drawPosText(textArray, count << 1, posPtr, *paint);
+ if (text) {
+ env->ReleaseCharArrayElements(text, textArray, 0);
+ }
+ if (pos) {
+ env->ReleaseFloatArrayElements(pos, posArray, 0);
+ }
+ delete[] posPtr;
+ }
+
+ static void drawPosText__String_FPaint(JNIEnv* env, jobject,
+ SkCanvas* canvas, jstring text,
+ jfloatArray pos, SkPaint* paint) {
+ const void* text_ = text ? env->GetStringChars(text, NULL) : NULL;
+ int byteLength = text ? env->GetStringLength(text) : 0;
+ float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
+ int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
+ SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
+
+ for (int indx = 0; indx < posCount; indx++) {
+ posPtr[indx].fX = SkFloatToScalar(posArray[indx << 1]);
+ posPtr[indx].fY = SkFloatToScalar(posArray[(indx << 1) + 1]);
+ }
+ canvas->drawPosText(text_, byteLength << 1, posPtr, *paint);
+ if (text) {
+ env->ReleaseStringChars(text, (const jchar*) text_);
+ }
+ if (pos) {
+ env->ReleaseFloatArrayElements(pos, posArray, 0);
+ }
+ delete[] posPtr;
+ }
+
+ static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
+ SkCanvas* canvas, jcharArray text, int index, int count,
+ SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+
+ jchar* textArray = env->GetCharArrayElements(text, NULL);
+ canvas->drawTextOnPathHV(textArray + index, count << 1, *path,
+ SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
+ env->ReleaseCharArrayElements(text, textArray, 0);
+ }
+
+ static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
+ SkCanvas* canvas, jstring text, SkPath* path,
+ jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+ const jchar* text_ = env->GetStringChars(text, NULL);
+ int byteLength = env->GetStringLength(text) << 1;
+ canvas->drawTextOnPathHV(text_, byteLength, *path,
+ SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint);
+ env->ReleaseStringChars(text, text_);
+ }
+
+ static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas,
+ jobject bounds) {
+ SkRect r;
+ SkIRect ir;
+ bool result = canvas->getClipBounds(&r);
+
+ r.round(&ir);
+ (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
+ return result;
+ }
+
+ static void getCTM(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkMatrix* matrix) {
+ *matrix = canvas->getTotalMatrix();
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static JNINativeMethod gCanvasMethods[] = {
+ {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
+ {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
+ {"initGL","()I", (void*) SkCanvasGlue::initGL},
+ {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
+ {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
+ {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
+ {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
+ {"nativeSetViewport", "(III)V", (void*) SkCanvasGlue::setViewport},
+ {"save","()I", (void*) SkCanvasGlue::saveAll},
+ {"save","(I)I", (void*) SkCanvasGlue::save},
+ {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
+ (void*) SkCanvasGlue::saveLayer},
+ {"native_saveLayer","(IFFFFII)I", (void*) SkCanvasGlue::saveLayer4F},
+ {"native_saveLayerAlpha","(ILandroid/graphics/RectF;II)I",
+ (void*) SkCanvasGlue::saveLayerAlpha},
+ {"native_saveLayerAlpha","(IFFFFII)I",
+ (void*) SkCanvasGlue::saveLayerAlpha4F},
+ {"restore","()V", (void*) SkCanvasGlue::restore},
+ {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount},
+ {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount},
+ {"translate","(FF)V", (void*) SkCanvasGlue::translate},
+ {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF},
+ {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F},
+ {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF},
+ {"native_concat","(II)V", (void*) SkCanvasGlue::concat},
+ {"native_setMatrix","(II)V", (void*) SkCanvasGlue::setMatrix},
+ {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF},
+ {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII},
+ {"clipRect","(Landroid/graphics/RectF;)Z",
+ (void*) SkCanvasGlue::clipRect_RectF},
+ {"clipRect","(Landroid/graphics/Rect;)Z",
+ (void*) SkCanvasGlue::clipRect_Rect},
+ {"native_clipRect","(IFFFFI)Z", (void*) SkCanvasGlue::clipRect},
+ {"native_clipPath","(III)Z", (void*) SkCanvasGlue::clipPath},
+ {"native_clipRegion","(III)Z", (void*) SkCanvasGlue::clipRegion},
+ {"nativeSetDrawFilter", "(II)V", (void*) SkCanvasGlue::setDrawFilter},
+ {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
+ (void*) SkCanvasGlue::getClipBounds},
+ {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
+ {"native_quickReject","(ILandroid/graphics/RectF;I)Z",
+ (void*) SkCanvasGlue::quickReject__RectFI},
+ {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
+ {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
+ {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
+ {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
+ {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
+ {"native_drawColor","(III)V", (void*) SkCanvasGlue::drawColor__II},
+ {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
+ {"drawPoint", "(FFLandroid/graphics/Paint;)V",
+ (void*) SkCanvasGlue::drawPoint},
+ {"drawPoints", "([FIILandroid/graphics/Paint;)V",
+ (void*) SkCanvasGlue::drawPoints},
+ {"drawLines", "([FIILandroid/graphics/Paint;)V",
+ (void*) SkCanvasGlue::drawLines},
+ {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
+ {"native_drawRect","(ILandroid/graphics/RectF;I)V",
+ (void*) SkCanvasGlue::drawRect__RectFPaint},
+ {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
+ {"native_drawOval","(ILandroid/graphics/RectF;I)V",
+ (void*) SkCanvasGlue::drawOval},
+ {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
+ {"native_drawArc","(ILandroid/graphics/RectF;FFZI)V",
+ (void*) SkCanvasGlue::drawArc},
+ {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
+ (void*) SkCanvasGlue::drawRoundRect},
+ {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
+ {"native_drawBitmap","(IIFFI)V",
+ (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
+ {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;I)V",
+ (void*) SkCanvasGlue::drawBitmapRF},
+ {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;I)V",
+ (void*) SkCanvasGlue::drawBitmapRR},
+ {"native_drawBitmap", "(I[IIIIIIIZI)V",
+ (void*)SkCanvasGlue::drawBitmapArray},
+
+ {"nativeDrawBitmapMatrix", "(IIII)V",
+ (void*)SkCanvasGlue::drawBitmapMatrix},
+ {"nativeDrawBitmapMesh", "(IIII[FI[III)V",
+ (void*)SkCanvasGlue::drawBitmapMesh},
+ {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
+ (void*)SkCanvasGlue::drawVertices},
+ {"native_drawText","(I[CIIFFI)V",
+ (void*) SkCanvasGlue::drawText___CIIFFPaint},
+ {"native_drawText","(ILjava/lang/String;IIFFI)V",
+ (void*) SkCanvasGlue::drawText__StringIIFFPaint},
+ {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V",
+ (void*) SkCanvasGlue::drawString},
+ {"native_drawPosText","(I[CII[FI)V",
+ (void*) SkCanvasGlue::drawPosText___CII_FPaint},
+ {"native_drawPosText","(ILjava/lang/String;[FI)V",
+ (void*) SkCanvasGlue::drawPosText__String_FPaint},
+ {"native_drawTextOnPath","(I[CIIIFFI)V",
+ (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
+ {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
+ (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
+ {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
+
+ {"freeGlCaches", "()V", (void*) SkCanvasGlue::freeGlCaches}
+};
+
+#include <android_runtime/AndroidRuntime.h>
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
+ SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+int register_android_graphics_Canvas(JNIEnv* env) {
+ int result;
+
+ REG(env, "android/graphics/Canvas", gCanvasMethods);
+
+ return result;
+}
+
+}
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
new file mode 100644
index 0000000..b6ec4a2
--- /dev/null
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -0,0 +1,98 @@
+/* libs/android_runtime/android/graphics/ColorFilter.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkColorFilter.h"
+#include "SkColorMatrixFilter.h"
+
+namespace android {
+
+class SkColorFilterGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject clazz, SkColorFilter* obj) {
+ obj->safeUnref();
+ }
+
+ static SkColorFilter* CreatePorterDuffFilter(JNIEnv* env, jobject,
+ jint srcColor, SkPorterDuff::Mode porterDuffMode) {
+ return SkColorFilter::CreatePorterDuffFilter(srcColor, porterDuffMode);
+ }
+
+ static SkColorFilter* CreateLightingFilter(JNIEnv* env, jobject,
+ jint mul, jint add) {
+ return SkColorFilter::CreateLightingFilter(mul, add);
+ }
+
+ static SkColorFilter* CreateColorMatrixFilter(JNIEnv* env, jobject,
+ jfloatArray jarray) {
+ AutoJavaFloatArray autoArray(env, jarray, 20);
+ const float* src = autoArray.ptr();
+
+#ifdef SK_SCALAR_IS_FIXED
+ SkFixed array[20];
+ for (int i = 0; i < 20; i++) {
+ array[i] = SkFloatToScalar(src[i]);
+ }
+ return new SkColorMatrixFilter(array);
+#else
+ return new SkColorMatrixFilter(src);
+#endif
+ }
+
+};
+
+static JNINativeMethod colorfilter_methods[] = {
+ {"finalizer", "(I)V", (void*) SkColorFilterGlue::finalizer}
+};
+
+static JNINativeMethod porterduff_methods[] = {
+ {"native_CreatePorterDuffFilter","(II)I",
+ (void*) SkColorFilterGlue::CreatePorterDuffFilter}
+};
+
+static JNINativeMethod lighting_methods[] = {
+ {"native_CreateLightingFilter","(II)I",
+ (void*) SkColorFilterGlue::CreateLightingFilter}
+};
+
+static JNINativeMethod colormatrix_methods[] = {
+ {"nativeColorMatrixFilter","([F)I",
+ (void*) SkColorFilterGlue::CreateColorMatrixFilter}
+};
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
+ SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+
+int register_android_graphics_ColorFilter(JNIEnv* env) {
+ int result;
+
+ REG(env, "android/graphics/ColorFilter", colorfilter_methods);
+ REG(env, "android/graphics/PorterDuffColorFilter", porterduff_methods);
+ REG(env, "android/graphics/LightingColorFilter", lighting_methods);
+ REG(env, "android/graphics/ColorMatrixColorFilter", colormatrix_methods);
+
+ return 0;
+}
+
+}
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
new file mode 100644
index 0000000..002fdf9
--- /dev/null
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -0,0 +1,212 @@
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#define RETURN_NULL_IF_NULL(value) \
+ do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
+
+static jclass gInputStream_Clazz;
+static jmethodID gInputStream_resetMethodID;
+static jmethodID gInputStream_availableMethodID;
+static jmethodID gInputStream_readMethodID;
+static jmethodID gInputStream_skipMethodID;
+
+class JavaInputStreamAdaptor : public SkStream {
+public:
+ JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
+ : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
+ SkASSERT(ar);
+ fCapacity = env->GetArrayLength(ar);
+ SkASSERT(fCapacity > 0);
+ fBytesRead = 0;
+ }
+
+ virtual bool rewind() {
+ JNIEnv* env = fEnv;
+
+ fBytesRead = 0;
+
+ env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ printf("------- reset threw an exception\n");
+ return false;
+ }
+ return true;
+ }
+
+ virtual size_t read(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);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ printf("---- read threw an exception\n");
+ return 0;
+ }
+
+ if (n <= 0) {
+ break; // eof
+ }
+
+ jbyte* array = env->GetByteArrayElements(fJavaByteArray, NULL);
+ memcpy(buffer, array, n);
+ env->ReleaseByteArrayElements(fJavaByteArray, array, 0);
+
+ buffer = (void*)((char*)buffer + n);
+ bytesRead += n;
+ size -= n;
+ fBytesRead += n;
+ } while (size != 0);
+
+ return bytesRead;
+ }
+
+private:
+ JNIEnv* fEnv;
+ jobject fJavaInputStream; // the caller owns this object
+ jbyteArray fJavaByteArray; // the caller owns this object
+ size_t fCapacity;
+ size_t fBytesRead;
+};
+
+SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
+ jbyteArray storage) {
+ static bool gInited;
+
+ if (!gInited) {
+ gInputStream_Clazz = env->FindClass("java/io/InputStream");
+ RETURN_NULL_IF_NULL(gInputStream_Clazz);
+ gInputStream_Clazz = (jclass)env->NewGlobalRef(gInputStream_Clazz);
+
+ gInputStream_resetMethodID = env->GetMethodID(gInputStream_Clazz,
+ "reset", "()V");
+ gInputStream_availableMethodID = env->GetMethodID(gInputStream_Clazz,
+ "available", "()I");
+ gInputStream_readMethodID = env->GetMethodID(gInputStream_Clazz,
+ "read", "([BII)I");
+ gInputStream_skipMethodID = env->GetMethodID(gInputStream_Clazz,
+ "skip", "(J)J");
+
+ RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
+ RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
+ RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
+ RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
+
+ gInited = true;
+ }
+
+ return new JavaInputStreamAdaptor(env, stream, storage);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jclass gOutputStream_Clazz;
+static jmethodID gOutputStream_writeMethodID;
+static jmethodID gOutputStream_flushMethodID;
+
+class SkJavaOutputStream : public SkWStream {
+public:
+ SkJavaOutputStream(JNIEnv* env, jobject stream, jbyteArray storage)
+ : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) {
+ fCapacity = env->GetArrayLength(storage);
+ }
+
+ virtual bool write(const void* buffer, size_t size) {
+ JNIEnv* env = fEnv;
+ jbyteArray storage = fJavaByteArray;
+
+ while (size > 0) {
+ size_t requested = size;
+ if (requested > fCapacity) {
+ requested = fCapacity;
+ }
+
+ jbyte* array = env->GetByteArrayElements(storage, NULL);
+ memcpy(array, buffer, requested);
+ env->ReleaseByteArrayElements(storage, array, 0);
+
+ fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID,
+ storage, 0, requested);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ printf("------- write threw an exception\n");
+ return false;
+ }
+
+ buffer = (void*)((char*)buffer + requested);
+ size -= requested;
+ }
+ return true;
+ }
+
+ virtual void flush() {
+ fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
+ }
+
+private:
+ JNIEnv* fEnv;
+ jobject fJavaOutputStream; // the caller owns this object
+ jbyteArray fJavaByteArray; // the caller owns this object
+ size_t fCapacity;
+};
+
+SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
+ jbyteArray storage) {
+ static bool gInited;
+
+ if (!gInited) {
+ gOutputStream_Clazz = env->FindClass("java/io/OutputStream");
+ RETURN_NULL_IF_NULL(gOutputStream_Clazz);
+ gOutputStream_Clazz = (jclass)env->NewGlobalRef(gOutputStream_Clazz);
+
+ gOutputStream_writeMethodID = env->GetMethodID(gOutputStream_Clazz,
+ "write", "([BII)V");
+ RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
+ gOutputStream_flushMethodID = env->GetMethodID(gOutputStream_Clazz,
+ "flush", "()V");
+ RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
+
+ gInited = true;
+ }
+
+ return new SkJavaOutputStream(env, stream, storage);
+}
+
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
new file mode 100644
index 0000000..cf21dde
--- /dev/null
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
@@ -0,0 +1,13 @@
+#ifndef CreateJavaOutputStream_DEFINED
+#define CreateJavaOutputStream_DEFINED
+
+//#include <android_runtime/AndroidRuntime.h>
+#include "jni.h"
+#include "SkStream.h"
+
+SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
+ jbyteArray storage);
+SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
+ jbyteArray storage);
+
+#endif
diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp
new file mode 100644
index 0000000..496e712
--- /dev/null
+++ b/core/jni/android/graphics/DrawFilter.cpp
@@ -0,0 +1,76 @@
+/* libs/android_runtime/android/graphics/ColorFilter.cpp
+**
+** Copyright 2006, 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.
+*/
+
+// This file was generated from the C++ include file: SkColorFilter.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkDrawFilter.h"
+#include "SkPaintFlagsDrawFilter.h"
+#include "SkPaint.h"
+
+namespace android {
+
+class SkDrawFilterGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject clazz, SkDrawFilter* obj) {
+ obj->safeUnref();
+ }
+
+ static SkDrawFilter* CreatePaintFlagsDF(JNIEnv* env, jobject clazz,
+ int clearFlags, int setFlags) {
+ // trim off any out-of-range bits
+ clearFlags &= SkPaint::kAllFlags;
+ setFlags &= SkPaint::kAllFlags;
+
+ if (clearFlags | setFlags) {
+ return new SkPaintFlagsDrawFilter(clearFlags, setFlags);
+ } else {
+ return NULL;
+ }
+ }
+};
+
+static JNINativeMethod drawfilter_methods[] = {
+ {"nativeDestructor", "(I)V", (void*) SkDrawFilterGlue::finalizer}
+};
+
+static JNINativeMethod paintflags_methods[] = {
+ {"nativeConstructor","(II)I", (void*) SkDrawFilterGlue::CreatePaintFlagsDF}
+};
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+
+int register_android_graphics_DrawFilter(JNIEnv* env) {
+ int result;
+
+ REG(env, "android/graphics/DrawFilter", drawfilter_methods);
+ REG(env, "android/graphics/PaintFlagsDrawFilter", paintflags_methods);
+
+ return 0;
+}
+
+}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
new file mode 100644
index 0000000..f8ccf72
--- /dev/null
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -0,0 +1,578 @@
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include "NIOBuffer.h"
+#include "SkPicture.h"
+#include "SkRegion.h"
+#include <android_runtime/AndroidRuntime.h>
+
+//#define TRACK_LOCK_COUNT
+
+void doThrow(JNIEnv* env, const char* exc, const char* msg) {
+ // don't throw a new exception if we already have one pending
+ if (env->ExceptionCheck() == JNI_FALSE) {
+ jclass npeClazz;
+
+ npeClazz = env->FindClass(exc);
+ LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
+
+ env->ThrowNew(npeClazz, msg);
+ }
+}
+
+void doThrowNPE(JNIEnv* env) {
+ doThrow(env, "java/lang/NullPointerException");
+}
+
+void doThrowAIOOBE(JNIEnv* env) {
+ doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
+}
+
+void doThrowRE(JNIEnv* env, const char* msg) {
+ doThrow(env, "java/lang/RuntimeException", msg);
+}
+
+void doThrowIAE(JNIEnv* env, const char* msg) {
+ doThrow(env, "java/lang/IllegalArgumentException", msg);
+}
+
+void doThrowISE(JNIEnv* env, const char* msg) {
+ doThrow(env, "java/lang/IllegalStateException", msg);
+}
+
+void doThrowOOME(JNIEnv* env, const char* msg) {
+ doThrow(env, "java/lang/OutOfMemoryError", msg);
+}
+
+bool GraphicsJNI::hasException(JNIEnv *env) {
+ if (env->ExceptionCheck() != 0) {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array,
+ int minLength)
+: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
+ SkASSERT(env);
+ if (array) {
+ fLen = env->GetArrayLength(array);
+ if (fLen < minLength) {
+ sk_throw();
+ }
+ fPtr = env->GetFloatArrayElements(array, NULL);
+ }
+}
+
+AutoJavaFloatArray::~AutoJavaFloatArray() {
+ if (fPtr) {
+ fEnv->ReleaseFloatArrayElements(fArray, fPtr, 0);
+ }
+}
+
+AutoJavaIntArray::AutoJavaIntArray(JNIEnv* env, jintArray array,
+ int minLength)
+: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
+ SkASSERT(env);
+ if (array) {
+ fLen = env->GetArrayLength(array);
+ if (fLen < minLength) {
+ sk_throw();
+ }
+ fPtr = env->GetIntArrayElements(array, NULL);
+ }
+}
+
+AutoJavaIntArray::~AutoJavaIntArray() {
+ if (fPtr) {
+ fEnv->ReleaseIntArrayElements(fArray, fPtr, 0);
+ }
+}
+
+AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array,
+ int minLength)
+: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
+ SkASSERT(env);
+ if (array) {
+ fLen = env->GetArrayLength(array);
+ if (fLen < minLength) {
+ sk_throw();
+ }
+ fPtr = env->GetShortArrayElements(array, NULL);
+ }
+}
+
+AutoJavaShortArray::~AutoJavaShortArray() {
+ if (fPtr) {
+ fEnv->ReleaseShortArrayElements(fArray, fPtr, 0);
+ }
+}
+
+AutoJavaByteArray::AutoJavaByteArray(JNIEnv* env, jbyteArray array,
+ int minLength)
+: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
+ SkASSERT(env);
+ if (array) {
+ fLen = env->GetArrayLength(array);
+ if (fLen < minLength) {
+ sk_throw();
+ }
+ fPtr = env->GetByteArrayElements(array, NULL);
+ }
+}
+
+AutoJavaByteArray::~AutoJavaByteArray() {
+ if (fPtr) {
+ fEnv->ReleaseByteArrayElements(fArray, fPtr, 0);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jclass gRect_class;
+static jfieldID gRect_leftFieldID;
+static jfieldID gRect_topFieldID;
+static jfieldID gRect_rightFieldID;
+static jfieldID gRect_bottomFieldID;
+
+static jclass gRectF_class;
+static jfieldID gRectF_leftFieldID;
+static jfieldID gRectF_topFieldID;
+static jfieldID gRectF_rightFieldID;
+static jfieldID gRectF_bottomFieldID;
+
+static jclass gPoint_class;
+static jfieldID gPoint_xFieldID;
+static jfieldID gPoint_yFieldID;
+
+static jclass gPointF_class;
+static jfieldID gPointF_xFieldID;
+static jfieldID gPointF_yFieldID;
+
+static jclass gBitmap_class;
+static jfieldID gBitmap_nativeInstanceID;
+static jmethodID gBitmap_constructorMethodID;
+static jmethodID gBitmap_allocBufferMethodID;
+
+static jclass gBitmapConfig_class;
+static jfieldID gBitmapConfig_nativeInstanceID;
+
+static jclass gCanvas_class;
+static jfieldID gCanvas_nativeInstanceID;
+
+static jclass gPaint_class;
+static jfieldID gPaint_nativeInstanceID;
+
+static jclass gPicture_class;
+static jfieldID gPicture_nativeInstanceID;
+
+static jclass gRegion_class;
+static jfieldID gRegion_nativeInstanceID;
+static jmethodID gRegion_constructorMethodID;
+
+static jobject gVMRuntime_singleton;
+static jmethodID gVMRuntime_trackExternalAllocationMethodID;
+static jmethodID gVMRuntime_trackExternalFreeMethodID;
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
+{
+ SkASSERT(env->IsInstanceOf(obj, gRect_class));
+
+ *L = env->GetIntField(obj, gRect_leftFieldID);
+ *T = env->GetIntField(obj, gRect_topFieldID);
+ *R = env->GetIntField(obj, gRect_rightFieldID);
+ *B = env->GetIntField(obj, gRect_bottomFieldID);
+}
+
+void GraphicsJNI::set_jrect(JNIEnv* env, jobject obj, int L, int T, int R, int B)
+{
+ SkASSERT(env->IsInstanceOf(obj, gRect_class));
+
+ env->SetIntField(obj, gRect_leftFieldID, L);
+ env->SetIntField(obj, gRect_topFieldID, T);
+ env->SetIntField(obj, gRect_rightFieldID, R);
+ env->SetIntField(obj, gRect_bottomFieldID, B);
+}
+
+SkIRect* GraphicsJNI::jrect_to_irect(JNIEnv* env, jobject obj, SkIRect* ir)
+{
+ SkASSERT(env->IsInstanceOf(obj, gRect_class));
+
+ ir->set(env->GetIntField(obj, gRect_leftFieldID),
+ env->GetIntField(obj, gRect_topFieldID),
+ env->GetIntField(obj, gRect_rightFieldID),
+ env->GetIntField(obj, gRect_bottomFieldID));
+ return ir;
+}
+
+void GraphicsJNI::irect_to_jrect(const SkIRect& ir, JNIEnv* env, jobject obj)
+{
+ SkASSERT(env->IsInstanceOf(obj, gRect_class));
+
+ env->SetIntField(obj, gRect_leftFieldID, ir.fLeft);
+ env->SetIntField(obj, gRect_topFieldID, ir.fTop);
+ env->SetIntField(obj, gRect_rightFieldID, ir.fRight);
+ env->SetIntField(obj, gRect_bottomFieldID, ir.fBottom);
+}
+
+SkRect* GraphicsJNI::jrectf_to_rect(JNIEnv* env, jobject obj, SkRect* r)
+{
+ SkASSERT(env->IsInstanceOf(obj, gRectF_class));
+
+ r->set(SkFloatToScalar(env->GetFloatField(obj, gRectF_leftFieldID)),
+ SkFloatToScalar(env->GetFloatField(obj, gRectF_topFieldID)),
+ SkFloatToScalar(env->GetFloatField(obj, gRectF_rightFieldID)),
+ SkFloatToScalar(env->GetFloatField(obj, gRectF_bottomFieldID)));
+ return r;
+}
+
+SkRect* GraphicsJNI::jrect_to_rect(JNIEnv* env, jobject obj, SkRect* r)
+{
+ SkASSERT(env->IsInstanceOf(obj, gRect_class));
+
+ r->set(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)),
+ SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)),
+ SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)),
+ SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID)));
+ return r;
+}
+
+void GraphicsJNI::rect_to_jrectf(const SkRect& r, JNIEnv* env, jobject obj)
+{
+ SkASSERT(env->IsInstanceOf(obj, gRectF_class));
+
+ env->SetFloatField(obj, gRectF_leftFieldID, SkScalarToFloat(r.fLeft));
+ env->SetFloatField(obj, gRectF_topFieldID, SkScalarToFloat(r.fTop));
+ env->SetFloatField(obj, gRectF_rightFieldID, SkScalarToFloat(r.fRight));
+ env->SetFloatField(obj, gRectF_bottomFieldID, SkScalarToFloat(r.fBottom));
+}
+
+SkIPoint* GraphicsJNI::jpoint_to_ipoint(JNIEnv* env, jobject obj, SkIPoint* point)
+{
+ SkASSERT(env->IsInstanceOf(obj, gPoint_class));
+
+ point->set(env->GetIntField(obj, gPoint_xFieldID),
+ env->GetIntField(obj, gPoint_yFieldID));
+ return point;
+}
+
+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);
+}
+
+SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point)
+{
+ SkASSERT(env->IsInstanceOf(obj, gPointF_class));
+
+ point->set(SkFloatToScalar(env->GetIntField(obj, gPointF_xFieldID)),
+ SkFloatToScalar(env->GetIntField(obj, gPointF_yFieldID)));
+ return point;
+}
+
+void GraphicsJNI::point_to_jpointf(const SkPoint& r, JNIEnv* env, jobject obj)
+{
+ SkASSERT(env->IsInstanceOf(obj, gPointF_class));
+
+ env->SetFloatField(obj, gPointF_xFieldID, SkScalarToFloat(r.fX));
+ env->SetFloatField(obj, gPointF_yFieldID, SkScalarToFloat(r.fY));
+}
+
+SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
+ SkASSERT(env);
+ SkASSERT(bitmap);
+ SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
+ SkBitmap* b = (SkBitmap*)env->GetIntField(bitmap, gBitmap_nativeInstanceID);
+ SkASSERT(b);
+ return b;
+}
+
+SkBitmap::Config GraphicsJNI::getNativeBitmapConfig(JNIEnv* env,
+ jobject jconfig) {
+ SkASSERT(env);
+ if (NULL == jconfig) {
+ return SkBitmap::kNo_Config;
+ }
+ SkASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class));
+ int c = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID);
+ if (c < 0 || c >= SkBitmap::kConfigCount) {
+ c = SkBitmap::kNo_Config;
+ }
+ return static_cast<SkBitmap::Config>(c);
+}
+
+SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
+ SkASSERT(env);
+ SkASSERT(canvas);
+ SkASSERT(env->IsInstanceOf(canvas, gCanvas_class));
+ SkCanvas* c = (SkCanvas*)env->GetIntField(canvas, gCanvas_nativeInstanceID);
+ SkASSERT(c);
+ return c;
+}
+
+SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) {
+ SkASSERT(env);
+ SkASSERT(paint);
+ SkASSERT(env->IsInstanceOf(paint, gPaint_class));
+ SkPaint* p = (SkPaint*)env->GetIntField(paint, gPaint_nativeInstanceID);
+ SkASSERT(p);
+ return p;
+}
+
+SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
+{
+ SkASSERT(env);
+ SkASSERT(picture);
+ SkASSERT(env->IsInstanceOf(picture, gPicture_class));
+ SkPicture* p = (SkPicture*)env->GetIntField(picture, gPicture_nativeInstanceID);
+ SkASSERT(p);
+ return p;
+}
+
+SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
+{
+ SkASSERT(env);
+ SkASSERT(region);
+ SkASSERT(env->IsInstanceOf(region, gRegion_class));
+ SkRegion* r = (SkRegion*)env->GetIntField(region, gRegion_nativeInstanceID);
+ SkASSERT(r);
+ return r;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
+ jbyteArray ninepatch)
+{
+ SkASSERT(bitmap != NULL);
+ SkASSERT(NULL != bitmap->pixelRef());
+
+ jobject obj = env->AllocObject(gBitmap_class);
+ if (obj) {
+ env->CallVoidMethod(obj, gBitmap_constructorMethodID,
+ (jint)bitmap, isMutable, ninepatch);
+ if (hasException(env)) {
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
+{
+ SkASSERT(region != NULL);
+ jobject obj = env->AllocObject(gRegion_class);
+ if (obj) {
+ env->CallVoidMethod(obj, gRegion_constructorMethodID, (jint)region, 0);
+ if (hasException(env)) {
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+#include "SkPixelRef.h"
+
+static JNIEnv* vm2env(JavaVM* vm)
+{
+ JNIEnv* env = NULL;
+ if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env)
+ {
+ SkDebugf("------- [%p] vm->GetEnv() failed\n", vm);
+ sk_throw();
+ }
+ return env;
+}
+
+#ifdef TRACK_LOCK_COUNT
+ static int gLockCount;
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkMallocPixelRef.h"
+
+/* Extend SkMallocPixelRef to inform the VM when we free up the storage
+*/
+class AndroidPixelRef : public SkMallocPixelRef {
+public:
+ /** Allocate the specified buffer for pixels. The memory is freed when the
+ last owner of this pixelref is gone. Our caller has already informed
+ the VM of our allocation.
+ */
+ AndroidPixelRef(JNIEnv* env, void* storage, size_t size,
+ SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) {
+ SkASSERT(storage);
+ SkASSERT(env);
+
+ if (env->GetJavaVM(&fVM) != JNI_OK) {
+ SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
+ sk_throw();
+ }
+ }
+
+ virtual ~AndroidPixelRef() {
+ JNIEnv* env = vm2env(fVM);
+// SkDebugf("-------------- inform VM we're releasing %d bytes\n", this->getSize());
+ jlong jsize = this->getSize(); // the VM wants longs for the size
+ env->CallVoidMethod(gVMRuntime_singleton,
+ gVMRuntime_trackExternalFreeMethodID,
+ jsize);
+ if (GraphicsJNI::hasException(env)) {
+ env->ExceptionClear();
+ }
+ }
+
+private:
+ JavaVM* fVM;
+};
+
+bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
+ SkColorTable* ctable) {
+ Sk64 size64 = bitmap->getSize64();
+ if (size64.isNeg() || !size64.is32()) {
+ doThrow(env, "java/lang/IllegalArgumentException",
+ "bitmap size exceeds 32bits");
+ return false;
+ }
+
+ size_t size = size64.get32();
+ // SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
+ jlong jsize = size; // the VM wants longs for the size
+ bool r = env->CallBooleanMethod(gVMRuntime_singleton,
+ gVMRuntime_trackExternalAllocationMethodID,
+ jsize);
+ if (GraphicsJNI::hasException(env)) {
+ return false;
+ }
+ if (!r) {
+ LOGE("VM won't let us allocate %zd bytes\n", size);
+ doThrowOOME(env, "bitmap size exceeds VM budget");
+ return false;
+ }
+
+ // call the version of malloc that returns null on failure
+ void* addr = sk_malloc_flags(size, 0);
+ if (NULL == addr) {
+ // SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size);
+ // we didn't actually allocate it, so inform the VM
+ env->CallVoidMethod(gVMRuntime_singleton,
+ gVMRuntime_trackExternalFreeMethodID,
+ jsize);
+ if (!GraphicsJNI::hasException(env)) {
+ doThrowOOME(env, "bitmap size too large for malloc");
+ }
+ return false;
+ }
+
+ bitmap->setPixelRef(new AndroidPixelRef(env, addr, size, ctable))->unref();
+ // since we're already allocated, we lockPixels right away
+ // HeapAllocator behaves this way too
+ bitmap->lockPixels();
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) : fEnv(env)
+{
+}
+
+bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+ return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static jclass make_globalref(JNIEnv* env, const char classname[])
+{
+ jclass c = env->FindClass(classname);
+ SkASSERT(c);
+ return (jclass)env->NewGlobalRef(c);
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+ const char fieldname[], const char type[])
+{
+ jfieldID id = env->GetFieldID(clazz, fieldname, type);
+ SkASSERT(id);
+ return id;
+}
+
+int register_android_graphics_Graphics(JNIEnv* env)
+{
+ jmethodID m;
+ jclass c;
+
+ gRect_class = make_globalref(env, "android/graphics/Rect");
+ gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I");
+ gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I");
+ gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I");
+ gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I");
+
+ gRectF_class = make_globalref(env, "android/graphics/RectF");
+ gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F");
+ gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F");
+ gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F");
+ gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F");
+
+ gPoint_class = make_globalref(env, "android/graphics/Point");
+ gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I");
+ gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I");
+
+ gPointF_class = make_globalref(env, "android/graphics/PointF");
+ gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
+ gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
+
+ gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
+ gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
+ gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
+ "(IZ[B)V");
+
+ gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
+ gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
+ "nativeInt", "I");
+
+ gCanvas_class = make_globalref(env, "android/graphics/Canvas");
+ gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "I");
+
+ gPaint_class = make_globalref(env, "android/graphics/Paint");
+ gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I");
+
+ gPicture_class = make_globalref(env, "android/graphics/Picture");
+ gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "I");
+
+ gRegion_class = make_globalref(env, "android/graphics/Region");
+ gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "I");
+ gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>",
+ "(II)V");
+
+ // Get the VMRuntime class.
+ c = env->FindClass("dalvik/system/VMRuntime");
+ SkASSERT(c);
+ // Look up VMRuntime.getRuntime().
+ m = env->GetStaticMethodID(c, "getRuntime", "()Ldalvik/system/VMRuntime;");
+ SkASSERT(m);
+ // Call VMRuntime.getRuntime() and hold onto its result.
+ gVMRuntime_singleton = env->CallStaticObjectMethod(c, m);
+ SkASSERT(gVMRuntime_singleton);
+ gVMRuntime_singleton = (jobject)env->NewGlobalRef(gVMRuntime_singleton);
+ // Look up the VMRuntime methods we'll be using.
+ gVMRuntime_trackExternalAllocationMethodID =
+ env->GetMethodID(c, "trackExternalAllocation", "(J)Z");
+ gVMRuntime_trackExternalFreeMethodID =
+ env->GetMethodID(c, "trackExternalFree", "(J)V");
+
+ NIOBuffer::RegisterJNI(env);
+
+ return 0;
+}
+
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
new file mode 100644
index 0000000..e67b20b
--- /dev/null
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -0,0 +1,156 @@
+#ifndef GraphicsJNI_DEFINED
+#define GraphicsJNI_DEFINED
+
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkBitmap.h"
+#include <jni.h>
+
+class SkCanvas;
+class SkPaint;
+class SkPicture;
+
+class GraphicsJNI {
+public:
+ // returns true if an exception is set (and dumps it out to the Log)
+ static bool hasException(JNIEnv*);
+
+ static void get_jrect(JNIEnv*, jobject jrect, int* L, int* T, int* R, int* B);
+ static void set_jrect(JNIEnv*, jobject jrect, int L, int T, int R, int B);
+
+ static SkIRect* jrect_to_irect(JNIEnv*, jobject jrect, SkIRect*);
+ static void irect_to_jrect(const SkIRect&, JNIEnv*, jobject jrect);
+
+ static SkRect* jrectf_to_rect(JNIEnv*, jobject jrectf, SkRect*);
+ static SkRect* jrect_to_rect(JNIEnv*, jobject jrect, SkRect*);
+ static void rect_to_jrectf(const SkRect&, JNIEnv*, jobject jrectf);
+
+ static void set_jpoint(JNIEnv*, jobject jrect, int x, int y);
+
+ static SkIPoint* jpoint_to_ipoint(JNIEnv*, jobject jpoint, SkIPoint* point);
+ static void ipoint_to_jpoint(const SkIPoint& point, JNIEnv*, jobject jpoint);
+
+ static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point);
+ static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
+
+ static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
+ static SkPaint* getNativePaint(JNIEnv*, jobject paint);
+ static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
+ static SkPicture* getNativePicture(JNIEnv*, jobject picture);
+ static SkRegion* getNativeRegion(JNIEnv*, jobject region);
+
+ /** Return the corresponding native config from the java Config enum,
+ or kNo_Config if the java object is null.
+ */
+ static SkBitmap::Config getNativeBitmapConfig(JNIEnv*, jobject jconfig);
+
+ /** Create a java Bitmap object given the native bitmap (required) and optional
+ storage array (may be null). If storage is specified, then it must already be
+ locked, and its native address set as the bitmap's pixels. If storage is null,
+ then the bitmap must be an owner of its natively allocated pixels (via allocPixels).
+ */
+ static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
+ jbyteArray ninePatch);
+
+ static jobject createRegion(JNIEnv* env, SkRegion* region);
+
+ /** Set a pixelref for the bitmap (needs setConfig to already be called)
+ Returns true on success. If it returns false, then it failed, and the
+ appropriate exception will have been raised.
+ */
+ static bool setJavaPixelRef(JNIEnv*, SkBitmap*, SkColorTable* ctable);
+
+ /** Copy the colors in colors[] to the bitmap, convert to the correct
+ format along the way.
+ */
+ static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset,
+ int srcStride, int x, int y, int width, int height,
+ const SkBitmap& dstBitmap);
+};
+
+class JavaPixelAllocator : public SkBitmap::Allocator {
+public:
+ JavaPixelAllocator(JNIEnv* env);
+ // overrides
+ virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
+
+private:
+ JNIEnv* fEnv;
+};
+
+class AutoJavaFloatArray {
+public:
+ AutoJavaFloatArray(JNIEnv* env, jfloatArray array, int minLength = 0);
+ ~AutoJavaFloatArray();
+
+ float* ptr() const { return fPtr; }
+ int length() const { return fLen; }
+
+private:
+ JNIEnv* fEnv;
+ jfloatArray fArray;
+ float* fPtr;
+ int fLen;
+};
+
+class AutoJavaIntArray {
+public:
+ AutoJavaIntArray(JNIEnv* env, jintArray array, int minLength = 0);
+ ~AutoJavaIntArray();
+
+ jint* ptr() const { return fPtr; }
+ int length() const { return fLen; }
+
+private:
+ JNIEnv* fEnv;
+ jintArray fArray;
+ jint* fPtr;
+ int fLen;
+};
+
+class AutoJavaShortArray {
+public:
+ AutoJavaShortArray(JNIEnv* env, jshortArray array, int minLength = 0);
+ ~AutoJavaShortArray();
+
+ jshort* ptr() const { return fPtr; }
+ int length() const { return fLen; }
+
+private:
+ JNIEnv* fEnv;
+ jshortArray fArray;
+ jshort* fPtr;
+ int fLen;
+};
+
+class AutoJavaByteArray {
+public:
+ AutoJavaByteArray(JNIEnv* env, jbyteArray array, int minLength = 0);
+ ~AutoJavaByteArray();
+
+ jbyte* ptr() const { return fPtr; }
+ int length() const { return fLen; }
+
+private:
+ JNIEnv* fEnv;
+ jbyteArray fArray;
+ jbyte* fPtr;
+ int fLen;
+};
+
+void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL);
+void doThrowNPE(JNIEnv* env);
+void doThrowAIOOBE(JNIEnv* env); // Array Index Out Of Bounds Exception
+void doThrowIAE(JNIEnv* env, const char* msg = NULL); // Illegal Argument
+void doThrowRE(JNIEnv* env, const char* msg = NULL); // Runtime
+void doThrowISE(JNIEnv* env, const char* msg = NULL); // Illegal State
+void doThrowOOME(JNIEnv* env, const char* msg = NULL); // Out of memory
+
+#define NPE_CHECK_RETURN_ZERO(env, object) \
+ do { if (NULL == (object)) { doThrowNPE(env); return 0; } } while (0)
+
+#define NPE_CHECK_RETURN_VOID(env, object) \
+ do { if (NULL == (object)) { doThrowNPE(env); return; } } while (0)
+
+#endif
+
diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp
new file mode 100644
index 0000000..beec351
--- /dev/null
+++ b/core/jni/android/graphics/Interpolator.cpp
@@ -0,0 +1,97 @@
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "GraphicsJNI.h"
+#include "SkInterpolator.h"
+#include "SkTemplates.h"
+
+static SkInterpolator* Interpolator_constructor(JNIEnv* env, jobject clazz, int valueCount, int frameCount)
+{
+ return new SkInterpolator(valueCount, frameCount);
+}
+
+static void Interpolator_destructor(JNIEnv* env, jobject clazz, SkInterpolator* interp)
+{
+ delete interp;
+}
+
+static void Interpolator_reset(JNIEnv* env, jobject clazz, SkInterpolator* interp, int valueCount, int frameCount)
+{
+ interp->reset(valueCount, frameCount);
+}
+
+static void Interpolator_setKeyFrame(JNIEnv* env, jobject clazz, SkInterpolator* interp, int index, int msec, jfloatArray valueArray, jfloatArray blendArray)
+{
+ SkScalar blendStorage[4];
+ SkScalar* blend = NULL;
+
+ AutoJavaFloatArray autoValues(env, valueArray);
+ float* values = autoValues.ptr();
+ int i, n = autoValues.length();
+
+ SkAutoSTMalloc<16, SkScalar> storage(n);
+ SkScalar* scalars = storage.get();
+
+ for (i = 0; i < n; i++)
+ scalars[i] = SkFloatToScalar(values[i]);
+
+ if (blendArray != NULL) {
+ AutoJavaFloatArray autoBlend(env, blendArray, 4);
+ values = autoBlend.ptr();
+ for (i = 0; i < 4; i++)
+ blendStorage[i] = SkFloatToScalar(values[i]);
+ blend = blendStorage;
+ }
+
+ interp->setKeyFrame(index, msec, scalars, blend);
+}
+
+static void Interpolator_setRepeatMirror(JNIEnv* env, jobject clazz, SkInterpolator* interp, float repeatCount, jboolean mirror)
+{
+ if (repeatCount > 32000)
+ repeatCount = 32000;
+
+ interp->setRepeatCount(SkFloatToScalar(repeatCount));
+ interp->setMirror(mirror != 0);
+}
+
+static int Interpolator_timeToValues(JNIEnv* env, jobject clazz, SkInterpolator* interp, int msec, jfloatArray valueArray)
+{
+ SkInterpolatorBase::Result result;
+
+ float* values = valueArray ? env->GetFloatArrayElements(valueArray, NULL) : NULL;
+ result = interp->timeToValues(msec, (SkScalar*)values);
+
+ if (valueArray) {
+ int n = env->GetArrayLength(valueArray);
+ for (int i = 0; i < n; i++) {
+ values[i] = SkScalarToFloat(*(SkScalar*)&values[i]);
+ }
+ env->ReleaseFloatArrayElements(valueArray, values, 0);
+ }
+
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gInterpolatorMethods[] = {
+ { "nativeConstructor", "(II)I", (void*)Interpolator_constructor },
+ { "nativeDestructor", "(I)V", (void*)Interpolator_destructor },
+ { "nativeReset", "(III)V", (void*)Interpolator_reset },
+ { "nativeSetKeyFrame", "(III[F[F)V", (void*)Interpolator_setKeyFrame },
+ { "nativeSetRepeatMirror", "(IFZ)V", (void*)Interpolator_setRepeatMirror },
+ { "nativeTimeToValues", "(II[F)I", (void*)Interpolator_timeToValues }
+};
+
+int register_android_graphics_Interpolator(JNIEnv* env);
+int register_android_graphics_Interpolator(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/Interpolator",
+ gInterpolatorMethods,
+ SK_ARRAY_COUNT(gInterpolatorMethods));
+}
diff --git a/core/jni/android/graphics/LayerRasterizer.cpp b/core/jni/android/graphics/LayerRasterizer.cpp
new file mode 100644
index 0000000..7c45889
--- /dev/null
+++ b/core/jni/android/graphics/LayerRasterizer.cpp
@@ -0,0 +1,34 @@
+#include "SkLayerRasterizer.h"
+#include <jni.h>
+
+class SkLayerRasterizerGlue {
+public:
+ static SkRasterizer* create(JNIEnv* env, jobject) {
+ return new SkLayerRasterizer();
+ }
+
+ static void addLayer(JNIEnv* env, jobject, SkLayerRasterizer* layer, const SkPaint* paint, float dx, float dy) {
+ SkASSERT(layer);
+ SkASSERT(paint);
+ layer->addLayer(*paint, SkFloatToScalar(dx), SkFloatToScalar(dy));
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gLayerRasterizerMethods[] = {
+ { "nativeConstructor", "()I", (void*)SkLayerRasterizerGlue::create },
+ { "nativeAddLayer", "(IIFF)V", (void*)SkLayerRasterizerGlue::addLayer }
+};
+
+int register_android_graphics_LayerRasterizer(JNIEnv* env);
+int register_android_graphics_LayerRasterizer(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/LayerRasterizer",
+ gLayerRasterizerMethods,
+ SK_ARRAY_COUNT(gLayerRasterizerMethods));
+}
+
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
new file mode 100644
index 0000000..e6048cd
--- /dev/null
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -0,0 +1,61 @@
+#include "GraphicsJNI.h"
+#include "SkMaskFilter.h"
+#include "SkBlurMaskFilter.h"
+
+#include <jni.h>
+
+class SkMaskFilterGlue {
+public:
+ static void destructor(JNIEnv* env, jobject, SkMaskFilter* filter) {
+ SkASSERT(filter);
+ filter->unref();
+ }
+
+ static SkMaskFilter* createBlur(JNIEnv* env, jobject, float radius, int blurStyle) {
+ return SkBlurMaskFilter::Create(SkFloatToScalar(radius), (SkBlurMaskFilter::BlurStyle)blurStyle);
+ }
+
+ static SkMaskFilter* createEmboss(JNIEnv* env, jobject, jfloatArray dirArray, float ambient, float specular, float radius) {
+ SkScalar direction[3];
+
+ AutoJavaFloatArray autoDir(env, dirArray, 3);
+ float* values = autoDir.ptr();
+ for (int i = 0; i < 3; i++) {
+ direction[i] = SkFloatToScalar(values[i]);
+ }
+
+ return SkBlurMaskFilter::CreateEmboss(direction, SkFloatToScalar(ambient),
+ SkFloatToScalar(specular), SkFloatToScalar(radius));
+ }
+};
+
+static JNINativeMethod gMaskFilterMethods[] = {
+ { "nativeDestructor", "(I)V", (void*)SkMaskFilterGlue::destructor }
+};
+
+static JNINativeMethod gBlurMaskFilterMethods[] = {
+ { "nativeConstructor", "(FI)I", (void*)SkMaskFilterGlue::createBlur }
+};
+
+static JNINativeMethod gEmbossMaskFilterMethods[] = {
+ { "nativeConstructor", "([FFFF)I", (void*)SkMaskFilterGlue::createEmboss }
+};
+
+#include <android_runtime/AndroidRuntime.h>
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+int register_android_graphics_MaskFilter(JNIEnv* env);
+int register_android_graphics_MaskFilter(JNIEnv* env)
+{
+ int result;
+
+ REG(env, "android/graphics/MaskFilter", gMaskFilterMethods);
+ REG(env, "android/graphics/BlurMaskFilter", gBlurMaskFilterMethods);
+ REG(env, "android/graphics/EmbossMaskFilter", gEmbossMaskFilterMethods);
+
+ return 0;
+}
+
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
new file mode 100644
index 0000000..b782766
--- /dev/null
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -0,0 +1,412 @@
+/* libs/android_runtime/android/graphics/Matrix.cpp
+**
+** Copyright 2006, 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.
+*/
+
+// This file was generated from the C++ include file: SkMatrix.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkMatrix.h"
+#include "SkTemplates.h"
+
+namespace android {
+
+class SkMatrixGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject clazz, SkMatrix* obj) {
+ delete obj;
+ }
+
+ static SkMatrix* create(JNIEnv* env, jobject clazz, const SkMatrix* src) {
+ SkMatrix* obj = new SkMatrix();
+ if (src)
+ *obj = *src;
+ else
+ obj->reset();
+ return obj;
+ }
+
+ static jboolean isIdentity(JNIEnv* env, jobject clazz, SkMatrix* obj) {
+ return obj->isIdentity();
+ }
+
+ static jboolean rectStaysRect(JNIEnv* env, jobject clazz, SkMatrix* obj) {
+ return obj->rectStaysRect();
+ }
+
+ static void reset(JNIEnv* env, jobject clazz, SkMatrix* obj) {
+ obj->reset();
+ }
+
+ static void set(JNIEnv* env, jobject clazz, SkMatrix* obj, SkMatrix* other) {
+ *obj = *other;
+ }
+
+ static void setTranslate(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ obj->setTranslate(dx_, dy_);
+ }
+
+ static void setScale__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sx, jfloat sy, jfloat px, jfloat py) {
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ obj->setScale(sx_, sy_, px_, py_);
+ }
+
+ static void setScale__FF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sx, jfloat sy) {
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ obj->setScale(sx_, sy_);
+ }
+
+ static void setRotate__FFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat degrees, jfloat px, jfloat py) {
+ SkScalar degrees_ = SkFloatToScalar(degrees);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ obj->setRotate(degrees_, px_, py_);
+ }
+
+ static void setRotate__F(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat degrees) {
+ SkScalar degrees_ = SkFloatToScalar(degrees);
+ obj->setRotate(degrees_);
+ }
+
+ static void setSinCos__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sinValue, jfloat cosValue, jfloat px, jfloat py) {
+ SkScalar sinValue_ = SkFloatToScalar(sinValue);
+ SkScalar cosValue_ = SkFloatToScalar(cosValue);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ obj->setSinCos(sinValue_, cosValue_, px_, py_);
+ }
+
+ static void setSinCos__FF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sinValue, jfloat cosValue) {
+ SkScalar sinValue_ = SkFloatToScalar(sinValue);
+ SkScalar cosValue_ = SkFloatToScalar(cosValue);
+ obj->setSinCos(sinValue_, cosValue_);
+ }
+
+ static void setSkew__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat kx, jfloat ky, jfloat px, jfloat py) {
+ SkScalar kx_ = SkFloatToScalar(kx);
+ SkScalar ky_ = SkFloatToScalar(ky);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ obj->setSkew(kx_, ky_, px_, py_);
+ }
+
+ static void setSkew__FF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat kx, jfloat ky) {
+ SkScalar kx_ = SkFloatToScalar(kx);
+ SkScalar ky_ = SkFloatToScalar(ky);
+ obj->setSkew(kx_, ky_);
+ }
+
+ static jboolean setConcat(JNIEnv* env, jobject clazz, SkMatrix* obj, SkMatrix* a, SkMatrix* b) {
+ return obj->setConcat(*a, *b);
+ }
+
+ static jboolean preTranslate(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ return obj->preTranslate(dx_, dy_);
+ }
+
+ static jboolean preScale__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sx, jfloat sy, jfloat px, jfloat py) {
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ return obj->preScale(sx_, sy_, px_, py_);
+ }
+
+ static jboolean preScale__FF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sx, jfloat sy) {
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ return obj->preScale(sx_, sy_);
+ }
+
+ static jboolean preRotate__FFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat degrees, jfloat px, jfloat py) {
+ SkScalar degrees_ = SkFloatToScalar(degrees);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ return obj->preRotate(degrees_, px_, py_);
+ }
+
+ static jboolean preRotate__F(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat degrees) {
+ SkScalar degrees_ = SkFloatToScalar(degrees);
+ return obj->preRotate(degrees_);
+ }
+
+ static jboolean preSkew__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat kx, jfloat ky, jfloat px, jfloat py) {
+ SkScalar kx_ = SkFloatToScalar(kx);
+ SkScalar ky_ = SkFloatToScalar(ky);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ return obj->preSkew(kx_, ky_, px_, py_);
+ }
+
+ static jboolean preSkew__FF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat kx, jfloat ky) {
+ SkScalar kx_ = SkFloatToScalar(kx);
+ SkScalar ky_ = SkFloatToScalar(ky);
+ return obj->preSkew(kx_, ky_);
+ }
+
+ static jboolean preConcat(JNIEnv* env, jobject clazz, SkMatrix* obj, SkMatrix* other) {
+ return obj->preConcat(*other);
+ }
+
+ static jboolean postTranslate(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ return obj->postTranslate(dx_, dy_);
+ }
+
+ static jboolean postScale__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sx, jfloat sy, jfloat px, jfloat py) {
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ return obj->postScale(sx_, sy_, px_, py_);
+ }
+
+ static jboolean postScale__FF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat sx, jfloat sy) {
+ SkScalar sx_ = SkFloatToScalar(sx);
+ SkScalar sy_ = SkFloatToScalar(sy);
+ return obj->postScale(sx_, sy_);
+ }
+
+ static jboolean postRotate__FFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat degrees, jfloat px, jfloat py) {
+ SkScalar degrees_ = SkFloatToScalar(degrees);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ return obj->postRotate(degrees_, px_, py_);
+ }
+
+ static jboolean postRotate__F(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat degrees) {
+ SkScalar degrees_ = SkFloatToScalar(degrees);
+ return obj->postRotate(degrees_);
+ }
+
+ static jboolean postSkew__FFFF(JNIEnv* env, jobject clazz, SkMatrix* obj, jfloat kx, jfloat ky, jfloat px, jfloat py) {
+ SkScalar kx_ = SkFloatToScalar(kx);
+ SkScalar ky_ = SkFloatToScalar(ky);
+ SkScalar px_ = SkFloatToScalar(px);
+ SkScalar py_ = SkFloatToScalar(py);
+ return obj->postSkew(kx_, ky_, px_, py_);
+ }
+
+ static jboolean postSkew__FF(JNIEnv* env, jobject clazz, SkMatrix* matrix, jfloat kx, jfloat ky) {
+ SkScalar kx_ = SkFloatToScalar(kx);
+ SkScalar ky_ = SkFloatToScalar(ky);
+ return matrix->postSkew(kx_, ky_);
+ }
+
+ static jboolean postConcat(JNIEnv* env, jobject clazz, SkMatrix* matrix, SkMatrix* other) {
+ return matrix->postConcat(*other);
+ }
+
+ static jboolean setRectToRect(JNIEnv* env, jobject clazz, SkMatrix* matrix, jobject src, jobject dst, SkMatrix::ScaleToFit stf) {
+ SkRect src_;
+ GraphicsJNI::jrectf_to_rect(env, src, &src_);
+ SkRect dst_;
+ GraphicsJNI::jrectf_to_rect(env, dst, &dst_);
+ return matrix->setRectToRect(src_, dst_, stf);
+ }
+
+ static jboolean setPolyToPoly(JNIEnv* env, jobject clazz, SkMatrix* matrix,
+ jfloatArray jsrc, int srcIndex,
+ jfloatArray jdst, int dstIndex, int ptCount) {
+ SkASSERT(srcIndex >= 0);
+ SkASSERT(dstIndex >= 0);
+ SkASSERT((unsigned)ptCount <= 4);
+
+ AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1));
+ AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1));
+ float* src = autoSrc.ptr() + srcIndex;
+ float* dst = autoDst.ptr() + dstIndex;
+
+#ifdef SK_SCALAR_IS_FIXED
+ SkPoint srcPt[4], dstPt[4];
+ for (int i = 0; i < ptCount; i++) {
+ int x = i << 1;
+ int y = x + 1;
+ srcPt[i].set(SkFloatToScalar(src[x]), SkFloatToScalar(src[y]));
+ dstPt[i].set(SkFloatToScalar(dst[x]), SkFloatToScalar(dst[y]));
+ }
+ return matrix->setPolyToPoly(srcPt, dstPt, ptCount);
+#else
+ return matrix->setPolyToPoly((const SkPoint*)src, (const SkPoint*)dst,
+ ptCount);
+#endif
+ }
+
+ static jboolean invert(JNIEnv* env, jobject clazz, SkMatrix* matrix, SkMatrix* inverse) {
+ return matrix->invert(inverse);
+ }
+
+ static void mapPoints(JNIEnv* env, jobject clazz, SkMatrix* matrix,
+ jfloatArray dst, int dstIndex,
+ jfloatArray src, int srcIndex,
+ int ptCount, bool isPts) {
+ SkASSERT(ptCount >= 0);
+ AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1));
+ AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1));
+ float* srcArray = autoSrc.ptr() + srcIndex;
+ float* dstArray = autoDst.ptr() + dstIndex;
+
+#ifdef SK_SCALAR_IS_FIXED
+ // we allocate twice the count, 1 set for src, 1 for dst
+ SkAutoSTMalloc<32, SkPoint> storage(ptCount * 2);
+ SkPoint* pts = storage.get();
+ SkPoint* srcPt = pts;
+ SkPoint* dstPt = pts + ptCount;
+
+ int i;
+ for (i = 0; i < ptCount; i++) {
+ srcPt[i].set(SkFloatToScalar(srcArray[i << 1]),
+ SkFloatToScalar(srcArray[(i << 1) + 1]));
+ }
+
+ if (isPts)
+ matrix->mapPoints(dstPt, srcPt, ptCount);
+ else
+ matrix->mapVectors(dstPt, srcPt, ptCount);
+
+ for (i = 0; i < ptCount; i++) {
+ dstArray[i << 1] = SkScalarToFloat(dstPt[i].fX);
+ dstArray[(i << 1) + 1] = SkScalarToFloat(dstPt[i].fY);
+ }
+#else
+ if (isPts)
+ matrix->mapPoints((SkPoint*)dstArray, (const SkPoint*)srcArray,
+ ptCount);
+ else
+ matrix->mapVectors((SkVector*)dstArray, (const SkVector*)srcArray,
+ ptCount);
+#endif
+ }
+
+ static jboolean mapRect__RectFRectF(JNIEnv* env, jobject clazz, SkMatrix* matrix, jobjectArray dst, jobject src) {
+ SkRect dst_, src_;
+ GraphicsJNI::jrectf_to_rect(env, src, &src_);
+ jboolean rectStaysRect = matrix->mapRect(&dst_, src_);
+ GraphicsJNI::rect_to_jrectf(dst_, env, dst);
+ return rectStaysRect;
+ }
+
+ static jfloat mapRadius(JNIEnv* env, jobject clazz, SkMatrix* matrix, jfloat radius) {
+ return SkScalarToFloat(matrix->mapRadius(SkFloatToScalar(radius)));
+ }
+
+ static void getValues(JNIEnv* env, jobject clazz, SkMatrix* matrix, jfloatArray values) {
+ AutoJavaFloatArray autoValues(env, values, 9);
+ float* dst = autoValues.ptr();
+
+#ifdef SK_SCALAR_IS_FIXED
+ for (int i = 0; i < 6; i++) {
+ dst[i] = SkFixedToFloat(matrix->get(i));
+ }
+ for (int j = 6; j < 9; j++) {
+ dst[j] = SkFractToFloat(matrix->get(j));
+ }
+#else
+ for (int i = 0; i < 9; i++) {
+ dst[i] = matrix->get(i);
+ }
+#endif
+ }
+
+ static void setValues(JNIEnv* env, jobject clazz, SkMatrix* matrix, jfloatArray values) {
+ AutoJavaFloatArray autoValues(env, values, 9);
+ const float* src = autoValues.ptr();
+
+#ifdef SK_SCALAR_IS_FIXED
+ for (int i = 0; i < 6; i++) {
+ matrix->set(i, SkFloatToFixed(src[i]));
+ }
+ for (int j = 6; j < 9; j++) {
+ matrix->set(j, SkFloatToFract(src[j]));
+ }
+#else
+ for (int i = 0; i < 9; i++) {
+ matrix->set(i, src[i]);
+ }
+#endif
+ }
+
+ static jboolean equals(JNIEnv* env, jobject clazz, const SkMatrix* a, const SkMatrix* b) {
+ return *a == *b;
+ }
+ };
+
+static JNINativeMethod methods[] = {
+ {"finalizer", "(I)V", (void*) SkMatrixGlue::finalizer},
+ {"native_create","(I)I", (void*) SkMatrixGlue::create},
+ {"native_isIdentity","(I)Z", (void*) SkMatrixGlue::isIdentity},
+ {"native_rectStaysRect","(I)Z", (void*) SkMatrixGlue::rectStaysRect},
+ {"native_reset","(I)V", (void*) SkMatrixGlue::reset},
+ {"native_set","(II)V", (void*) SkMatrixGlue::set},
+ {"native_setTranslate","(IFF)V", (void*) SkMatrixGlue::setTranslate},
+ {"native_setScale","(IFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
+ {"native_setScale","(IFF)V", (void*) SkMatrixGlue::setScale__FF},
+ {"native_setRotate","(IFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
+ {"native_setRotate","(IF)V", (void*) SkMatrixGlue::setRotate__F},
+ {"native_setSinCos","(IFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
+ {"native_setSinCos","(IFF)V", (void*) SkMatrixGlue::setSinCos__FF},
+ {"native_setSkew","(IFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
+ {"native_setSkew","(IFF)V", (void*) SkMatrixGlue::setSkew__FF},
+ {"native_setConcat","(III)Z", (void*) SkMatrixGlue::setConcat},
+ {"native_preTranslate","(IFF)Z", (void*) SkMatrixGlue::preTranslate},
+ {"native_preScale","(IFFFF)Z", (void*) SkMatrixGlue::preScale__FFFF},
+ {"native_preScale","(IFF)Z", (void*) SkMatrixGlue::preScale__FF},
+ {"native_preRotate","(IFFF)Z", (void*) SkMatrixGlue::preRotate__FFF},
+ {"native_preRotate","(IF)Z", (void*) SkMatrixGlue::preRotate__F},
+ {"native_preSkew","(IFFFF)Z", (void*) SkMatrixGlue::preSkew__FFFF},
+ {"native_preSkew","(IFF)Z", (void*) SkMatrixGlue::preSkew__FF},
+ {"native_preConcat","(II)Z", (void*) SkMatrixGlue::preConcat},
+ {"native_postTranslate","(IFF)Z", (void*) SkMatrixGlue::postTranslate},
+ {"native_postScale","(IFFFF)Z", (void*) SkMatrixGlue::postScale__FFFF},
+ {"native_postScale","(IFF)Z", (void*) SkMatrixGlue::postScale__FF},
+ {"native_postRotate","(IFFF)Z", (void*) SkMatrixGlue::postRotate__FFF},
+ {"native_postRotate","(IF)Z", (void*) SkMatrixGlue::postRotate__F},
+ {"native_postSkew","(IFFFF)Z", (void*) SkMatrixGlue::postSkew__FFFF},
+ {"native_postSkew","(IFF)Z", (void*) SkMatrixGlue::postSkew__FF},
+ {"native_postConcat","(II)Z", (void*) SkMatrixGlue::postConcat},
+ {"native_setRectToRect","(ILandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect},
+ {"native_setPolyToPoly","(I[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
+ {"native_invert","(II)Z", (void*) SkMatrixGlue::invert},
+ {"native_mapPoints","(I[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
+ {"native_mapRect","(ILandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF},
+ {"native_mapRadius","(IF)F", (void*) SkMatrixGlue::mapRadius},
+ {"native_getValues","(I[F)V", (void*) SkMatrixGlue::getValues},
+ {"native_setValues","(I[F)V", (void*) SkMatrixGlue::setValues},
+ {"native_equals", "(II)Z", (void*) SkMatrixGlue::equals}
+};
+
+int register_android_graphics_Matrix(JNIEnv* env) {
+ int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Matrix", methods,
+ sizeof(methods) / sizeof(methods[0]));
+ return result;
+}
+
+}
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
new file mode 100644
index 0000000..5c48077
--- /dev/null
+++ b/core/jni/android/graphics/Movie.cpp
@@ -0,0 +1,155 @@
+#include "SkMovie.h"
+#include "SkStream.h"
+#include "GraphicsJNI.h"
+#include "SkTemplates.h"
+#include "SkUtils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <utils/Asset.h>
+#include <utils/ResourceTypes.h>
+#include <netinet/in.h>
+
+#if 0
+ #define TRACE_BITMAP(code) code
+#else
+ #define TRACE_BITMAP(code)
+#endif
+
+static jclass gMovie_class;
+static jmethodID gMovie_constructorMethodID;
+static jfieldID gMovie_nativeInstanceID;
+
+jobject create_jmovie(JNIEnv* env, SkMovie* moov) {
+ if (NULL == moov) {
+ return NULL;
+ }
+ jobject obj = env->AllocObject(gMovie_class);
+ if (obj) {
+ env->CallVoidMethod(obj, gMovie_constructorMethodID, (jint)moov);
+ }
+ return obj;
+}
+
+static SkMovie* J2Movie(JNIEnv* env, jobject movie) {
+ SkASSERT(env);
+ SkASSERT(movie);
+ SkASSERT(env->IsInstanceOf(movie, gMovie_class));
+ SkMovie* m = (SkMovie*)env->GetIntField(movie, gMovie_nativeInstanceID);
+ SkASSERT(m);
+ return m;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int movie_width(JNIEnv* env, jobject movie) {
+ NPE_CHECK_RETURN_ZERO(env, movie);
+ return J2Movie(env, movie)->width();
+}
+
+static int movie_height(JNIEnv* env, jobject movie) {
+ NPE_CHECK_RETURN_ZERO(env, movie);
+ return J2Movie(env, movie)->height();
+}
+
+static jboolean movie_isOpaque(JNIEnv* env, jobject movie) {
+ NPE_CHECK_RETURN_ZERO(env, movie);
+ return J2Movie(env, movie)->isOpaque();
+}
+
+static int movie_duration(JNIEnv* env, jobject movie) {
+ NPE_CHECK_RETURN_ZERO(env, movie);
+ return J2Movie(env, movie)->duration();
+}
+
+static jboolean movie_setTime(JNIEnv* env, jobject movie, int ms) {
+ NPE_CHECK_RETURN_ZERO(env, movie);
+ return J2Movie(env, movie)->setTime(ms);
+}
+
+static void movie_draw(JNIEnv* env, jobject movie, jobject canvas,
+ jfloat fx, jfloat fy, jobject jpaint) {
+ NPE_CHECK_RETURN_VOID(env, movie);
+ NPE_CHECK_RETURN_VOID(env, canvas);
+ // its OK for paint to be null
+
+ SkMovie* m = J2Movie(env, movie);
+ SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
+ SkScalar sx = SkFloatToScalar(fx);
+ SkScalar sy = SkFloatToScalar(fy);
+ const SkBitmap& b = m->bitmap();
+ const SkPaint* p = jpaint ? GraphicsJNI::getNativePaint(env, jpaint) : NULL;
+
+ c->drawBitmap(b, sx, sy, p);
+}
+
+static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
+
+ NPE_CHECK_RETURN_ZERO(env, istream);
+
+ // what is the lifetime of the array? Can the skstream hold onto it?
+ jbyteArray byteArray = env->NewByteArray(16*1024);
+ SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
+ if (NULL == strm) {
+ return 0;
+ }
+
+ SkMovie* moov = SkMovie::DecodeStream(strm);
+ strm->unref();
+ return create_jmovie(env, moov);
+}
+
+static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
+ jbyteArray byteArray,
+ int offset, int length) {
+
+ NPE_CHECK_RETURN_ZERO(env, byteArray);
+
+ int totalLength = env->GetArrayLength(byteArray);
+ if ((offset | length) < 0 || offset + length > totalLength) {
+ doThrow(env, "java/lang/ArrayIndexException");
+ return 0;
+ }
+
+ AutoJavaByteArray ar(env, byteArray);
+ SkMovie* moov = SkMovie::DecodeMemory(ar.ptr() + offset, length);
+ return create_jmovie(env, moov);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gMethods[] = {
+ { "width", "()I", (void*)movie_width },
+ { "height", "()I", (void*)movie_height },
+ { "isOpaque", "()Z", (void*)movie_isOpaque },
+ { "duration", "()I", (void*)movie_duration },
+ { "setTime", "(I)Z", (void*)movie_setTime },
+ { "draw", "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
+ (void*)movie_draw },
+ { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
+ (void*)movie_decodeStream },
+ { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
+ (void*)movie_decodeByteArray },
+};
+
+#define kClassPathName "android/graphics/Movie"
+
+#define RETURN_ERR_IF_NULL(value) do { if (!(value)) { assert(0); return -1; } } while (false)
+
+int register_android_graphics_Movie(JNIEnv* env);
+int register_android_graphics_Movie(JNIEnv* env)
+{
+ gMovie_class = env->FindClass(kClassPathName);
+ RETURN_ERR_IF_NULL(gMovie_class);
+ gMovie_class = (jclass)env->NewGlobalRef(gMovie_class);
+
+ gMovie_constructorMethodID = env->GetMethodID(gMovie_class, "<init>", "(I)V");
+ RETURN_ERR_IF_NULL(gMovie_constructorMethodID);
+
+ gMovie_nativeInstanceID = env->GetFieldID(gMovie_class, "mNativeMovie", "I");
+ RETURN_ERR_IF_NULL(gMovie_nativeInstanceID);
+
+ return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+ gMethods, SK_ARRAY_COUNT(gMethods));
+}
diff --git a/core/jni/android/graphics/NIOBuffer.cpp b/core/jni/android/graphics/NIOBuffer.cpp
new file mode 100644
index 0000000..cb937a3
--- /dev/null
+++ b/core/jni/android/graphics/NIOBuffer.cpp
@@ -0,0 +1,143 @@
+#include "NIOBuffer.h"
+#include "GraphicsJNI.h"
+
+// enable this to dump each time we ref/unref a global java object (buffer)
+//
+//#define TRACE_GLOBAL_REFS
+
+//#define TRACE_ARRAY_LOCKS
+
+static jclass gNIOAccess_classID;
+static jmethodID gNIOAccess_getBasePointer;
+static jmethodID gNIOAccess_getBaseArray;
+static jmethodID gNIOAccess_getBaseArrayOffset;
+static jmethodID gNIOAccess_getRemainingBytes;
+
+void NIOBuffer::RegisterJNI(JNIEnv* env) {
+ if (0 != gNIOAccess_classID) {
+ return; // already called
+ }
+
+ jclass c = env->FindClass("java/nio/NIOAccess");
+ gNIOAccess_classID = (jclass)env->NewGlobalRef(c);
+
+ gNIOAccess_getBasePointer = env->GetStaticMethodID(gNIOAccess_classID,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ gNIOAccess_getBaseArray = env->GetStaticMethodID(gNIOAccess_classID,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ gNIOAccess_getBaseArrayOffset = env->GetStaticMethodID(gNIOAccess_classID,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+ gNIOAccess_getRemainingBytes = env->GetStaticMethodID(gNIOAccess_classID,
+ "getRemainingBytes", "(Ljava/nio/Buffer;)I");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef TRACE_GLOBAL_REFS
+ static int gGlobalRefs;
+#endif
+
+#ifdef TRACE_ARRAY_LOCKS
+ static int gLockCount;
+#endif
+
+NIOBuffer::NIOBuffer(JNIEnv* env, jobject buffer) {
+ fBuffer = env->NewGlobalRef(buffer);
+#ifdef TRACE_GLOBAL_REFS
+ SkDebugf("------------ newglobalref bbuffer %X %d\n", buffer, gGlobalRefs++);
+#endif
+ fLockedPtr = NULL;
+ fLockedArray = NULL;
+}
+
+NIOBuffer::~NIOBuffer() {
+ // free() needs to have already been called
+ if (NULL != fBuffer) {
+ SkDebugf("----- leaked fBuffer in NIOBuffer");
+ sk_throw();
+ }
+}
+
+void NIOBuffer::free(JNIEnv* env) {
+
+ if (NULL != fLockedPtr) {
+ SkDebugf("======= free: array still locked %x %p\n", fLockedArray, fLockedPtr);
+ }
+
+
+ if (NULL != fBuffer) {
+#ifdef TRACE_GLOBAL_REFS
+ SkDebugf("----------- deleteglobalref buffer %X %d\n", fBuffer, --gGlobalRefs);
+#endif
+ env->DeleteGlobalRef(fBuffer);
+ fBuffer = NULL;
+ }
+}
+
+void* NIOBuffer::lock(JNIEnv* env, int* remaining) {
+ if (NULL != fLockedPtr) {
+ SkDebugf("======= lock: array still locked %x %p\n", fLockedArray, fLockedPtr);
+ }
+
+ fLockedPtr = NULL;
+ fLockedArray = NULL;
+
+ if (NULL != remaining) {
+ *remaining = env->CallStaticIntMethod(gNIOAccess_classID,
+ gNIOAccess_getRemainingBytes,
+ fBuffer);
+ if (GraphicsJNI::hasException(env)) {
+ return NULL;
+ }
+ }
+
+ jlong pointer = env->CallStaticLongMethod(gNIOAccess_classID,
+ gNIOAccess_getBasePointer,
+ fBuffer);
+ if (GraphicsJNI::hasException(env)) {
+ return NULL;
+ }
+ if (0 != pointer) {
+ return reinterpret_cast<void*>(pointer);
+ }
+
+ fLockedArray = (jbyteArray)env->CallStaticObjectMethod(gNIOAccess_classID,
+ gNIOAccess_getBaseArray,
+ fBuffer);
+ if (GraphicsJNI::hasException(env) || NULL == fLockedArray) {
+ return NULL;
+ }
+ jint offset = env->CallStaticIntMethod(gNIOAccess_classID,
+ gNIOAccess_getBaseArrayOffset,
+ fBuffer);
+ fLockedPtr = env->GetByteArrayElements(fLockedArray, NULL);
+ if (GraphicsJNI::hasException(env)) {
+ SkDebugf("------------ failed to lockarray %x\n", fLockedArray);
+ return NULL;
+ }
+#ifdef TRACE_ARRAY_LOCKS
+ SkDebugf("------------ lockarray %x %p %d\n",
+ fLockedArray, fLockedPtr, gLockCount++);
+#endif
+ if (NULL == fLockedPtr) {
+ offset = 0;
+ }
+ return (char*)fLockedPtr + offset;
+}
+
+void NIOBuffer::unlock(JNIEnv* env, bool dataChanged) {
+ if (NULL != fLockedPtr) {
+#ifdef TRACE_ARRAY_LOCKS
+ SkDebugf("------------ unlockarray %x %p %d\n",
+ fLockedArray, fLockedPtr, --gLockCount);
+#endif
+ env->ReleaseByteArrayElements(fLockedArray, (jbyte*)fLockedPtr,
+ dataChanged ? 0 : JNI_ABORT);
+
+ fLockedPtr = NULL;
+ fLockedArray = NULL;
+ } else {
+ SkDebugf("============= unlock called with null ptr %x\n", fLockedArray);
+ }
+}
+
diff --git a/core/jni/android/graphics/NIOBuffer.h b/core/jni/android/graphics/NIOBuffer.h
new file mode 100644
index 0000000..36b5554
--- /dev/null
+++ b/core/jni/android/graphics/NIOBuffer.h
@@ -0,0 +1,27 @@
+#ifndef NIOBuffer_DEFINED
+#define NIOBuffer_DEFINED
+
+#include <jni.h>
+#include "SkBitmap.h"
+
+class NIOBuffer {
+public:
+ NIOBuffer(JNIEnv* env, jobject buffer);
+ // this checks to ensure that free() was called
+ ~NIOBuffer();
+
+ void* lock(JNIEnv* env, int* remaining);
+ void unlock(JNIEnv* env, bool dataChanged);
+ // must be called before destructor
+ void free(JNIEnv* env);
+
+ // call once on boot, to setup JNI globals
+ static void RegisterJNI(JNIEnv*);
+
+private:
+ jobject fBuffer;
+ void* fLockedPtr;
+ jbyteArray fLockedArray;
+};
+
+#endif
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
new file mode 100644
index 0000000..a098d89
--- /dev/null
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -0,0 +1,142 @@
+#include <utils/ResourceTypes.h>
+
+#include "SkRegion.h"
+#include "GraphicsJNI.h"
+
+#include "JNIHelp.h"
+
+extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
+ const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+ const SkPaint* paint, SkRegion** outRegion);
+
+using namespace android;
+
+class SkNinePatchGlue {
+public:
+ static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj)
+ {
+ if (NULL == obj) {
+ return false;
+ }
+ 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;
+ }
+ return false;
+ }
+
+ static void validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj)
+ {
+ if (env->GetArrayLength(obj) < (int) (sizeof(Res_png_9patch))) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Array too small for chunk.");
+ return;
+ }
+
+ // XXX Also check that dimensions are correct.
+ }
+
+ 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)
+ {
+ 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());
+ memcpy(chunk, array, chunkSize);
+ Res_png_9patch::deserialize(chunk);
+ NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
+ env->ReleaseByteArrayElements(chunkObj, array, 0);
+ }
+ }
+
+ static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF,
+ const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
+ {
+ SkASSERT(canvas);
+ SkASSERT(boundsRectF);
+ SkASSERT(bitmap);
+ SkASSERT(chunkObj);
+ // paint is optional
+
+ SkRect bounds;
+ GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
+
+ draw(env, canvas, bounds, bitmap, chunkObj, paint);
+ }
+
+ static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect,
+ const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
+ {
+ SkASSERT(canvas);
+ SkASSERT(boundsRect);
+ SkASSERT(bitmap);
+ SkASSERT(chunkObj);
+ // paint is optional
+
+ SkRect bounds;
+ GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
+ draw(env, canvas, bounds, bitmap, chunkObj, paint);
+ }
+
+ static jint getTransparentRegion(JNIEnv* env, jobject,
+ const SkBitmap* bitmap, jbyteArray chunkObj,
+ jobject boundsRect)
+ {
+ SkASSERT(bitmap);
+ SkASSERT(chunkObj);
+ SkASSERT(boundsRect);
+
+ SkRect bounds;
+ GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
+ 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());
+ memcpy(chunk, array, chunkSize);
+ Res_png_9patch::deserialize(chunk);
+ SkRegion* region = NULL;
+ NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
+ env->ReleaseByteArrayElements(chunkObj, array, 0);
+ return (jint)region;
+ }
+
+ return 0;
+ }
+
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gNinePatchMethods[] = {
+ { "isNinePatchChunk", "([B)Z", (void*)SkNinePatchGlue::isNinePatchChunk },
+ { "validateNinePatchChunk", "(I[B)V", (void*)SkNinePatchGlue::validateNinePatchChunk },
+ { "nativeDraw", "(ILandroid/graphics/RectF;I[BI)V", (void*)SkNinePatchGlue::drawF },
+ { "nativeDraw", "(ILandroid/graphics/Rect;I[BI)V", (void*)SkNinePatchGlue::drawI },
+ { "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I",
+ (void*)SkNinePatchGlue::getTransparentRegion }
+};
+
+int register_android_graphics_NinePatch(JNIEnv* env);
+int register_android_graphics_NinePatch(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/NinePatch",
+ gNinePatchMethods,
+ SK_ARRAY_COUNT(gNinePatchMethods));
+}
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
new file mode 100644
index 0000000..ba63ae4
--- /dev/null
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -0,0 +1,320 @@
+/*
+**
+** Copyright 2006, 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 "NinePatch"
+
+#include <utils/ResourceTypes.h>
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkNinePatch.h"
+#include "SkPaint.h"
+#include "SkUnPreMultiply.h"
+
+#define USE_TRACEx
+
+#ifdef USE_TRACE
+ static bool gTrace;
+#endif
+
+#include "SkColorPriv.h"
+
+#include <utils/Log.h>
+
+static bool getColor(const SkBitmap& bitmap, int x, int y, SkColor* c) {
+ switch (bitmap.getConfig()) {
+ case SkBitmap::kARGB_8888_Config:
+ *c = SkUnPreMultiply::PMColorToColor(*bitmap.getAddr32(x, y));
+ break;
+ case SkBitmap::kRGB_565_Config:
+ *c = SkPixel16ToPixel32(*bitmap.getAddr16(x, y));
+ break;
+ case SkBitmap::kARGB_4444_Config:
+ *c = SkUnPreMultiply::PMColorToColor(
+ SkPixel4444ToPixel32(*bitmap.getAddr16(x, y)));
+ break;
+ case SkBitmap::kIndex8_Config: {
+ SkColorTable* ctable = bitmap.getColorTable();
+ *c = SkUnPreMultiply::PMColorToColor(
+ (*ctable)[*bitmap.getAddr8(x, y)]);
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+
+static SkColor modAlpha(SkColor c, int alpha) {
+ int scale = alpha + (alpha >> 7);
+ int a = SkColorGetA(c) * scale >> 8;
+ return SkColorSetA(c, a);
+}
+
+static void drawStretchyPatch(SkCanvas* canvas, SkIRect& src, const SkRect& dst,
+ const SkBitmap& bitmap, const SkPaint& paint,
+ SkColor initColor, uint32_t colorHint,
+ bool hasXfer) {
+ if (colorHint != android::Res_png_9patch::NO_COLOR) {
+ ((SkPaint*)&paint)->setColor(modAlpha(colorHint, paint.getAlpha()));
+ canvas->drawRect(dst, paint);
+ ((SkPaint*)&paint)->setColor(initColor);
+ } else if (src.width() == 1 && src.height() == 1) {
+ SkColor c;
+ if (!getColor(bitmap, src.fLeft, src.fTop, &c)) {
+ goto SLOW_CASE;
+ }
+ if (0 != c || hasXfer) {
+ SkColor prev = paint.getColor();
+ ((SkPaint*)&paint)->setColor(c);
+ canvas->drawRect(dst, paint);
+ ((SkPaint*)&paint)->setColor(prev);
+ }
+ } else {
+ SLOW_CASE:
+ canvas->drawBitmapRect(bitmap, &src, dst, &paint);
+ }
+}
+
+SkScalar calculateStretch(SkScalar boundsLimit, SkScalar startingPoint,
+ int srcSpace, int numStrechyPixelsRemaining,
+ int numFixedPixelsRemaining) {
+ SkScalar spaceRemaining = boundsLimit - startingPoint;
+ SkScalar stretchySpaceRemaining =
+ spaceRemaining - SkIntToScalar(numFixedPixelsRemaining);
+ return SkScalarMulDiv(srcSpace, stretchySpaceRemaining,
+ numStrechyPixelsRemaining);
+}
+
+void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
+ const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+ const SkPaint* paint, SkRegion** outRegion) {
+ // 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)) {
+ SkNinePatch::DrawMesh(canvas, bounds, bitmap,
+ chunk.xDivs, chunk.numXDivs,
+ chunk.yDivs, chunk.numYDivs,
+ paint);
+ return;
+ }
+
+#ifdef USE_TRACE
+ gTrace = true;
+#endif
+
+ SkASSERT(canvas || outRegion);
+
+#if 0
+ if (canvas) {
+ const SkMatrix& m = canvas->getTotalMatrix();
+ SkDebugf("ninepatch [%g %g %g] [%g %g %g]\n",
+ SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
+ SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
+ }
+#endif
+
+#ifdef USE_TRACE
+ if (gTrace) {
+ SkDEBUGF(("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height())));
+ SkDEBUGF(("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height()));
+ SkDEBUGF(("======== ninepatch xDivs [%d,%d]\n", chunk.xDivs[0], chunk.xDivs[1]));
+ SkDEBUGF(("======== ninepatch yDivs [%d,%d]\n", chunk.yDivs[0], chunk.yDivs[1]));
+ }
+#endif
+
+ if (bounds.isEmpty() ||
+ bitmap.width() == 0 || bitmap.height() == 0 ||
+ (paint && paint->getXfermode() == NULL && paint->getAlpha() == 0))
+ {
+#ifdef USE_TRACE
+ if (gTrace) SkDEBUGF(("======== abort ninepatch draw\n"));
+#endif
+ return;
+ }
+
+ // should try a quick-reject test before calling lockPixels
+
+ SkAutoLockPixels alp(bitmap);
+ // after the lock, it is valid to check getPixels()
+ if (bitmap.getPixels() == NULL)
+ return;
+
+ SkPaint defaultPaint;
+ if (NULL == paint) {
+ paint = &defaultPaint;
+ }
+
+ const bool hasXfer = paint->getXfermode() != NULL;
+ SkRect dst;
+ SkIRect src;
+
+ const int32_t x0 = chunk.xDivs[0];
+ const int32_t y0 = chunk.yDivs[0];
+ const SkColor initColor = ((SkPaint*)paint)->getColor();
+ const uint8_t numXDivs = chunk.numXDivs;
+ const uint8_t numYDivs = chunk.numYDivs;
+ int i;
+ int j;
+ int colorIndex = 0;
+ uint32_t color;
+ bool xIsStretchable;
+ const bool initialXIsStretchable = (x0 == 0);
+ bool yIsStretchable = (y0 == 0);
+ const int bitmapWidth = bitmap.width();
+ const int bitmapHeight = bitmap.height();
+
+ SkScalar* dstRights = (SkScalar*) alloca((numXDivs + 1) * sizeof(SkScalar));
+ bool dstRightsHaveBeenCached = false;
+
+ int numStretchyXPixelsRemaining = 0;
+ for (i = 0; i < numXDivs; i += 2) {
+ numStretchyXPixelsRemaining += chunk.xDivs[i + 1] - chunk.xDivs[i];
+ }
+ int numFixedXPixelsRemaining = bitmapWidth - numStretchyXPixelsRemaining;
+ int numStretchyYPixelsRemaining = 0;
+ for (i = 0; i < numYDivs; i += 2) {
+ numStretchyYPixelsRemaining += chunk.yDivs[i + 1] - chunk.yDivs[i];
+ }
+ int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining;
+
+#if 0
+ SkDebugf("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
+ bitmap.width(), bitmap.height(),
+ SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+ SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
+ numXDivs, numYDivs);
+#endif
+
+ src.fTop = 0;
+ dst.fTop = bounds.fTop;
+ // The first row always starts with the top being at y=0 and the bottom
+ // being either yDivs[1] (if yDivs[0]=0) of yDivs[0]. In the former case
+ // the first row is stretchable along the Y axis, otherwise it is fixed.
+ // The last row always ends with the bottom being bitmap.height and the top
+ // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or
+ // yDivs[numYDivs-1]. In the former case the last row is stretchable along
+ // the Y axis, otherwise it is fixed.
+ //
+ // The first and last columns are similarly treated with respect to the X
+ // axis.
+ //
+ // The above is to help explain some of the special casing that goes on the
+ // code below.
+
+ // The initial yDiv and whether the first row is considered stretchable or
+ // not depends on whether yDiv[0] was zero or not.
+ for (j = yIsStretchable ? 1 : 0;
+ j <= numYDivs && src.fTop < bitmapHeight;
+ j++, yIsStretchable = !yIsStretchable) {
+ src.fLeft = 0;
+ dst.fLeft = bounds.fLeft;
+ if (j == numYDivs) {
+ src.fBottom = bitmapHeight;
+ dst.fBottom = bounds.fBottom;
+ } else {
+ src.fBottom = chunk.yDivs[j];
+ const int srcYSize = src.fBottom - src.fTop;
+ if (yIsStretchable) {
+ dst.fBottom = dst.fTop + calculateStretch(bounds.fBottom, dst.fTop,
+ srcYSize,
+ numStretchyYPixelsRemaining,
+ numFixedYPixelsRemaining);
+ numStretchyYPixelsRemaining -= srcYSize;
+ } else {
+ dst.fBottom = dst.fTop + SkIntToScalar(srcYSize);
+ numFixedYPixelsRemaining -= srcYSize;
+ }
+ }
+
+ xIsStretchable = initialXIsStretchable;
+ // The initial xDiv and whether the first column is considered
+ // stretchable or not depends on whether xDiv[0] was zero or not.
+ for (i = xIsStretchable ? 1 : 0;
+ i <= numXDivs && src.fLeft < bitmapWidth;
+ i++, xIsStretchable = !xIsStretchable) {
+ color = chunk.colors[colorIndex++];
+ if (i == numXDivs) {
+ src.fRight = bitmapWidth;
+ dst.fRight = bounds.fRight;
+ } else {
+ src.fRight = chunk.xDivs[i];
+ if (dstRightsHaveBeenCached) {
+ dst.fRight = dstRights[i];
+ } else {
+ const int srcXSize = src.fRight - src.fLeft;
+ if (xIsStretchable) {
+ dst.fRight = dst.fLeft + calculateStretch(bounds.fRight, dst.fLeft,
+ srcXSize,
+ numStretchyXPixelsRemaining,
+ numFixedXPixelsRemaining);
+ numStretchyXPixelsRemaining -= srcXSize;
+ } else {
+ dst.fRight = dst.fLeft + SkIntToScalar(srcXSize);
+ numFixedXPixelsRemaining -= srcXSize;
+ }
+ dstRights[i] = dst.fRight;
+ }
+ }
+ // If this horizontal patch is too small to be displayed, leave
+ // the destination left edge where it is and go on to the next patch
+ // in the source.
+ if (src.fLeft >= src.fRight) {
+ src.fLeft = src.fRight;
+ continue;
+ }
+ // Make sure that we actually have room to draw any bits
+ if (dst.fRight <= dst.fLeft || dst.fBottom <= dst.fTop) {
+ goto nextDiv;
+ }
+ // If this patch is transparent, skip and don't draw.
+ if (color == android::Res_png_9patch::TRANSPARENT_COLOR && !hasXfer) {
+ if (outRegion) {
+ if (*outRegion == NULL) {
+ *outRegion = new SkRegion();
+ }
+ SkIRect idst;
+ dst.round(&idst);
+ //LOGI("Adding trans rect: (%d,%d)-(%d,%d)\n",
+ // idst.fLeft, idst.fTop, idst.fRight, idst.fBottom);
+ (*outRegion)->op(idst, SkRegion::kUnion_Op);
+ }
+ goto nextDiv;
+ }
+ if (canvas) {
+#if 0
+ SkDebugf("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
+ src.fLeft, src.fTop, src.width(), src.height(),
+ SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
+ SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
+ if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
+ SkDebugf("--- skip patch\n");
+ }
+#endif
+ drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor,
+ color, hasXfer);
+ }
+
+nextDiv:
+ src.fLeft = src.fRight;
+ dst.fLeft = dst.fRight;
+ }
+ src.fTop = src.fBottom;
+ dst.fTop = dst.fBottom;
+ dstRightsHaveBeenCached = true;
+ }
+}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
new file mode 100644
index 0000000..05830de
--- /dev/null
+++ b/core/jni/android/graphics/Paint.cpp
@@ -0,0 +1,605 @@
+/* libs/android_runtime/android/graphics/Paint.cpp
+**
+** Copyright 2006, 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.
+*/
+
+// This file was generated from the C++ include file: SkPaint.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkBlurDrawLooper.h"
+#include "SkColorFilter.h"
+#include "SkMaskFilter.h"
+#include "SkRasterizer.h"
+#include "SkShader.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+namespace android {
+
+struct JMetricsID {
+ jfieldID top;
+ jfieldID ascent;
+ jfieldID descent;
+ jfieldID bottom;
+ jfieldID leading;
+};
+
+static jclass gFontMetrics_class;
+static JMetricsID gFontMetrics_fieldID;
+
+static jclass gFontMetricsInt_class;
+static JMetricsID gFontMetricsInt_fieldID;
+
+class SkPaintGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject clazz, SkPaint* obj) {
+ delete obj;
+ }
+
+ static SkPaint* init(JNIEnv* env, jobject clazz) {
+ SkPaint* obj = new SkPaint();
+ // utf16 is required for java
+ obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ return obj;
+ }
+
+ static SkPaint* intiWithPaint(JNIEnv* env, jobject clazz, SkPaint* paint) {
+ SkPaint* obj = new SkPaint(*paint);
+ return obj;
+ }
+
+ static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
+ obj->reset();
+ }
+
+ static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
+ *dst = *src;
+ }
+
+ static jint getFlags(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return GraphicsJNI::getNativePaint(env, paint)->getFlags();
+ }
+
+ static void setFlags(JNIEnv* env, jobject paint, jint flags) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setFlags(flags);
+ }
+
+ static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setAntiAlias(aa);
+ }
+
+ static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setLinearText(linearText);
+ }
+
+ static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setSubpixelText(subpixelText);
+ }
+
+ static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setUnderlineText(underlineText);
+ }
+
+ static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
+ }
+
+ static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
+ }
+
+ static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setFilterBitmap(filterBitmap);
+ }
+
+ static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setDither(dither);
+ }
+
+ static jint getStyle(JNIEnv* env, jobject clazz, SkPaint* obj) {
+ return obj->getStyle();
+ }
+
+ static void setStyle(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Style style) {
+ obj->setStyle(style);
+ }
+
+ static jint getColor(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return GraphicsJNI::getNativePaint(env, paint)->getColor();
+ }
+
+ static jint getAlpha(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return GraphicsJNI::getNativePaint(env, paint)->getAlpha();
+ }
+
+ static void setColor(JNIEnv* env, jobject paint, jint color) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setColor(color);
+ }
+
+ static void setAlpha(JNIEnv* env, jobject paint, jint a) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setAlpha(a);
+ }
+
+ static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeWidth());
+ }
+
+ static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setStrokeWidth(SkFloatToScalar(width));
+ }
+
+ static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeMiter());
+ }
+
+ static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setStrokeMiter(SkFloatToScalar(miter));
+ }
+
+ static jint getStrokeCap(JNIEnv* env, jobject clazz, SkPaint* obj) {
+ return obj->getStrokeCap();
+ }
+
+ static void setStrokeCap(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Cap cap) {
+ obj->setStrokeCap(cap);
+ }
+
+ static jint getStrokeJoin(JNIEnv* env, jobject clazz, SkPaint* obj) {
+ return obj->getStrokeJoin();
+ }
+
+ static void setStrokeJoin(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Join join) {
+ obj->setStrokeJoin(join);
+ }
+
+ static jboolean getFillPath(JNIEnv* env, jobject clazz, SkPaint* obj, SkPath* src, SkPath* dst) {
+ return obj->getFillPath(*src, dst);
+ }
+
+ static SkShader* setShader(JNIEnv* env, jobject clazz, SkPaint* obj, SkShader* shader) {
+ return obj->setShader(shader);
+ }
+
+ static SkColorFilter* setColorFilter(JNIEnv* env, jobject clazz, SkPaint* obj, SkColorFilter* filter) {
+ return obj->setColorFilter(filter);
+ }
+
+ static SkXfermode* setXfermode(JNIEnv* env, jobject clazz, SkPaint* obj, SkXfermode* xfermode) {
+ return obj->setXfermode(xfermode);
+ }
+
+ static SkPathEffect* setPathEffect(JNIEnv* env, jobject clazz, SkPaint* obj, SkPathEffect* effect) {
+ return obj->setPathEffect(effect);
+ }
+
+ static SkMaskFilter* setMaskFilter(JNIEnv* env, jobject clazz, SkPaint* obj, SkMaskFilter* maskfilter) {
+ return obj->setMaskFilter(maskfilter);
+ }
+
+ static SkTypeface* setTypeface(JNIEnv* env, jobject clazz, SkPaint* obj, SkTypeface* typeface) {
+ return obj->setTypeface(typeface);
+ }
+
+ static SkRasterizer* setRasterizer(JNIEnv* env, jobject clazz, SkPaint* obj, SkRasterizer* rasterizer) {
+ return obj->setRasterizer(rasterizer);
+ }
+
+ static jint getTextAlign(JNIEnv* env, jobject clazz, SkPaint* obj) {
+ return obj->getTextAlign();
+ }
+
+ static void setTextAlign(JNIEnv* env, jobject clazz, SkPaint* obj, SkPaint::Align align) {
+ obj->setTextAlign(align);
+ }
+
+ static jfloat getTextSize(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize());
+ }
+
+ static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setTextSize(SkFloatToScalar(textSize));
+ }
+
+ static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextScaleX());
+ }
+
+ static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setTextScaleX(SkFloatToScalar(scaleX));
+ }
+
+ static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSkewX());
+ }
+
+ static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
+ NPE_CHECK_RETURN_VOID(env, paint);
+ GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(SkFloatToScalar(skewX));
+ }
+
+ static jfloat ascent(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ SkPaint::FontMetrics metrics;
+ (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
+ return SkScalarToFloat(metrics.fAscent);
+ }
+
+ static jfloat descent(JNIEnv* env, jobject paint) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ SkPaint::FontMetrics metrics;
+ (void)GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
+ return SkScalarToFloat(metrics.fDescent);
+ }
+
+ static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ SkPaint::FontMetrics metrics;
+ SkScalar spacing = GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
+
+ if (metricsObj) {
+ SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
+ }
+ return SkScalarToFloat(spacing);
+ }
+
+ static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
+ NPE_CHECK_RETURN_ZERO(env, paint);
+ SkPaint::FontMetrics metrics;
+
+ GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics);
+ int ascent = SkScalarRound(metrics.fAscent);
+ int descent = SkScalarRound(metrics.fDescent);
+ int leading = SkScalarRound(metrics.fLeading);
+
+ if (metricsObj) {
+ SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloor(metrics.fTop));
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeil(metrics.fBottom));
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
+ }
+ return descent - ascent + leading;
+ }
+
+ static jfloat measureText_CII(JNIEnv* env, jobject jpaint, jcharArray text, int index, int count) {
+ 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");
+ return 0;
+ }
+
+ jfloat width = SkScalarToFloat(paint->measureText(textArray + index, count << 1));
+ env->ReleaseCharArrayElements(text, textArray, 0);
+ return width;
+ }
+
+ static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) {
+ NPE_CHECK_RETURN_ZERO(env, jpaint);
+ NPE_CHECK_RETURN_ZERO(env, text);
+
+ SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ size_t textLength = env->GetStringLength(text);
+
+ int count = end - start;
+ if ((start | count) < 0 || (size_t)count > textLength) {
+ doThrow(env, "IndexOutOfBoundsException");
+ return 0;
+ }
+
+ jfloat width = SkScalarToFloat(paint->measureText(textArray + start, count << 1));
+ env->ReleaseStringChars(text, textArray);
+ return width;
+ }
+
+ static jfloat measureText_String(JNIEnv* env, jobject jpaint, jstring text) {
+ NPE_CHECK_RETURN_ZERO(env, jpaint);
+ NPE_CHECK_RETURN_ZERO(env, text);
+
+ SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ size_t textLength = env->GetStringLength(text);
+
+ jfloat width = SkScalarToFloat(paint->measureText(textArray, textLength << 1));
+ env->ReleaseStringChars(text, textArray);
+ return width;
+ }
+
+ static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths) {
+ AutoJavaFloatArray autoWidths(env, widths, count);
+ jfloat* widthsArray = autoWidths.ptr();
+ SkScalar* scalarArray = (SkScalar*)widthsArray;
+
+ count = paint->getTextWidths(text, count << 1, scalarArray);
+ for (int i = 0; i < count; i++) {
+ widthsArray[i] = SkScalarToFloat(scalarArray[i]);
+ }
+ return count;
+ }
+
+ 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);
+ count = dotextwidths(env, paint, textArray + index, count, widths);
+ env->ReleaseCharArrayElements(text, textArray, 0);
+ return count;
+ }
+
+ static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloatArray widths) {
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ int count = dotextwidths(env, paint, textArray + start, end - start, widths);
+ env->ReleaseStringChars(text, textArray);
+ return count;
+ }
+
+ 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);
+ paint->getTextPath(textArray + index, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), path);
+ env->ReleaseCharArrayElements(text, textArray, 0);
+ }
+
+ static void getTextPath__StringIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ paint->getTextPath(textArray + start, (end - start) << 1, SkFloatToScalar(x), SkFloatToScalar(y), path);
+ env->ReleaseStringChars(text, textArray);
+ }
+
+ static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius,
+ jfloat dx, jfloat dy, int color) {
+ NPE_CHECK_RETURN_VOID(env, jpaint);
+
+ SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+ if (radius <= 0) {
+ paint->setLooper(NULL);
+ }
+ else {
+ paint->setLooper(new SkBlurDrawLooper(SkFloatToScalar(radius),
+ SkFloatToScalar(dx),
+ SkFloatToScalar(dy),
+ (SkColor)color))->unref();
+ }
+ }
+
+ static int breakText(JNIEnv* env, const SkPaint& paint, const jchar text[],
+ int count, float maxWidth, jfloatArray jmeasured,
+ SkPaint::TextBufferDirection tbd) {
+ SkASSERT(paint.getTextEncoding() == SkPaint::kUTF16_TextEncoding);
+
+ SkScalar measured;
+ size_t bytes = paint.breakText(text, count << 1,
+ SkFloatToScalar(maxWidth), &measured, tbd);
+ SkASSERT((bytes & 1) == 0);
+
+ if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
+ AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
+ jfloat* array = autoMeasured.ptr();
+ array[0] = SkScalarToFloat(measured);
+ }
+ return bytes >> 1;
+ }
+
+ static int breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
+ int index, int count, float maxWidth, jfloatArray jmeasuredWidth) {
+ NPE_CHECK_RETURN_ZERO(env, jpaint);
+ NPE_CHECK_RETURN_ZERO(env, jtext);
+
+ SkPaint::TextBufferDirection tbd;
+ if (count < 0) {
+ tbd = SkPaint::kBackward_TextBufferDirection;
+ count = -count;
+ }
+ else {
+ tbd = SkPaint::kForward_TextBufferDirection;
+ }
+
+ if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
+ doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
+ return 0;
+ }
+
+ SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+ jchar* text = env->GetCharArrayElements(jtext, NULL);
+ count = breakText(env, *paint, text + index, count, maxWidth,
+ jmeasuredWidth, tbd);
+ env->ReleaseCharArrayElements(jtext, text, 0);
+ return count;
+ }
+
+ static int breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
+ bool forwards, float maxWidth, jfloatArray jmeasuredWidth) {
+ NPE_CHECK_RETURN_ZERO(env, jpaint);
+ NPE_CHECK_RETURN_ZERO(env, jtext);
+
+ SkPaint::TextBufferDirection tbd = forwards ?
+ SkPaint::kForward_TextBufferDirection :
+ SkPaint::kBackward_TextBufferDirection;
+
+ SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+ int count = env->GetStringLength(jtext);
+ const jchar* text = env->GetStringChars(jtext, NULL);
+ count = breakText(env, *paint, text, count, maxWidth,
+ jmeasuredWidth, tbd);
+ env->ReleaseStringChars(jtext, text);
+ return count;
+ }
+
+ static void doTextBounds(JNIEnv* env, const jchar* text, int count,
+ jobject bounds, const SkPaint& paint)
+ {
+ SkRect r;
+ SkIRect ir;
+
+ paint.measureText(text, count << 1, &r);
+ r.roundOut(&ir);
+ GraphicsJNI::irect_to_jrect(ir, env, bounds);
+ }
+
+ static void getStringBounds(JNIEnv* env, jobject, const SkPaint* paint,
+ jstring text, int start, int end, jobject bounds)
+ {
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ doTextBounds(env, textArray + start, end - start, bounds, *paint);
+ env->ReleaseStringChars(text, textArray);
+ }
+
+ static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint,
+ jcharArray text, int index, int count, jobject bounds)
+ {
+ jchar* textArray = env->GetCharArrayElements(text, NULL);
+ doTextBounds(env, textArray + index, count, bounds, *paint);
+ env->ReleaseCharArrayElements(text, textArray, 0);
+ }
+
+};
+
+static JNINativeMethod methods[] = {
+ {"finalizer", "(I)V", (void*) SkPaintGlue::finalizer},
+ {"native_init","()I", (void*) SkPaintGlue::init},
+ {"native_initWithPaint","(I)I", (void*) SkPaintGlue::intiWithPaint},
+ {"native_reset","(I)V", (void*) SkPaintGlue::reset},
+ {"native_set","(II)V", (void*) SkPaintGlue::assign},
+ {"getFlags","()I", (void*) SkPaintGlue::getFlags},
+ {"setFlags","(I)V", (void*) SkPaintGlue::setFlags},
+ {"setAntiAlias","(Z)V", (void*) SkPaintGlue::setAntiAlias},
+ {"setSubpixelText","(Z)V", (void*) SkPaintGlue::setSubpixelText},
+ {"setLinearText","(Z)V", (void*) SkPaintGlue::setLinearText},
+ {"setUnderlineText","(Z)V", (void*) SkPaintGlue::setUnderlineText},
+ {"setStrikeThruText","(Z)V", (void*) SkPaintGlue::setStrikeThruText},
+ {"setFakeBoldText","(Z)V", (void*) SkPaintGlue::setFakeBoldText},
+ {"setFilterBitmap","(Z)V", (void*) SkPaintGlue::setFilterBitmap},
+ {"setDither","(Z)V", (void*) SkPaintGlue::setDither},
+ {"native_getStyle","(I)I", (void*) SkPaintGlue::getStyle},
+ {"native_setStyle","(II)V", (void*) SkPaintGlue::setStyle},
+ {"getColor","()I", (void*) SkPaintGlue::getColor},
+ {"setColor","(I)V", (void*) SkPaintGlue::setColor},
+ {"getAlpha","()I", (void*) SkPaintGlue::getAlpha},
+ {"setAlpha","(I)V", (void*) SkPaintGlue::setAlpha},
+ {"getStrokeWidth","()F", (void*) SkPaintGlue::getStrokeWidth},
+ {"setStrokeWidth","(F)V", (void*) SkPaintGlue::setStrokeWidth},
+ {"getStrokeMiter","()F", (void*) SkPaintGlue::getStrokeMiter},
+ {"setStrokeMiter","(F)V", (void*) SkPaintGlue::setStrokeMiter},
+ {"native_getStrokeCap","(I)I", (void*) SkPaintGlue::getStrokeCap},
+ {"native_setStrokeCap","(II)V", (void*) SkPaintGlue::setStrokeCap},
+ {"native_getStrokeJoin","(I)I", (void*) SkPaintGlue::getStrokeJoin},
+ {"native_setStrokeJoin","(II)V", (void*) SkPaintGlue::setStrokeJoin},
+ {"native_getFillPath","(III)Z", (void*) SkPaintGlue::getFillPath},
+ {"native_setShader","(II)I", (void*) SkPaintGlue::setShader},
+ {"native_setColorFilter","(II)I", (void*) SkPaintGlue::setColorFilter},
+ {"native_setXfermode","(II)I", (void*) SkPaintGlue::setXfermode},
+ {"native_setPathEffect","(II)I", (void*) SkPaintGlue::setPathEffect},
+ {"native_setMaskFilter","(II)I", (void*) SkPaintGlue::setMaskFilter},
+ {"native_setTypeface","(II)I", (void*) SkPaintGlue::setTypeface},
+ {"native_setRasterizer","(II)I", (void*) SkPaintGlue::setRasterizer},
+ {"native_getTextAlign","(I)I", (void*) SkPaintGlue::getTextAlign},
+ {"native_setTextAlign","(II)V", (void*) SkPaintGlue::setTextAlign},
+ {"getTextSize","()F", (void*) SkPaintGlue::getTextSize},
+ {"setTextSize","(F)V", (void*) SkPaintGlue::setTextSize},
+ {"getTextScaleX","()F", (void*) SkPaintGlue::getTextScaleX},
+ {"setTextScaleX","(F)V", (void*) SkPaintGlue::setTextScaleX},
+ {"getTextSkewX","()F", (void*) SkPaintGlue::getTextSkewX},
+ {"setTextSkewX","(F)V", (void*) SkPaintGlue::setTextSkewX},
+ {"ascent","()F", (void*) SkPaintGlue::ascent},
+ {"descent","()F", (void*) SkPaintGlue::descent},
+ {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)SkPaintGlue::getFontMetrics},
+ {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)SkPaintGlue::getFontMetricsInt},
+ {"measureText","([CII)F", (void*) SkPaintGlue::measureText_CII},
+ {"measureText","(Ljava/lang/String;)F", (void*) SkPaintGlue::measureText_String},
+ {"measureText","(Ljava/lang/String;II)F", (void*) SkPaintGlue::measureText_StringII},
+ {"breakText","([CIIF[F)I", (void*) SkPaintGlue::breakTextC},
+ {"breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
+ {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
+ {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
+ {"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___CIIFFPath},
+ {"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__StringIIFFPath},
+ {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
+ (void*) SkPaintGlue::getStringBounds },
+ {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
+ (void*) SkPaintGlue::getCharArrayBounds },
+ {"setShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
+};
+
+static jfieldID req_fieldID(jfieldID id) {
+ SkASSERT(id);
+ return id;
+}
+
+int register_android_graphics_Paint(JNIEnv* env) {
+ gFontMetrics_class = env->FindClass("android/graphics/Paint$FontMetrics");
+ SkASSERT(gFontMetrics_class);
+ gFontMetrics_class = (jclass)env->NewGlobalRef(gFontMetrics_class);
+
+ gFontMetrics_fieldID.top = req_fieldID(env->GetFieldID(gFontMetrics_class, "top", "F"));
+ gFontMetrics_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetrics_class, "ascent", "F"));
+ gFontMetrics_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetrics_class, "descent", "F"));
+ gFontMetrics_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetrics_class, "bottom", "F"));
+ gFontMetrics_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetrics_class, "leading", "F"));
+
+ gFontMetricsInt_class = env->FindClass("android/graphics/Paint$FontMetricsInt");
+ SkASSERT(gFontMetricsInt_class);
+ gFontMetricsInt_class = (jclass)env->NewGlobalRef(gFontMetricsInt_class);
+
+ gFontMetricsInt_fieldID.top = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "top", "I"));
+ gFontMetricsInt_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "ascent", "I"));
+ gFontMetricsInt_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "descent", "I"));
+ gFontMetricsInt_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "bottom", "I"));
+ gFontMetricsInt_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "leading", "I"));
+
+ int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Paint", methods,
+ sizeof(methods) / sizeof(methods[0]));
+ return result;
+}
+
+}
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
new file mode 100644
index 0000000..effb1c8
--- /dev/null
+++ b/core/jni/android/graphics/Path.cpp
@@ -0,0 +1,306 @@
+/* libs/android_runtime/android/graphics/Path.cpp
+**
+** Copyright 2006, 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.
+*/
+
+// This file was generated from the C++ include file: SkPath.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkPath.h"
+
+namespace android {
+
+class SkPathGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject clazz, SkPath* obj) {
+ delete obj;
+ }
+
+ static SkPath* init1(JNIEnv* env, jobject clazz) {
+ return new SkPath();
+ }
+
+ static SkPath* init2(JNIEnv* env, jobject clazz, SkPath* val) {
+ return new SkPath(*val);
+ }
+
+ static void reset(JNIEnv* env, jobject clazz, SkPath* obj) {
+ obj->reset();
+ }
+
+ static void rewind(JNIEnv* env, jobject clazz, SkPath* obj) {
+ obj->rewind();
+ }
+
+ static void assign(JNIEnv* env, jobject clazz, SkPath* dst, const SkPath* src) {
+ *dst = *src;
+ }
+
+ static jint getFillType(JNIEnv* env, jobject clazz, SkPath* obj) {
+ return obj->getFillType();
+ }
+
+ static void setFillType(JNIEnv* env, jobject clazz, SkPath* path,
+ SkPath::FillType ft) {
+ path->setFillType(ft);
+ }
+
+ static jboolean isEmpty(JNIEnv* env, jobject clazz, SkPath* obj) {
+ return obj->isEmpty();
+ }
+
+ static jboolean isRect(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect) {
+ SkRect rect_;
+ jboolean result = obj->isRect(&rect_);
+ GraphicsJNI::rect_to_jrectf(rect_, env, rect);
+ return result;
+ }
+
+ static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, SkPath::BoundsType btype) {
+ SkRect bounds_;
+ obj->computeBounds(&bounds_, btype);
+ GraphicsJNI::rect_to_jrectf(bounds_, env, bounds);
+ }
+
+ static void incReserve(JNIEnv* env, jobject clazz, SkPath* obj, jint extraPtCount) {
+ obj->incReserve(extraPtCount);
+ }
+
+ static void moveTo__FF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x, jfloat y) {
+ SkScalar x_ = SkFloatToScalar(x);
+ SkScalar y_ = SkFloatToScalar(y);
+ obj->moveTo(x_, y_);
+ }
+
+ static void rMoveTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ obj->rMoveTo(dx_, dy_);
+ }
+
+ static void lineTo__FF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x, jfloat y) {
+ SkScalar x_ = SkFloatToScalar(x);
+ SkScalar y_ = SkFloatToScalar(y);
+ obj->lineTo(x_, y_);
+ }
+
+ static void rLineTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ obj->rLineTo(dx_, dy_);
+ }
+
+ static void quadTo__FFFF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x1, jfloat y1, jfloat x2, jfloat y2) {
+ SkScalar x1_ = SkFloatToScalar(x1);
+ SkScalar y1_ = SkFloatToScalar(y1);
+ SkScalar x2_ = SkFloatToScalar(x2);
+ SkScalar y2_ = SkFloatToScalar(y2);
+ obj->quadTo(x1_, y1_, x2_, y2_);
+ }
+
+ static void rQuadTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) {
+ SkScalar dx1_ = SkFloatToScalar(dx1);
+ SkScalar dy1_ = SkFloatToScalar(dy1);
+ SkScalar dx2_ = SkFloatToScalar(dx2);
+ SkScalar dy2_ = SkFloatToScalar(dy2);
+ obj->rQuadTo(dx1_, dy1_, dx2_, dy2_);
+ }
+
+ static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
+ SkScalar x1_ = SkFloatToScalar(x1);
+ SkScalar y1_ = SkFloatToScalar(y1);
+ SkScalar x2_ = SkFloatToScalar(x2);
+ SkScalar y2_ = SkFloatToScalar(y2);
+ SkScalar x3_ = SkFloatToScalar(x3);
+ SkScalar y3_ = SkFloatToScalar(y3);
+ obj->cubicTo(x1_, y1_, x2_, y2_, x3_, y3_);
+ }
+
+ static void rCubicTo(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
+ SkScalar x1_ = SkFloatToScalar(x1);
+ SkScalar y1_ = SkFloatToScalar(y1);
+ SkScalar x2_ = SkFloatToScalar(x2);
+ SkScalar y2_ = SkFloatToScalar(y2);
+ SkScalar x3_ = SkFloatToScalar(x3);
+ SkScalar y3_ = SkFloatToScalar(y3);
+ obj->rCubicTo(x1_, y1_, x2_, y2_, x3_, y3_);
+ }
+
+ static void arcTo(JNIEnv* env, jobject clazz, SkPath* obj, jobject oval, jfloat startAngle, jfloat sweepAngle, jboolean forceMoveTo) {
+ SkRect oval_;
+ GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
+ SkScalar startAngle_ = SkFloatToScalar(startAngle);
+ SkScalar sweepAngle_ = SkFloatToScalar(sweepAngle);
+ obj->arcTo(oval_, startAngle_, sweepAngle_, forceMoveTo);
+ }
+
+ static void close(JNIEnv* env, jobject clazz, SkPath* obj) {
+ obj->close();
+ }
+
+ static void addRect__RectFI(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect, SkPath::Direction dir) {
+ SkRect rect_;
+ GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
+ obj->addRect(rect_, dir);
+ }
+
+ static void addRect__FFFFI(JNIEnv* env, jobject clazz, SkPath* obj, jfloat left, jfloat top, jfloat right, jfloat bottom, SkPath::Direction dir) {
+ SkScalar left_ = SkFloatToScalar(left);
+ SkScalar top_ = SkFloatToScalar(top);
+ SkScalar right_ = SkFloatToScalar(right);
+ SkScalar bottom_ = SkFloatToScalar(bottom);
+ obj->addRect(left_, top_, right_, bottom_, dir);
+ }
+
+ static void addOval(JNIEnv* env, jobject clazz, SkPath* obj, jobject oval, SkPath::Direction dir) {
+ SkRect oval_;
+ GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
+ obj->addOval(oval_, dir);
+ }
+
+ static void addCircle(JNIEnv* env, jobject clazz, SkPath* obj, jfloat x, jfloat y, jfloat radius, SkPath::Direction dir) {
+ SkScalar x_ = SkFloatToScalar(x);
+ SkScalar y_ = SkFloatToScalar(y);
+ SkScalar radius_ = SkFloatToScalar(radius);
+ obj->addCircle(x_, y_, radius_, dir);
+ }
+
+ static void addArc(JNIEnv* env, jobject clazz, SkPath* obj, jobject oval, jfloat startAngle, jfloat sweepAngle) {
+ SkRect oval_;
+ GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
+ SkScalar startAngle_ = SkFloatToScalar(startAngle);
+ SkScalar sweepAngle_ = SkFloatToScalar(sweepAngle);
+ obj->addArc(oval_, startAngle_, sweepAngle_);
+ }
+
+ static void addRoundRectXY(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect,
+ jfloat rx, jfloat ry, SkPath::Direction dir) {
+ SkRect rect_;
+ GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
+ SkScalar rx_ = SkFloatToScalar(rx);
+ SkScalar ry_ = SkFloatToScalar(ry);
+ obj->addRoundRect(rect_, rx_, ry_, dir);
+ }
+
+ static void addRoundRect8(JNIEnv* env, jobject, SkPath* obj, jobject rect,
+ jfloatArray array, SkPath::Direction dir) {
+ SkRect rect_;
+ GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
+ AutoJavaFloatArray afa(env, array, 8);
+ const float* src = afa.ptr();
+ SkScalar dst[8];
+
+ for (int i = 0; i < 8; i++) {
+ dst[i] = SkFloatToScalar(src[i]);
+ }
+ obj->addRoundRect(rect_, dst, dir);
+ }
+
+ static void addPath__PathFF(JNIEnv* env, jobject clazz, SkPath* obj, SkPath* src, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ obj->addPath(*src, dx_, dy_);
+ }
+
+ static void addPath__Path(JNIEnv* env, jobject clazz, SkPath* obj, SkPath* src) {
+ obj->addPath(*src);
+ }
+
+ static void addPath__PathMatrix(JNIEnv* env, jobject clazz, SkPath* obj, SkPath* src, SkMatrix* matrix) {
+ obj->addPath(*src, *matrix);
+ }
+
+ static void offset__FFPath(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy, SkPath* dst) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ obj->offset(dx_, dy_, dst);
+ }
+
+ static void offset__FF(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ obj->offset(dx_, dy_);
+ }
+
+ static void setLastPoint(JNIEnv* env, jobject clazz, SkPath* obj, jfloat dx, jfloat dy) {
+ SkScalar dx_ = SkFloatToScalar(dx);
+ SkScalar dy_ = SkFloatToScalar(dy);
+ obj->setLastPt(dx_, dy_);
+ }
+
+ static void transform__MatrixPath(JNIEnv* env, jobject clazz, SkPath* obj, SkMatrix* matrix, SkPath* dst) {
+ obj->transform(*matrix, dst);
+ }
+
+ static void transform__Matrix(JNIEnv* env, jobject clazz, SkPath* obj, SkMatrix* matrix) {
+ obj->transform(*matrix);
+ }
+
+};
+
+static JNINativeMethod methods[] = {
+ {"finalizer", "(I)V", (void*) SkPathGlue::finalizer},
+ {"init1","()I", (void*) SkPathGlue::init1},
+ {"init2","(I)I", (void*) SkPathGlue::init2},
+ {"native_reset","(I)V", (void*) SkPathGlue::reset},
+ {"native_rewind","(I)V", (void*) SkPathGlue::rewind},
+ {"native_set","(II)V", (void*) SkPathGlue::assign},
+ {"native_getFillType","(I)I", (void*) SkPathGlue::getFillType},
+ {"native_setFillType","(II)V", (void*) SkPathGlue::setFillType},
+ {"native_isEmpty","(I)Z", (void*) SkPathGlue::isEmpty},
+ {"native_isRect","(ILandroid/graphics/RectF;)Z", (void*) SkPathGlue::isRect},
+ {"native_computeBounds","(ILandroid/graphics/RectF;I)V", (void*) SkPathGlue::computeBounds},
+ {"native_incReserve","(II)V", (void*) SkPathGlue::incReserve},
+ {"native_moveTo","(IFF)V", (void*) SkPathGlue::moveTo__FF},
+ {"native_rMoveTo","(IFF)V", (void*) SkPathGlue::rMoveTo},
+ {"native_lineTo","(IFF)V", (void*) SkPathGlue::lineTo__FF},
+ {"native_rLineTo","(IFF)V", (void*) SkPathGlue::rLineTo},
+ {"native_quadTo","(IFFFF)V", (void*) SkPathGlue::quadTo__FFFF},
+ {"native_rQuadTo","(IFFFF)V", (void*) SkPathGlue::rQuadTo},
+ {"native_cubicTo","(IFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF},
+ {"native_rCubicTo","(IFFFFFF)V", (void*) SkPathGlue::rCubicTo},
+ {"native_arcTo","(ILandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo},
+ {"native_close","(I)V", (void*) SkPathGlue::close},
+ {"native_addRect","(ILandroid/graphics/RectF;I)V", (void*) SkPathGlue::addRect__RectFI},
+ {"native_addRect","(IFFFFI)V", (void*) SkPathGlue::addRect__FFFFI},
+ {"native_addOval","(ILandroid/graphics/RectF;I)V", (void*) SkPathGlue::addOval},
+ {"native_addCircle","(IFFFI)V", (void*) SkPathGlue::addCircle},
+ {"native_addArc","(ILandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc},
+ {"native_addRoundRect","(ILandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY},
+ {"native_addRoundRect","(ILandroid/graphics/RectF;[FI)V", (void*) SkPathGlue::addRoundRect8},
+ {"native_addPath","(IIFF)V", (void*) SkPathGlue::addPath__PathFF},
+ {"native_addPath","(II)V", (void*) SkPathGlue::addPath__Path},
+ {"native_addPath","(III)V", (void*) SkPathGlue::addPath__PathMatrix},
+ {"native_offset","(IFFI)V", (void*) SkPathGlue::offset__FFPath},
+ {"native_offset","(IFF)V", (void*) SkPathGlue::offset__FF},
+ {"native_setLastPoint","(IFF)V", (void*) SkPathGlue::setLastPoint},
+ {"native_transform","(III)V", (void*) SkPathGlue::transform__MatrixPath},
+ {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix}
+};
+
+int register_android_graphics_Path(JNIEnv* env) {
+ int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Path", methods,
+ sizeof(methods) / sizeof(methods[0]));
+ return result;
+}
+
+}
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
new file mode 100644
index 0000000..0ecb004
--- /dev/null
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -0,0 +1,113 @@
+#include <jni.h>
+#include "GraphicsJNI.h"
+
+#include "SkPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkDiscretePathEffect.h"
+#include "Sk1DPathEffect.h"
+#include "SkTemplates.h"
+
+class SkPathEffectGlue {
+public:
+
+ static void destructor(JNIEnv* env, jobject, SkPathEffect* effect) {
+ effect->safeUnref();
+ }
+
+ static SkPathEffect* Compose_constructor(JNIEnv* env, jobject,
+ SkPathEffect* outer, SkPathEffect* inner) {
+ return new SkComposePathEffect(outer, inner);
+ }
+
+ static SkPathEffect* Sum_constructor(JNIEnv* env, jobject,
+ SkPathEffect* first, SkPathEffect* second) {
+ return new SkSumPathEffect(first, second);
+ }
+
+ static SkPathEffect* Dash_constructor(JNIEnv* env, jobject,
+ jfloatArray intervalArray, float phase) {
+ AutoJavaFloatArray autoInterval(env, intervalArray);
+ int count = autoInterval.length() & ~1; // even number
+ float* values = autoInterval.ptr();
+
+ SkAutoSTMalloc<32, SkScalar> storage(count);
+ SkScalar* intervals = storage.get();
+ for (int i = 0; i < count; i++) {
+ intervals[i] = SkFloatToScalar(values[i]);
+ }
+ return new SkDashPathEffect(intervals, count, SkFloatToScalar(phase));
+ }
+
+ static SkPathEffect* OneD_constructor(JNIEnv* env, jobject,
+ const SkPath* shape, float advance, float phase, int style) {
+ SkASSERT(shape != NULL);
+ return new SkPath1DPathEffect(*shape, SkFloatToScalar(advance),
+ SkFloatToScalar(phase), (SkPath1DPathEffect::Style)style);
+ }
+
+ static SkPathEffect* Corner_constructor(JNIEnv* env, jobject, float radius){
+ return new SkCornerPathEffect(SkFloatToScalar(radius));
+ }
+
+ static SkPathEffect* Discrete_constructor(JNIEnv* env, jobject,
+ float length, float deviation) {
+ return new SkDiscretePathEffect(SkFloatToScalar(length),
+ SkFloatToScalar(deviation));
+ }
+
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static JNINativeMethod gPathEffectMethods[] = {
+ { "nativeDestructor", "(I)V", (void*)SkPathEffectGlue::destructor }
+};
+
+static JNINativeMethod gComposePathEffectMethods[] = {
+ { "nativeCreate", "(II)I", (void*)SkPathEffectGlue::Compose_constructor }
+};
+
+static JNINativeMethod gSumPathEffectMethods[] = {
+ { "nativeCreate", "(II)I", (void*)SkPathEffectGlue::Sum_constructor }
+};
+
+static JNINativeMethod gDashPathEffectMethods[] = {
+ { "nativeCreate", "([FF)I", (void*)SkPathEffectGlue::Dash_constructor }
+};
+
+static JNINativeMethod gPathDashPathEffectMethods[] = {
+ { "nativeCreate", "(IFFI)I", (void*)SkPathEffectGlue::OneD_constructor }
+};
+
+static JNINativeMethod gCornerPathEffectMethods[] = {
+ { "nativeCreate", "(F)I", (void*)SkPathEffectGlue::Corner_constructor }
+};
+
+static JNINativeMethod gDiscretePathEffectMethods[] = {
+ { "nativeCreate", "(FF)I", (void*)SkPathEffectGlue::Discrete_constructor }
+};
+
+#include <android_runtime/AndroidRuntime.h>
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
+ SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+int register_android_graphics_PathEffect(JNIEnv* env);
+int register_android_graphics_PathEffect(JNIEnv* env)
+{
+ int result;
+
+ REG(env, "android/graphics/PathEffect", gPathEffectMethods);
+ REG(env, "android/graphics/ComposePathEffect", gComposePathEffectMethods);
+ REG(env, "android/graphics/SumPathEffect", gSumPathEffectMethods);
+ REG(env, "android/graphics/DashPathEffect", gDashPathEffectMethods);
+ REG(env, "android/graphics/PathDashPathEffect", gPathDashPathEffectMethods);
+ REG(env, "android/graphics/CornerPathEffect", gCornerPathEffectMethods);
+ REG(env, "android/graphics/DiscretePathEffect", gDiscretePathEffectMethods);
+
+ return 0;
+}
+
diff --git a/core/jni/android/graphics/PathMeasure.cpp b/core/jni/android/graphics/PathMeasure.cpp
new file mode 100644
index 0000000..51a3f3a
--- /dev/null
+++ b/core/jni/android/graphics/PathMeasure.cpp
@@ -0,0 +1,138 @@
+/* libs/android_runtime/android/graphics/PathMeasure.cpp
+**
+** Copyright 2007, 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.
+*/
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkPathMeasure.h"
+
+/* We declare an explicit pair, so that we don't have to rely on the java
+ client to be sure not to edit the path while we have an active measure
+ object associated with it.
+
+ This costs us the copy of the path, for the sake of not allowing a bad
+ java client to randomly crash (since we can't detect the case where the
+ native path has been modified).
+
+ The C side does have this risk, but it chooses for speed over safety. If it
+ later changes this, and is internally safe from changes to the path, then
+ we can remove this explicit copy from our JNI code.
+
+ Note that we do not have a reference on the java side to the java path.
+ Were we to not need the native copy here, we would want to add a java
+ reference, so that the java path would not get GD'd while the measure object
+ was still alive.
+*/
+struct PathMeasurePair {
+ PathMeasurePair() {}
+ PathMeasurePair(const SkPath& path, bool forceClosed)
+ : fPath(path), fMeasure(fPath, forceClosed) {}
+
+ SkPath fPath; // copy of the user's path
+ SkPathMeasure fMeasure; // this guy points to fPath
+};
+
+namespace android {
+
+class SkPathMeasureGlue {
+public:
+
+ static PathMeasurePair* create(JNIEnv* env, jobject clazz, const SkPath* path, jboolean forceClosed) {
+ return path ? new PathMeasurePair(*path, forceClosed) : new PathMeasurePair;
+ }
+
+ static void setPath(JNIEnv* env, jobject clazz, PathMeasurePair* pair, const SkPath* path, jboolean forceClosed) {
+ if (NULL == path) {
+ pair->fPath.reset();
+ } else {
+ pair->fPath = *path;
+ }
+ pair->fMeasure.setPath(&pair->fPath, forceClosed);
+ }
+
+ static jfloat getLength(JNIEnv* env, jobject clazz, PathMeasurePair* pair) {
+ return SkScalarToFloat(pair->fMeasure.getLength());
+ }
+
+ static void convertTwoElemFloatArray(JNIEnv* env, jfloatArray array, const SkScalar src[2]) {
+ AutoJavaFloatArray autoArray(env, array, 2);
+ jfloat* ptr = autoArray.ptr();
+ ptr[0] = SkScalarToFloat(src[0]);
+ ptr[1] = SkScalarToFloat(src[1]);
+ }
+
+ static jboolean getPosTan(JNIEnv* env, jobject clazz, PathMeasurePair* pair, jfloat dist, jfloatArray pos, jfloatArray tan) {
+ SkScalar tmpPos[2], tmpTan[2];
+ SkScalar* posPtr = pos ? tmpPos : NULL;
+ SkScalar* tanPtr = tan ? tmpTan : NULL;
+
+ if (!pair->fMeasure.getPosTan(SkFloatToScalar(dist), (SkPoint*)posPtr, (SkVector*)tanPtr)) {
+ return false;
+ }
+
+ if (pos) {
+ convertTwoElemFloatArray(env, pos, tmpPos);
+ }
+ if (tan) {
+ convertTwoElemFloatArray(env, tan, tmpTan);
+ }
+ return true;
+ }
+
+ static jboolean getMatrix(JNIEnv* env, jobject clazz, PathMeasurePair* pair, jfloat dist,
+ SkMatrix* matrix, int flags) {
+ return pair->fMeasure.getMatrix(SkFloatToScalar(dist), matrix, (SkPathMeasure::MatrixFlags)flags);
+ }
+
+ static jboolean getSegment(JNIEnv* env, jobject clazz, PathMeasurePair* pair, jfloat startF,
+ jfloat stopF, SkPath* dst, jboolean startWithMoveTo) {
+ return pair->fMeasure.getSegment(SkFloatToScalar(startF), SkFloatToScalar(stopF), dst, startWithMoveTo);
+ }
+
+ static jboolean isClosed(JNIEnv* env, jobject clazz, PathMeasurePair* pair) {
+ return pair->fMeasure.isClosed();
+ }
+
+ static jboolean nextContour(JNIEnv* env, jobject clazz, PathMeasurePair* pair) {
+ return pair->fMeasure.nextContour();
+ }
+
+ static void destroy(JNIEnv* env, jobject clazz, PathMeasurePair* pair) {
+ delete pair;
+ }
+};
+
+static JNINativeMethod methods[] = {
+ {"native_create", "(IZ)I", (void*) SkPathMeasureGlue::create },
+ {"native_setPath", "(IIZ)V", (void*) SkPathMeasureGlue::setPath },
+ {"native_getLength", "(I)F", (void*) SkPathMeasureGlue::getLength },
+ {"native_getPosTan", "(IF[F[F)Z", (void*) SkPathMeasureGlue::getPosTan },
+ {"native_getMatrix", "(IFII)Z", (void*) SkPathMeasureGlue::getMatrix },
+ {"native_getSegment", "(IFFIZ)Z", (void*) SkPathMeasureGlue::getSegment },
+ {"native_isClosed", "(I)Z", (void*) SkPathMeasureGlue::isClosed },
+ {"native_nextContour", "(I)Z", (void*) SkPathMeasureGlue::nextContour },
+ {"native_destroy", "(I)V", (void*) SkPathMeasureGlue::destroy }
+};
+
+int register_android_graphics_PathMeasure(JNIEnv* env) {
+ int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/PathMeasure", methods,
+ sizeof(methods) / sizeof(methods[0]));
+ return result;
+}
+
+}
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
new file mode 100644
index 0000000..5ab6dd3
--- /dev/null
+++ b/core/jni/android/graphics/Picture.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkCanvas.h"
+#include "SkPicture.h"
+#include "SkTemplates.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+namespace android {
+
+class SkPictureGlue {
+public:
+ static SkPicture* newPicture(JNIEnv* env, jobject, const SkPicture* src) {
+ if (src) {
+ return new SkPicture(*src);
+ } else {
+ return new SkPicture;
+ }
+ }
+
+ static SkPicture* deserialize(JNIEnv* env, jobject, jobject jstream,
+ jbyteArray jstorage) {
+ SkPicture* picture = NULL;
+ SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
+ if (strm) {
+ picture = new SkPicture(strm);
+ delete strm;
+ }
+ return picture;
+ }
+
+ static void killPicture(JNIEnv* env, jobject, SkPicture* picture) {
+ SkASSERT(picture);
+ delete picture;
+ }
+
+ static void draw(JNIEnv* env, jobject, SkCanvas* canvas,
+ SkPicture* picture) {
+ SkASSERT(canvas);
+ SkASSERT(picture);
+ picture->draw(canvas);
+ }
+
+ static bool serialize(JNIEnv* env, jobject, SkPicture* picture,
+ jobject jstream, jbyteArray jstorage) {
+ SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
+
+ if (NULL != strm) {
+ picture->serialize(strm);
+ delete strm;
+ return true;
+ }
+ return false;
+ }
+
+ static int getWidth(JNIEnv* env, jobject jpic) {
+ NPE_CHECK_RETURN_ZERO(env, jpic);
+ return GraphicsJNI::getNativePicture(env, jpic)->width();
+ }
+
+ static int getHeight(JNIEnv* env, jobject jpic) {
+ NPE_CHECK_RETURN_ZERO(env, jpic);
+ return GraphicsJNI::getNativePicture(env, jpic)->height();
+ }
+
+ static SkCanvas* beginRecording(JNIEnv* env, jobject, SkPicture* pict,
+ int w, int h) {
+ // beginRecording does not ref its return value, it just returns it.
+ SkCanvas* canvas = pict->beginRecording(w, h);
+ // the java side will wrap this guy in a Canvas.java, which will call
+ // unref in its finalizer, so we have to ref it here, so that both that
+ // Canvas.java and our picture can both be owners
+ canvas->ref();
+ return canvas;
+ }
+
+ static void endRecording(JNIEnv* env, jobject, SkPicture* pict) {
+ pict->endRecording();
+ }
+};
+
+static JNINativeMethod gPictureMethods[] = {
+ {"getWidth", "()I", (void*) SkPictureGlue::getWidth},
+ {"getHeight", "()I", (void*) SkPictureGlue::getHeight},
+ {"nativeConstructor", "(I)I", (void*) SkPictureGlue::newPicture},
+ {"nativeCreateFromStream", "(Ljava/io/InputStream;[B)I", (void*)SkPictureGlue::deserialize},
+ {"nativeBeginRecording", "(III)I", (void*) SkPictureGlue::beginRecording},
+ {"nativeEndRecording", "(I)V", (void*) SkPictureGlue::endRecording},
+ {"nativeDraw", "(II)V", (void*) SkPictureGlue::draw},
+ {"nativeWriteToStream", "(ILjava/io/OutputStream;[B)Z", (void*)SkPictureGlue::serialize},
+ {"nativeDestructor","(I)V", (void*) SkPictureGlue::killPicture}
+};
+
+#include <android_runtime/AndroidRuntime.h>
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
+ SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+int register_android_graphics_Picture(JNIEnv* env) {
+ int result;
+
+ REG(env, "android/graphics/Picture", gPictureMethods);
+
+ return result;
+}
+
+}
+
+
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
new file mode 100644
index 0000000..47de601
--- /dev/null
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -0,0 +1,52 @@
+/* libs/android_runtime/android/graphics/PorterDuff.cpp
+**
+** Copyright 2006, 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.
+*/
+
+// This file was generated from the C++ include file: SkPorterDuff.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkPorterDuff.h"
+
+namespace android {
+
+class SkPorterDuffGlue {
+public:
+
+ static SkXfermode* CreateXfermode(JNIEnv* env, jobject,
+ SkPorterDuff::Mode mode) {
+ return SkPorterDuff::CreateXfermode(mode);
+ }
+
+};
+
+static JNINativeMethod methods[] = {
+ {"nativeCreateXfermode","(I)I", (void*) SkPorterDuffGlue::CreateXfermode},
+};
+
+int register_android_graphics_PorterDuff(JNIEnv* env) {
+ int result = AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/PorterDuffXfermode", methods,
+ sizeof(methods) / sizeof(methods[0]));
+ return result;
+}
+
+}
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
new file mode 100644
index 0000000..db70b57
--- /dev/null
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -0,0 +1,50 @@
+/* libs/android_runtime/android/graphics/Rasterizer.cpp
+**
+** Copyright 2006, 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.
+*/
+
+// This file was generated from the C++ include file: SkRasterizer.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkRasterizer.h"
+
+namespace android {
+
+class SkRasterizerGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject clazz, SkRasterizer* obj) {
+ obj->safeUnref();
+ }
+
+};
+
+static JNINativeMethod methods[] = {
+ {"finalizer", "(I)V", (void*) SkRasterizerGlue::finalizer}
+};
+
+int register_android_graphics_Rasterizer(JNIEnv* env) {
+ int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Rasterizer", methods,
+ sizeof(methods) / sizeof(methods[0]));
+ return result;
+}
+
+}
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
new file mode 100644
index 0000000..00d6cd9
--- /dev/null
+++ b/core/jni/android/graphics/Region.cpp
@@ -0,0 +1,231 @@
+#include "SkRegion.h"
+#include "SkPath.h"
+#include "GraphicsJNI.h"
+
+#include <jni.h>
+
+static jfieldID gRegion_nativeInstanceFieldID;
+
+static inline SkRegion* GetSkRegion(JNIEnv* env, jobject regionObject) {
+ SkRegion* rgn = (SkRegion*)env->GetIntField(regionObject, gRegion_nativeInstanceFieldID);
+ SkASSERT(rgn != NULL);
+ return rgn;
+}
+
+static SkRegion* Region_constructor(JNIEnv* env, jobject) {
+ return new SkRegion;
+}
+
+static void Region_destructor(JNIEnv* env, jobject, SkRegion* region) {
+ SkASSERT(region);
+ delete region;
+}
+
+static void Region_setRegion(JNIEnv* env, jobject, SkRegion* dst, const SkRegion* src) {
+ SkASSERT(dst && src);
+ *dst = *src;
+}
+
+static jboolean Region_setRect(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom) {
+ return dst->setRect(left, top, right, bottom);
+}
+
+static jboolean Region_setPath(JNIEnv* env, jobject, SkRegion* dst,
+ const SkPath* path, const SkRegion* clip) {
+ SkASSERT(dst && path && clip);
+ return dst->setPath(*path, *clip);
+}
+
+static jboolean Region_getBounds(JNIEnv* env, jobject, SkRegion* region, jobject rectBounds) {
+ GraphicsJNI::irect_to_jrect(region->getBounds(), env, rectBounds);
+ return !region->isEmpty();
+}
+
+static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, const SkRegion* region, SkPath* path) {
+ return region->getBoundaryPath(path);
+}
+
+static jboolean Region_op0(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom, int op) {
+ SkIRect ir;
+
+ ir.set(left, top, right, bottom);
+ return dst->op(ir, (SkRegion::Op)op);
+}
+
+static jboolean Region_op1(JNIEnv* env, jobject, SkRegion* dst, jobject rectObject, const SkRegion* region, int op) {
+ SkIRect ir;
+ GraphicsJNI::jrect_to_irect(env, rectObject, &ir);
+ return dst->op(ir, *region, (SkRegion::Op)op);
+}
+
+static jboolean Region_op2(JNIEnv* env, jobject, SkRegion* dst, const SkRegion* region1, const SkRegion* region2, int op) {
+ return dst->op(*region1, *region2, (SkRegion::Op)op);
+}
+
+//////////////////////////////////// These are methods, not static
+
+static jboolean Region_isEmpty(JNIEnv* env, jobject region) {
+ return GetSkRegion(env, region)->isEmpty();
+}
+
+static jboolean Region_isRect(JNIEnv* env, jobject region) {
+ return GetSkRegion(env, region)->isRect();
+}
+
+static jboolean Region_isComplex(JNIEnv* env, jobject region) {
+ return GetSkRegion(env, region)->isComplex();
+}
+
+static jboolean Region_contains(JNIEnv* env, jobject region, int x, int y) {
+ return GetSkRegion(env, region)->contains(x, y);
+}
+
+static jboolean Region_quickContains(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
+ return GetSkRegion(env, region)->quickContains(left, top, right, bottom);
+}
+
+static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
+ SkIRect ir;
+ ir.set(left, top, right, bottom);
+ return GetSkRegion(env, region)->quickReject(ir);
+}
+
+static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) {
+ return GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other));
+}
+
+static void Region_translate(JNIEnv* env, jobject region, int x, int y, jobject dst) {
+ SkRegion* rgn = GetSkRegion(env, region);
+ if (dst)
+ rgn->translate(x, y, GetSkRegion(env, dst));
+ else
+ rgn->translate(x, y);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "Parcel.h"
+#include "android_util_Binder.h"
+
+static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
+{
+ if (parcel == NULL) {
+ return NULL;
+ }
+
+ android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+ SkRegion* region = new SkRegion;
+ size_t size = p->readInt32();
+ region->unflatten(p->readInplace(size));
+
+ return region;
+}
+
+static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, const SkRegion* region, jobject parcel)
+{
+ if (parcel == NULL) {
+ return false;
+ }
+
+ android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+ size_t size = region->flatten(NULL);
+ p->writeInt32(size);
+ region->flatten(p->writeInplace(size));
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct RgnIterPair {
+ SkRegion fRgn; // a copy of the caller's region
+ SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn)
+
+ RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
+ // have our iterator reference our copy (fRgn), so we know it will be
+ // unchanged for the lifetime of the iterator
+ fIter.reset(fRgn);
+ }
+};
+
+static RgnIterPair* RegionIter_constructor(JNIEnv* env, jobject, const SkRegion* region)
+{
+ SkASSERT(region);
+ return new RgnIterPair(*region);
+}
+
+static void RegionIter_destructor(JNIEnv* env, jobject, RgnIterPair* pair)
+{
+ SkASSERT(pair);
+ delete pair;
+}
+
+static jboolean RegionIter_next(JNIEnv* env, jobject, RgnIterPair* pair, jobject rectObject)
+{
+ // the caller has checked that rectObject is not nul
+ SkASSERT(pair);
+ SkASSERT(rectObject);
+
+ if (!pair->fIter.done()) {
+ GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject);
+ pair->fIter.next();
+ return true;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gRegionIterMethods[] = {
+ { "nativeConstructor", "(I)I", (void*)RegionIter_constructor },
+ { "nativeDestructor", "(I)V", (void*)RegionIter_destructor },
+ { "nativeNext", "(ILandroid/graphics/Rect;)Z", (void*)RegionIter_next }
+};
+
+static JNINativeMethod gRegionMethods[] = {
+ // these are static methods
+ { "nativeConstructor", "()I", (void*)Region_constructor },
+ { "nativeDestructor", "(I)V", (void*)Region_destructor },
+ { "nativeSetRegion", "(II)Z", (void*)Region_setRegion },
+ { "nativeSetRect", "(IIIII)Z", (void*)Region_setRect },
+ { "nativeSetPath", "(III)Z", (void*)Region_setPath },
+ { "nativeGetBounds", "(ILandroid/graphics/Rect;)Z", (void*)Region_getBounds },
+ { "nativeGetBoundaryPath", "(II)Z", (void*)Region_getBoundaryPath },
+ { "nativeOp", "(IIIIII)Z", (void*)Region_op0 },
+ { "nativeOp", "(ILandroid/graphics/Rect;II)Z", (void*)Region_op1 },
+ { "nativeOp", "(IIII)Z", (void*)Region_op2 },
+ // these are methods that take the java region object
+ { "isEmpty", "()Z", (void*)Region_isEmpty },
+ { "isRect", "()Z", (void*)Region_isRect },
+ { "isComplex", "()Z", (void*)Region_isComplex },
+ { "contains", "(II)Z", (void*)Region_contains },
+ { "quickContains", "(IIII)Z", (void*)Region_quickContains },
+ { "quickReject", "(IIII)Z", (void*)Region_quickRejectIIII },
+ { "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn },
+ { "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate },
+ // parceling methods
+ { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I", (void*)Region_createFromParcel },
+ { "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel }
+};
+
+int register_android_graphics_Region(JNIEnv* env);
+int register_android_graphics_Region(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/graphics/Region");
+ SkASSERT(clazz);
+
+ gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "I");
+ SkASSERT(gRegion_nativeInstanceFieldID);
+
+ int result = android::AndroidRuntime::registerNativeMethods(env, "android/graphics/Region",
+ gRegionMethods, SK_ARRAY_COUNT(gRegionMethods));
+ if (result < 0)
+ return result;
+
+ return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
+ gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
+}
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
new file mode 100644
index 0000000..71dc875
--- /dev/null
+++ b/core/jni/android/graphics/Shader.cpp
@@ -0,0 +1,273 @@
+#include <jni.h>
+#include "GraphicsJNI.h"
+
+#include "SkShader.h"
+#include "SkGradientShader.h"
+#include "SkPorterDuff.h"
+#include "SkShaderExtras.h"
+#include "SkTemplates.h"
+#include "SkXfermode.h"
+
+static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, jfloatArray hsvArray)
+{
+ SkScalar hsv[3];
+ SkRGBToHSV(red, green, blue, hsv);
+
+ AutoJavaFloatArray autoHSV(env, hsvArray, 3);
+ float* values = autoHSV.ptr();
+ for (int i = 0; i < 3; i++) {
+ values[i] = SkScalarToFloat(hsv[i]);
+ }
+}
+
+static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArray)
+{
+ AutoJavaFloatArray autoHSV(env, hsvArray, 3);
+ float* values = autoHSV.ptr();;
+ SkScalar hsv[3];
+
+ for (int i = 0; i < 3; i++) {
+ hsv[i] = SkFloatToScalar(values[i]);
+ }
+
+ return SkHSVToColor(alpha, hsv);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static void Shader_destructor(JNIEnv* env, jobject, SkShader* shader)
+{
+ SkASSERT(shader != NULL);
+ shader->unref();
+}
+
+static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix)
+{
+ SkASSERT(shader != NULL);
+ return shader->getLocalMatrix(matrix);
+}
+
+static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const SkMatrix* matrix)
+{
+ SkASSERT(shader != NULL);
+
+ if (NULL == matrix) {
+ shader->resetLocalMatrix();
+ }
+ else {
+ shader->setLocalMatrix(*matrix);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static SkShader* BitmapShader_constructor(JNIEnv* env, jobject, const SkBitmap* bitmap,
+ int tileModeX, int tileModeY)
+{
+ return SkShader::CreateBitmapShader(*bitmap,
+ (SkShader::TileMode)tileModeX,
+ (SkShader::TileMode)tileModeY);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static SkShader* LinearGradient_create1(JNIEnv* env, jobject,
+ float x0, float y0, float x1, float y1,
+ jintArray colorArray, jfloatArray posArray, int tileMode)
+{
+ SkPoint pts[2];
+ 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);
+
+ SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
+ SkScalar* pos = NULL;
+
+ if (posArray) {
+ AutoJavaFloatArray autoPos(env, posArray, count);
+ const float* posValues = autoPos.ptr();
+ pos = (SkScalar*)storage.get();
+ for (size_t i = 0; i < count; i++)
+ pos[i] = SkFloatToScalar(posValues[i]);
+ }
+
+ SkShader* shader = SkGradientShader::CreateLinear(pts, (const SkColor*)colorValues,
+ pos, count, (SkShader::TileMode)tileMode);
+ env->ReleaseIntArrayElements(colorArray, colorValues, 0);
+ return shader;
+}
+
+static SkShader* LinearGradient_create2(JNIEnv* env, jobject,
+ float x0, float y0, float x1, float y1,
+ int color0, int color1, int tileMode)
+{
+ SkPoint pts[2];
+ pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
+ pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));
+
+ SkColor colors[2];
+ colors[0] = color0;
+ colors[1] = color1;
+
+ return SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
+ float x, float y, float radius,
+ jintArray colorArray, jfloatArray posArray, int tileMode)
+{
+ SkPoint center;
+ center.set(SkFloatToScalar(x), SkFloatToScalar(y));
+
+ size_t count = env->GetArrayLength(colorArray);
+ int* colorValues = env->GetIntArrayElements(colorArray, NULL);
+
+ SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
+ SkScalar* pos = NULL;
+
+ if (posArray) {
+ AutoJavaFloatArray autoPos(env, posArray, count);
+ const float* posValues = autoPos.ptr();
+ pos = (SkScalar*)storage.get();
+ for (size_t i = 0; i < count; i++)
+ 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);
+ return shader;
+}
+
+static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
+ float x, float y, float radius,
+ int color0, int color1, int tileMode)
+{
+ SkPoint center;
+ center.set(SkFloatToScalar(x), SkFloatToScalar(y));
+
+ SkColor colors[2];
+ colors[0] = color0;
+ colors[1] = color1;
+
+ return SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL,
+ 2, (SkShader::TileMode)tileMode);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+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);
+
+ SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
+ SkScalar* pos = NULL;
+
+ if (NULL != jpositions) {
+ AutoJavaFloatArray autoPos(env, jpositions, count);
+ const float* posValues = autoPos.ptr();
+ pos = (SkScalar*)storage.get();
+ 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);
+ return shader;
+}
+
+static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
+ int color0, int color1)
+{
+ SkColor colors[2];
+ colors[0] = color0;
+ colors[1] = color1;
+ return SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y),
+ colors, NULL, 2);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static SkShader* ComposeShader_create1(JNIEnv* env, jobject,
+ SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
+{
+ return new SkComposeShader(shaderA, shaderB, mode);
+}
+
+static SkShader* ComposeShader_create2(JNIEnv* env, jobject,
+ SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode mode)
+{
+ SkAutoUnref au(SkPorterDuff::CreateXfermode(mode));
+
+ return new SkComposeShader(shaderA, shaderB, (SkXfermode*)au.get());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static JNINativeMethod gColorMethods[] = {
+ { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
+ { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
+};
+
+static JNINativeMethod gShaderMethods[] = {
+ { "nativeDestructor", "(I)V", (void*)Shader_destructor },
+ { "nativeGetLocalMatrix", "(II)Z", (void*)Shader_getLocalMatrix },
+ { "nativeSetLocalMatrix", "(II)V", (void*)Shader_setLocalMatrix }
+};
+
+static JNINativeMethod gBitmapShaderMethods[] = {
+ { "nativeCreate", "(III)I", (void*)BitmapShader_constructor }
+};
+
+static JNINativeMethod gLinearGradientMethods[] = {
+ { "nativeCreate1", "(FFFF[I[FI)I", (void*)LinearGradient_create1 },
+ { "nativeCreate2", "(FFFFIII)I", (void*)LinearGradient_create2 }
+};
+
+static JNINativeMethod gRadialGradientMethods[] = {
+ {"nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 },
+ {"nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 }
+};
+
+static JNINativeMethod gSweepGradientMethods[] = {
+ {"nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 },
+ {"nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 }
+};
+
+static JNINativeMethod gComposeShaderMethods[] = {
+ {"nativeCreate1", "(III)I", (void*)ComposeShader_create1 },
+ {"nativeCreate2", "(III)I", (void*)ComposeShader_create2 }
+};
+
+#include <android_runtime/AndroidRuntime.h>
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+int register_android_graphics_Shader(JNIEnv* env);
+int register_android_graphics_Shader(JNIEnv* env)
+{
+ int result;
+
+ REG(env, "android/graphics/Color", gColorMethods);
+ REG(env, "android/graphics/Shader", gShaderMethods);
+ REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
+ REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
+ REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
+ REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
+ REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
+
+ return result;
+}
+
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
new file mode 100644
index 0000000..32954ce
--- /dev/null
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -0,0 +1,156 @@
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "GraphicsJNI.h"
+#include <android_runtime/android_util_AssetManager.h>
+#include "SkStream.h"
+#include "SkTypeface.h"
+#include <utils/AssetManager.h>
+
+using namespace android;
+
+class AutoJavaStringToUTF8 {
+public:
+ AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str)
+ {
+ fCStr = env->GetStringUTFChars(str, NULL);
+ }
+ ~AutoJavaStringToUTF8()
+ {
+ fEnv->ReleaseStringUTFChars(fJStr, fCStr);
+ }
+ const char* c_str() const { return fCStr; }
+
+private:
+ JNIEnv* fEnv;
+ jstring fJStr;
+ const char* fCStr;
+};
+
+static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name,
+ SkTypeface::Style style) {
+ SkTypeface* face;
+
+ if (NULL == name) {
+ face = SkTypeface::Create(NULL, (SkTypeface::Style)style);
+ }
+ else {
+ AutoJavaStringToUTF8 str(env, name);
+ face = SkTypeface::Create(str.c_str(), style);
+ }
+ return face;
+}
+
+static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* family, int style) {
+ return SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
+}
+
+static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
+ face->unref();
+}
+
+static int Typeface_getStyle(JNIEnv* env, jobject obj, SkTypeface* face) {
+ return face->getStyle();
+}
+
+class AssetStream : public SkStream {
+public:
+ AssetStream(Asset* asset, bool hasMemoryBase) : fAsset(asset)
+ {
+ fMemoryBase = hasMemoryBase ? fAsset->getBuffer(false) : NULL;
+ }
+
+ virtual ~AssetStream()
+ {
+ delete fAsset;
+ }
+
+ virtual const void* getMemoryBase()
+ {
+ return fMemoryBase;
+ }
+
+ virtual bool rewind()
+ {
+ off_t pos = fAsset->seek(0, SEEK_SET);
+ return pos != (off_t)-1;
+ }
+
+ virtual size_t read(void* buffer, size_t size)
+ {
+ ssize_t amount;
+
+ if (NULL == buffer)
+ {
+ if (0 == size) // caller is asking us for our total length
+ return fAsset->getLength();
+
+ // asset->seek returns new total offset
+ // we want to return amount that was skipped
+
+ off_t oldOffset = fAsset->seek(0, SEEK_CUR);
+ if (-1 == oldOffset)
+ return 0;
+ off_t newOffset = fAsset->seek(size, SEEK_CUR);
+ if (-1 == newOffset)
+ return 0;
+
+ amount = newOffset - oldOffset;
+ }
+ else
+ {
+ amount = fAsset->read(buffer, size);
+ }
+
+ if (amount < 0)
+ amount = 0;
+ return amount;
+ }
+
+private:
+ Asset* fAsset;
+ const void* fMemoryBase;
+};
+
+static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject,
+ jobject jassetMgr,
+ jstring jpath) {
+
+ NPE_CHECK_RETURN_ZERO(env, jassetMgr);
+ NPE_CHECK_RETURN_ZERO(env, jpath);
+
+ AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
+ if (NULL == mgr) {
+ return NULL;
+ }
+
+ AutoJavaStringToUTF8 str(env, jpath);
+ Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+ if (NULL == asset) {
+ return NULL;
+ }
+
+ return SkTypeface::CreateFromStream(new AssetStream(asset, true));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static JNINativeMethod gTypefaceMethods[] = {
+ { "nativeCreate", "(Ljava/lang/String;I)I", (void*)Typeface_create },
+ { "nativeCreateFromTypeface", "(II)I", (void*)Typeface_createFromTypeface },
+ { "nativeUnref", "(I)V", (void*)Typeface_unref },
+ { "nativeGetStyle", "(I)I", (void*)Typeface_getStyle },
+ { "nativeCreateFromAsset",
+ "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
+ (void*)Typeface_createFromAsset }
+};
+
+int register_android_graphics_Typeface(JNIEnv* env);
+int register_android_graphics_Typeface(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/Typeface",
+ gTypefaceMethods,
+ SK_ARRAY_COUNT(gTypefaceMethods));
+}
+
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
new file mode 100644
index 0000000..2b53d28
--- /dev/null
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkAvoidXfermode.h"
+#include "SkPixelXorXfermode.h"
+
+namespace android {
+
+class SkXfermodeGlue {
+public:
+
+ static void finalizer(JNIEnv* env, jobject, SkXfermode* obj)
+ {
+ obj->safeUnref();
+ }
+
+ static SkXfermode* avoid_create(JNIEnv* env, jobject, SkColor opColor,
+ U8CPU tolerance, SkAvoidXfermode::Mode mode)
+ {
+ return new SkAvoidXfermode(opColor, tolerance, mode);
+ }
+
+ static SkXfermode* pixelxor_create(JNIEnv* env, jobject, SkColor opColor)
+ {
+ return new SkPixelXorXfermode(opColor);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static JNINativeMethod gXfermodeMethods[] = {
+ {"finalizer", "(I)V", (void*) SkXfermodeGlue::finalizer}
+};
+
+static JNINativeMethod gAvoidMethods[] = {
+ {"nativeCreate", "(III)I", (void*) SkXfermodeGlue::avoid_create}
+};
+
+static JNINativeMethod gPixelXorMethods[] = {
+ {"nativeCreate", "(I)I", (void*) SkXfermodeGlue::pixelxor_create}
+};
+
+#include <android_runtime/AndroidRuntime.h>
+
+#define REG(env, name, array) \
+ result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
+ SK_ARRAY_COUNT(array)); \
+ if (result < 0) return result
+
+int register_android_graphics_Xfermode(JNIEnv* env) {
+ int result;
+
+ REG(env, "android/graphics/Xfermode", gXfermodeMethods);
+ REG(env, "android/graphics/AvoidXfermode", gAvoidMethods);
+ REG(env, "android/graphics/PixelXorXfermode", gPixelXorMethods);
+
+ return 0;
+}
+
+}
diff --git a/core/jni/android/opengl/poly.h b/core/jni/android/opengl/poly.h
new file mode 100644
index 0000000..85b44e3
--- /dev/null
+++ b/core/jni/android/opengl/poly.h
@@ -0,0 +1,51 @@
+/*
+**
+** Copyright 2007, 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.
+*/
+
+/* Based on the public domain code:
+ * Generic Convex Polygon Scan Conversion and Clipping
+ * by Paul Heckbert
+ * from "Graphics Gems", Academic Press, 1990
+ */
+
+
+#ifndef POLY_HDR
+#define POLY_HDR
+
+namespace android {
+
+#define POLY_NMAX 10 /* max #sides to a polygon; change if needed */
+/* note that poly_clip, given an n-gon as input, might output an (n+6)gon */
+/* POLY_NMAX=10 is thus appropriate if input polygons are triangles or quads */
+
+typedef struct { /* A POLYGON VERTEX */
+ float sx, sy, sz, sw; /* screen space position (sometimes homo.) */
+} Poly_vert;
+
+typedef struct { /* A POLYGON */
+ int n; /* number of sides */
+ Poly_vert vert[POLY_NMAX]; /* vertices */
+} Poly;
+
+#define POLY_CLIP_OUT 0 /* polygon entirely outside box */
+#define POLY_CLIP_PARTIAL 1 /* polygon partially inside */
+#define POLY_CLIP_IN 2 /* polygon entirely inside box */
+
+int poly_clip_to_frustum(Poly *p1);
+
+} // namespace android
+
+#endif
diff --git a/core/jni/android/opengl/poly_clip.cpp b/core/jni/android/opengl/poly_clip.cpp
new file mode 100644
index 0000000..04e4b17
--- /dev/null
+++ b/core/jni/android/opengl/poly_clip.cpp
@@ -0,0 +1,155 @@
+/*
+**
+** Copyright 2007, 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.
+*/
+
+/*
+ * Generic Convex Polygon Scan Conversion and Clipping
+ * by Paul Heckbert
+ * from "Graphics Gems", Academic Press, 1990
+ */
+
+/* Based on the public domain code:
+ * poly_clip.c: homogeneous 3-D convex polygon clipper
+ *
+ * Paul Heckbert 1985, Dec 1989
+ */
+
+#include "poly.h"
+#include "string.h"
+
+#define LOG_TAG "StreetView"
+#include <utils/Log.h>
+
+namespace android {
+
+#define SWAP(a, b, temp) {temp = a; a = b; b = temp;}
+#define COORD(vert, i) ((float *)(vert))[i]
+
+#define CLIP_AND_SWAP(elem, sign, k, p, q, r) { \
+ poly_clip_to_halfspace(p, q, &v->elem-(float *)v, sign, sign*k); \
+ if (q->n==0) {p1->n = 0; return POLY_CLIP_OUT;} \
+ SWAP(p, q, r); \
+}
+
+/*
+ * poly_clip_to_halfspace: clip convex polygon p against a plane,
+ * copying the portion satisfying sign*s[index] < k*sw into q,
+ * where s is a Poly_vert* cast as a float*.
+ * index is an index into the array of floats at each vertex, such that
+ * s[index] is sx, sy, or sz (screen space x, y, or z).
+ * Thus, to clip against xmin, use
+ * poly_clip_to_halfspace(p, q, XINDEX, -1., -xmin);
+ * and to clip against xmax, use
+ * poly_clip_to_halfspace(p, q, XINDEX, 1., xmax);
+ */
+
+void poly_clip_to_halfspace(Poly* p, Poly* q, int index, float sign, float k)
+{
+ unsigned long m;
+ float *up, *vp, *wp;
+ Poly_vert *v;
+ int i;
+ Poly_vert *u;
+ float t, tu, tv;
+
+ q->n = 0;
+
+ /* start with u=vert[n-1], v=vert[0] */
+ u = &p->vert[p->n-1];
+ tu = sign*COORD(u, index) - u->sw*k;
+ for (v= &p->vert[0], i=p->n; i>0; i--, u=v, tu=tv, v++) {
+ /* on old polygon (p), u is previous vertex, v is current vertex */
+ /* tv is negative if vertex v is in */
+ tv = sign*COORD(v, index) - v->sw*k;
+ if ((tu <= 0.0f) ^ (tv <= 0.0f)) {
+ /* edge crosses plane; add intersection point to q */
+ t = tu/(tu-tv);
+ up = (float *)u;
+ vp = (float *)v;
+ wp = (float *)&q->vert[q->n].sx;
+ for(int i = 0; i < 4; i++, wp++, up++, vp++) {
+ *wp = *up+t*(*vp-*up);
+ }
+ q->n++;
+ }
+ if (tv<=0.0f) /* vertex v is in, copy it to q */
+ q->vert[q->n++] = *v;
+ }
+}
+
+/*
+ * poly_clip_to_frustum: Clip the convex polygon p1 to the screen space frustum
+ * using the homogeneous screen coordinates (sx, sy, sz, sw) of each vertex,
+ * testing if v->sx/v->sw > box->x0 and v->sx/v->sw < box->x1,
+ * and similar tests for y and z, for each vertex v of the polygon.
+ * If polygon is entirely inside box, then POLY_CLIP_IN is returned.
+ * If polygon is entirely outside box, then POLY_CLIP_OUT is returned.
+ * Otherwise, if the polygon is cut by the box, p1 is modified and
+ * POLY_CLIP_PARTIAL is returned.
+ *
+ * Given an n-gon as input, clipping against 6 planes could generate an
+ * (n+6)gon, so POLY_NMAX in poly.h must be big enough to allow that.
+ */
+
+int poly_clip_to_frustum(Poly *p1)
+{
+ int x0out = 0, x1out = 0, y0out = 0, y1out = 0, z0out = 0, z1out = 0;
+ int i;
+ Poly_vert *v;
+ Poly p2, *p, *q, *r;
+
+ /* count vertices "outside" with respect to each of the six planes */
+ for (v=p1->vert, i=p1->n; i>0; i--, v++) {
+ float sw = v->sw;
+ if (v->sx < -sw) x0out++; /* out on left */
+ if (v->sx > sw) x1out++; /* out on right */
+ if (v->sy < -sw) y0out++; /* out on top */
+ if (v->sy > sw) y1out++; /* out on bottom */
+ if (v->sz < -sw) z0out++; /* out on near */
+ if (v->sz > sw) z1out++; /* out on far */
+ }
+
+ /* check if all vertices inside */
+ if (x0out+x1out+y0out+y1out+z0out+z1out == 0)
+ return POLY_CLIP_IN;
+
+ /* check if all vertices are "outside" any of the six planes */
+ if (x0out==p1->n || x1out==p1->n || y0out==p1->n ||
+ y1out==p1->n || z0out==p1->n || z1out==p1->n) {
+ p1->n = 0;
+ return POLY_CLIP_OUT;
+ }
+
+ /*
+ * now clip against each of the planes that might cut the polygon,
+ * at each step toggling between polygons p1 and p2
+ */
+ p = p1;
+ q = &p2;
+ if (x0out) CLIP_AND_SWAP(sx, -1.0f, -1.0f, p, q, r);
+ if (x1out) CLIP_AND_SWAP(sx, 1.0f, 1.0f, p, q, r);
+ if (y0out) CLIP_AND_SWAP(sy, -1.0f, -1.0f, p, q, r);
+ if (y1out) CLIP_AND_SWAP(sy, 1.0f, 1.0f, p, q, r);
+ if (z0out) CLIP_AND_SWAP(sz, -1.0f, -1.0f, p, q, r);
+ if (z1out) CLIP_AND_SWAP(sz, 1.0f, 1.0f, p, q, r);
+
+ /* if result ended up in p2 then copy it to p1 */
+ if (p==&p2)
+ memcpy(p1, &p2, sizeof(Poly)-(POLY_NMAX-p2.n)*sizeof(Poly_vert));
+ return POLY_CLIP_PARTIAL;
+}
+
+} // namespace android
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
new file mode 100644
index 0000000..5cd2ceb
--- /dev/null
+++ b/core/jni/android/opengl/util.cpp
@@ -0,0 +1,730 @@
+/**
+ ** Copyright 2007, 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.
+ */
+
+#include <nativehelper/jni.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
+
+#include <GLES/gl.h>
+
+#include <graphics/SkBitmap.h>
+
+#include "android_runtime/AndroidRuntime.h"
+
+#undef LOG_TAG
+#define LOG_TAG "OpenGLUtil"
+#include <utils/Log.h>
+#include "utils/misc.h"
+
+#include "poly.h"
+
+namespace android {
+
+static jclass gIAEClass;
+static jclass gUOEClass;
+
+static inline
+void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
+ pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
+ pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
+ pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
+ pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
+}
+
+class MallocHelper {
+public:
+ MallocHelper() {
+ mData = 0;
+ }
+
+ ~MallocHelper() {
+ if (mData != 0) {
+ free(mData);
+ }
+ }
+
+ void* alloc(size_t size) {
+ mData = malloc(size);
+ return mData;
+ }
+
+private:
+ void* mData;
+};
+
+#if 0
+static
+void
+print_poly(const char* label, Poly* pPoly) {
+ LOGI("%s: %d verts", label, pPoly->n);
+ for(int i = 0; i < pPoly->n; i++) {
+ Poly_vert* pV = & pPoly->vert[i];
+ LOGI("[%d] %g, %g, %g %g", i, pV->sx, pV->sy, pV->sz, pV->sw);
+ }
+}
+#endif
+
+static
+int visibilityTest(float* pWS, float* pPositions, int positionsLength,
+ unsigned short* pIndices, int indexCount) {
+ MallocHelper mallocHelper;
+ int result = POLY_CLIP_OUT;
+ float* pTransformed = 0;
+ int transformedIndexCount = 0;
+
+ if ( indexCount < 3 ) {
+ return POLY_CLIP_OUT;
+ }
+
+ // Find out how many vertices we need to transform
+ // We transform every vertex between the min and max indices, inclusive.
+ // This is OK for the data sets we expect to use with this function, but
+ // for other loads it might be better to use a more sophisticated vertex
+ // cache of some sort.
+
+ int minIndex = 65536;
+ int maxIndex = -1;
+ for(int i = 0; i < indexCount; i++) {
+ int index = pIndices[i];
+ if ( index < minIndex ) {
+ minIndex = index;
+ }
+ if ( index > maxIndex ) {
+ maxIndex = index;
+ }
+ }
+
+ if ( maxIndex * 3 > positionsLength) {
+ return -1;
+ }
+
+ transformedIndexCount = maxIndex - minIndex + 1;
+ pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
+
+ if (pTransformed == 0 ) {
+ return -2;
+ }
+
+ // Transform the vertices
+ {
+ const float* pSrc = pPositions + 3 * minIndex;
+ float* pDst = pTransformed;
+ for (int i = 0; i < transformedIndexCount; i++, pSrc += 3, pDst += 4) {
+ mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS, pDst);
+ }
+ }
+
+ // Clip the triangles
+
+ Poly poly;
+ float* pDest = & poly.vert[0].sx;
+ for (int i = 0; i < indexCount; i += 3) {
+ poly.n = 3;
+ memcpy(pDest , pTransformed + 4 * (pIndices[i ] - minIndex), 4 * sizeof(float));
+ memcpy(pDest + 4, pTransformed + 4 * (pIndices[i + 1] - minIndex), 4 * sizeof(float));
+ memcpy(pDest + 8, pTransformed + 4 * (pIndices[i + 2] - minIndex), 4 * sizeof(float));
+ result = poly_clip_to_frustum(&poly);
+ if ( result != POLY_CLIP_OUT) {
+ return result;
+ }
+ }
+
+ return result;
+}
+
+template<class JArray, class T>
+class ArrayHelper {
+public:
+ ArrayHelper(JNIEnv* env, JArray ref, jint offset, jint minSize) {
+ mEnv = env;
+ mRef = ref;
+ mOffset = offset;
+ mMinSize = minSize;
+ mBase = 0;
+ mReleaseParam = JNI_ABORT;
+ }
+
+ ~ArrayHelper() {
+ if (mBase) {
+ mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
+ }
+ }
+
+ // We seperate the bounds check from the initialization because we want to
+ // be able to bounds-check multiple arrays, and we can't throw an exception
+ // after we've called GetPrimitiveArrayCritical.
+
+ // Return true if the bounds check succeeded
+ // Else instruct the runtime to throw an exception
+
+ bool check() {
+ if ( ! mRef) {
+ mEnv->ThrowNew(gIAEClass, "array == null");
+ return false;
+ }
+ if ( mOffset < 0) {
+ mEnv->ThrowNew(gIAEClass, "offset < 0");
+ return false;
+ }
+ mLength = mEnv->GetArrayLength(mRef) - mOffset;
+ if (mLength < mMinSize ) {
+ mEnv->ThrowNew(gIAEClass, "length - offset < n");
+ return false;
+ }
+ return true;
+ }
+
+ // Bind the array.
+
+ void bind() {
+ mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
+ mData = mBase + mOffset;
+ }
+
+ void commitChanges() {
+ mReleaseParam = 0;
+ }
+
+ T* mData;
+ int mLength;
+
+private:
+ T* mBase;
+ JNIEnv* mEnv;
+ JArray mRef;
+ jint mOffset;
+ jint mMinSize;
+ int mReleaseParam;
+};
+
+typedef ArrayHelper<jfloatArray, float> FloatArrayHelper;
+typedef ArrayHelper<jcharArray, unsigned short> UnsignedShortArrayHelper;
+typedef ArrayHelper<jintArray, int> IntArrayHelper;
+typedef ArrayHelper<jbyteArray, unsigned char> ByteArrayHelper;
+
+inline float distance2(float x, float y, float z) {
+ return x * x + y * y + z * z;
+}
+
+inline float distance(float x, float y, float z) {
+ return sqrtf(distance2(x, y, z));
+}
+
+static
+void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
+ jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
+ jfloatArray sphere_ref, jint sphereOffset) {
+ FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
+ FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
+
+ bool checkOK = positions.check() && sphere.check();
+ if (! checkOK) {
+ return;
+ }
+
+ positions.bind();
+ sphere.bind();
+
+ if ( positionsCount < 1 ) {
+ env->ThrowNew(gIAEClass, "positionsCount < 1");
+ return;
+ }
+
+ const float* pSrc = positions.mData;
+
+ // find bounding box
+ float x0 = *pSrc++;
+ float x1 = x0;
+ float y0 = *pSrc++;
+ float y1 = y0;
+ float z0 = *pSrc++;
+ float z1 = z0;
+
+ for(int i = 1; i < positionsCount; i++) {
+ {
+ float x = *pSrc++;
+ if (x < x0) {
+ x0 = x;
+ }
+ else if (x > x1) {
+ x1 = x;
+ }
+ }
+ {
+ float y = *pSrc++;
+ if (y < y0) {
+ y0 = y;
+ }
+ else if (y > y1) {
+ y1 = y;
+ }
+ }
+ {
+ float z = *pSrc++;
+ if (z < z0) {
+ z0 = z;
+ }
+ else if (z > z1) {
+ z1 = z;
+ }
+ }
+ }
+
+ // Because we know our input meshes fit pretty well into bounding boxes,
+ // just take the diagonal of the box as defining our sphere.
+ float* pSphere = sphere.mData;
+ float dx = x1 - x0;
+ float dy = y1 - y0;
+ float dz = z1 - z0;
+ *pSphere++ = x0 + dx * 0.5f;
+ *pSphere++ = y0 + dy * 0.5f;
+ *pSphere++ = z0 + dz * 0.5f;
+ *pSphere++ = distance(dx, dy, dz) * 0.5f;
+
+ sphere.commitChanges();
+}
+
+static void normalizePlane(float* p) {
+ float rdist = 1.0f / distance(p[0], p[1], p[2]);
+ for(int i = 0; i < 4; i++) {
+ p[i] *= rdist;
+ }
+}
+
+static inline float dot3(float x0, float y0, float z0, float x1, float y1, float z1) {
+ return x0 * x1 + y0 * y1 + z0 * z1;
+}
+
+static inline float signedDistance(const float* pPlane, float x, float y, float z) {
+ return dot3(pPlane[0], pPlane[1], pPlane[2], x, y, z) + pPlane[3];
+}
+
+// Return true if the sphere intersects or is inside the frustum
+
+static bool sphereHitsFrustum(const float* pFrustum, const float* pSphere) {
+ float x = pSphere[0];
+ float y = pSphere[1];
+ float z = pSphere[2];
+ float negRadius = -pSphere[3];
+ for (int i = 0; i < 6; i++, pFrustum += 4) {
+ if (signedDistance(pFrustum, x, y, z) <= negRadius) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void computeFrustum(const float* m, float* f) {
+ float m3 = m[3];
+ float m7 = m[7];
+ float m11 = m[11];
+ float m15 = m[15];
+ // right
+ f[0] = m3 - m[0];
+ f[1] = m7 - m[4];
+ f[2] = m11 - m[8];
+ f[3] = m15 - m[12];
+ normalizePlane(f);
+ f+= 4;
+
+ // left
+ f[0] = m3 + m[0];
+ f[1] = m7 + m[4];
+ f[2] = m11 + m[8];
+ f[3] = m15 + m[12];
+ normalizePlane(f);
+ f+= 4;
+
+ // top
+ f[0] = m3 - m[1];
+ f[1] = m7 - m[5];
+ f[2] = m11 - m[9];
+ f[3] = m15 - m[13];
+ normalizePlane(f);
+ f+= 4;
+
+ // bottom
+ f[0] = m3 + m[1];
+ f[1] = m7 + m[5];
+ f[2] = m11 + m[9];
+ f[3] = m15 + m[13];
+ normalizePlane(f);
+ f+= 4;
+
+ // far
+ f[0] = m3 - m[2];
+ f[1] = m7 - m[6];
+ f[2] = m11 - m[10];
+ f[3] = m15 - m[14];
+ normalizePlane(f);
+ f+= 4;
+
+ // near
+ f[0] = m3 + m[2];
+ f[1] = m7 + m[6];
+ f[2] = m11 + m[10];
+ f[3] = m15 + m[14];
+ normalizePlane(f);
+}
+
+static
+int util_frustumCullSpheres(JNIEnv *env, jclass clazz,
+ jfloatArray mvp_ref, jint mvpOffset,
+ jfloatArray spheres_ref, jint spheresOffset, jint spheresCount,
+ jintArray results_ref, jint resultsOffset, jint resultsCapacity) {
+ float frustum[6*4];
+ int outputCount;
+ int* pResults;
+ float* pSphere;
+ FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
+ FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
+ IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
+
+ bool initializedOK = mvp.check() && spheres.check() && results.check();
+ if (! initializedOK) {
+ return -1;
+ }
+
+ mvp.bind();
+ spheres.bind();
+ results.bind();
+
+ computeFrustum(mvp.mData, frustum);
+
+ // Cull the spheres
+
+ pSphere = spheres.mData;
+ pResults = results.mData;
+ outputCount = 0;
+ for(int i = 0; i < spheresCount; i++, pSphere += 4) {
+ if (sphereHitsFrustum(frustum, pSphere)) {
+ if (outputCount < resultsCapacity) {
+ *pResults++ = i;
+ }
+ outputCount++;
+ }
+ }
+ results.commitChanges();
+ return outputCount;
+}
+
+/*
+ public native int visibilityTest(float[] ws, int wsOffset,
+ float[] positions, int positionsOffset,
+ char[] indices, int indicesOffset, int indexCount);
+ */
+
+static
+int util_visibilityTest(JNIEnv *env, jclass clazz,
+ jfloatArray ws_ref, jint wsOffset,
+ jfloatArray positions_ref, jint positionsOffset,
+ jcharArray indices_ref, jint indicesOffset, jint indexCount) {
+
+ FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
+ FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
+ UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
+
+ bool checkOK = ws.check() && positions.check() && indices.check();
+ if (! checkOK) {
+ // Return value will be ignored, because an exception has been thrown.
+ return -1;
+ }
+
+ if (indices.mLength < indexCount) {
+ env->ThrowNew(gIAEClass, "length < offset + indexCount");
+ // Return value will be ignored, because an exception has been thrown.
+ return -1;
+ }
+
+ ws.bind();
+ positions.bind();
+ indices.bind();
+
+ return visibilityTest(ws.mData,
+ positions.mData, positions.mLength,
+ indices.mData, indexCount);
+}
+
+#define I(_i, _j) ((_j)+ 4*(_i))
+
+static
+void multiplyMM(float* r, const float* lhs, const float* rhs)
+{
+ for (int i=0 ; i<4 ; i++) {
+ register const float rhs_i0 = rhs[ I(i,0) ];
+ register float ri0 = lhs[ I(0,0) ] * rhs_i0;
+ register float ri1 = lhs[ I(0,1) ] * rhs_i0;
+ register float ri2 = lhs[ I(0,2) ] * rhs_i0;
+ register float ri3 = lhs[ I(0,3) ] * rhs_i0;
+ for (int j=1 ; j<4 ; j++) {
+ register const float rhs_ij = rhs[ I(i,j) ];
+ ri0 += lhs[ I(j,0) ] * rhs_ij;
+ ri1 += lhs[ I(j,1) ] * rhs_ij;
+ ri2 += lhs[ I(j,2) ] * rhs_ij;
+ ri3 += lhs[ I(j,3) ] * rhs_ij;
+ }
+ r[ I(i,0) ] = ri0;
+ r[ I(i,1) ] = ri1;
+ r[ I(i,2) ] = ri2;
+ r[ I(i,3) ] = ri3;
+ }
+}
+
+static
+void util_multiplyMM(JNIEnv *env, jclass clazz,
+ jfloatArray result_ref, jint resultOffset,
+ jfloatArray lhs_ref, jint lhsOffset,
+ jfloatArray rhs_ref, jint rhsOffset) {
+
+ FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
+ FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
+ FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
+
+ bool checkOK = resultMat.check() && lhs.check() && rhs.check();
+
+ if ( !checkOK ) {
+ return;
+ }
+
+ resultMat.bind();
+ lhs.bind();
+ rhs.bind();
+
+ multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
+
+ resultMat.commitChanges();
+}
+
+static
+void multiplyMV(float* r, const float* lhs, const float* rhs)
+{
+ mx4transform(rhs[0], rhs[1], rhs[2], rhs[3], lhs, r);
+}
+
+static
+void util_multiplyMV(JNIEnv *env, jclass clazz,
+ jfloatArray result_ref, jint resultOffset,
+ jfloatArray lhs_ref, jint lhsOffset,
+ jfloatArray rhs_ref, jint rhsOffset) {
+
+ FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
+ FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
+ FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
+
+ bool checkOK = resultV.check() && lhs.check() && rhs.check();
+
+ if ( !checkOK ) {
+ return;
+ }
+
+ resultV.bind();
+ lhs.bind();
+ rhs.bind();
+
+ multiplyMV(resultV.mData, lhs.mData, rhs.mData);
+
+ resultV.commitChanges();
+}
+
+// ---------------------------------------------------------------------------
+
+static jfieldID nativeBitmapID = 0;
+
+void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
+{
+ jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
+ nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
+}
+
+static int checkFormat(SkBitmap::Config config, int format, int type)
+{
+ switch(config) {
+ case SkBitmap::kIndex8_Config:
+ if (format == GL_PALETTE8_RGBA8_OES)
+ return 0;
+ case SkBitmap::kARGB_8888_Config:
+ case SkBitmap::kA8_Config:
+ if (type == GL_UNSIGNED_BYTE)
+ return 0;
+ case SkBitmap::kARGB_4444_Config:
+ case SkBitmap::kRGB_565_Config:
+ switch (type) {
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ return 0;
+ case GL_UNSIGNED_BYTE:
+ if (format == GL_LUMINANCE_ALPHA)
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return -1;
+}
+
+static int getInternalFormat(SkBitmap::Config config)
+{
+ switch(config) {
+ case SkBitmap::kA8_Config:
+ return GL_ALPHA;
+ case SkBitmap::kARGB_4444_Config:
+ return GL_RGBA;
+ case SkBitmap::kARGB_8888_Config:
+ return GL_RGBA;
+ case SkBitmap::kIndex8_Config:
+ return GL_PALETTE8_RGBA8_OES;
+ case SkBitmap::kRGB_565_Config:
+ return GL_RGB;
+ default:
+ return -1;
+ }
+}
+
+static jint util_texImage2D(JNIEnv *env, jclass clazz,
+ jint target, jint level, jint internalformat,
+ jobject jbitmap, jint type, jint border)
+{
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+ if (internalformat < 0) {
+ internalformat = getInternalFormat(config);
+ }
+ int err = checkFormat(config, internalformat, type);
+ if (err)
+ return err;
+ bitmap.lockPixels();
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* p = bitmap.getPixels();
+ if (internalformat == GL_PALETTE8_RGBA8_OES) {
+ if (sizeof(SkPMColor) != sizeof(uint32_t)) {
+ err = -1;
+ goto error;
+ }
+ const size_t size = bitmap.getSize();
+ const size_t palette_size = 256*sizeof(SkPMColor);
+ void* const data = malloc(size + palette_size);
+ if (data) {
+ void* const pixels = (char*)data + palette_size;
+ SkColorTable* ctable = bitmap.getColorTable();
+ memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
+ memcpy(pixels, p, size);
+ ctable->unlockColors(false);
+ glCompressedTexImage2D(target, level, internalformat, w, h, border, 0, data);
+ free(data);
+ } else {
+ err = -1;
+ }
+ } else {
+ glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
+ }
+error:
+ bitmap.unlockPixels();
+ return err;
+}
+
+static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
+ jint target, jint level, jint xoffset, jint yoffset,
+ jobject jbitmap, jint format, jint type)
+{
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)env->GetIntField(jbitmap, nativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+ if (format < 0) {
+ format = getInternalFormat(config);
+ if (format == GL_PALETTE8_RGBA8_OES)
+ return -1; // glCompressedTexSubImage2D() not supported
+ }
+ int err = checkFormat(config, format, type);
+ if (err)
+ return err;
+ bitmap.lockPixels();
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* p = bitmap.getPixels();
+ glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
+ bitmap.unlockPixels();
+ return 0;
+}
+
+/*
+ * JNI registration
+ */
+
+static void
+lookupClasses(JNIEnv* env) {
+ gIAEClass = (jclass) env->NewGlobalRef(
+ env->FindClass("java/lang/IllegalArgumentException"));
+ gUOEClass = (jclass) env->NewGlobalRef(
+ env->FindClass("java/lang/UnsupportedOperationException"));
+}
+
+static JNINativeMethod gMatrixMethods[] = {
+ { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
+ { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
+};
+
+static JNINativeMethod gVisiblityMethods[] = {
+ { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
+ { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
+ { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
+};
+
+static JNINativeMethod gUtilsMethods[] = {
+ {"nativeClassInit", "()V", (void*)nativeUtilsClassInit },
+ { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
+ { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
+};
+
+typedef struct _ClassRegistrationInfo {
+ const char* classPath;
+ JNINativeMethod* methods;
+ size_t methodCount;
+} ClassRegistrationInfo;
+
+static ClassRegistrationInfo gClasses[] = {
+ {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
+ {"android/opengl/Visibility", gVisiblityMethods, NELEM(gVisiblityMethods)},
+ {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
+};
+
+int register_android_opengl_classes(JNIEnv* env)
+{
+ lookupClasses(env);
+ int result = 0;
+ for (int i = 0; i < NELEM(gClasses); i++) {
+ ClassRegistrationInfo* cri = &gClasses[i];
+ result = AndroidRuntime::registerNativeMethods(env,
+ cri->classPath, cri->methods, cri->methodCount);
+ if (result < 0) {
+ LOGE("Failed to register %s: %d", cri->classPath, result);
+ break;
+ }
+ }
+ return result;
+}
+
+} // namespace android
+
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
new file mode 100755
index 0000000..7f87d80
--- /dev/null
+++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
@@ -0,0 +1,553 @@
+/*
+** Copyright 2006, 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 "BluetoothAudioGateway.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"
+
+#define USE_ACCEPT_DIRECTLY (0)
+#define USE_SELECT (0) /* 1 for select(), 0 for poll(); used only when
+ USE_ACCEPT_DIRECTLY == 0 */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <ctype.h>
+
+#if USE_SELECT
+#include <sys/select.h>
+#else
+#include <sys/poll.h>
+#endif
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jfieldID field_mNativeData;
+ /* in */
+static jfieldID field_mHandsfreeAgRfcommChannel;
+static jfieldID field_mHeadsetAgRfcommChannel;
+ /* out */
+static jfieldID field_mTimeoutRemainingMs; /* out */
+
+static jfieldID field_mConnectingHeadsetAddress;
+static jfieldID field_mConnectingHeadsetRfcommChannel; /* -1 when not connected */
+static jfieldID field_mConnectingHeadsetSocketFd;
+
+static jfieldID field_mConnectingHandsfreeAddress;
+static jfieldID field_mConnectingHandsfreeRfcommChannel; /* -1 when not connected */
+static jfieldID field_mConnectingHandsfreeSocketFd;
+
+
+typedef struct {
+ int hcidev;
+ int hf_ag_rfcomm_channel;
+ int hs_ag_rfcomm_channel;
+ int hf_ag_rfcomm_sock;
+ int hs_ag_rfcomm_sock;
+} native_data_t;
+
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ return (native_data_t *)(env->GetIntField(object,
+ field_mNativeData));
+}
+
+static int setup_listening_socket(int dev, int channel);
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+
+ /* in */
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+ field_mHandsfreeAgRfcommChannel =
+ get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
+ field_mHeadsetAgRfcommChannel =
+ get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
+
+ /* out */
+ field_mConnectingHeadsetAddress =
+ get_field(env, clazz,
+ "mConnectingHeadsetAddress", "Ljava/lang/String;");
+ field_mConnectingHeadsetRfcommChannel =
+ get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
+ field_mConnectingHeadsetSocketFd =
+ get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
+
+ field_mConnectingHandsfreeAddress =
+ get_field(env, clazz,
+ "mConnectingHandsfreeAddress", "Ljava/lang/String;");
+ field_mConnectingHandsfreeRfcommChannel =
+ get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
+ field_mConnectingHandsfreeSocketFd =
+ get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
+
+ field_mTimeoutRemainingMs =
+ get_field(env, clazz, "mTimeoutRemainingMs", "I");
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return;
+ }
+
+ nat->hcidev = BLUETOOTH_ADAPTER_HCI_NUM;
+
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ nat->hf_ag_rfcomm_channel =
+ env->GetIntField(object, field_mHandsfreeAgRfcommChannel);
+ nat->hs_ag_rfcomm_channel =
+ env->GetIntField(object, field_mHeadsetAgRfcommChannel);
+ LOGV("HF RFCOMM channel = %d.", nat->hf_ag_rfcomm_channel);
+ LOGV("HS RFCOMM channel = %d.", nat->hs_ag_rfcomm_channel);
+
+ /* Set the default values of these to -1. */
+ env->SetIntField(object, field_mConnectingHeadsetRfcommChannel, -1);
+ env->SetIntField(object, field_mConnectingHandsfreeRfcommChannel, -1);
+
+ nat->hf_ag_rfcomm_sock = -1;
+ nat->hs_ag_rfcomm_sock = -1;
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ free(nat);
+ }
+#endif
+}
+
+#ifdef HAVE_BLUETOOTH
+
+#if USE_ACCEPT_DIRECTLY==0
+static int set_nb(int sk, bool nb) {
+ int flags = fcntl(sk, F_GETFL);
+ if (flags < 0) {
+ LOGE("Can't get socket flags with fcntl(): %s (%d)",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+ flags &= ~O_NONBLOCK;
+ if (nb) flags |= O_NONBLOCK;
+ int status = fcntl(sk, F_SETFL, flags);
+ if (status < 0) {
+ LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+ return 0;
+}
+#endif /*USE_ACCEPT_DIRECTLY==0*/
+
+static int do_accept(JNIEnv* env, jobject object, int ag_fd,
+ jfieldID out_fd,
+ jfieldID out_address,
+ jfieldID out_channel) {
+
+#if USE_ACCEPT_DIRECTLY==0
+ if (set_nb(ag_fd, true) < 0)
+ return -1;
+#endif
+
+ struct sockaddr_rc raddr;
+ int alen = sizeof(raddr);
+ int nsk = accept(ag_fd, (struct sockaddr *) &raddr, &alen);
+ if (nsk < 0) {
+ LOGE("Error on accept from socket fd %d: %s (%d).",
+ ag_fd,
+ strerror(errno),
+ errno);
+#if USE_ACCEPT_DIRECTLY==0
+ set_nb(ag_fd, false);
+#endif
+ return -1;
+ }
+
+ env->SetIntField(object, out_fd, nsk);
+ env->SetIntField(object, out_channel, raddr.rc_channel);
+
+ char addr[BTADDR_SIZE];
+ get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
+ env->SetObjectField(object, out_address, env->NewStringUTF(addr));
+
+ LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
+ ag_fd,
+ nsk,
+ addr,
+ raddr.rc_channel);
+#if USE_ACCEPT_DIRECTLY==0
+ set_nb(ag_fd, false);
+#endif
+ return 0;
+}
+
+#if USE_SELECT
+static inline int on_accept_set_fields(JNIEnv* env, jobject object,
+ fd_set *rset, int ag_fd,
+ jfieldID out_fd,
+ jfieldID out_address,
+ jfieldID out_channel) {
+
+ env->SetIntField(object, out_channel, -1);
+
+ if (ag_fd >= 0 && FD_ISSET(ag_fd, &rset)) {
+ return do_accept(env, object, ag_fd,
+ out_fd, out_address, out_channel);
+ }
+ else {
+ LOGI("fd = %d, FD_ISSET() = %d",
+ ag_fd,
+ FD_ISSET(ag_fd, &rset));
+ if (ag_fd >= 0 && !FD_ISSET(ag_fd, &rset)) {
+ LOGE("WTF???");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif
+#endif /* HAVE_BLUETOOTH */
+
+static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
+ jint timeout_ms) {
+// LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+
+ env->SetIntField(object, field_mTimeoutRemainingMs, timeout_ms);
+
+ int n = 0;
+ native_data_t *nat = get_native_data(env, object);
+#if USE_ACCEPT_DIRECTLY
+ if (nat->hf_ag_rfcomm_channel > 0) {
+ LOGI("Setting HF AG server socket to RFCOMM port %d!",
+ nat->hf_ag_rfcomm_channel);
+ struct timeval tv;
+ int len = sizeof(tv);
+ if (getsockopt(nat->hf_ag_rfcomm_channel,
+ SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
+ LOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
+ nat->hf_ag_rfcomm_channel,
+ strerror(errno),
+ errno);
+ return JNI_FALSE;
+ }
+ LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
+ (int)tv.tv_sec, (int)tv.tv_usec);
+ if (timeout_ms >= 0) {
+ tv.tv_sec = timeout_ms / 1000;
+ tv.tv_usec = 1000 * (timeout_ms % 1000);
+ if (setsockopt(nat->hf_ag_rfcomm_channel,
+ SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ LOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
+ nat->hf_ag_rfcomm_channel,
+ strerror(errno),
+ errno);
+ return JNI_FALSE;
+ }
+ LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
+ (int)tv.tv_sec, (int)tv.tv_usec);
+ }
+
+ if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
+ field_mConnectingHandsfreeSocketFd,
+ field_mConnectingHandsfreeAddress,
+ field_mConnectingHandsfreeRfcommChannel))
+ {
+ env->SetIntField(object, field_mTimeoutRemainingMs, 0);
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+ }
+#else
+#if USE_SELECT
+ fd_set rset;
+ FD_ZERO(&rset);
+ int cnt = 0;
+ if (nat->hf_ag_rfcomm_channel > 0) {
+ LOGI("Setting HF AG server socket to RFCOMM port %d!",
+ nat->hf_ag_rfcomm_channel);
+ cnt++;
+ FD_SET(nat->hf_ag_rfcomm_sock, &rset);
+ }
+ if (nat->hs_ag_rfcomm_channel > 0) {
+ LOGI("Setting HS AG server socket to RFCOMM port %d!",
+ nat->hs_ag_rfcomm_channel);
+ cnt++;
+ FD_SET(nat->hs_ag_rfcomm_sock, &rset);
+ }
+ if (cnt == 0) {
+ LOGE("Neither HF nor HS listening sockets are open!");
+ return JNI_FALSE;
+ }
+
+ struct timeval to;
+ if (timeout_ms >= 0) {
+ to.tv_sec = timeout_ms / 1000;
+ to.tv_usec = 1000 * (timeout_ms % 1000);
+ }
+ n = select(MAX(nat->hf_ag_rfcomm_sock,
+ nat->hs_ag_rfcomm_sock) + 1,
+ &rset,
+ NULL,
+ NULL,
+ (timeout_ms < 0 ? NULL : &to));
+ if (timeout_ms > 0) {
+ jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
+ LOGI("Remaining time %ldms", (long)remaining);
+ env->SetIntField(object, field_mTimeoutRemainingMs,
+ remaining);
+ }
+
+ LOGI("listening select() returned %d", n);
+
+ if (n <= 0) {
+ if (n < 0) {
+ LOGE("listening select() on RFCOMM sockets: %s (%d)",
+ strerror(errno),
+ errno);
+ }
+ return JNI_FALSE;
+ }
+
+ n = on_accept_set_fields(env, object,
+ &rset, nat->hf_ag_rfcomm_sock,
+ field_mConnectingHandsfreeSocketFd,
+ field_mConnectingHandsfreeAddress,
+ field_mConnectingHandsfreeRfcommChannel);
+
+ n += on_accept_set_fields(env, object,
+ &rset, nat->hs_ag_rfcomm_sock,
+ field_mConnectingHeadsetSocketFd,
+ field_mConnectingHeadsetAddress,
+ field_mConnectingHeadsetRfcommChannel);
+
+ return !n ? JNI_TRUE : JNI_FALSE;
+#else
+ struct pollfd fds[2];
+ int cnt = 0;
+ if (nat->hf_ag_rfcomm_channel > 0) {
+// LOGI("Setting HF AG server socket %d to RFCOMM port %d!",
+// nat->hf_ag_rfcomm_sock,
+// nat->hf_ag_rfcomm_channel);
+ fds[cnt].fd = nat->hf_ag_rfcomm_sock;
+ fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
+ cnt++;
+ }
+ if (nat->hs_ag_rfcomm_channel > 0) {
+// LOGI("Setting HS AG server socket %d to RFCOMM port %d!",
+// nat->hs_ag_rfcomm_sock,
+// nat->hs_ag_rfcomm_channel);
+ fds[cnt].fd = nat->hs_ag_rfcomm_sock;
+ fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
+ cnt++;
+ }
+ if (cnt == 0) {
+ LOGE("Neither HF nor HS listening sockets are open!");
+ return JNI_FALSE;
+ }
+ n = poll(fds, cnt, timeout_ms);
+ if (n <= 0) {
+ if (n < 0) {
+ LOGE("listening poll() on RFCOMM sockets: %s (%d)",
+ strerror(errno),
+ errno);
+ }
+ else {
+ env->SetIntField(object, field_mTimeoutRemainingMs, 0);
+// LOGI("listening poll() on RFCOMM socket timed out");
+ }
+ return JNI_FALSE;
+ }
+
+ //LOGI("listening poll() on RFCOMM socket returned %d", n);
+ int err = 0;
+ for (cnt = 0; cnt < (int)(sizeof(fds)/sizeof(fds[0])); cnt++) {
+ //LOGI("Poll on fd %d revent = %d.", fds[cnt].fd, fds[cnt].revents);
+ if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
+ if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
+ LOGI("Accepting HF connection.\n");
+ err += do_accept(env, object, fds[cnt].fd,
+ field_mConnectingHandsfreeSocketFd,
+ field_mConnectingHandsfreeAddress,
+ field_mConnectingHandsfreeRfcommChannel);
+ n--;
+ }
+ }
+ else if (fds[cnt].fd == nat->hs_ag_rfcomm_sock) {
+ if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
+ LOGI("Accepting HS connection.\n");
+ err += do_accept(env, object, fds[cnt].fd,
+ field_mConnectingHeadsetSocketFd,
+ field_mConnectingHeadsetAddress,
+ field_mConnectingHeadsetRfcommChannel);
+ n--;
+ }
+ }
+ } /* for */
+
+ if (n != 0) {
+ LOGI("Bogus poll(): %d fake pollfd entrie(s)!", n);
+ return JNI_FALSE;
+ }
+
+ return !err ? JNI_TRUE : JNI_FALSE;
+#endif /* USE_SELECT */
+#endif /* USE_ACCEPT_DIRECTLY */
+#else
+ return JNI_FALSE;
+#endif /* HAVE_BLUETOOTH */
+}
+
+static jboolean setUpListeningSocketsNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+
+ nat->hf_ag_rfcomm_sock =
+ setup_listening_socket(nat->hcidev, nat->hf_ag_rfcomm_channel);
+ if (nat->hf_ag_rfcomm_sock < 0)
+ return JNI_FALSE;
+
+ nat->hs_ag_rfcomm_sock =
+ setup_listening_socket(nat->hcidev, nat->hs_ag_rfcomm_channel);
+ if (nat->hs_ag_rfcomm_sock < 0) {
+ close(nat->hf_ag_rfcomm_sock);
+ nat->hf_ag_rfcomm_sock = -1;
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif /* HAVE_BLUETOOTH */
+}
+
+#ifdef HAVE_BLUETOOTH
+static int setup_listening_socket(int dev, int channel) {
+ struct sockaddr_rc laddr;
+ int sk, lm;
+
+ sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ LOGE("Can't create RFCOMM socket");
+ return -1;
+ }
+
+ if (debug_no_encrypt()) {
+ lm = RFCOMM_LM_AUTH;
+ } else {
+ lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+ }
+
+ if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
+ LOGE("Can't set RFCOMM link mode");
+ close(sk);
+ return -1;
+ }
+
+ laddr.rc_family = AF_BLUETOOTH;
+ bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
+ laddr.rc_channel = channel;
+
+ if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
+ LOGE("Can't bind RFCOMM socket");
+ close(sk);
+ return -1;
+ }
+
+ listen(sk, 10);
+ return sk;
+}
+#endif /* HAVE_BLUETOOTH */
+
+/*
+ private native void tearDownListeningSocketsNative();
+*/
+static void tearDownListeningSocketsNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+
+ if (nat->hf_ag_rfcomm_sock > 0) {
+ if (close(nat->hf_ag_rfcomm_sock) < 0) {
+ LOGE("Could not close HF server socket: %s (%d)\n",
+ strerror(errno), errno);
+ }
+ nat->hf_ag_rfcomm_sock = -1;
+ }
+ if (nat->hs_ag_rfcomm_sock > 0) {
+ if (close(nat->hs_ag_rfcomm_sock) < 0) {
+ LOGE("Could not close HS server socket: %s (%d)\n",
+ strerror(errno), errno);
+ }
+ nat->hs_ag_rfcomm_sock = -1;
+ }
+#endif /* HAVE_BLUETOOTH */
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+
+ {"setUpListeningSocketsNative", "()Z", (void *)setUpListeningSocketsNative},
+ {"tearDownListeningSocketsNative", "()V", (void *)tearDownListeningSocketsNative},
+ {"waitForHandsfreeConnectNative", "(I)Z", (void *)waitForHandsfreeConnectNative},
+};
+
+int register_android_bluetooth_BluetoothAudioGateway(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/bluetooth/BluetoothAudioGateway", sMethods,
+ NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_bluetooth_Database.cpp b/core/jni/android_bluetooth_Database.cpp
new file mode 100644
index 0000000..136c9a3
--- /dev/null
+++ b/core/jni/android_bluetooth_Database.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2007 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 DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Database"
+#define LOG_TAG "bluetooth_Database.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static DBusConnection* conn = NULL; // Singleton thread-safe connection
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ conn = NULL;
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+
+#ifdef HAVE_BLUETOOTH
+ if (conn == NULL) {
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_threads_init_default();
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ LOGE("Could not get onto the system bus!");
+ dbus_error_free(&err);
+ }
+ }
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+}
+
+static jint addServiceRecordNative(JNIEnv *env, jobject object,
+ jbyteArray record) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ if (conn != NULL) {
+ jbyte* c_record = env->GetByteArrayElements(record, NULL);
+ DBusMessage *reply = dbus_func_args(env,
+ conn,
+ BLUEZ_DBUS_BASE_PATH,
+ DBUS_CLASS_NAME,
+ "AddServiceRecord",
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &c_record,
+ env->GetArrayLength(record),
+ DBUS_TYPE_INVALID);
+ env->ReleaseByteArrayElements(record, c_record, JNI_ABORT);
+ return reply ? dbus_returns_uint32(env, reply) : -1;
+ }
+#endif
+ return -1;
+}
+
+static jint addServiceRecordFromXmlNative(JNIEnv *env, jobject object,
+ jstring record) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ if (conn != NULL) {
+ const char *c_record = env->GetStringUTFChars(record, NULL);
+ DBusMessage *reply = dbus_func_args(env,
+ conn,
+ BLUEZ_DBUS_BASE_PATH,
+ DBUS_CLASS_NAME,
+ "AddServiceRecordFromXML",
+ DBUS_TYPE_STRING, &c_record,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(record, c_record);
+ return reply ? dbus_returns_uint32(env, reply) : -1;
+ }
+#endif
+ return -1;
+}
+
+static void updateServiceRecordNative(JNIEnv *env, jobject object,
+ jint handle,
+ jbyteArray record) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ if (conn != NULL) {
+ jbyte* c_record = env->GetByteArrayElements(record, NULL);
+ DBusMessage *reply = dbus_func_args(env,
+ conn,
+ BLUEZ_DBUS_BASE_PATH,
+ DBUS_CLASS_NAME,
+ "UpdateServiceRecord",
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &c_record,
+ env->GetArrayLength(record),
+ DBUS_TYPE_INVALID);
+ env->ReleaseByteArrayElements(record, c_record, JNI_ABORT);
+ }
+#endif
+}
+
+static void updateServiceRecordFromXmlNative(JNIEnv *env, jobject object,
+ jint handle,
+ jstring record) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ if (conn != NULL) {
+ const char *c_record = env->GetStringUTFChars(record, NULL);
+ DBusMessage *reply = dbus_func_args(env,
+ conn,
+ BLUEZ_DBUS_BASE_PATH,
+ DBUS_CLASS_NAME,
+ "UpdateServiceRecordFromXML",
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_STRING, &c_record,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(record, c_record);
+ }
+#endif
+}
+
+/* private static native void removeServiceRecordNative(int handle); */
+static void removeServiceRecordNative(JNIEnv *env, jobject object,
+ jint handle) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ if (conn != NULL) {
+ DBusMessage *reply = dbus_func_args(env,
+ conn,
+ BLUEZ_DBUS_BASE_PATH,
+ DBUS_CLASS_NAME,
+ "RemoveServiceRecord",
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+ }
+#endif
+}
+
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+ {"addServiceRecordNative", "([B)I", (void*)addServiceRecordNative},
+ {"addServiceRecordFromXmlNative", "(Ljava/lang/String;)I", (void*)addServiceRecordFromXmlNative},
+ {"updateServiceRecordNative", "(I[B)V", (void*)updateServiceRecordNative},
+ {"updateServiceRecordFromXmlNative", "(ILjava/lang/String;)V", (void*)updateServiceRecordFromXmlNative},
+ {"removeServiceRecordNative", "(I)V", (void*)removeServiceRecordNative},
+};
+
+int register_android_bluetooth_Database(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/bluetooth/Database", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_bluetooth_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp
new file mode 100644
index 0000000..bb19e92
--- /dev/null
+++ b/core/jni/android_bluetooth_HeadsetBase.cpp
@@ -0,0 +1,548 @@
+/*
+** Copyright 2006, 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 "BT HSHFP"
+
+#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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jfieldID field_mNativeData;
+static jfieldID field_mAddress;
+static jfieldID field_mRfcommChannel;
+static jfieldID field_mTimeoutRemainingMs;
+
+typedef struct {
+ jstring address;
+ const char *c_address;
+ int rfcomm_channel;
+ int last_read_err;
+ int rfcomm_sock;
+ int rfcomm_connected; // -1 in progress, 0 not connected, 1 connected
+ int rfcomm_sock_flags;
+} native_data_t;
+
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ return (native_data_t *)(env->GetIntField(object, field_mNativeData));
+}
+
+static const char CRLF[] = "\xd\xa";
+static const int CRLF_LEN = 2;
+
+static inline int write_error_check(int fd, const char* line, int len) {
+ int ret;
+ errno = 0;
+ ret = write(fd, line, len);
+ if (ret < 0) {
+ LOGE("%s: write() failed: %s (%d)", __FUNCTION__, strerror(errno),
+ errno);
+ return -1;
+ }
+ if (ret != len) {
+ LOGE("%s: write() only wrote %d of %d bytes", __FUNCTION__, ret, len);
+ return -1;
+ }
+ return 0;
+}
+
+static int send_line(int fd, const char* line) {
+ int nw;
+ int len = strlen(line);
+ int llen = len + CRLF_LEN * 2 + 1;
+ char *buffer = (char *)calloc(llen, sizeof(char));
+
+ snprintf(buffer, llen, "%s%s%s", CRLF, line, CRLF);
+
+ if (write_error_check(fd, buffer, llen - 1)) {
+ free(buffer);
+ return -1;
+ }
+ free(buffer);
+ return 0;
+}
+
+static const char* get_line(int fd, char *buf, int len, int timeout_ms,
+ int *err) {
+ char *bufit=buf;
+ int fd_flags = fcntl(fd, F_GETFL, 0);
+ struct pollfd pfd;
+
+again:
+ *bufit = 0;
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ *err = errno = 0;
+ int ret = poll(&pfd, 1, timeout_ms);
+ if (ret < 0) {
+ LOGE("poll() error\n");
+ *err = errno;
+ return NULL;
+ }
+ if (ret == 0) {
+ return NULL;
+ }
+
+ if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
+ LOGW("RFCOMM poll() returned success (%d), "
+ "but with an unexpected revents bitmask: %#x\n", ret, pfd.revents);
+ errno = EIO;
+ *err = errno;
+ return NULL;
+ }
+
+ while ((int)(bufit - buf) < len)
+ {
+ errno = 0;
+ int rc = read(fd, bufit, 1);
+
+ if (!rc)
+ break;
+
+ if (rc < 0) {
+ if (errno == EBUSY) {
+ LOGI("read() error %s (%d): repeating read()...",
+ strerror(errno), errno);
+ goto again;
+ }
+ *err = errno;
+ LOGE("read() error %s (%d)", strerror(errno), errno);
+ return NULL;
+ }
+
+
+ if (*bufit=='\xd') {
+ break;
+ }
+
+ if (*bufit=='\xa')
+ bufit = buf;
+ else
+ bufit++;
+ }
+
+ *bufit = '\x0';
+ LOG(LOG_INFO, "Bluetooth AT recv", buf);
+
+ return buf;
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+ field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
+ field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I");
+ field_mRfcommChannel = get_field(env, clazz, "mRfcommChannel", "I");
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object,
+ jint socketFd) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return;
+ }
+
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ nat->address =
+ (jstring)env->NewGlobalRef(env->GetObjectField(object,
+ field_mAddress));
+ nat->c_address = env->GetStringUTFChars(nat->address, NULL);
+ nat->rfcomm_channel = env->GetIntField(object, field_mRfcommChannel);
+ nat->rfcomm_sock = socketFd;
+ nat->rfcomm_connected = socketFd >= 0;
+ if (nat->rfcomm_connected)
+ LOGI("%s: ALREADY CONNECTED!", __FUNCTION__);
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ env->ReleaseStringUTFChars(nat->address, nat->c_address);
+ env->DeleteGlobalRef(nat->address);
+ if (nat)
+ free(nat);
+#endif
+}
+
+static jboolean connectNative(JNIEnv *env, jobject obj)
+{
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ int lm;
+ struct sockaddr_rc addr;
+ native_data_t *nat = get_native_data(env, obj);
+
+ nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+
+ if (nat->rfcomm_sock < 0) {
+ LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
+ strerror(errno));
+ return JNI_FALSE;
+ }
+
+ if (debug_no_encrypt()) {
+ lm = RFCOMM_LM_AUTH;
+ } else {
+ lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+ }
+
+ if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
+ sizeof(lm)) < 0) {
+ LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
+ close(nat->rfcomm_sock);
+ return JNI_FALSE;
+ }
+
+ memset(&addr, 0, sizeof(struct sockaddr_rc));
+ get_bdaddr(nat->c_address, &addr.rc_bdaddr);
+ addr.rc_channel = nat->rfcomm_channel;
+ addr.rc_family = AF_BLUETOOTH;
+ nat->rfcomm_connected = 0;
+ while (nat->rfcomm_connected == 0) {
+ if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr,
+ sizeof(addr)) < 0) {
+ if (errno == EINTR) continue;
+ LOGE("%s: connect() failed: %s\n", __FUNCTION__, strerror(errno));
+ close(nat->rfcomm_sock);
+ nat->rfcomm_sock = -1;
+ return JNI_FALSE;
+ } else {
+ nat->rfcomm_connected = 1;
+ }
+ }
+
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ struct sockaddr_rc addr;
+ native_data_t *nat = get_native_data(env, obj);
+
+ if (nat->rfcomm_connected) {
+ LOGV("RFCOMM socket is already connected or connection is in progress.");
+ return JNI_TRUE;
+ }
+
+ if (nat->rfcomm_sock < 0) {
+ int lm;
+
+ nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (nat->rfcomm_sock < 0) {
+ LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
+ strerror(errno));
+ return JNI_FALSE;
+ }
+
+ if (debug_no_encrypt()) {
+ lm = RFCOMM_LM_AUTH;
+ } else {
+ lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+ }
+
+ if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
+ sizeof(lm)) < 0) {
+ LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
+ close(nat->rfcomm_sock);
+ return JNI_FALSE;
+ }
+ LOGI("Created RFCOMM socket fd %d.", nat->rfcomm_sock);
+ }
+
+ memset(&addr, 0, sizeof(struct sockaddr_rc));
+ get_bdaddr(nat->c_address, &addr.rc_bdaddr);
+ addr.rc_channel = nat->rfcomm_channel;
+ addr.rc_family = AF_BLUETOOTH;
+ if (nat->rfcomm_sock_flags >= 0) {
+ nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0);
+ if (fcntl(nat->rfcomm_sock,
+ F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) {
+ int rc;
+ nat->rfcomm_connected = 0;
+ errno = 0;
+ rc = connect(nat->rfcomm_sock,
+ (struct sockaddr *)&addr,
+ sizeof(addr));
+
+ if (rc >= 0) {
+ nat->rfcomm_connected = 1;
+ LOGI("async connect successful");
+ return JNI_TRUE;
+ }
+ else if (rc < 0) {
+ if (errno == EINPROGRESS || errno == EAGAIN)
+ {
+ LOGI("async connect is in progress (%s)",
+ strerror(errno));
+ nat->rfcomm_connected = -1;
+ return JNI_TRUE;
+ }
+ else
+ {
+ LOGE("async connect error: %s (%d)", strerror(errno), errno);
+ close(nat->rfcomm_sock);
+ nat->rfcomm_sock = -1;
+ return JNI_FALSE;
+ }
+ }
+ } // fcntl(nat->rfcomm_sock ...)
+ } // if (nat->rfcomm_sock_flags >= 0)
+#endif
+ return JNI_FALSE;
+}
+
+static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
+ jint timeout_ms) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ struct sockaddr_rc addr;
+ native_data_t *nat = get_native_data(env, obj);
+
+ env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms);
+
+ if (nat->rfcomm_connected > 0) {
+ LOGI("RFCOMM is already connected!");
+ return 1;
+ }
+
+ if (nat->rfcomm_sock >= 0 && nat->rfcomm_connected == 0) {
+ LOGI("Re-opening RFCOMM socket.");
+ close(nat->rfcomm_sock);
+ nat->rfcomm_sock = -1;
+ }
+ if (JNI_FALSE == connectAsyncNative(env, obj)) {
+ LOGI("Failed to re-open RFCOMM socket!");
+ return -1;
+ }
+
+ if (nat->rfcomm_sock >= 0) {
+ /* Do an asynchronous select() */
+ int n;
+ fd_set rset, wset;
+ struct timeval to;
+
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_SET(nat->rfcomm_sock, &rset);
+ FD_SET(nat->rfcomm_sock, &wset);
+ if (timeout_ms >= 0) {
+ to.tv_sec = timeout_ms / 1000;
+ to.tv_usec = 1000 * (timeout_ms % 1000);
+ }
+ n = select(nat->rfcomm_sock + 1,
+ &rset,
+ &wset,
+ NULL,
+ (timeout_ms < 0 ? NULL : &to));
+
+ if (timeout_ms > 0) {
+ jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
+ LOGV("Remaining time %ldms", (long)remaining);
+ env->SetIntField(obj, field_mTimeoutRemainingMs,
+ remaining);
+ }
+
+ if (n <= 0) {
+ if (n < 0) {
+ LOGE("select() on RFCOMM socket: %s (%d)",
+ strerror(errno),
+ errno);
+ return -1;
+ }
+ return 0;
+ }
+ /* n must be equal to 1 and either rset or wset must have the
+ file descriptor set. */
+ LOGV("select() returned %d.", n);
+ if (FD_ISSET(nat->rfcomm_sock, &rset) ||
+ FD_ISSET(nat->rfcomm_sock, &wset))
+ {
+ /* A trial async read() will tell us if everything is OK. */
+ {
+ char ch;
+ errno = 0;
+ int nr = read(nat->rfcomm_sock, &ch, 1);
+ /* It should be that nr != 1 because we just opened a socket
+ and we haven't sent anything over it for the other side to
+ respond... but one can't be paranoid enough.
+ */
+ if (nr >= 0 || errno != EAGAIN) {
+ LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n",
+ strerror(errno),
+ errno,
+ nr);
+ /* Clear the rfcomm_connected flag to cause this function
+ to re-create the socket and re-attempt the connect()
+ the next time it is called.
+ */
+ nat->rfcomm_connected = 0;
+ /* Restore the blocking properties of the socket. */
+ fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
+ close(nat->rfcomm_sock);
+ nat->rfcomm_sock = -1;
+ return -1;
+ }
+ }
+ /* Restore the blocking properties of the socket. */
+ fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
+ LOGI("Successful RFCOMM socket connect.");
+ nat->rfcomm_connected = 1;
+ return 1;
+ }
+ }
+ else LOGE("RFCOMM socket file descriptor %d is bad!",
+ nat->rfcomm_sock);
+#endif
+ return -1;
+}
+
+static void disconnectNative(JNIEnv *env, jobject obj) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_sock >= 0) {
+ close(nat->rfcomm_sock);
+ nat->rfcomm_sock = -1;
+ nat->rfcomm_connected = 0;
+ }
+#endif
+}
+
+static void pretty_log_urc(const char *urc) {
+ size_t i;
+ bool in_line_break = false;
+ char *buf = (char *)calloc(strlen(urc) + 1, sizeof(char));
+
+ strcpy(buf, urc);
+ for (i = 0; i < strlen(buf); i++) {
+ switch(buf[i]) {
+ case '\r':
+ case '\n':
+ in_line_break = true;
+ buf[i] = ' ';
+ break;
+ default:
+ if (in_line_break) {
+ in_line_break = false;
+ buf[i-1] = '\n';
+ }
+ }
+ }
+ LOG(LOG_INFO, "Bluetooth AT sent", buf);
+
+ free(buf);
+}
+
+static jboolean sendURCNative(JNIEnv *env, jobject obj, jstring urc) {
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_connected) {
+ const char *c_urc = env->GetStringUTFChars(urc, NULL);
+ jboolean ret = send_line(nat->rfcomm_sock, c_urc) == 0 ? JNI_TRUE : JNI_FALSE;
+ if (ret == JNI_TRUE) pretty_log_urc(c_urc);
+ env->ReleaseStringUTFChars(urc, c_urc);
+ return ret;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jstring readNative(JNIEnv *env, jobject obj, jint timeout_ms) {
+#ifdef HAVE_BLUETOOTH
+ {
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_connected) {
+ char buf[128];
+ const char *ret = get_line(nat->rfcomm_sock,
+ buf, sizeof(buf),
+ timeout_ms,
+ &nat->last_read_err);
+ return ret ? env->NewStringUTF(ret) : NULL;
+ }
+ return NULL;
+ }
+#else
+ return NULL;
+#endif
+}
+
+static jint getLastReadStatusNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ {
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_connected)
+ return (jint)nat->last_read_err;
+ return 0;
+ }
+#else
+ return 0;
+#endif
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initializeNativeDataNative", "(I)V", (void *)initializeNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+ {"connectNative", "()Z", (void *)connectNative},
+ {"connectAsyncNative", "()Z", (void *)connectAsyncNative},
+ {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
+ {"disconnectNative", "()V", (void *)disconnectNative},
+ {"sendURCNative", "(Ljava/lang/String;)Z", (void *)sendURCNative},
+ {"readNative", "(I)Ljava/lang/String;", (void *)readNative},
+ {"getLastReadStatusNative", "()I", (void *)getLastReadStatusNative},
+};
+
+int register_android_bluetooth_HeadsetBase(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/bluetooth/HeadsetBase", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_bluetooth_RfcommSocket.cpp b/core/jni/android_bluetooth_RfcommSocket.cpp
new file mode 100644
index 0000000..3ed35d9
--- /dev/null
+++ b/core/jni/android_bluetooth_RfcommSocket.cpp
@@ -0,0 +1,621 @@
+/*
+** Copyright 2006, 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 "bluetooth_RfcommSocket.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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jfieldID field_mNativeData;
+static jfieldID field_mTimeoutRemainingMs;
+static jfieldID field_mAcceptTimeoutRemainingMs;
+static jfieldID field_mAddress;
+static jfieldID field_mPort;
+
+typedef struct {
+ jstring address;
+ const char *c_address;
+ int rfcomm_channel;
+ int last_read_err;
+ int rfcomm_sock;
+ // < 0 -- in progress,
+ // 0 -- not connected
+ // > 0 connected
+ // 1 input is open
+ // 2 output is open
+ // 3 both input and output are open
+ int rfcomm_connected;
+ int rfcomm_sock_flags;
+} native_data_t;
+
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ return (native_data_t *)(env->GetIntField(object, field_mNativeData));
+}
+
+static inline void init_socket_info(
+ JNIEnv *env, jobject object,
+ native_data_t *nat,
+ jstring address,
+ jint rfcomm_channel) {
+ nat->address = (jstring)env->NewGlobalRef(address);
+ nat->c_address = env->GetStringUTFChars(nat->address, NULL);
+ nat->rfcomm_channel = (int)rfcomm_channel;
+}
+
+static inline void cleanup_socket_info(JNIEnv *env, native_data_t *nat) {
+ if (nat->c_address != NULL) {
+ env->ReleaseStringUTFChars(nat->address, nat->c_address);
+ env->DeleteGlobalRef(nat->address);
+ nat->c_address = NULL;
+ }
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+ field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I");
+ field_mAcceptTimeoutRemainingMs = get_field(env, clazz, "mAcceptTimeoutRemainingMs", "I");
+ field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
+ field_mPort = get_field(env, clazz, "mPort", "I");
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (nat == NULL) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return;
+ }
+
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ nat->rfcomm_sock = -1;
+ nat->rfcomm_connected = 0;
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ free(nat);
+ }
+#endif
+}
+
+static jobject createNative(JNIEnv *env, jobject obj) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ int lm;
+ native_data_t *nat = get_native_data(env, obj);
+ nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+
+ if (nat->rfcomm_sock < 0) {
+ LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
+ strerror(errno));
+ return NULL;
+ }
+
+ lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+
+ if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
+ sizeof(lm)) < 0) {
+ LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
+ close(nat->rfcomm_sock);
+ return NULL;
+ }
+
+ return jniCreateFileDescriptor(env, nat->rfcomm_sock);
+#else
+ return NULL;
+#endif
+}
+
+static void destroyNative(JNIEnv *env, jobject obj) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, obj);
+ cleanup_socket_info(env, nat);
+ if (nat->rfcomm_sock >= 0) {
+ close(nat->rfcomm_sock);
+ nat->rfcomm_sock = -1;
+ }
+#endif
+}
+
+
+static jboolean connectNative(JNIEnv *env, jobject obj,
+ jstring address, jint port) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, obj);
+
+ if (nat->rfcomm_sock >= 0) {
+ if (nat->rfcomm_connected) {
+ LOGI("RFCOMM socket: %s.",
+ (nat->rfcomm_connected > 0) ? "already connected" : "connection is in progress");
+ return JNI_TRUE;
+ }
+
+ init_socket_info(env, obj, nat, address, port);
+
+ struct sockaddr_rc addr;
+ memset(&addr, 0, sizeof(struct sockaddr_rc));
+ get_bdaddr(nat->c_address, &addr.rc_bdaddr);
+ addr.rc_channel = nat->rfcomm_channel;
+ addr.rc_family = AF_BLUETOOTH;
+ nat->rfcomm_connected = 0;
+
+ while (nat->rfcomm_connected == 0) {
+ if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr,
+ sizeof(addr)) < 0) {
+ if (errno == EINTR) continue;
+ LOGE("connect error: %s (%d)\n", strerror(errno), errno);
+ break;
+ } else {
+ nat->rfcomm_connected = 3; // input and output
+ }
+ }
+ } else {
+ LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
+ }
+
+ if (nat->rfcomm_connected > 0) {
+ env->SetIntField(obj, field_mPort, port);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean connectAsyncNative(JNIEnv *env, jobject obj,
+ jstring address, jint port) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, obj);
+
+ if (nat->rfcomm_sock < 0) {
+ LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (nat->rfcomm_connected) {
+ LOGI("RFCOMM socket: %s.",
+ (nat->rfcomm_connected > 0) ?
+ "already connected" : "connection is in progress");
+ return JNI_TRUE;
+ }
+
+ init_socket_info(env, obj, nat, address, port);
+
+ struct sockaddr_rc addr;
+ memset(&addr, 0, sizeof(struct sockaddr_rc));
+ get_bdaddr(nat->c_address, &addr.rc_bdaddr);
+ addr.rc_channel = nat->rfcomm_channel;
+ addr.rc_family = AF_BLUETOOTH;
+
+ nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0);
+ if (fcntl(nat->rfcomm_sock,
+ F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) {
+ int rc;
+ nat->rfcomm_connected = 0;
+ errno = 0;
+ rc = connect(nat->rfcomm_sock,
+ (struct sockaddr *)&addr,
+ sizeof(addr));
+
+ if (rc >= 0) {
+ nat->rfcomm_connected = 3;
+ LOGI("RFCOMM async connect immediately successful");
+ env->SetIntField(obj, field_mPort, port);
+ return JNI_TRUE;
+ }
+ else if (rc < 0) {
+ if (errno == EINPROGRESS || errno == EAGAIN)
+ {
+ LOGI("RFCOMM async connect is in progress (%s)",
+ strerror(errno));
+ nat->rfcomm_connected = -1;
+ env->SetIntField(obj, field_mPort, port);
+ return JNI_TRUE;
+ }
+ else
+ {
+ LOGE("RFCOMM async connect error (%d): %s (%d)",
+ nat->rfcomm_sock, strerror(errno), errno);
+ return JNI_FALSE;
+ }
+ }
+ } // fcntl(nat->rfcomm_sock ...)
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean interruptAsyncConnectNative(JNIEnv *env, jobject obj) {
+ //WRITEME
+ return JNI_TRUE;
+}
+
+static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
+ jint timeout_ms) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ struct sockaddr_rc addr;
+ native_data_t *nat = get_native_data(env, obj);
+
+ env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms);
+
+ if (nat->rfcomm_sock < 0) {
+ LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
+ return -1;
+ }
+
+ if (nat->rfcomm_connected > 0) {
+ LOGI("%s: RFCOMM is already connected!", __FUNCTION__);
+ return 1;
+ }
+
+ /* Do an asynchronous select() */
+ int n;
+ fd_set rset, wset;
+ struct timeval to;
+
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_SET(nat->rfcomm_sock, &rset);
+ FD_SET(nat->rfcomm_sock, &wset);
+ if (timeout_ms >= 0) {
+ to.tv_sec = timeout_ms / 1000;
+ to.tv_usec = 1000 * (timeout_ms % 1000);
+ }
+ n = select(nat->rfcomm_sock + 1,
+ &rset,
+ &wset,
+ NULL,
+ (timeout_ms < 0 ? NULL : &to));
+
+ if (timeout_ms > 0) {
+ jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
+ LOGI("Remaining time %ldms", (long)remaining);
+ env->SetIntField(obj, field_mTimeoutRemainingMs,
+ remaining);
+ }
+
+ if (n <= 0) {
+ if (n < 0) {
+ LOGE("select() on RFCOMM socket: %s (%d)",
+ strerror(errno),
+ errno);
+ return -1;
+ }
+ return 0;
+ }
+ /* n must be equal to 1 and either rset or wset must have the
+ file descriptor set. */
+ LOGI("select() returned %d.", n);
+ if (FD_ISSET(nat->rfcomm_sock, &rset) ||
+ FD_ISSET(nat->rfcomm_sock, &wset)) {
+ /* A trial async read() will tell us if everything is OK. */
+ char ch;
+ errno = 0;
+ int nr = read(nat->rfcomm_sock, &ch, 1);
+ /* It should be that nr != 1 because we just opened a socket
+ and we haven't sent anything over it for the other side to
+ respond... but one can't be paranoid enough.
+ */
+ if (nr >= 0 || errno != EAGAIN) {
+ LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n",
+ strerror(errno),
+ errno,
+ nr);
+ /* Clear the rfcomm_connected flag to cause this function
+ to re-create the socket and re-attempt the connect()
+ the next time it is called.
+ */
+ nat->rfcomm_connected = 0;
+ /* Restore the blocking properties of the socket. */
+ fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
+ return -1;
+ }
+ /* Restore the blocking properties of the socket. */
+ fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
+ LOGI("Successful RFCOMM socket connect.");
+ nat->rfcomm_connected = 3; // input and output
+ return 1;
+ }
+#endif
+ return -1;
+}
+
+static jboolean shutdownNative(JNIEnv *env, jobject obj,
+ jboolean shutdownInput) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ /* NOTE: If you change the bcode to modify nat, make sure you
+ add synchronize(this) to the method calling this native
+ method.
+ */
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_sock < 0) {
+ LOGE("socket(RFCOMM) error: socket not created");
+ return JNI_FALSE;
+ }
+ int rc = shutdown(nat->rfcomm_sock,
+ shutdownInput ? SHUT_RD : SHUT_WR);
+ if (!rc) {
+ nat->rfcomm_connected &=
+ shutdownInput ? ~1 : ~2;
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jint isConnectedNative(JNIEnv *env, jobject obj) {
+ LOGI(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ const native_data_t *nat = get_native_data(env, obj);
+ return nat->rfcomm_connected;
+#endif
+ return 0;
+}
+
+//@@@@@@@@@ bind to device???
+static jboolean bindNative(JNIEnv *env, jobject obj, jstring device,
+ jint port) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+
+ /* NOTE: If you change the code to modify nat, make sure you
+ add synchronize(this) to the method calling this native
+ method.
+ */
+ const native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_sock < 0) {
+ LOGE("socket(RFCOMM) error: socket not created");
+ return JNI_FALSE;
+ }
+
+ struct sockaddr_rc laddr;
+ int lm;
+
+ lm = 0;
+/*
+ lm |= RFCOMM_LM_MASTER;
+ lm |= RFCOMM_LM_AUTH;
+ lm |= RFCOMM_LM_ENCRYPT;
+ lm |= RFCOMM_LM_SECURE;
+*/
+
+ if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
+ LOGE("Can't set RFCOMM link mode");
+ return JNI_FALSE;
+ }
+
+ laddr.rc_family = AF_BLUETOOTH;
+ bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
+ laddr.rc_channel = port;
+
+ if (bind(nat->rfcomm_sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
+ LOGE("Can't bind RFCOMM socket");
+ return JNI_FALSE;
+ }
+
+ env->SetIntField(obj, field_mPort, port);
+
+ return JNI_TRUE;
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean listenNative(JNIEnv *env, jobject obj, jint backlog) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ /* NOTE: If you change the code to modify nat, make sure you
+ add synchronize(this) to the method calling this native
+ method.
+ */
+ const native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_sock < 0) {
+ LOGE("socket(RFCOMM) error: socket not created");
+ return JNI_FALSE;
+ }
+ return listen(nat->rfcomm_sock, backlog) < 0 ? JNI_FALSE : JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static int set_nb(int sk, bool nb) {
+ int flags = fcntl(sk, F_GETFL);
+ if (flags < 0) {
+ LOGE("Can't get socket flags with fcntl(): %s (%d)",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+ flags &= ~O_NONBLOCK;
+ if (nb) flags |= O_NONBLOCK;
+ int status = fcntl(sk, F_SETFL, flags);
+ if (status < 0) {
+ LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+ return 0;
+}
+
+// Note: the code should check at a higher level to see whether
+// listen() has been called.
+#ifdef HAVE_BLUETOOTH
+static int do_accept(JNIEnv* env, jobject object, int sock,
+ jobject newsock,
+ jfieldID out_address,
+ bool must_succeed) {
+
+ if (must_succeed && set_nb(sock, true) < 0)
+ return -1;
+
+ struct sockaddr_rc raddr;
+ int alen = sizeof(raddr);
+ int nsk = accept(sock, (struct sockaddr *) &raddr, &alen);
+ if (nsk < 0) {
+ LOGE("Error on accept from socket fd %d: %s (%d).",
+ sock,
+ strerror(errno),
+ errno);
+ if (must_succeed) set_nb(sock, false);
+ return -1;
+ }
+
+ char addr[BTADDR_SIZE];
+ get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
+ env->SetObjectField(newsock, out_address, env->NewStringUTF(addr));
+
+ LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
+ sock,
+ nsk,
+ addr,
+ raddr.rc_channel);
+ if (must_succeed) set_nb(sock, false);
+ return nsk;
+}
+#endif /*HAVE_BLUETOOTH*/
+
+static jobject acceptNative(JNIEnv *env, jobject obj,
+ jobject newsock, jint timeoutMs) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat->rfcomm_sock < 0) {
+ LOGE("socket(RFCOMM) error: socket not created");
+ return JNI_FALSE;
+ }
+
+ if (newsock == NULL) {
+ LOGE("%s: newsock = NULL\n", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ int nsk = -1;
+ if (timeoutMs < 0) {
+ /* block until accept() succeeds */
+ nsk = do_accept(env, obj, nat->rfcomm_sock,
+ newsock, field_mAddress, false);
+ if (nsk < 0) {
+ return NULL;
+ }
+ }
+ else {
+ /* wait with a timeout */
+
+ struct pollfd fds;
+ fds.fd = nat->rfcomm_sock;
+ fds.events = POLLIN | POLLPRI | POLLOUT | POLLERR;
+
+ env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, 0);
+ int n = poll(&fds, 1, timeoutMs);
+ if (n <= 0) {
+ if (n < 0) {
+ LOGE("listening poll() on RFCOMM socket: %s (%d)",
+ strerror(errno),
+ errno);
+ env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, timeoutMs);
+ }
+ else {
+ LOGI("listening poll() on RFCOMM socket timed out");
+ }
+ return NULL;
+ }
+
+ LOGI("listening poll() on RFCOMM socket returned %d", n);
+ if (fds.fd == nat->rfcomm_sock) {
+ if (fds.revents & (POLLIN | POLLPRI | POLLOUT)) {
+ LOGI("Accepting connection.\n");
+ nsk = do_accept(env, obj, nat->rfcomm_sock,
+ newsock, field_mAddress, true);
+ if (nsk < 0) {
+ return NULL;
+ }
+ }
+ }
+ }
+
+ LOGI("Connection accepted, new socket fd = %d.", nsk);
+ native_data_t *newnat = get_native_data(env, newsock);
+ newnat->rfcomm_sock = nsk;
+ newnat->rfcomm_connected = 3;
+ return jniCreateFileDescriptor(env, nsk);
+#else
+ return NULL;
+#endif
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+
+ {"createNative", "()Ljava/io/FileDescriptor;", (void *)createNative},
+ {"destroyNative", "()V", (void *)destroyNative},
+ {"connectNative", "(Ljava/lang/String;I)Z", (void *)connectNative},
+ {"connectAsyncNative", "(Ljava/lang/String;I)Z", (void *)connectAsyncNative},
+ {"interruptAsyncConnectNative", "()Z", (void *)interruptAsyncConnectNative},
+ {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
+ {"shutdownNative", "(Z)Z", (void *)shutdownNative},
+ {"isConnectedNative", "()I", (void *)isConnectedNative},
+
+ {"bindNative", "(Ljava/lang/String;I)Z", (void*)bindNative},
+ {"listenNative", "(I)Z", (void*)listenNative},
+ {"acceptNative", "(Landroid/bluetooth/RfcommSocket;I)Ljava/io/FileDescriptor;", (void*)acceptNative},
+};
+
+int register_android_bluetooth_RfcommSocket(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/bluetooth/RfcommSocket", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_bluetooth_ScoSocket.cpp b/core/jni/android_bluetooth_ScoSocket.cpp
new file mode 100644
index 0000000..3afe5f5
--- /dev/null
+++ b/core/jni/android_bluetooth_ScoSocket.cpp
@@ -0,0 +1,506 @@
+/*
+** 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 "bluetooth_ScoSocket.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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sco.h>
+#endif
+
+/* Ideally, blocking I/O on a SCO socket would return when another thread
+ * calls close(). However it does not right now, in fact close() on a SCO
+ * socket has strange behavior (returns a bogus value) when other threads
+ * are performing blocking I/O on that socket. So, to workaround, we always
+ * call close() from the same thread that does blocking I/O. This requires the
+ * use of a socketpair to signal the blocking I/O to abort.
+ *
+ * Unfortunately I don't know a way to abort connect() yet, but at least this
+ * times out after the BT page timeout (10 seconds currently), so the thread
+ * will die eventually. The fact that the thread can outlive
+ * the Java object forces us to use a mutex in destoryNative().
+ *
+ * The JNI API is entirely async.
+ *
+ * Also note this class deals only with SCO connections, not with data
+ * transmission.
+ */
+namespace android {
+#ifdef HAVE_BLUETOOTH
+
+static JavaVM *jvm;
+static jfieldID field_mNativeData;
+static jmethodID method_onAccepted;
+static jmethodID method_onConnected;
+static jmethodID method_onClosed;
+
+struct thread_data_t;
+static void *work_thread(void *arg);
+static int connect_work(const char *address);
+static int accept_work(int signal_sk);
+static void wait_for_close(int sk, int signal_sk);
+static void closeNative(JNIEnv *env, jobject object);
+
+/* shared native data - protected by mutex */
+typedef struct {
+ pthread_mutex_t mutex;
+ int signal_sk; // socket to signal blocked I/O to unblock
+ jobject object; // JNI global ref to the Java object
+ thread_data_t *thread_data; // pointer to thread local data
+ // max 1 thread per sco socket
+} native_data_t;
+
+/* thread local data */
+struct thread_data_t {
+ native_data_t *nat;
+ bool is_accept; // accept (listening) or connect (outgoing) thread
+ int signal_sk; // socket for thread to listen for unblock signal
+ char address[BTADDR_SIZE]; // BT addres as string
+};
+
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ return (native_data_t *)(env->GetIntField(object, field_mNativeData));
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ if (env->GetJavaVM(&jvm) < 0) {
+ LOGE("Could not get handle to the VM");
+ }
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+ method_onAccepted = env->GetMethodID(clazz, "onAccepted", "(I)V");
+ method_onConnected = env->GetMethodID(clazz, "onConnected", "(I)V");
+ method_onClosed = env->GetMethodID(clazz, "onClosed", "()V");
+#endif
+}
+
+/* Returns false if a serious error occured */
+static jboolean initNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+
+ native_data_t *nat = (native_data_t *) calloc(1, sizeof(native_data_t));
+ if (nat == NULL) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ pthread_mutex_init(&nat->mutex, NULL);
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ nat->signal_sk = -1;
+ nat->object = NULL;
+ nat->thread_data = NULL;
+
+#endif
+ return JNI_TRUE;
+}
+
+static void destroyNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+
+ closeNative(env, object);
+
+ pthread_mutex_lock(&nat->mutex);
+ if (nat->thread_data != NULL) {
+ nat->thread_data->nat = NULL;
+ }
+ pthread_mutex_unlock(&nat->mutex);
+ pthread_mutex_destroy(&nat->mutex);
+
+ free(nat);
+#endif
+}
+
+static jboolean acceptNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ int signal_sks[2];
+ pthread_t thread;
+ struct thread_data_t *data = NULL;
+
+ pthread_mutex_lock(&nat->mutex);
+ if (nat->signal_sk != -1) {
+ pthread_mutex_unlock(&nat->mutex);
+ return JNI_FALSE;
+ }
+
+ // setup socketpair to pass messages between threads
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sks) < 0) {
+ LOGE("%s: socketpair() failed: %s", __FUNCTION__, strerror(errno));
+ pthread_mutex_unlock(&nat->mutex);
+ return JNI_FALSE;
+ }
+ nat->signal_sk = signal_sks[0];
+ nat->object = env->NewGlobalRef(object);
+
+ data = (thread_data_t *)calloc(1, sizeof(thread_data_t));
+ if (data == NULL) {
+ LOGE("%s: out of memory", __FUNCTION__);
+ pthread_mutex_unlock(&nat->mutex);
+ return JNI_FALSE;
+ }
+ nat->thread_data = data;
+ pthread_mutex_unlock(&nat->mutex);
+
+ data->signal_sk = signal_sks[1];
+ data->nat = nat;
+ data->is_accept = true;
+
+ if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) {
+ LOGE("%s: pthread_create() failed: %s", __FUNCTION__, strerror(errno));
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean connectNative(JNIEnv *env, jobject object, jstring address) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ int signal_sks[2];
+ pthread_t thread;
+ struct thread_data_t *data;
+ const char *c_address;
+
+ pthread_mutex_lock(&nat->mutex);
+ if (nat->signal_sk != -1) {
+ pthread_mutex_unlock(&nat->mutex);
+ return JNI_FALSE;
+ }
+
+ // setup socketpair to pass messages between threads
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sks) < 0) {
+ LOGE("%s: socketpair() failed: %s\n", __FUNCTION__, strerror(errno));
+ pthread_mutex_unlock(&nat->mutex);
+ return JNI_FALSE;
+ }
+ nat->signal_sk = signal_sks[0];
+ nat->object = env->NewGlobalRef(object);
+
+ data = (thread_data_t *)calloc(1, sizeof(thread_data_t));
+ if (data == NULL) {
+ LOGE("%s: out of memory", __FUNCTION__);
+ pthread_mutex_unlock(&nat->mutex);
+ return JNI_FALSE;
+ }
+ pthread_mutex_unlock(&nat->mutex);
+
+ data->signal_sk = signal_sks[1];
+ data->nat = nat;
+ c_address = env->GetStringUTFChars(address, NULL);
+ strlcpy(data->address, c_address, BTADDR_SIZE);
+ env->ReleaseStringUTFChars(address, c_address);
+ data->is_accept = false;
+
+ if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) {
+ LOGE("%s: pthread_create() failed: %s", __FUNCTION__, strerror(errno));
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+
+#endif
+ return JNI_FALSE;
+}
+
+static void closeNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ int signal_sk;
+
+ pthread_mutex_lock(&nat->mutex);
+ signal_sk = nat->signal_sk;
+ nat->signal_sk = -1;
+ env->DeleteGlobalRef(nat->object);
+ nat->object = NULL;
+ pthread_mutex_unlock(&nat->mutex);
+
+ if (signal_sk >= 0) {
+ LOGV("%s: signal_sk = %d", __FUNCTION__, signal_sk);
+ unsigned char dummy;
+ write(signal_sk, &dummy, sizeof(dummy));
+ close(signal_sk);
+ }
+#endif
+}
+
+#ifdef HAVE_BLUETOOTH
+/* thread entry point */
+static void *work_thread(void *arg) {
+ JNIEnv* env;
+ thread_data_t *data = (thread_data_t *)arg;
+ int sk;
+
+ LOGV(__FUNCTION__);
+ if (jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
+ LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
+ return NULL;
+ }
+
+ /* connect the SCO socket */
+ if (data->is_accept) {
+ LOGV("SCO OBJECT %p ACCEPT #####", data->nat->object);
+ sk = accept_work(data->signal_sk);
+ LOGV("SCO OBJECT %p END ACCEPT *****", data->nat->object);
+ } else {
+ sk = connect_work(data->address);
+ }
+
+ /* callback with connection result */
+ if (data->nat == NULL) {
+ LOGV("%s: object destroyed!", __FUNCTION__);
+ goto done;
+ }
+ pthread_mutex_lock(&data->nat->mutex);
+ if (data->nat->object == NULL) {
+ pthread_mutex_unlock(&data->nat->mutex);
+ LOGV("%s: callback cancelled", __FUNCTION__);
+ goto done;
+ }
+ if (data->is_accept) {
+ env->CallVoidMethod(data->nat->object, method_onAccepted, sk);
+ } else {
+ env->CallVoidMethod(data->nat->object, method_onConnected, sk);
+ }
+ pthread_mutex_unlock(&data->nat->mutex);
+
+ if (sk < 0) {
+ goto done;
+ }
+
+ LOGV("SCO OBJECT %p %d CONNECTED +++ (%s)", data->nat->object, sk,
+ data->is_accept ? "in" : "out");
+
+ /* wait for the socket to close */
+ LOGV("wait_for_close()...");
+ wait_for_close(sk, data->signal_sk);
+ LOGV("wait_for_close() returned");
+
+ /* callback with close result */
+ if (data->nat == NULL) {
+ LOGV("%s: object destroyed!", __FUNCTION__);
+ goto done;
+ }
+ pthread_mutex_lock(&data->nat->mutex);
+ if (data->nat->object == NULL) {
+ LOGV("%s: callback cancelled", __FUNCTION__);
+ } else {
+ env->CallVoidMethod(data->nat->object, method_onClosed);
+ }
+ pthread_mutex_unlock(&data->nat->mutex);
+
+done:
+ if (sk >= 0) {
+ close(sk);
+ LOGV("SCO OBJECT %p %d CLOSED --- (%s)", data->nat->object, sk, data->is_accept ? "in" : "out");
+ }
+ if (data->signal_sk >= 0) {
+ close(data->signal_sk);
+ }
+ LOGV("SCO socket closed");
+
+ if (data->nat != NULL) {
+ pthread_mutex_lock(&data->nat->mutex);
+ env->DeleteGlobalRef(data->nat->object);
+ data->nat->object = NULL;
+ data->nat->thread_data = NULL;
+ pthread_mutex_unlock(&data->nat->mutex);
+ }
+
+ free(data);
+ if (jvm->DetachCurrentThread() != JNI_OK) {
+ LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
+ }
+
+ LOGV("work_thread() done");
+ return NULL;
+}
+
+static int accept_work(int signal_sk) {
+ LOGV(__FUNCTION__);
+ int sk;
+ int nsk;
+ int addr_sz;
+ int max_fd;
+ fd_set fds;
+ struct sockaddr_sco addr;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sk < 0) {
+ LOGE("%s socket() failed: %s", __FUNCTION__, strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ memcpy(&addr.sco_bdaddr, BDADDR_ANY, sizeof(bdaddr_t));
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ LOGE("%s bind() failed: %s", __FUNCTION__, strerror(errno));
+ goto error;
+ }
+
+ if (listen(sk, 1)) {
+ LOGE("%s: listen() failed: %s", __FUNCTION__, strerror(errno));
+ goto error;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr_sz = sizeof(addr);
+
+ FD_ZERO(&fds);
+ FD_SET(sk, &fds);
+ FD_SET(signal_sk, &fds);
+
+ max_fd = (sk > signal_sk) ? sk : signal_sk;
+ LOGI("Listening SCO socket...");
+ while (select(max_fd + 1, &fds, NULL, NULL, NULL) < 0) {
+ if (errno != EINTR) {
+ LOGE("%s: select() failed: %s", __FUNCTION__, strerror(errno));
+ goto error;
+ }
+ LOGV("%s: select() EINTR, retrying", __FUNCTION__);
+ }
+ LOGV("select() returned");
+ if (FD_ISSET(signal_sk, &fds)) {
+ // signal to cancel listening
+ LOGV("cancelled listening socket, closing");
+ goto error;
+ }
+ if (!FD_ISSET(sk, &fds)) {
+ LOGE("error: select() returned >= 0 with no fds set");
+ goto error;
+ }
+
+ nsk = accept(sk, (struct sockaddr *)&addr, &addr_sz);
+ if (nsk < 0) {
+ LOGE("%s: accept() failed: %s", __FUNCTION__, strerror(errno));
+ goto error;
+ }
+ LOGI("Connected SCO socket (incoming)");
+ close(sk); // The listening socket
+
+ return nsk;
+
+error:
+ close(sk);
+
+ return -1;
+}
+
+static int connect_work(const char *address) {
+ LOGV(__FUNCTION__);
+ struct sockaddr_sco addr;
+ int sk = -1;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sk < 0) {
+ LOGE("%s: socket() failed: %s", __FUNCTION__, strerror(errno));
+ return -1;
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ memcpy(&addr.sco_bdaddr, BDADDR_ANY, sizeof(bdaddr_t));
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ LOGE("%s: bind() failed: %s", __FUNCTION__, strerror(errno));
+ goto error;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ get_bdaddr(address, &addr.sco_bdaddr);
+ LOGI("Connecting to socket");
+ while (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ if (errno != EINTR) {
+ LOGE("%s: connect() failed: %s", __FUNCTION__, strerror(errno));
+ goto error;
+ }
+ LOGV("%s: connect() EINTR, retrying", __FUNCTION__);
+ }
+ LOGI("SCO socket connected (outgoing)");
+
+ return sk;
+
+error:
+ if (sk >= 0) close(sk);
+ return -1;
+}
+
+static void wait_for_close(int sk, int signal_sk) {
+ LOGV(__FUNCTION__);
+ pollfd p[2];
+
+ memset(p, 0, 2 * sizeof(pollfd));
+ p[0].fd = sk;
+ p[1].fd = signal_sk;
+ p[1].events = POLLIN | POLLPRI;
+
+ LOGV("poll...");
+
+ while (poll(p, 2, -1) < 0) { // blocks
+ if (errno != EINTR) {
+ LOGE("%s: poll() failed: %s", __FUNCTION__, strerror(errno));
+ break;
+ }
+ LOGV("%s: poll() EINTR, retrying", __FUNCTION__);
+ }
+
+ LOGV("poll() returned");
+}
+#endif
+
+static JNINativeMethod sMethods[] = {
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initNative", "()V", (void *)initNative},
+ {"destroyNative", "()V", (void *)destroyNative},
+ {"connectNative", "(Ljava/lang/String;)Z", (void *)connectNative},
+ {"acceptNative", "()Z", (void *)acceptNative},
+ {"closeNative", "()V", (void *)closeNative},
+};
+
+int register_android_bluetooth_ScoSocket(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/bluetooth/ScoSocket", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp
new file mode 100644
index 0000000..c81af1ce
--- /dev/null
+++ b/core/jni/android_bluetooth_common.cpp
@@ -0,0 +1,423 @@
+/*
+** Copyright 2006, 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 "bluetooth_common.cpp"
+
+#include "android_bluetooth_common.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <cutils/properties.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
+ const char *mtype) {
+ jfieldID field = env->GetFieldID(clazz, member, mtype);
+ if (field == NULL) {
+ LOGE("Can't find member %s", member);
+ }
+ return field;
+}
+
+typedef struct {
+ void (*user_cb)(DBusMessage *, void *);
+ void *user;
+ JNIEnv *env;
+} dbus_async_call_t;
+
+void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
+
+ dbus_async_call_t *req = (dbus_async_call_t *)data;
+ DBusMessage *msg;
+
+ /* This is guaranteed to be non-NULL, because this function is called only
+ when once the remote method invokation returns. */
+ msg = dbus_pending_call_steal_reply(call);
+
+ if (msg) {
+ if (req->user_cb) {
+ // The user may not deref the message object.
+ req->user_cb(msg, req->user);
+ }
+ dbus_message_unref(msg);
+ }
+
+ //dbus_message_unref(req->method);
+ dbus_pending_call_cancel(call);
+ dbus_pending_call_unref(call);
+ free(req);
+}
+
+dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ void (*user_cb)(DBusMessage *, void *),
+ void *user,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ va_list args) {
+ DBusMessage *msg = NULL;
+ const char *name;
+ dbus_async_call_t *pending;
+ dbus_bool_t reply = FALSE;
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
+
+ if (msg == NULL) {
+ LOGE("Could not allocate D-Bus message object!");
+ goto done;
+ }
+
+ /* append arguments */
+ if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
+ LOGE("Could not append argument to method call!");
+ goto done;
+ }
+
+ /* Make the call. */
+ pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
+ if (pending) {
+ DBusPendingCall *call;
+
+ pending->env = env;
+ pending->user_cb = user_cb;
+ pending->user = user;
+ //pending->method = msg;
+
+ reply = dbus_connection_send_with_reply(conn, msg,
+ &call,
+ timeout_ms);
+ if (reply == TRUE) {
+ dbus_pending_call_set_notify(call,
+ dbus_func_args_async_callback,
+ pending,
+ NULL);
+ }
+ }
+
+done:
+ if (msg) dbus_message_unref(msg);
+ return reply;
+}
+
+dbus_bool_t dbus_func_args_async(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ void (*reply)(DBusMessage *, void *),
+ void *user,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...) {
+ dbus_bool_t ret;
+ va_list lst;
+ va_start(lst, first_arg_type);
+ ret = dbus_func_args_async_valist(env, conn,
+ timeout_ms,
+ reply, user,
+ path, ifc, func,
+ first_arg_type, lst);
+ va_end(lst);
+ return ret;
+}
+
+// If err is NULL, then any errors will be LOGE'd, and free'd and the reply
+// will be NULL.
+// If err is not NULL, then it is assumed that dbus_error_init was already
+// called, and error's will be returned to the caller without logging. The
+// return value is NULL iff an error was set. The client must free the error if
+// set.
+DBusMessage * dbus_func_args_timeout_valist(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ DBusError *err,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ va_list args) {
+
+ DBusMessage *msg = NULL, *reply = NULL;
+ const char *name;
+ bool return_error = (err != NULL);
+
+ if (!return_error) {
+ err = (DBusError*)malloc(sizeof(DBusError));
+ dbus_error_init(err);
+ }
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
+
+ if (msg == NULL) {
+ LOGE("Could not allocate D-Bus message object!");
+ goto done;
+ }
+
+ /* append arguments */
+ if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
+ LOGE("Could not append argument to method call!");
+ goto done;
+ }
+
+ /* Make the call. */
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, timeout_ms, err);
+ if (!return_error && dbus_error_is_set(err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg);
+ }
+
+done:
+ if (!return_error) {
+ free(err);
+ }
+ if (msg) dbus_message_unref(msg);
+ return reply;
+}
+
+DBusMessage * dbus_func_args_timeout(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...) {
+ DBusMessage *ret;
+ va_list lst;
+ va_start(lst, first_arg_type);
+ ret = dbus_func_args_timeout_valist(env, conn, timeout_ms, NULL,
+ path, ifc, func,
+ first_arg_type, lst);
+ va_end(lst);
+ return ret;
+}
+
+DBusMessage * dbus_func_args(JNIEnv *env,
+ DBusConnection *conn,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...) {
+ DBusMessage *ret;
+ va_list lst;
+ va_start(lst, first_arg_type);
+ ret = dbus_func_args_timeout_valist(env, conn, -1, NULL,
+ path, ifc, func,
+ first_arg_type, lst);
+ va_end(lst);
+ return ret;
+}
+
+DBusMessage * dbus_func_args_error(JNIEnv *env,
+ DBusConnection *conn,
+ DBusError *err,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...) {
+ DBusMessage *ret;
+ va_list lst;
+ va_start(lst, first_arg_type);
+ ret = dbus_func_args_timeout_valist(env, conn, -1, err,
+ path, ifc, func,
+ first_arg_type, lst);
+ va_end(lst);
+ return ret;
+}
+
+jint dbus_returns_int32(JNIEnv *env, DBusMessage *reply) {
+
+ DBusError err;
+ jint ret = -1;
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(reply, &err,
+ DBUS_TYPE_INT32, &ret,
+ DBUS_TYPE_INVALID)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+ dbus_message_unref(reply);
+ return ret;
+}
+
+jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply) {
+
+ DBusError err;
+ jint ret = -1;
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(reply, &err,
+ DBUS_TYPE_UINT32, &ret,
+ DBUS_TYPE_INVALID)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+ dbus_message_unref(reply);
+ return ret;
+}
+
+jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply) {
+
+ DBusError err;
+ jstring ret = NULL;
+ const char *name;
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args(reply, &err,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID)) {
+ ret = env->NewStringUTF(name);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+ dbus_message_unref(reply);
+
+ return ret;
+}
+
+jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply) {
+ DBusError err;
+ jboolean ret = JNI_FALSE;
+ dbus_bool_t val = FALSE;
+
+ dbus_error_init(&err);
+
+ /* Check the return value. */
+ if (dbus_message_get_args(reply, &err,
+ DBUS_TYPE_BOOLEAN, &val,
+ DBUS_TYPE_INVALID)) {
+ ret = val == TRUE ? JNI_TRUE : JNI_FALSE;
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+
+ dbus_message_unref(reply);
+ return ret;
+}
+
+jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
+
+ DBusError err;
+ char **list;
+ int i, len;
+ jobjectArray strArray = NULL;
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args (reply,
+ &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &list, &len,
+ DBUS_TYPE_INVALID)) {
+ jclass stringClass;
+ jstring classNameStr;
+
+ //LOGV("%s: there are %d elements in string array!", __FUNCTION__, len);
+
+ stringClass = env->FindClass("java/lang/String");
+ strArray = env->NewObjectArray(len, stringClass, NULL);
+
+ for (i = 0; i < len; i++) {
+ //LOGV("%s: array[%d] = [%s]", __FUNCTION__, i, list[i]);
+ env->SetObjectArrayElement(strArray, i,
+ env->NewStringUTF(list[i]));
+ }
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+
+ dbus_message_unref(reply);
+ return strArray;
+}
+
+jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) {
+
+ DBusError err;
+ int i, len;
+ jbyte *list;
+ jbyteArray byteArray = NULL;
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args(reply, &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &list, &len,
+ DBUS_TYPE_INVALID)) {
+ //LOGV("%s: there are %d elements in byte array!", __FUNCTION__, len);
+ byteArray = env->NewByteArray(len);
+ if (byteArray)
+ env->SetByteArrayRegion(byteArray, 0, len, list);
+
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+
+ dbus_message_unref(reply);
+ return byteArray;
+}
+
+void get_bdaddr(const char *str, bdaddr_t *ba) {
+ char *d = ((char *)ba) + 5, *endp;
+ int i;
+ for(i = 0; i < 6; i++) {
+ *d-- = strtol(str, &endp, 16);
+ if (*endp != ':' && i != 5) {
+ memset(ba, 0, sizeof(bdaddr_t));
+ return;
+ }
+ str = endp + 1;
+ }
+}
+
+void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
+ const uint8_t *b = (const uint8_t *)ba;
+ sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ b[5], b[4], b[3], b[2], b[1], b[0]);
+}
+
+bool debug_no_encrypt() {
+ return false;
+#if 0
+ char value[PROPERTY_VALUE_MAX] = "";
+
+ property_get("debug.bt.no_encrypt", value, "");
+ if (!strncmp("true", value, PROPERTY_VALUE_MAX) ||
+ !strncmp("1", value, PROPERTY_VALUE_MAX)) {
+ LOGD("mandatory bluetooth encryption disabled");
+ return true;
+ } else {
+ return false;
+ }
+#endif
+}
+#endif
+
+} /* namespace android */
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
new file mode 100644
index 0000000..e77cd30
--- /dev/null
+++ b/core/jni/android_bluetooth_common.h
@@ -0,0 +1,137 @@
+/*
+** Copyright 2006, 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.
+*/
+
+#ifndef ANDROID_BLUETOOTH_COMMON_H
+#define ANDROID_BLUETOOTH_COMMON_H
+
+// Set to 0 to enable verbose bluetooth logging
+#define LOG_NDEBUG 1
+
+#include "jni.h"
+#include "utils/Log.h"
+
+#include <errno.h>
+#include <stdint.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#include <bluetooth/bluetooth.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+#define BLUEZ_DBUS_BASE_PATH "/org/bluez"
+#define BLUEZ_DBUS_BASE_IFC "org.bluez"
+
+// It would be nicer to retrieve this from bluez using GetDefaultAdapter,
+// but this is only possible when the adapter is up (and hcid is running).
+// It is much easier just to hardcode bluetooth adapter to hci0
+#define BLUETOOTH_ADAPTER_HCI_NUM 0
+#define BLUEZ_ADAPTER_OBJECT_NAME BLUEZ_DBUS_BASE_PATH "/hci0"
+
+#define BTADDR_SIZE 18 // size of BT address character array (including null)
+
+jfieldID get_field(JNIEnv *env,
+ jclass clazz,
+ const char *member,
+ const char *mtype);
+
+// LOGE and free a D-Bus error
+// Using #define so that __FUNCTION__ resolves usefully
+#define LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg) \
+ { LOGE("%s: D-Bus error in %s: %s (%s)", __FUNCTION__, \
+ dbus_message_get_member((msg)), (err)->name, (err)->message); \
+ dbus_error_free((err)); }
+#define LOG_AND_FREE_DBUS_ERROR(err) \
+ { LOGE("%s: D-Bus error: %s (%s)", __FUNCTION__, \
+ (err)->name, (err)->message); \
+ dbus_error_free((err)); }
+
+dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ void (*reply)(DBusMessage *, void *),
+ void *user,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ va_list args);
+
+dbus_bool_t dbus_func_args_async(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ void (*reply)(DBusMessage *, void *),
+ void *user,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...);
+
+DBusMessage * dbus_func_args(JNIEnv *env,
+ DBusConnection *conn,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...);
+
+DBusMessage * dbus_func_args_error(JNIEnv *env,
+ DBusConnection *conn,
+ DBusError *err,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...);
+
+DBusMessage * dbus_func_args_timeout(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ ...);
+
+DBusMessage * dbus_func_args_timeout_valist(JNIEnv *env,
+ DBusConnection *conn,
+ int timeout_ms,
+ DBusError *err,
+ const char *path,
+ const char *ifc,
+ const char *func,
+ int first_arg_type,
+ va_list args);
+
+jint dbus_returns_int32(JNIEnv *env, DBusMessage *reply);
+jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply);
+jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply);
+jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply);
+jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply);
+jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply);
+
+void get_bdaddr(const char *str, bdaddr_t *ba);
+void get_bdaddr_as_string(const bdaddr_t *ba, char *str);
+
+bool debug_no_encrypt();
+
+#endif
+} /* namespace android */
+
+#endif/*ANDROID_BLUETOOTH_COMMON_H*/
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
new file mode 100644
index 0000000..f19fbbf
--- /dev/null
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CursorWindow"
+
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "CursorWindow.h"
+#include "sqlite3_exception.h"
+#include "android_util_Binder.h"
+
+
+namespace android {
+
+static jfieldID gWindowField;
+static jfieldID gBufferField;
+static jfieldID gSizeCopiedField;
+
+#define GET_WINDOW(env, object) ((CursorWindow *)env->GetIntField(object, gWindowField))
+#define SET_WINDOW(env, object, window) (env->SetIntField(object, gWindowField, (int)window))
+#define SET_BUFFER(env, object, buf) (env->SetObjectField(object, gBufferField, buf))
+#define SET_SIZE_COPIED(env, object, size) (env->SetIntField(object, gSizeCopiedField, size))
+
+CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow)
+{
+ return GET_WINDOW(env, javaWindow);
+}
+
+static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly)
+{
+ uint8_t * data;
+ size_t size;
+ CursorWindow * window;
+
+ window = new CursorWindow(MAX_WINDOW_SIZE);
+ if (!window) {
+ jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object");
+ return;
+ }
+
+ if (!window->initBuffer(localOnly)) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Couldn't init cursor window");
+ delete window;
+ return;
+ }
+
+LOG_WINDOW("native_init_empty: window = %p", window);
+ SET_WINDOW(env, object, window);
+}
+
+static void native_init_memory(JNIEnv * env, jobject object, jobject memObj)
+{
+ sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj));
+ if (memory == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Couldn't get native binder");
+ return;
+ }
+
+ CursorWindow * window = new CursorWindow();
+ if (!window) {
+ jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object");
+ return;
+ }
+ if (!window->setMemory(memory)) {
+ jniThrowException(env, "java/lang/RuntimeException", "No memory in memObj");
+ delete window;
+ return;
+ }
+
+LOG_WINDOW("native_init_memory: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window);
+ SET_WINDOW(env, object, window);
+}
+
+static jobject native_getBinder(JNIEnv * env, jobject object)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ if (window) {
+ sp<IMemory> memory = window->getMemory();
+ if (memory != NULL) {
+ sp<IBinder> binder = memory->asBinder();
+ return javaObjectForIBinder(env, binder);
+ }
+ }
+ return NULL;
+}
+
+static void native_clear(JNIEnv * env, jobject object)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Clearing window %p", window);
+ if (window == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", "clear() called after close()");
+ return;
+ }
+ window->clear();
+}
+
+static void native_close(JNIEnv * env, jobject object)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ if (window) {
+LOG_WINDOW("Closing window %p", window);
+ delete window;
+ SET_WINDOW(env, object, 0);
+ }
+}
+
+static void throwExceptionWithRowCol(JNIEnv * env, jint row, jint column)
+{
+ char buf[100];
+ snprintf(buf, sizeof(buf), "get field slot from row %d col %d failed", row, column);
+ jniThrowException(env, "java/lang/IllegalStateException", buf);
+}
+
+static void throwUnknowTypeException(JNIEnv * env, jint type)
+{
+ char buf[80];
+ snprintf(buf, sizeof(buf), "UNKNOWN type %d", type);
+ jniThrowException(env, "java/lang/IllegalStateException", buf);
+}
+
+static jlong getLong_native(JNIEnv * env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Getting long for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return 0;
+ }
+
+ uint8_t type = field.type;
+ if (type == FIELD_TYPE_INTEGER) {
+ int64_t value;
+ if (window->getLong(row, column, &value)) {
+ return value;
+ }
+ return 0;
+ } else if (type == FIELD_TYPE_STRING) {
+ uint32_t size = field.data.buffer.size;
+ if (size > 0) {
+#if WINDOW_STORAGE_UTF8
+ return strtoll((char const *)window->offsetToPtr(field.data.buffer.offset), NULL, 0);
+#else
+ String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2);
+ char const * str = ascii.string();
+ return strtoll(str, NULL, 0);
+#endif
+ } else {
+ return 0;
+ }
+ } else if (type == FIELD_TYPE_FLOAT) {
+ double value;
+ if (window->getDouble(row, column, &value)) {
+ return value;
+ }
+ return 0;
+ } else if (type == FIELD_TYPE_NULL) {
+ return 0;
+ } else if (type == FIELD_TYPE_BLOB) {
+ throw_sqlite3_exception(env, "Unable to convert BLOB to long");
+ return 0;
+ } else {
+ throwUnknowTypeException(env, type);
+ return 0;
+ }
+}
+
+static jbyteArray getBlob_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ uint8_t type = field.type;
+ if (type == FIELD_TYPE_BLOB || type == FIELD_TYPE_STRING) {
+ jbyteArray byteArray = env->NewByteArray(field.data.buffer.size);
+ LOG_ASSERT(byteArray, "Native could not create new byte[]");
+ env->SetByteArrayRegion(byteArray, 0, field.data.buffer.size,
+ (const jbyte*)window->offsetToPtr(field.data.buffer.offset));
+ return byteArray;
+ } else if (type == FIELD_TYPE_INTEGER) {
+ throw_sqlite3_exception(env, "INTEGER data in getBlob_native ");
+ } else if (type == FIELD_TYPE_FLOAT) {
+ throw_sqlite3_exception(env, "FLOAT data in getBlob_native ");
+ } else if (type == FIELD_TYPE_NULL) {
+ // do nothing
+ } else {
+ throwUnknowTypeException(env, type);
+ }
+ return NULL;
+}
+
+static jboolean isBlob_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type == FIELD_TYPE_BLOB || field.type == FIELD_TYPE_NULL;
+}
+
+static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ uint8_t type = field.type;
+ if (type == FIELD_TYPE_STRING) {
+ uint32_t size = field.data.buffer.size;
+ if (size > 0) {
+#if WINDOW_STORAGE_UTF8
+ // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
+ String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
+ return env->NewString((jchar const *)utf16.string(), utf16.size());
+#else
+ return env->NewString((jchar const *)window->offsetToPtr(field.data.buffer.offset), size / 2);
+#endif
+ } else {
+ return env->NewStringUTF("");
+ }
+ } else if (type == FIELD_TYPE_INTEGER) {
+ int64_t value;
+ if (window->getLong(row, column, &value)) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%lld", value);
+ return env->NewStringUTF(buf);
+ }
+ return NULL;
+ } else if (type == FIELD_TYPE_FLOAT) {
+ double value;
+ if (window->getDouble(row, column, &value)) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%g", value);
+ return env->NewStringUTF(buf);
+ }
+ return NULL;
+ } else if (type == FIELD_TYPE_NULL) {
+ return NULL;
+ } else if (type == FIELD_TYPE_BLOB) {
+ throw_sqlite3_exception(env, "Unable to convert BLOB to string");
+ return NULL;
+ } else {
+ throwUnknowTypeException(env, type);
+ return NULL;
+ }
+}
+
+/**
+ * Use this only to convert characters that are known to be within the
+ * 0-127 range for direct conversion to UTF-16
+ */
+static jint charToJchar(const char* src, jchar* dst, jint bufferSize)
+{
+ int32_t len = strlen(src);
+
+ if (bufferSize < len) {
+ len = bufferSize;
+ }
+
+ for (int i = 0; i < len; i++) {
+ *dst++ = (*src++ & 0x7F);
+ }
+ return len;
+}
+
+static jcharArray copyStringToBuffer_native(JNIEnv* env, jobject object, jint row,
+ jint column, jint bufferSize, jobject buf)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot");
+ return NULL;
+ }
+
+ jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField);
+ if (buffer == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null");
+ return NULL;
+ }
+ jchar* dst = env->GetCharArrayElements(buffer, NULL);
+ uint8_t type = field.type;
+ uint32_t sizeCopied = 0;
+ jcharArray newArray = NULL;
+ if (type == FIELD_TYPE_STRING) {
+ uint32_t size = field.data.buffer.size;
+ if (size > 0) {
+#if WINDOW_STORAGE_UTF8
+ // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
+ String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
+ int32_t strSize = utf16.size();
+ if (strSize > bufferSize || dst == NULL) {
+ newArray = env->NewCharArray(strSize);
+ env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string());
+ } else {
+ memcpy(dst, (jchar const *)utf16.string(), strSize * 2);
+ }
+ sizeCopied = strSize;
+#else
+ sizeCopied = size/2 + size % 2;
+ if (size > bufferSize * 2 || dst == NULL) {
+ newArray = env->NewCharArray(sizeCopied);
+ memcpy(newArray, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size);
+ } else {
+ memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size);
+ }
+#endif
+ }
+ } else if (type == FIELD_TYPE_INTEGER) {
+ int64_t value;
+ if (window->getLong(row, column, &value)) {
+ char buf[32];
+ int len;
+ snprintf(buf, sizeof(buf), "%lld", value);
+ jchar* dst = env->GetCharArrayElements(buffer, NULL);
+ sizeCopied = charToJchar(buf, dst, bufferSize);
+ }
+ } else if (type == FIELD_TYPE_FLOAT) {
+ double value;
+ if (window->getDouble(row, column, &value)) {
+ char tempbuf[32];
+ snprintf(tempbuf, sizeof(tempbuf), "%g", value);
+ jchar* dst = env->GetCharArrayElements(buffer, NULL);
+ sizeCopied = charToJchar(tempbuf, dst, bufferSize);
+ }
+ } else if (type == FIELD_TYPE_NULL) {
+ } else if (type == FIELD_TYPE_BLOB) {
+ throw_sqlite3_exception(env, "Unable to convert BLOB to string");
+ } else {
+ LOGE("Unknown field type %d", type);
+ throw_sqlite3_exception(env, "UNKNOWN type in copyStringToBuffer_native()");
+ }
+ SET_SIZE_COPIED(env, buf, sizeCopied);
+ env->ReleaseCharArrayElements(buffer, dst, JNI_OK);
+ return newArray;
+}
+
+static jdouble getDouble_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return 0.0;
+ }
+
+ uint8_t type = field.type;
+ if (type == FIELD_TYPE_FLOAT) {
+ double value;
+ if (window->getDouble(row, column, &value)) {
+ return value;
+ }
+ return 0.0;
+ } else if (type == FIELD_TYPE_STRING) {
+ uint32_t size = field.data.buffer.size;
+ if (size > 0) {
+#if WINDOW_STORAGE_UTF8
+ return strtod((char const *)window->offsetToPtr(field.data.buffer.offset), NULL);
+#else
+ String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2);
+ char const * str = ascii.string();
+ return strtod(str, NULL);
+#endif
+ } else {
+ return 0.0;
+ }
+ } else if (type == FIELD_TYPE_INTEGER) {
+ int64_t value;
+ if (window->getLong(row, column, &value)) {
+ return (double) value;
+ }
+ return 0.0;
+ } else if (type == FIELD_TYPE_NULL) {
+ return 0.0;
+ } else if (type == FIELD_TYPE_BLOB) {
+ throw_sqlite3_exception(env, "Unable to convert BLOB to double");
+ return 0.0;
+ } else {
+ throwUnknowTypeException(env, type);
+ return 0.0;
+ }
+}
+
+static jboolean isNull_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window);
+
+ bool isNull;
+ if (window->getNull(row, column, &isNull)) {
+ return isNull;
+ }
+
+ //TODO throw execption?
+ return true;
+}
+
+static jint getNumRows(JNIEnv * env, jobject object)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ return window->getNumRows();
+}
+
+static jboolean setNumColumns(JNIEnv * env, jobject object, jint columnNum)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ return window->setNumColumns(columnNum);
+}
+
+static jboolean allocRow(JNIEnv * env, jobject object)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ return window->allocRow() != NULL;
+}
+
+static jboolean putBlob_native(JNIEnv * env, jobject object, jbyteArray value, jint row, jint col)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ if (!value) {
+ LOG_WINDOW("How did a null value send to here");
+ return false;
+ }
+ field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col);
+ if (fieldSlot == NULL) {
+ LOG_WINDOW(" getFieldSlotWithCheck error ");
+ return false;
+ }
+
+ jint len = env->GetArrayLength(value);
+ int offset = window->alloc(len);
+ if (!offset) {
+ LOG_WINDOW("Failed allocating %u bytes", len);
+ return false;
+ }
+ jbyte * bytes = env->GetByteArrayElements(value, NULL);
+ window->copyIn(offset, (uint8_t const *)bytes, len);
+
+ // This must be updated after the call to alloc(), since that
+ // may move the field around in the window
+ fieldSlot->type = FIELD_TYPE_BLOB;
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = len;
+ env->ReleaseByteArrayElements(value, bytes, JNI_ABORT);
+ LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, col, len, offset);
+ return true;
+}
+
+static jboolean putString_native(JNIEnv * env, jobject object, jstring value, jint row, jint col)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ if (!value) {
+ LOG_WINDOW("How did a null value send to here");
+ return false;
+ }
+ field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col);
+ if (fieldSlot == NULL) {
+ LOG_WINDOW(" getFieldSlotWithCheck error ");
+ return false;
+ }
+
+#if WINDOW_STORAGE_UTF8
+ int len = env->GetStringUTFLength(value) + 1;
+ char const * valStr = env->GetStringUTFChars(value, NULL);
+#else
+ int len = env->GetStringLength(value);
+ // GetStringLength return number of chars and one char takes 2 bytes
+ len *= 2;
+ const jchar* valStr = env->GetStringChars(value, NULL);
+#endif
+ if (!valStr) {
+ LOG_WINDOW("value can't be transfer to UTFChars");
+ return false;
+ }
+
+ int offset = window->alloc(len);
+ if (!offset) {
+ LOG_WINDOW("Failed allocating %u bytes", len);
+#if WINDOW_STORAGE_UTF8
+ env->ReleaseStringUTFChars(value, valStr);
+#else
+ env->ReleaseStringChars(value, valStr);
+#endif
+ return false;
+ }
+
+ window->copyIn(offset, (uint8_t const *)valStr, len);
+
+ // This must be updated after the call to alloc(), since that
+ // may move the field around in the window
+ fieldSlot->type = FIELD_TYPE_STRING;
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = len;
+
+ LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, col, len, offset);
+#if WINDOW_STORAGE_UTF8
+ env->ReleaseStringUTFChars(value, valStr);
+#else
+ env->ReleaseStringChars(value, valStr);
+#endif
+
+ return true;
+}
+
+static jboolean putLong_native(JNIEnv * env, jobject object, jlong value, jint row, jint col)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ if (!window->putLong(row, col, value)) {
+ LOG_WINDOW(" getFieldSlotWithCheck error ");
+ return false;
+ }
+
+ LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, col, value);
+
+ return true;
+}
+
+static jboolean putDouble_native(JNIEnv * env, jobject object, jdouble value, jint row, jint col)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ if (!window->putDouble(row, col, value)) {
+ LOG_WINDOW(" getFieldSlotWithCheck error ");
+ return false;
+ }
+
+ LOG_WINDOW("%d,%d is FLOAT %lf", row, col, value);
+
+ return true;
+}
+
+static jboolean putNull_native(JNIEnv * env, jobject object, jint row, jint col)
+{
+ CursorWindow * window = GET_WINDOW(env, object);
+ if (!window->putNull(row, col)) {
+ LOG_WINDOW(" getFieldSlotWithCheck error ");
+ return false;
+ }
+
+ LOG_WINDOW("%d,%d is NULL", row, col);
+
+ return true;
+}
+
+// free the last row
+static void freeLastRow(JNIEnv * env, jobject object) {
+ CursorWindow * window = GET_WINDOW(env, object);
+ window->freeLastRow();
+}
+
+static JNINativeMethod sMethods[] =
+{
+ /* name, signature, funcPtr */
+ {"native_init", "(Z)V", (void *)native_init_empty},
+ {"native_init", "(Landroid/os/IBinder;)V", (void *)native_init_memory},
+ {"native_getBinder", "()Landroid/os/IBinder;", (void *)native_getBinder},
+ {"native_clear", "()V", (void *)native_clear},
+ {"close_native", "()V", (void *)native_close},
+ {"getLong_native", "(II)J", (void *)getLong_native},
+ {"getBlob_native", "(II)[B", (void *)getBlob_native},
+ {"isBlob_native", "(II)Z", (void *)isBlob_native},
+ {"getString_native", "(II)Ljava/lang/String;", (void *)getString_native},
+ {"copyStringToBuffer_native", "(IIILandroid/database/CharArrayBuffer;)[C", (void *)copyStringToBuffer_native},
+ {"getDouble_native", "(II)D", (void *)getDouble_native},
+ {"isNull_native", "(II)Z", (void *)isNull_native},
+ {"getNumRows_native", "()I", (void *)getNumRows},
+ {"setNumColumns_native", "(I)Z", (void *)setNumColumns},
+ {"allocRow_native", "()Z", (void *)allocRow},
+ {"putBlob_native", "([BII)Z", (void *)putBlob_native},
+ {"putString_native", "(Ljava/lang/String;II)Z", (void *)putString_native},
+ {"putLong_native", "(JII)Z", (void *)putLong_native},
+ {"putDouble_native", "(DII)Z", (void *)putDouble_native},
+ {"freeLastRow_native", "()V", (void *)freeLastRow},
+ {"putNull_native", "(II)Z", (void *)putNull_native},
+};
+
+int register_android_database_CursorWindow(JNIEnv * env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/database/CursorWindow");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/CursorWindow");
+ return -1;
+ }
+
+ gWindowField = env->GetFieldID(clazz, "nWindow", "I");
+
+ if (gWindowField == NULL) {
+ LOGE("Error locating fields");
+ return -1;
+ }
+
+ clazz = env->FindClass("android/database/CharArrayBuffer");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/CharArrayBuffer");
+ return -1;
+ }
+
+ gBufferField = env->GetFieldID(clazz, "data", "[C");
+
+ if (gBufferField == NULL) {
+ LOGE("Error locating fields data in CharArrayBuffer");
+ return -1;
+ }
+
+ gSizeCopiedField = env->GetFieldID(clazz, "sizeCopied", "I");
+
+ if (gSizeCopiedField == NULL) {
+ LOGE("Error locating fields sizeCopied in CharArrayBuffer");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow",
+ sMethods, NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
new file mode 100644
index 0000000..66f0118
--- /dev/null
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2006-2007 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Database"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <sqlite3.h>
+#include <sqlite3_android.h>
+#include <string.h>
+#include <utils.h>
+#include <ctype.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+
+#include "sqlite3_exception.h"
+
+#define UTF16_STORAGE 0
+#define INVALID_VERSION -1
+#define SQLITE_SOFT_HEAP_LIMIT (4 * 1024 * 1024)
+#define ANDROID_TABLE "android_metadata"
+
+namespace android {
+
+enum {
+ OPEN_READWRITE = 0x00000000,
+ OPEN_READONLY = 0x00000001,
+ OPEN_READ_MASK = 0x00000001,
+ NO_LOCALIZED_COLLATORS = 0x00000010,
+ CREATE_IF_NECESSARY = 0x10000000
+};
+
+static jfieldID offset_db_handle;
+
+/* public native void dbopen(String path, int flags, String locale); */
+static void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags)
+{
+ int err;
+ sqlite3 * handle = NULL;
+ sqlite3_stmt * statement = NULL;
+ char const * path8 = env->GetStringUTFChars(pathString, NULL);
+ int sqliteFlags;
+
+ // convert our flags into the sqlite flags
+ if (flags & CREATE_IF_NECESSARY) {
+ sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
+ } else if (flags & OPEN_READONLY) {
+ sqliteFlags = SQLITE_OPEN_READONLY;
+ } else {
+ sqliteFlags = SQLITE_OPEN_READWRITE;
+ }
+
+ err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags);
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+ // The soft heap limit prevents the page cache allocations from growing
+ // beyond the given limit, no matter what the max page cache sizes are
+ // set to. The limit does not, as of 3.5.0, affect any other allocations.
+ sqlite3_soft_heap_limit(SQLITE_SOFT_HEAP_LIMIT);
+
+ // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY
+ err = sqlite3_busy_timeout(handle, 1000 /* ms */);
+ if (err != SQLITE_OK) {
+ LOGE("sqlite3_busy_timeout(handle, 1000) failed for \"%s\"\n", path8);
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+#ifdef DB_INTEGRITY_CHECK
+ static const char* integritySql = "pragma integrity_check(1);";
+ err = sqlite3_prepare_v2(handle, integritySql, -1, &statement, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("sqlite_prepare_v2(handle, \"%s\") failed for \"%s\"\n", integritySql, path8);
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+ // first is OK or error message
+ err = sqlite3_step(statement);
+ if (err != SQLITE_ROW) {
+ LOGE("integrity check failed for \"%s\"\n", integritySql, path8);
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ } else {
+ const char *text = (const char*)sqlite3_column_text(statement, 0);
+ if (strcmp(text, "ok") != 0) {
+ LOGE("integrity check failed for \"%s\": %s\n", integritySql, path8, text);
+ jniThrowException(env, "android/database/sqlite/SQLiteDatabaseCorruptException", text);
+ goto done;
+ }
+ }
+#endif
+
+ err = register_android_functions(handle, UTF16_STORAGE);
+ if (err) {
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+ LOGV("Opened '%s' - %p\n", path8, handle);
+ env->SetIntField(object, offset_db_handle, (int) handle);
+ handle = NULL; // The caller owns the handle now.
+
+done:
+ // Release allocated resources
+ if (path8 != NULL) env->ReleaseStringUTFChars(pathString, path8);
+ if (statement != NULL) sqlite3_finalize(statement);
+ if (handle != NULL) sqlite3_close(handle);
+}
+
+/* public native void close(); */
+static void dbclose(JNIEnv* env, jobject object)
+{
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+
+ if (handle != NULL) {
+ LOGV("Closing database: handle=%p\n", handle);
+ int result = sqlite3_close(handle);
+ if (result == SQLITE_OK) {
+ LOGV("Closed %p\n", handle);
+ env->SetIntField(object, offset_db_handle, 0);
+ } else {
+ // This can happen if sub-objects aren't closed first. Make sure the caller knows.
+ throw_sqlite3_exception(env, handle);
+ LOGE("sqlite3_close(%p) failed: %d\n", handle, result);
+ }
+ }
+}
+
+/* public native void native_execSQL(String sql); */
+static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString)
+{
+ int err;
+ int stepErr;
+ sqlite3_stmt * statement = NULL;
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+ jchar const * sql = env->GetStringChars(sqlString, NULL);
+ jsize sqlLen = env->GetStringLength(sqlString);
+
+ if (sql == NULL || sqlLen == 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "You must supply an SQL string");
+ return;
+ }
+
+ err = sqlite3_prepare16_v2(handle, sql, sqlLen * 2, &statement, NULL);
+
+ env->ReleaseStringChars(sqlString, sql);
+
+ if (err != SQLITE_OK) {
+ char const * sql8 = env->GetStringUTFChars(sqlString, NULL);
+ LOGE("Failure %d (%s) on %p when preparing '%s'.\n", err, sqlite3_errmsg(handle), handle, sql8);
+ throw_sqlite3_exception(env, handle, sql8);
+ env->ReleaseStringUTFChars(sqlString, sql8);
+ return;
+ }
+
+ stepErr = sqlite3_step(statement);
+ err = sqlite3_finalize(statement);
+
+ if (stepErr != SQLITE_DONE) {
+ if (stepErr == SQLITE_ROW) {
+ throw_sqlite3_exception(env, "Queries cannot be performed using execSQL(), use query() instead.");
+ } else {
+ char const * sql8 = env->GetStringUTFChars(sqlString, NULL);
+ LOGE("Failure %d (%s) on %p when executing '%s'\n", err, sqlite3_errmsg(handle), handle, sql8);
+ throw_sqlite3_exception(env, handle, sql8);
+ env->ReleaseStringUTFChars(sqlString, sql8);
+
+ }
+ } else IF_LOGV() {
+ char const * sql8 = env->GetStringUTFChars(sqlString, NULL);
+ LOGV("Success on %p when executing '%s'\n", handle, sql8);
+ env->ReleaseStringUTFChars(sqlString, sql8);
+ }
+}
+
+/* native long lastInsertRow(); */
+static jlong lastInsertRow(JNIEnv* env, jobject object)
+{
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+
+ return sqlite3_last_insert_rowid(handle);
+}
+
+/* native int lastChangeCount(); */
+static jint lastChangeCount(JNIEnv* env, jobject object)
+{
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+
+ return sqlite3_changes(handle);
+}
+
+/* set locale in the android_metadata table, install localized collators, and rebuild indexes */
+static void native_setLocale(JNIEnv* env, jobject object, jstring localeString, jint flags)
+{
+ if ((flags & NO_LOCALIZED_COLLATORS)) return;
+
+ int err;
+ char const* locale8 = env->GetStringUTFChars(localeString, NULL);
+ sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
+ sqlite3_stmt* stmt = NULL;
+ char** meta = NULL;
+ int rowCount, colCount;
+ char* dbLocale = NULL;
+
+ // create the table, if necessary and possible
+ if (!(flags & OPEN_READONLY)) {
+ static const char *createSql ="CREATE TABLE IF NOT EXISTS " ANDROID_TABLE " (locale TEXT)";
+ err = sqlite3_exec(handle, createSql, NULL, NULL, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("CREATE TABLE " ANDROID_TABLE " failed\n");
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+ }
+
+ // try to read from the table
+ static const char *selectSql = "SELECT locale FROM " ANDROID_TABLE " LIMIT 1";
+ err = sqlite3_get_table(handle, selectSql, &meta, &rowCount, &colCount, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("SELECT locale FROM " ANDROID_TABLE " failed\n");
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+ dbLocale = (rowCount >= 1) ? meta[1 * colCount + 0] : NULL;
+
+ if (dbLocale != NULL && !strcmp(dbLocale, locale8)) {
+ // database locale is the same as the desired locale; set up the collators and go
+ err = register_localized_collators(handle, locale8, UTF16_STORAGE);
+ if (err != SQLITE_OK) throw_sqlite3_exception(env, handle);
+ goto done; // no database changes needed
+ }
+
+ if ((flags & OPEN_READONLY)) {
+ // read-only database, so we're going to have to put up with whatever we got
+ err = register_localized_collators(handle, dbLocale ? dbLocale : locale8, UTF16_STORAGE);
+ if (err != SQLITE_OK) throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+ // need to update android_metadata and indexes atomically, so use a transaction...
+ err = sqlite3_exec(handle, "BEGIN TRANSACTION", NULL, NULL, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("BEGIN TRANSACTION failed setting locale\n");
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+ err = register_localized_collators(handle, dbLocale ? dbLocale : locale8, UTF16_STORAGE);
+ if (err != SQLITE_OK) {
+ LOGE("register_localized_collators() failed setting locale\n");
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+ err = sqlite3_exec(handle, "DELETE FROM " ANDROID_TABLE, NULL, NULL, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("DELETE failed setting locale\n");
+ throw_sqlite3_exception(env, handle);
+ goto rollback;
+ }
+
+ static const char *sql = "INSERT INTO " ANDROID_TABLE " (locale) VALUES(?);";
+ err = sqlite3_prepare_v2(handle, sql, -1, &stmt, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("sqlite3_prepare_v2(\"%s\") failed\n", sql);
+ throw_sqlite3_exception(env, handle);
+ goto rollback;
+ }
+
+ err = sqlite3_bind_text(stmt, 1, locale8, -1, SQLITE_TRANSIENT);
+ if (err != SQLITE_OK) {
+ LOGE("sqlite3_bind_text() failed setting locale\n");
+ throw_sqlite3_exception(env, handle);
+ goto rollback;
+ }
+
+ err = sqlite3_step(stmt);
+ if (err != SQLITE_OK && err != SQLITE_DONE) {
+ LOGE("sqlite3_step(\"%s\") failed setting locale\n", sql);
+ throw_sqlite3_exception(env, handle);
+ goto rollback;
+ }
+
+ err = sqlite3_exec(handle, "REINDEX LOCALIZED", NULL, NULL, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("REINDEX LOCALIZED failed\n");
+ throw_sqlite3_exception(env, handle);
+ goto rollback;
+ }
+
+ // all done, yay!
+ err = sqlite3_exec(handle, "COMMIT TRANSACTION", NULL, NULL, NULL);
+ if (err != SQLITE_OK) {
+ LOGE("COMMIT TRANSACTION failed setting locale\n");
+ throw_sqlite3_exception(env, handle);
+ goto done;
+ }
+
+rollback:
+ sqlite3_exec(handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
+
+done:
+ if (locale8 != NULL) env->ReleaseStringUTFChars(localeString, locale8);
+ if (stmt != NULL) sqlite3_finalize(stmt);
+ if (meta != NULL) sqlite3_free_table(meta);
+}
+
+static jint native_releaseMemory(JNIEnv *env, jobject clazz)
+{
+ // Attempt to release as much memory from the
+ return sqlite3_release_memory(SQLITE_SOFT_HEAP_LIMIT);
+}
+
+static JNINativeMethod sMethods[] =
+{
+ /* name, signature, funcPtr */
+ {"dbopen", "(Ljava/lang/String;I)V", (void *)dbopen},
+ {"dbclose", "()V", (void *)dbclose},
+ {"native_execSQL", "(Ljava/lang/String;)V", (void *)native_execSQL},
+ {"lastInsertRow", "()J", (void *)lastInsertRow},
+ {"lastChangeCount", "()I", (void *)lastChangeCount},
+ {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
+ {"releaseMemory", "()I", (void *)native_releaseMemory},
+};
+
+int register_android_database_SQLiteDatabase(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/database/sqlite/SQLiteDatabase");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/sqlite/SQLiteDatabase\n");
+ return -1;
+ }
+
+ offset_db_handle = env->GetFieldID(clazz, "mNativeHandle", "I");
+ if (offset_db_handle == NULL) {
+ LOGE("Can't find SQLiteDatabase.mNativeHandle\n");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase", sMethods, NELEM(sMethods));
+}
+
+/* throw a SQLiteException with a message appropriate for the error in handle */
+void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
+ throw_sqlite3_exception(env, handle, NULL);
+}
+
+/* throw a SQLiteException with the given message */
+void throw_sqlite3_exception(JNIEnv* env, const char* message) {
+ throw_sqlite3_exception(env, NULL, message);
+}
+
+/* throw a SQLiteException with a message appropriate for the error in handle
+ concatenated with the given message
+ */
+void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) {
+ if (handle) {
+ throw_sqlite3_exception(env, sqlite3_errcode(handle),
+ sqlite3_errmsg(handle), message);
+ } else {
+ // we use SQLITE_OK so that a generic SQLiteException is thrown;
+ // any code not specified in the switch statement below would do.
+ throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message);
+ }
+}
+
+/* throw a SQLiteException for a given error code */
+void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) {
+ if (errcode == SQLITE_DONE) {
+ throw_sqlite3_exception(env, errcode, NULL, message);
+ } else {
+ char temp[20];
+ sprintf(temp, "error code %d", errcode);
+ throw_sqlite3_exception(env, errcode, temp, message);
+ }
+}
+
+/* throw a SQLiteException for a given error code, sqlite3message, and
+ user message
+ */
+void throw_sqlite3_exception(JNIEnv* env, int errcode,
+ const char* sqlite3Message, const char* message) {
+ const char* exceptionClass;
+ switch (errcode) {
+ case SQLITE_IOERR:
+ exceptionClass = "android/database/sqlite/SQLiteDiskIOException";
+ break;
+ case SQLITE_CORRUPT:
+ exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
+ break;
+ case SQLITE_CONSTRAINT:
+ exceptionClass = "android/database/sqlite/SQLiteConstraintException";
+ break;
+ case SQLITE_ABORT:
+ exceptionClass = "android/database/sqlite/SQLiteAbortException";
+ break;
+ case SQLITE_DONE:
+ exceptionClass = "android/database/sqlite/SQLiteDoneException";
+ break;
+ case SQLITE_FULL:
+ exceptionClass = "android/database/sqlite/SQLiteFullException";
+ break;
+ case SQLITE_MISUSE:
+ exceptionClass = "android/database/sqlite/SQLiteMisuseException";
+ break;
+ default:
+ exceptionClass = "android/database/sqlite/SQLiteException";
+ break;
+ }
+
+ if (sqlite3Message != NULL && message != NULL) {
+ char* fullMessage = (char *)malloc(strlen(sqlite3Message) + strlen(message) + 3);
+ if (fullMessage != NULL) {
+ strcpy(fullMessage, sqlite3Message);
+ strcat(fullMessage, ": ");
+ strcat(fullMessage, message);
+ jniThrowException(env, exceptionClass, fullMessage);
+ free(fullMessage);
+ } else {
+ jniThrowException(env, exceptionClass, sqlite3Message);
+ }
+ } else if (sqlite3Message != NULL) {
+ jniThrowException(env, exceptionClass, sqlite3Message);
+ } else {
+ jniThrowException(env, exceptionClass, message);
+ }
+}
+
+
+} // namespace android
diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp
new file mode 100644
index 0000000..916df35
--- /dev/null
+++ b/core/jni/android_database_SQLiteDebug.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <JNIHelp.h>
+#include <jni.h>
+#include <utils/misc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <cutils/mspace.h>
+#include <utils/Log.h>
+
+#include <sqlite3.h>
+
+// From mem_mspace.c in libsqlite
+extern "C" mspace sqlite3_get_mspace();
+
+// From sqlite.c, hacked in for Android
+extern "C" void sqlite3_get_pager_stats(sqlite3_int64 * totalBytesOut,
+ sqlite3_int64 * referencedBytesOut,
+ sqlite3_int64 * dbBytesOut,
+ int * numPagersOut);
+
+namespace android {
+
+static jfieldID gTotalBytesField;
+static jfieldID gReferencedBytesField;
+static jfieldID gDbBytesField;
+static jfieldID gNumPagersField;
+
+
+#define USE_MSPACE 0
+
+static void getPagerStats(JNIEnv *env, jobject clazz, jobject statsObj)
+{
+ sqlite3_int64 totalBytes;
+ sqlite3_int64 referencedBytes;
+ sqlite3_int64 dbBytes;
+ int numPagers;
+
+ sqlite3_get_pager_stats(&totalBytes, &referencedBytes, &dbBytes,
+ &numPagers);
+
+ env->SetLongField(statsObj, gTotalBytesField, totalBytes);
+ env->SetLongField(statsObj, gReferencedBytesField, referencedBytes);
+ env->SetLongField(statsObj, gDbBytesField, dbBytes);
+ env->SetIntField(statsObj, gNumPagersField, numPagers);
+}
+
+static jlong getHeapSize(JNIEnv *env, jobject clazz)
+{
+#if !NO_MALLINFO
+ struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace());
+ struct mallinfo info = dlmallinfo();
+ return (jlong) info.usmblks;
+#elif USE_MSPACE
+ mspace space = sqlite3_get_mspace();
+ if (space != 0) {
+ return mspace_footprint(space);
+ } else {
+ return 0;
+ }
+#else
+ return 0;
+#endif
+}
+
+static jlong getHeapAllocatedSize(JNIEnv *env, jobject clazz)
+{
+#if !NO_MALLINFO
+ struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace());
+ return (jlong) info.uordblks;
+#else
+ return sqlite3_memory_used();
+#endif
+}
+
+static jlong getHeapFreeSize(JNIEnv *env, jobject clazz)
+{
+#if !NO_MALLINFO
+ struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace());
+ return (jlong) info.fordblks;
+#else
+ return getHeapSize(env, clazz) - sqlite3_memory_used();
+#endif
+}
+
+static int read_mapinfo(FILE *fp,
+ int *sharedPages, int *privatePages)
+{
+ char line[1024];
+ int len;
+ int skip;
+
+ unsigned start = 0, size = 0, resident = 0;
+ unsigned shared_clean = 0, shared_dirty = 0;
+ unsigned private_clean = 0, private_dirty = 0;
+ unsigned referenced = 0;
+
+ int isAnon = 0;
+ int isHeap = 0;
+
+again:
+ skip = 0;
+
+ if(fgets(line, 1024, fp) == 0) return 0;
+
+ len = strlen(line);
+ if (len < 1) return 0;
+ line[--len] = 0;
+
+ /* ignore guard pages */
+ if (line[18] == '-') skip = 1;
+
+ start = strtoul(line, 0, 16);
+
+ if (len > 50 && !strncmp(line + 49, "/tmp/sqlite-heap", strlen("/tmp/sqlite-heap"))) {
+ isHeap = 1;
+ }
+
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Size: %d kB", &size) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Rss: %d kB", &resident) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Shared_Clean: %d kB", &shared_clean) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Shared_Dirty: %d kB", &shared_dirty) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Private_Clean: %d kB", &private_clean) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Private_Dirty: %d kB", &private_dirty) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Referenced: %d kB", &referenced) != 1) return 0;
+
+ if (skip) {
+ goto again;
+ }
+
+ if (isHeap) {
+ *sharedPages += shared_dirty;
+ *privatePages += private_dirty;
+ }
+ return 1;
+}
+
+static void load_maps(int pid, int *sharedPages, int *privatePages)
+{
+ char tmp[128];
+ FILE *fp;
+
+ sprintf(tmp, "/proc/%d/smaps", pid);
+ fp = fopen(tmp, "r");
+ if (fp == 0) return;
+
+ while (read_mapinfo(fp, sharedPages, privatePages) != 0) {
+ // Do nothing
+ }
+ fclose(fp);
+}
+
+static void getHeapDirtyPages(JNIEnv *env, jobject clazz, jintArray pages)
+{
+ int _pages[2];
+
+ _pages[0] = 0;
+ _pages[1] = 0;
+
+ load_maps(getpid(), &_pages[0], &_pages[1]);
+
+ // Convert from kbytes to 4K pages
+ _pages[0] /= 4;
+ _pages[1] /= 4;
+
+ env->SetIntArrayRegion(pages, 0, 2, _pages);
+}
+
+/*
+ * JNI registration.
+ */
+
+static JNINativeMethod gMethods[] =
+{
+ { "getPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V",
+ (void*) getPagerStats },
+ { "getHeapSize", "()J", (void*) getHeapSize },
+ { "getHeapAllocatedSize", "()J", (void*) getHeapAllocatedSize },
+ { "getHeapFreeSize", "()J", (void*) getHeapFreeSize },
+ { "getHeapDirtyPages", "([I)V", (void*) getHeapDirtyPages },
+};
+
+int register_android_database_SQLiteDebug(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/database/sqlite/SQLiteDebug$PagerStats");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/sqlite/SQLiteDebug$PagerStats");
+ return -1;
+ }
+
+ gTotalBytesField = env->GetFieldID(clazz, "totalBytes", "J");
+ if (gTotalBytesField == NULL) {
+ LOGE("Can't find totalBytes");
+ return -1;
+ }
+
+ gReferencedBytesField = env->GetFieldID(clazz, "referencedBytes", "J");
+ if (gReferencedBytesField == NULL) {
+ LOGE("Can't find referencedBytes");
+ return -1;
+ }
+
+ gDbBytesField = env->GetFieldID(clazz, "databaseBytes", "J");
+ if (gDbBytesField == NULL) {
+ LOGE("Can't find databaseBytes");
+ return -1;
+ }
+
+ gNumPagersField = env->GetFieldID(clazz, "numPagers", "I");
+ if (gNumPagersField == NULL) {
+ LOGE("Can't find numPagers");
+ return -1;
+ }
+
+ return jniRegisterNativeMethods(env, "android/database/sqlite/SQLiteDebug",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_database_SQLiteProgram.cpp b/core/jni/android_database_SQLiteProgram.cpp
new file mode 100644
index 0000000..54e7de2
--- /dev/null
+++ b/core/jni/android_database_SQLiteProgram.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2006-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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Cursor"
+
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <sqlite3.h>
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sqlite3_exception.h"
+
+
+namespace android {
+
+static jfieldID gHandleField;
+static jfieldID gStatementField;
+
+
+#define GET_STATEMENT(env, object) \
+ (sqlite3_stmt *)env->GetIntField(object, gStatementField)
+#define GET_HANDLE(env, object) \
+ (sqlite3 *)env->GetIntField(object, gHandleField)
+
+
+sqlite3_stmt * compile(JNIEnv* env, jobject object,
+ sqlite3 * handle, jstring sqlString)
+{
+ int err;
+ jchar const * sql;
+ jsize sqlLen;
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ // Make sure not to leak the statement if it already exists
+ if (statement != NULL) {
+ sqlite3_finalize(statement);
+ env->SetIntField(object, gStatementField, 0);
+ }
+
+ // Compile the SQL
+ sql = env->GetStringChars(sqlString, NULL);
+ sqlLen = env->GetStringLength(sqlString);
+ err = sqlite3_prepare16_v2(handle, sql, sqlLen * 2, &statement, NULL);
+ env->ReleaseStringChars(sqlString, sql);
+
+ if (err == SQLITE_OK) {
+ // Store the statement in the Java object for future calls
+ LOGV("Prepared statement %p on %p", statement, handle);
+ env->SetIntField(object, gStatementField, (int)statement);
+ return statement;
+ } else {
+ // Error messages like 'near ")": syntax error' are not
+ // always helpful enough, so construct an error string that
+ // includes the query itself.
+ const char *query = env->GetStringUTFChars(sqlString, NULL);
+ char *message = (char*) malloc(strlen(query) + 50);
+ if (message) {
+ strcpy(message, ", while compiling: "); // less than 50 chars
+ strcat(message, query);
+ }
+ env->ReleaseStringUTFChars(sqlString, query);
+ throw_sqlite3_exception(env, handle, message);
+ free(message);
+ return NULL;
+ }
+}
+
+static void native_compile(JNIEnv* env, jobject object, jstring sqlString)
+{
+ compile(env, object, GET_HANDLE(env, object), sqlString);
+}
+
+static void native_bind_null(JNIEnv* env, jobject object,
+ jint index)
+{
+ int err;
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ err = sqlite3_bind_null(statement, index);
+ if (err != SQLITE_OK) {
+ char buf[32];
+ sprintf(buf, "handle %p", statement);
+ throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
+ return;
+ }
+}
+
+static void native_bind_long(JNIEnv* env, jobject object,
+ jint index, jlong value)
+{
+ int err;
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ err = sqlite3_bind_int64(statement, index, value);
+ if (err != SQLITE_OK) {
+ char buf[32];
+ sprintf(buf, "handle %p", statement);
+ throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
+ return;
+ }
+}
+
+static void native_bind_double(JNIEnv* env, jobject object,
+ jint index, jdouble value)
+{
+ int err;
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ err = sqlite3_bind_double(statement, index, value);
+ if (err != SQLITE_OK) {
+ char buf[32];
+ sprintf(buf, "handle %p", statement);
+ throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
+ return;
+ }
+}
+
+static void native_bind_string(JNIEnv* env, jobject object,
+ jint index, jstring sqlString)
+{
+ int err;
+ jchar const * sql;
+ jsize sqlLen;
+ sqlite3_stmt * statement= GET_STATEMENT(env, object);
+
+ sql = env->GetStringChars(sqlString, NULL);
+ sqlLen = env->GetStringLength(sqlString);
+ err = sqlite3_bind_text16(statement, index, sql, sqlLen * 2, SQLITE_TRANSIENT);
+ env->ReleaseStringChars(sqlString, sql);
+ if (err != SQLITE_OK) {
+ char buf[32];
+ sprintf(buf, "handle %p", statement);
+ throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
+ return;
+ }
+}
+
+static void native_bind_blob(JNIEnv* env, jobject object,
+ jint index, jbyteArray value)
+{
+ int err;
+ jchar const * sql;
+ jsize sqlLen;
+ sqlite3_stmt * statement= GET_STATEMENT(env, object);
+
+ jint len = env->GetArrayLength(value);
+ jbyte * bytes = env->GetByteArrayElements(value, NULL);
+
+ err = sqlite3_bind_blob(statement, index, bytes, len, SQLITE_TRANSIENT);
+ env->ReleaseByteArrayElements(value, bytes, JNI_ABORT);
+
+ if (err != SQLITE_OK) {
+ char buf[32];
+ sprintf(buf, "handle %p", statement);
+ throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
+ return;
+ }
+}
+
+static void native_clear_bindings(JNIEnv* env, jobject object)
+{
+ int err;
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ err = sqlite3_clear_bindings(statement);
+ if (err != SQLITE_OK) {
+ throw_sqlite3_exception(env, GET_HANDLE(env, object));
+ return;
+ }
+}
+
+static void native_finalize(JNIEnv* env, jobject object)
+{
+ int err;
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ if (statement != NULL) {
+ sqlite3_finalize(statement);
+ env->SetIntField(object, gStatementField, 0);
+ }
+}
+
+
+static JNINativeMethod sMethods[] =
+{
+ /* name, signature, funcPtr */
+ {"native_compile", "(Ljava/lang/String;)V", (void *)native_compile},
+ {"native_bind_null", "(I)V", (void *)native_bind_null},
+ {"native_bind_long", "(IJ)V", (void *)native_bind_long},
+ {"native_bind_double", "(ID)V", (void *)native_bind_double},
+ {"native_bind_string", "(ILjava/lang/String;)V", (void *)native_bind_string},
+ {"native_bind_blob", "(I[B)V", (void *)native_bind_blob},
+ {"native_clear_bindings", "()V", (void *)native_clear_bindings},
+ {"native_finalize", "()V", (void *)native_finalize},
+};
+
+int register_android_database_SQLiteProgram(JNIEnv * env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/database/sqlite/SQLiteProgram");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/sqlite/SQLiteProgram");
+ return -1;
+ }
+
+ gHandleField = env->GetFieldID(clazz, "nHandle", "I");
+ gStatementField = env->GetFieldID(clazz, "nStatement", "I");
+
+ if (gHandleField == NULL || gStatementField == NULL) {
+ LOGE("Error locating fields");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/database/sqlite/SQLiteProgram", sMethods, NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp
new file mode 100644
index 0000000..9458433
--- /dev/null
+++ b/core/jni/android_database_SQLiteQuery.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Cursor"
+
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <sqlite3.h>
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "CursorWindow.h"
+#include "sqlite3_exception.h"
+
+
+namespace android {
+
+sqlite3_stmt * compile(JNIEnv* env, jobject object,
+ sqlite3 * handle, jstring sqlString);
+
+// From android_database_CursorWindow.cpp
+CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
+
+static jfieldID gHandleField;
+static jfieldID gStatementField;
+
+
+#define GET_STATEMENT(env, object) \
+ (sqlite3_stmt *)env->GetIntField(object, gStatementField)
+#define GET_HANDLE(env, object) \
+ (sqlite3 *)env->GetIntField(object, gHandleField)
+
+static int skip_rows(sqlite3_stmt *statement, int maxRows) {
+ int retryCount = 0;
+ for (int i = 0; i < maxRows; i++) {
+ int err = sqlite3_step(statement);
+ if (err == SQLITE_ROW){
+ // do nothing
+ } else if (err == SQLITE_DONE) {
+ return i;
+ } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
+ // The table is locked, retry
+ LOG_WINDOW("Database locked, retrying");
+ if (retryCount > 50) {
+ LOGE("Bailing on database busy rety");
+ break;
+ }
+ // Sleep to give the thread holding the lock a chance to finish
+ usleep(1000);
+ retryCount++;
+ continue;
+ } else {
+ return -1;
+ }
+ }
+ LOGD("skip_rows row %d", maxRows);
+ return maxRows;
+}
+
+static int finish_program_and_get_row_count(sqlite3_stmt *statement) {
+ int numRows = 0;
+ int retryCount = 0;
+ while (true) {
+ int err = sqlite3_step(statement);
+ if (err == SQLITE_ROW){
+ numRows++;
+ } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
+ // The table is locked, retry
+ LOG_WINDOW("Database locked, retrying");
+ if (retryCount > 50) {
+ LOGE("Bailing on database busy rety");
+ break;
+ }
+ // Sleep to give the thread holding the lock a chance to finish
+ usleep(1000);
+ retryCount++;
+ continue;
+ } else {
+ // no need to throw exception
+ break;
+ }
+ }
+ sqlite3_reset(statement);
+ LOGD("finish_program_and_get_row_count row %d", numRows);
+ return numRows;
+}
+
+static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
+ jint startPos, jint offsetParam)
+{
+ int err;
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+ int numRows = 0;
+ int numColumns;
+ int retryCount;
+ int boundParams;
+ CursorWindow * window;
+
+ if (statement == NULL) {
+ LOGE("Invalid statement in fillWindow()");
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Attempting to access a deactivated, closed, or empty cursor");
+ return 0;
+ }
+
+ // Only do the binding if there is a valid offsetParam. If no binding needs to be done
+ // offsetParam will be set to 0, an invliad value.
+ if(offsetParam > 0) {
+ // Bind the offset parameter, telling the program which row to start with
+ err = sqlite3_bind_int(statement, offsetParam, startPos);
+ if (err != SQLITE_OK) {
+ LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ sqlite3_errmsg(GET_HANDLE(env, object)));
+ return 0;
+ }
+ LOG_WINDOW("Bound to startPos %d", startPos);
+ } else {
+ LOG_WINDOW("Not binding to startPos %d", startPos);
+ }
+
+ // Get the native window
+ window = get_window_from_object(env, javaWindow);
+ if (!window) {
+ LOGE("Invalid CursorWindow");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Bad CursorWindow");
+ return 0;
+ }
+ LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d", window->getNumRows(), window->size(), window->freeSpace());
+
+ numColumns = sqlite3_column_count(statement);
+ if (!window->setNumColumns(numColumns)) {
+ LOGE("Failed to change column count from %d to %d", window->getNumColumns(), numColumns);
+ jniThrowException(env, "java/lang/IllegalStateException", "numColumns mismatch");
+ return 0;
+ }
+
+ retryCount = 0;
+ if (startPos > 0) {
+ int num = skip_rows(statement, startPos);
+ if (num < 0) {
+ throw_sqlite3_exception(env, GET_HANDLE(env, object));
+ return 0;
+ } else if (num < startPos) {
+ LOGE("startPos %d > actual rows %d", startPos, num);
+ return num;
+ }
+ }
+
+ while(true) {
+ err = sqlite3_step(statement);
+ if (err == SQLITE_ROW) {
+ LOG_WINDOW("\nStepped statement %p to row %d", statement, startPos + numRows);
+ retryCount = 0;
+
+ // Allocate a new field directory for the row. This pointer is not reused
+ // since it mey be possible for it to be relocated on a call to alloc() when
+ // the field data is being allocated.
+ {
+ field_slot_t * fieldDir = window->allocRow();
+ if (!fieldDir) {
+ LOGE("Failed allocating fieldDir at startPos %d row %d", startPos, numRows);
+ return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
+ }
+ }
+
+ // Pack the row into the window
+ int i;
+ for (i = 0; i < numColumns; i++) {
+ int type = sqlite3_column_type(statement, i);
+ if (type == SQLITE_TEXT) {
+ // TEXT data
+#if WINDOW_STORAGE_UTF8
+ uint8_t const * text = (uint8_t const *)sqlite3_column_text(statement, i);
+ // SQLite does not include the NULL terminator in size, but does
+ // ensure all strings are NULL terminated, so increase size by
+ // one to make sure we store the terminator.
+ size_t size = sqlite3_column_bytes(statement, i) + 1;
+#else
+ uint8_t const * text = (uint8_t const *)sqlite3_column_text16(statement, i);
+ size_t size = sqlite3_column_bytes16(statement, i);
+#endif
+ int offset = window->alloc(size);
+ if (!offset) {
+ window->freeLastRow();
+ LOGE("Failed allocating %u bytes for text/blob at %d,%d", size,
+ startPos + numRows, i);
+ return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
+ }
+
+ window->copyIn(offset, text, size);
+
+ // This must be updated after the call to alloc(), since that
+ // may move the field around in the window
+ field_slot_t * fieldSlot = window->getFieldSlot(numRows, i);
+ fieldSlot->type = FIELD_TYPE_STRING;
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = size;
+
+ LOG_WINDOW("%d,%d is TEXT with %u bytes", startPos + numRows, i, size);
+ } else if (type == SQLITE_INTEGER) {
+ // INTEGER data
+ int64_t value = sqlite3_column_int64(statement, i);
+ if (!window->putLong(numRows, i, value)) {
+ window->freeLastRow();
+ LOGE("Failed allocating space for a long in column %d", i);
+ return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
+ }
+ LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + numRows, i, value);
+ } else if (type == SQLITE_FLOAT) {
+ // FLOAT data
+ double value = sqlite3_column_double(statement, i);
+ if (!window->putDouble(numRows, i, value)) {
+ window->freeLastRow();
+ LOGE("Failed allocating space for a double in column %d", i);
+ return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
+ }
+ LOG_WINDOW("%d,%d is FLOAT %lf", startPos + numRows, i, value);
+ } else if (type == SQLITE_BLOB) {
+ // BLOB data
+ uint8_t const * blob = (uint8_t const *)sqlite3_column_blob(statement, i);
+ size_t size = sqlite3_column_bytes16(statement, i);
+ int offset = window->alloc(size);
+ if (!offset) {
+ window->freeLastRow();
+ LOGE("Failed allocating %u bytes for blob at %d,%d", size,
+ startPos + numRows, i);
+ return startPos + numRows + finish_program_and_get_row_count(statement) + 1;
+ }
+
+ window->copyIn(offset, blob, size);
+
+ // This must be updated after the call to alloc(), since that
+ // may move the field around in the window
+ field_slot_t * fieldSlot = window->getFieldSlot(numRows, i);
+ fieldSlot->type = FIELD_TYPE_BLOB;
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = size;
+
+ LOG_WINDOW("%d,%d is Blob with %u bytes @ %d", startPos + numRows, i, size, offset);
+ } else if (type == SQLITE_NULL) {
+ // NULL field
+ window->putNull(numRows, i);
+
+ LOG_WINDOW("%d,%d is NULL", startPos + numRows, i);
+ } else {
+ // Unknown data
+ LOGE("Unknown column type when filling database window");
+ throw_sqlite3_exception(env, "Unknown column type when filling window");
+ break;
+ }
+ }
+
+ if (i < numColumns) {
+ // Not all the fields fit in the window
+ break;
+ }
+
+ // Mark the row as complete in the window
+ numRows++;
+ } else if (err == SQLITE_DONE) {
+ // All rows processed, bail
+ LOG_WINDOW("Processed all rows");
+ break;
+ } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
+ // The table is locked, retry
+ LOG_WINDOW("Database locked, retrying");
+ if (retryCount > 50) {
+ LOGE("Bailing on database busy rety");
+ break;
+ }
+
+ // Sleep to give the thread holding the lock a chance to finish
+ usleep(1000);
+
+ retryCount++;
+ continue;
+ } else {
+ throw_sqlite3_exception(env, GET_HANDLE(env, object));
+ break;
+ }
+ }
+
+ 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;
+}
+
+static jint native_column_count(JNIEnv* env, jobject object)
+{
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ return sqlite3_column_count(statement);
+}
+
+static jstring native_column_name(JNIEnv* env, jobject object, jint columnIndex)
+{
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+ char const * name;
+
+ name = sqlite3_column_name(statement, columnIndex);
+
+ return env->NewStringUTF(name);
+}
+
+
+static JNINativeMethod sMethods[] =
+{
+ /* name, signature, funcPtr */
+ {"native_fill_window", "(Landroid/database/CursorWindow;II)I", (void *)native_fill_window},
+ {"native_column_count", "()I", (void*)native_column_count},
+ {"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name},
+};
+
+int register_android_database_SQLiteQuery(JNIEnv * env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/database/sqlite/SQLiteQuery");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/sqlite/SQLiteQuery");
+ return -1;
+ }
+
+ gHandleField = env->GetFieldID(clazz, "nHandle", "I");
+ gStatementField = env->GetFieldID(clazz, "nStatement", "I");
+
+ if (gHandleField == NULL || gStatementField == NULL) {
+ LOGE("Error locating fields");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/database/sqlite/SQLiteQuery", sMethods, NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp
new file mode 100644
index 0000000..b615895
--- /dev/null
+++ b/core/jni/android_database_SQLiteStatement.cpp
@@ -0,0 +1,149 @@
+/* //device/libs/android_runtime/android_database_SQLiteCursor.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#undef LOG_TAG
+#define LOG_TAG "Cursor"
+
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <sqlite3.h>
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sqlite3_exception.h"
+
+namespace android {
+
+
+sqlite3_stmt * compile(JNIEnv* env, jobject object,
+ sqlite3 * handle, jstring sqlString);
+
+static jfieldID gHandleField;
+static jfieldID gStatementField;
+
+
+#define GET_STATEMENT(env, object) \
+ (sqlite3_stmt *)env->GetIntField(object, gStatementField)
+#define GET_HANDLE(env, object) \
+ (sqlite3 *)env->GetIntField(object, gHandleField)
+
+
+static void native_execute(JNIEnv* env, jobject object)
+{
+ int err;
+ sqlite3 * handle = GET_HANDLE(env, object);
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+
+ // Execute the statement
+ err = sqlite3_step(statement);
+
+ // Throw an exception if an error occured
+ if (err != SQLITE_DONE) {
+ throw_sqlite3_exception_errcode(env, err, NULL);
+ }
+
+ // Reset the statment so it's ready to use again
+ sqlite3_reset(statement);
+}
+
+static jlong native_1x1_long(JNIEnv* env, jobject object)
+{
+ int err;
+ sqlite3 * handle = GET_HANDLE(env, object);
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+ jlong value = -1;
+
+ // Execute the statement
+ err = sqlite3_step(statement);
+
+ // Handle the result
+ if (err == SQLITE_ROW) {
+ // No errors, read the data and return it
+ value = sqlite3_column_int64(statement, 0);
+ } else {
+ throw_sqlite3_exception_errcode(env, err, NULL);
+ }
+
+ // Reset the statment so it's ready to use again
+ sqlite3_reset(statement);
+
+ return value;
+}
+
+static jstring native_1x1_string(JNIEnv* env, jobject object)
+{
+ int err;
+ sqlite3 * handle = GET_HANDLE(env, object);
+ sqlite3_stmt * statement = GET_STATEMENT(env, object);
+ jstring value = NULL;
+
+ // Execute the statement
+ err = sqlite3_step(statement);
+
+ // Handle the result
+ if (err == SQLITE_ROW) {
+ // No errors, read the data and return it
+ char const * text = (char const *)sqlite3_column_text(statement, 0);
+ value = env->NewStringUTF(text);
+ } else {
+ throw_sqlite3_exception_errcode(env, err, NULL);
+ }
+
+ // Reset the statment so it's ready to use again
+ sqlite3_reset(statement);
+
+ return value;
+}
+
+
+static JNINativeMethod sMethods[] =
+{
+ /* name, signature, funcPtr */
+ {"native_execute", "()V", (void *)native_execute},
+ {"native_1x1_long", "()J", (void *)native_1x1_long},
+ {"native_1x1_string", "()Ljava/lang/String;", (void *)native_1x1_string},
+};
+
+int register_android_database_SQLiteStatement(JNIEnv * env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/database/sqlite/SQLiteStatement");
+ if (clazz == NULL) {
+ LOGE("Can't find android/database/sqlite/SQLiteStatement");
+ return -1;
+ }
+
+ gHandleField = env->GetFieldID(clazz, "nHandle", "I");
+ gStatementField = env->GetFieldID(clazz, "nStatement", "I");
+
+ if (gHandleField == NULL || gStatementField == NULL) {
+ LOGE("Error locating fields");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/database/sqlite/SQLiteStatement", sMethods, NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
new file mode 100644
index 0000000..c3b4e3c
--- /dev/null
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -0,0 +1,144 @@
+/* //device/libs/android_runtime/android_ddm_DdmHandleNativeHeap.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#undef LOG_TAG
+#define LOG_TAG "DdmHandleNativeHeap"
+
+#include <JNIHelp.h>
+#include <jni.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/Log.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(__arm__)
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+ size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
+
+extern "C" void free_malloc_leak_info(uint8_t* info);
+#endif
+
+#define MAPS_FILE_SIZE 65 * 1024
+
+struct Header {
+ size_t mapSize;
+ size_t allocSize;
+ size_t allocInfoSize;
+ size_t totalMemory;
+ size_t backtraceSize;
+};
+
+namespace android {
+
+/*
+ * Retrieve the native heap information and the info from /proc/<self>/maps,
+ * copy them into a byte[] with a "struct Header" that holds data offsets,
+ * and return the array.
+ */
+static jbyteArray getLeakInfo(JNIEnv *env, jobject clazz)
+{
+#if defined(__arm__)
+ // get the info in /proc/[pid]/map
+ Header header;
+ memset(&header, 0, sizeof(header));
+
+ pid_t pid = getpid();
+
+ char path[FILENAME_MAX];
+ sprintf(path, "/proc/%d/maps", pid);
+
+ struct stat sb;
+ int ret = stat(path, &sb);
+
+ uint8_t* mapsFile = NULL;
+ if (ret == 0) {
+ mapsFile = (uint8_t*)malloc(MAPS_FILE_SIZE);
+ int fd = open(path, O_RDONLY);
+
+ if (mapsFile != NULL && fd != -1) {
+ int amount = 0;
+ do {
+ uint8_t* ptr = mapsFile + header.mapSize;
+ amount = read(fd, ptr, MAPS_FILE_SIZE);
+ if (amount <= 0) {
+ if (errno != EINTR)
+ break;
+ else
+ continue;
+ }
+ header.mapSize += amount;
+ } while (header.mapSize < MAPS_FILE_SIZE);
+
+ LOGD("**** read %d bytes from '%s'", (int) header.mapSize, path);
+ }
+ }
+
+ uint8_t* allocBytes;
+ get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize,
+ &header.totalMemory, &header.backtraceSize);
+
+ jbyte* bytes = NULL;
+ jbyte* ptr = NULL;
+ jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize);
+ if (array == NULL) {
+ goto done;
+ }
+
+ bytes = env->GetByteArrayElements(array, NULL);
+ ptr = bytes;
+
+// LOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d",
+// header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
+
+ memcpy(ptr, &header, sizeof(header));
+ ptr += sizeof(header);
+
+ if (header.mapSize > 0 && mapsFile != NULL) {
+ memcpy(ptr, mapsFile, header.mapSize);
+ ptr += header.mapSize;
+ }
+
+ memcpy(ptr, allocBytes, header.allocSize);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+done:
+ if (mapsFile != NULL) {
+ free(mapsFile);
+ }
+ // free the info up!
+ free_malloc_leak_info(allocBytes);
+
+ return array;
+#else
+ return NULL;
+#endif
+}
+
+static JNINativeMethod method_table[] = {
+ { "getLeakInfo", "()[B", (void*)getLeakInfo },
+};
+
+int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env)
+{
+ return AndroidRuntime::registerNativeMethods(env, "android/ddm/DdmHandleNativeHeap", method_table, NELEM(method_table));
+}
+
+};
diff --git a/core/jni/android_debug_JNITest.cpp b/core/jni/android_debug_JNITest.cpp
new file mode 100644
index 0000000..f14201e
--- /dev/null
+++ b/core/jni/android_debug_JNITest.cpp
@@ -0,0 +1,119 @@
+/* //device/libs/android_runtime/android_debug_JNITest.cpp
+**
+** Copyright 2006, 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 "DebugJNI"
+
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+//#include "android_runtime/AndroidRuntime.h"
+
+namespace android {
+
+/*
+ * Implements:
+ * native int part1(int intArg, double doubleArg, String stringArg,
+ * int[] arrayArg)
+ */
+static jint android_debug_JNITest_part1(JNIEnv* env, jobject object,
+ jint intArg, jdouble doubleArg, jstring stringArg, jobjectArray arrayArg)
+{
+ jclass clazz;
+ jmethodID part2id;
+ jsize arrayLen;
+ jint arrayVal;
+ int result = -2;
+
+ LOGI("JNI test: in part1, intArg=%d, doubleArg=%.3f\n", intArg, doubleArg);
+
+ /* find "int part2(double doubleArg, int fromArray, String stringArg)" */
+ clazz = env->GetObjectClass(object);
+ part2id = env->GetMethodID(clazz,
+ "part2", "(DILjava/lang/String;)I");
+ if (part2id == NULL) {
+ LOGE("JNI test: unable to find part2\n");
+ return -1;
+ }
+
+ /* get the length of the array */
+ arrayLen = env->GetArrayLength(arrayArg);
+ LOGI(" array size is %d\n", arrayLen);
+
+ /*
+ * Get the last element in the array.
+ * Use the Get<type>ArrayElements functions instead if you need access
+ * to multiple elements.
+ */
+ arrayVal = (int) env->GetObjectArrayElement(arrayArg, arrayLen-1);
+ LOGI(" array val is %d\n", arrayVal);
+
+ /* call this->part2 */
+ result = env->CallIntMethod(object, part2id,
+ doubleArg, arrayVal, stringArg);
+
+ return result;
+}
+
+/*
+ * Implements:
+ * private static native int part3(String stringArg);
+ */
+static jint android_debug_JNITest_part3(JNIEnv* env, jclass clazz,
+ jstring stringArg)
+{
+ const char* utfChars;
+ jboolean isCopy;
+
+ LOGI("JNI test: in part3\n");
+
+ utfChars = env->GetStringUTFChars(stringArg, &isCopy);
+
+ LOGI(" String is '%s', isCopy=%d\n", (const char*) utfChars, isCopy);
+
+ env->ReleaseStringUTFChars(stringArg, utfChars);
+
+ return 2000;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "part1", "(IDLjava/lang/String;[I)I",
+ (void*) android_debug_JNITest_part1 },
+ { "part3", "(Ljava/lang/String;)I",
+ (void*) android_debug_JNITest_part3 },
+};
+int register_android_debug_JNITest(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "android/debug/JNITest",
+ gMethods, NELEM(gMethods));
+}
+
+#if 0
+/* trampoline into C++ */
+extern "C"
+int register_android_debug_JNITest_C(JNIEnv* env)
+{
+ return android::register_android_debug_JNITest(env);
+}
+#endif
+
+}; // namespace android
+
diff --git a/core/jni/android_graphics_PixelFormat.cpp b/core/jni/android_graphics_PixelFormat.cpp
new file mode 100644
index 0000000..0643622
--- /dev/null
+++ b/core/jni/android_graphics_PixelFormat.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <ui/PixelFormat.h>
+
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+struct offsets_t {
+ jfieldID bytesPerPixel;
+ jfieldID bitsPerPixel;
+};
+
+static offsets_t offsets;
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz = env->FindClass(exc);
+ env->ThrowNew(npeClazz, msg);
+}
+
+// ----------------------------------------------------------------------------
+
+static void android_graphics_getPixelFormatInfo(
+ JNIEnv* env, jobject clazz, jint format, jobject pixelFormatObject)
+{
+ PixelFormatInfo info;
+ status_t err = getPixelFormatInfo(format, &info);
+ if (err < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException");
+ return;
+ }
+ env->SetIntField(pixelFormatObject, offsets.bytesPerPixel, info.bytesPerPixel);
+ env->SetIntField(pixelFormatObject, offsets.bitsPerPixel, info.bitsPerPixel);
+}
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/graphics/PixelFormat";
+
+static void nativeClassInit(JNIEnv* env, jclass clazz);
+
+static JNINativeMethod gMethods[] = {
+ { "nativeClassInit", "()V",
+ (void*)nativeClassInit },
+ { "getPixelFormatInfo", "(ILandroid/graphics/PixelFormat;)V",
+ (void*)android_graphics_getPixelFormatInfo
+ }
+};
+
+void nativeClassInit(JNIEnv* env, jclass clazz)
+{
+ offsets.bytesPerPixel = env->GetFieldID(clazz, "bytesPerPixel", "I");
+ offsets.bitsPerPixel = env->GetFieldID(clazz, "bitsPerPixel", "I");
+}
+
+int register_android_graphics_PixelFormat(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
new file mode 100644
index 0000000..a29c27b
--- /dev/null
+++ b/core/jni/android_hardware_Camera.cpp
@@ -0,0 +1,451 @@
+/*
+**
+** 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 "Camera-JNI"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <ui/Surface.h>
+#include <ui/Camera.h>
+#include <utils/IMemory.h>
+
+using namespace android;
+
+enum CallbackMessageID {
+ kShutterCallback = 0,
+ kRawCallback = 1,
+ kJpegCallback = 2,
+ kPreviewCallback = 3,
+ kAutoFocusCallback = 4,
+ kErrorCallback = 5
+};
+
+enum CameraError {
+ kCameraErrorUnknown = 1,
+ kCameraErrorMediaServer = 100
+};
+
+
+struct fields_t {
+ jfieldID context;
+ jfieldID surface;
+ jfieldID listener_context;
+ jmethodID post_event;
+};
+
+static fields_t fields;
+
+struct callback_cookie {
+ jclass camera_class;
+ jobject camera_ref;
+};
+
+static Camera *get_native_camera(JNIEnv *env, jobject thiz)
+{
+ Camera *c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
+ if (c == 0)
+ jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
+
+ return c;
+}
+
+static void err_callback(status_t err, void *cookie)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ callback_cookie *c = (callback_cookie *)cookie;
+ int error;
+
+ switch (err) {
+ case DEAD_OBJECT:
+ error = kCameraErrorMediaServer;
+ break;
+ default:
+ error = kCameraErrorUnknown;
+ 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);
+}
+
+// connect to camera service
+static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
+{
+ sp<Camera> c = Camera::connect();
+
+ if (c == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ return;
+ }
+
+ // make sure camera hardware is alive
+ if (c->getStatus() != NO_ERROR) {
+ jniThrowException(env, "java/io/IOException", "Camera initialization failed");
+ return;
+ }
+
+ callback_cookie *cookie = new callback_cookie;
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ LOGE("Can't find android/hardware/Camera");
+ // XXX no idea what to throw here, can this even happen?
+ jniThrowException(env, "java/lang/Exception", NULL);
+ return;
+ }
+ cookie->camera_class = (jclass)env->NewGlobalRef(clazz);
+
+ // We use a weak reference so the Camera object can be garbage collected.
+ // The reference is only used as a proxy for callbacks.
+ cookie->camera_ref = env->NewGlobalRef(weak_this);
+ 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
+ c->incStrong(thiz);
+}
+
+// disconnect from camera service
+static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
+{
+ 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) {
+ 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);
+ delete cookie;
+ env->SetIntField(thiz, fields.listener_context, 0);
+ }
+ }
+}
+
+static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject surface)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+
+ sp<Surface> s = (Surface *)env->GetIntField(surface, fields.surface);
+ if (c->setPreviewDisplay(s) != NO_ERROR) {
+ jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
+ return;
+ }
+}
+
+static void preview_callback(const sp<IMemory>& mem, void *cookie)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ callback_cookie *c = (callback_cookie *)cookie;
+ int arg1 = 0, arg2 = 0;
+ jobject obj = NULL;
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+ uint8_t *data = ((uint8_t *)heap->base()) + offset;
+
+ jbyteArray array = env->NewByteArray(size);
+ if (array == NULL) {
+ LOGE("Couldn't allocate byte array for YUV data");
+ return;
+ }
+
+ jbyte *bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, data, size);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+ obj = array;
+
+ env->CallStaticVoidMethod(c->camera_class, fields.post_event,
+ c->camera_ref, kPreviewCallback, arg1, arg2, obj);
+ env->DeleteLocalRef(array);
+}
+
+static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+
+ if (c->startPreview() != NO_ERROR) {
+ jniThrowException(env, "java/io/IOException", "startPreview failed");
+ return;
+ }
+}
+
+static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+
+ c->stopPreview();
+}
+
+static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+
+ // Important: Only install preview_callback if the Java code has called
+ // 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);
+}
+
+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,
+ success, 0, NULL);
+}
+
+
+
+static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+ callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
+ c->setAutoFocusCallback(autofocus_callback_impl, cookie);
+ if (c->autoFocus() != NO_ERROR) {
+ jniThrowException(env, "java/io/IOException", "autoFocus failed");
+ }
+}
+
+static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ callback_cookie *c = (callback_cookie *)cookie;
+ int arg1 = 0, arg2 = 0;
+ jobject obj = NULL;
+
+ if (mem == NULL) {
+ env->CallStaticVoidMethod(c->camera_class, fields.post_event,
+ c->camera_ref, kJpegCallback, arg1, arg2, NULL);
+ return;
+ }
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ LOGV("jpeg_callback: mem off=%d, size=%d", offset, size);
+
+ uint8_t *heap_base = (uint8_t *)heap->base();
+ if (heap_base == NULL) {
+ LOGE("YUV heap is NULL");
+ return;
+ }
+
+ uint8_t *data = heap_base + offset;
+
+ jbyteArray array = env->NewByteArray(size);
+ if (array == NULL) {
+ LOGE("Couldn't allocate byte array for JPEG data");
+ return;
+ }
+
+ jbyte *bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, data, size);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+ obj = array;
+
+ env->CallStaticVoidMethod(c->camera_class, fields.post_event,
+ c->camera_ref, kJpegCallback, arg1, arg2, obj);
+ env->DeleteLocalRef(array);
+}
+
+static void shutter_callback_impl(void *cookie)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ callback_cookie *c = (callback_cookie *)cookie;
+ env->CallStaticVoidMethod(c->camera_class, fields.post_event,
+ c->camera_ref, kShutterCallback, 0, 0, NULL);
+}
+
+static void raw_callback(const sp<IMemory>& mem __attribute__((unused)),
+ void *cookie)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ callback_cookie *c = (callback_cookie *)cookie;
+ env->CallStaticVoidMethod(c->camera_class, fields.post_event,
+ c->camera_ref, kRawCallback, 0, 0, NULL);
+}
+
+static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+
+ callback_cookie *cookie =
+ (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
+ c->setShutterCallback(shutter_callback_impl, cookie);
+ c->setRawCallback(raw_callback, cookie);
+ c->setJpegCallback(jpeg_callback, cookie);
+ if (c->takePicture() != NO_ERROR) {
+ jniThrowException(env, "java/io/IOException", "takePicture failed");
+ return;
+ }
+
+ return;
+}
+
+static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return;
+
+ const jchar* str = env->GetStringCritical(params, 0);
+ String8 params8;
+ if (params) {
+ params8 = String8(str, env->GetStringLength(params));
+ env->ReleaseStringCritical(params, str);
+ }
+ if (c->setParameters(params8) != NO_ERROR) {
+ jniThrowException(env, "java/io/IllegalArgumentException", "setParameters failed");
+ return;
+ }
+}
+
+static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz)
+{
+ Camera *c = get_native_camera(env, thiz);
+ if (c == 0)
+ return 0;
+
+ return env->NewStringUTF(c->getParameters().string());
+}
+
+//-------------------------------------------------
+
+static JNINativeMethod camMethods[] = {
+ { "native_setup",
+ "(Ljava/lang/Object;)V",
+ (void*)android_hardware_Camera_native_setup },
+ { "native_release",
+ "()V",
+ (void*)android_hardware_Camera_release },
+ { "setPreviewDisplay",
+ "(Landroid/view/Surface;)V",
+ (void *)android_hardware_Camera_setPreviewDisplay },
+ { "startPreview",
+ "()V",
+ (void *)android_hardware_Camera_startPreview },
+ { "stopPreview",
+ "()V",
+ (void *)android_hardware_Camera_stopPreview },
+ { "setHasPreviewCallback",
+ "(Z)V",
+ (void *)android_hardware_Camera_setHasPreviewCallback },
+ { "native_autoFocus",
+ "()V",
+ (void *)android_hardware_Camera_autoFocus },
+ { "native_takePicture",
+ "()V",
+ (void *)android_hardware_Camera_takePicture },
+ { "native_setParameters",
+ "(Ljava/lang/String;)V",
+ (void *)android_hardware_Camera_setParameters },
+ { "native_getParameters",
+ "()Ljava/lang/String;",
+ (void *)android_hardware_Camera_getParameters }
+};
+
+struct field {
+ const char *class_name;
+ const char *field_name;
+ const char *field_type;
+ jfieldID *jfield;
+};
+
+static int find_fields(JNIEnv *env, field *fields, int count)
+{
+ for (int i = 0; i < count; i++) {
+ field *f = &fields[i];
+ jclass clazz = env->FindClass(f->class_name);
+ if (clazz == NULL) {
+ LOGE("Can't find %s", f->class_name);
+ return -1;
+ }
+
+ jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
+ if (field == NULL) {
+ LOGE("Can't find %s.%s", f->class_name, f->field_name);
+ return -1;
+ }
+
+ *(f->jfield) = field;
+ }
+
+ return 0;
+}
+
+// Get all the required offsets in java class and register native functions
+int register_android_hardware_Camera(JNIEnv *env)
+{
+ field fields_to_find[] = {
+ { "android/hardware/Camera", "mNativeContext", "I", &fields.context },
+ { "android/hardware/Camera", "mListenerContext", "I", &fields.listener_context },
+ { "android/view/Surface", "mSurface", "I", &fields.surface }
+ };
+
+ if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
+ return -1;
+
+ jclass clazz = env->FindClass("android/hardware/Camera");
+ fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.post_event == NULL) {
+ LOGE("Can't find android/hardware/Camera.postEventFromNative");
+ return -1;
+ }
+
+
+ // Register native functions
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
+ camMethods, NELEM(camMethods));
+}
+
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
new file mode 100644
index 0000000..e8dcd71
--- /dev/null
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "Sensors"
+
+#include <hardware/sensors.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+
+namespace android {
+
+/*
+ * The method below are not thread-safe and not intended to be
+ */
+
+static jint
+android_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
+}
+
+static jint
+android_data_close(JNIEnv *env, jclass clazz)
+{
+ return sensors_data_close();
+}
+
+static jint
+android_data_poll(JNIEnv *env, jclass clazz, jfloatArray values, jint sensors)
+{
+ sensors_data_t data;
+ int res = sensors_data_poll(&data, sensors);
+ if (res) {
+ 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;
+ }
+ return res;
+}
+
+static jint
+android_data_get_sensors(JNIEnv *env, jclass clazz)
+{
+ return sensors_data_get_sensors();
+}
+
+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 },
+};
+
+}; // namespace android
+
+using namespace android;
+
+int register_android_hardware_SensorManager(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env, "android/hardware/SensorManager",
+ gMethods, NELEM(gMethods));
+}
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
new file mode 100644
index 0000000..264cc51
--- /dev/null
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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_TAG "GpsLocationProvider"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "hardware/gps.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <string.h>
+#include <pthread.h>
+
+
+static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
+static jmethodID method_reportLocation;
+static jmethodID method_reportStatus;
+static jmethodID method_reportSvStatus;
+static jmethodID method_xtraDownloadRequest;
+
+static const GpsInterface* sGpsInterface = NULL;
+static const GpsXtraInterface* sGpsXtraInterface = NULL;
+
+// data written to by GPS callbacks
+static GpsLocation sGpsLocation;
+static GpsStatus sGpsStatus;
+static GpsSvStatus sGpsSvStatus;
+
+// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
+// and android_location_GpsLocationProvider_read_status
+static GpsLocation sGpsLocationCopy;
+static GpsStatus sGpsStatusCopy;
+static GpsSvStatus sGpsSvStatusCopy;
+
+enum CallbackType {
+ kLocation = 1,
+ kStatus = 2,
+ kSvStatus = 4,
+ kXtraDownloadRequest = 8,
+ kDisableRequest = 16,
+};
+static int sPendingCallbacks;
+
+namespace android {
+
+static void location_callback(GpsLocation* location)
+{
+ pthread_mutex_lock(&sEventMutex);
+
+ sPendingCallbacks |= kLocation;
+ memcpy(&sGpsLocation, location, sizeof(sGpsLocation));
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
+static void status_callback(GpsStatus* status)
+{
+ pthread_mutex_lock(&sEventMutex);
+
+ sPendingCallbacks |= kStatus;
+ memcpy(&sGpsStatus, status, sizeof(sGpsStatus));
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
+static void sv_status_callback(GpsSvStatus* sv_status)
+{
+ pthread_mutex_lock(&sEventMutex);
+
+ sPendingCallbacks |= kSvStatus;
+ memcpy(&sGpsSvStatus, sv_status, sizeof(GpsSvStatus));
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
+GpsCallbacks sGpsCallbacks = {
+ location_callback,
+ status_callback,
+ sv_status_callback,
+};
+
+static void
+download_request_callback()
+{
+ pthread_mutex_lock(&sEventMutex);
+ sPendingCallbacks |= kXtraDownloadRequest;
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
+GpsXtraCallbacks sGpsXtraCallbacks = {
+ download_request_callback,
+};
+
+
+static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+ method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
+ method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
+ method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
+ method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+}
+
+static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
+ if (!sGpsInterface)
+ sGpsInterface = gps_get_interface();
+ return (sGpsInterface != NULL);
+}
+
+static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
+{
+ if (!sGpsInterface)
+ sGpsInterface = gps_get_interface();
+ return (sGpsInterface && sGpsInterface->init(&sGpsCallbacks) == 0);
+}
+
+static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj)
+{
+ pthread_mutex_lock(&sEventMutex);
+ sPendingCallbacks |= kDisableRequest;
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
+static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
+{
+ sGpsInterface->cleanup();
+}
+
+static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jboolean singleFix, jint fixFrequency)
+{
+ int result = sGpsInterface->set_position_mode(GPS_POSITION_MODE_STANDALONE, (singleFix ? 0 : fixFrequency));
+ if (result) {
+ return result;
+ }
+
+ return (sGpsInterface->start() == 0);
+}
+
+static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
+{
+ return (sGpsInterface->stop() == 0);
+}
+
+static void android_location_GpsLocationProvider_set_fix_frequency(JNIEnv* env, jobject obj, jint fixFrequency)
+{
+ if (sGpsInterface->set_fix_frequency)
+ sGpsInterface->set_fix_frequency(fixFrequency);
+}
+
+static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
+{
+ sGpsInterface->delete_aiding_data(flags);
+}
+
+static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj)
+{
+ pthread_mutex_lock(&sEventMutex);
+ pthread_cond_wait(&sEventCond, &sEventMutex);
+
+ // copy and clear the callback flags
+ int pendingCallbacks = sPendingCallbacks;
+ sPendingCallbacks = 0;
+
+ // copy everything and unlock the mutex before calling into Java code to avoid the possibility
+ // of timeouts in the GPS engine.
+ memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
+ memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
+ memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
+ pthread_mutex_unlock(&sEventMutex);
+
+ if (pendingCallbacks & kLocation) {
+ env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
+ (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
+ (jdouble)sGpsLocationCopy.altitude,
+ (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
+ (jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
+ }
+ if (pendingCallbacks & kStatus) {
+ env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
+ }
+ if (pendingCallbacks & kSvStatus) {
+ env->CallVoidMethod(obj, method_reportSvStatus);
+ }
+ if (pendingCallbacks & kXtraDownloadRequest) {
+ env->CallVoidMethod(obj, method_xtraDownloadRequest);
+ }
+ if (pendingCallbacks & kDisableRequest) {
+ // don't need to do anything - we are just poking so wait_for_event will return.
+ }
+}
+
+static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
+ jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
+ jintArray maskArray)
+{
+ // this should only be called from within a call to reportStatus, so we don't need to lock here
+
+ jint* prns = env->GetIntArrayElements(prnArray, 0);
+ jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
+ jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
+ jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
+ jint* mask = env->GetIntArrayElements(maskArray, 0);
+
+ int num_svs = sGpsSvStatusCopy.num_svs;
+ for (int i = 0; i < num_svs; i++) {
+ prns[i] = sGpsSvStatusCopy.sv_list[i].prn;
+ snrs[i] = sGpsSvStatusCopy.sv_list[i].snr;
+ elev[i] = sGpsSvStatusCopy.sv_list[i].elevation;
+ azim[i] = sGpsSvStatusCopy.sv_list[i].azimuth;
+ }
+ mask[0] = sGpsSvStatusCopy.ephemeris_mask;
+ mask[1] = sGpsSvStatusCopy.almanac_mask;
+ mask[2] = sGpsSvStatusCopy.used_in_fix_mask;
+
+ env->ReleaseIntArrayElements(prnArray, prns, 0);
+ env->ReleaseFloatArrayElements(snrArray, snrs, 0);
+ env->ReleaseFloatArrayElements(elevArray, elev, 0);
+ env->ReleaseFloatArrayElements(azumArray, azim, 0);
+ env->ReleaseIntArrayElements(maskArray, mask, 0);
+ return num_svs;
+}
+
+static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time,
+ jlong timeReference, jint uncertainty)
+{
+ sGpsInterface->inject_time(time, timeReference, uncertainty);
+}
+
+static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
+{
+ if (!sGpsXtraInterface) {
+ sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
+ if (sGpsXtraInterface) {
+ int result = sGpsXtraInterface->init(&sGpsXtraCallbacks);
+ if (result) {
+ sGpsXtraInterface = NULL;
+ }
+ }
+ }
+
+ return (sGpsXtraInterface != NULL);
+}
+
+static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
+ jbyteArray data, jint length)
+{
+ jbyte* bytes = env->GetByteArrayElements(data, 0);
+ sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
+ env->ReleaseByteArrayElements(data, bytes, 0);
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
+ {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
+ {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
+ {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable},
+ {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
+ {"native_start", "(ZI)Z", (void*)android_location_GpsLocationProvider_start},
+ {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
+ {"native_set_fix_frequency", "(I)V", (void*)android_location_GpsLocationProvider_set_fix_frequency},
+ {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
+ {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
+ {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+ {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
+ {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
+ {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
+};
+
+int register_android_location_GpsLocationProvider(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
new file mode 100644
index 0000000..99785a2
--- /dev/null
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -0,0 +1,186 @@
+/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+**
+** Copyright 2006, 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 "AudioSystem"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+enum AudioError {
+ kAudioStatusOk = 0,
+ kAudioStatusError = 1,
+ kAudioStatusMediaServerDied = 100
+};
+
+static int check_AudioSystem_Command(status_t status)
+{
+ if (status == NO_ERROR) {
+ return kAudioStatusOk;
+ } else {
+ return kAudioStatusError;
+ }
+}
+
+static int
+android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
+{
+ LOGV("setVolume(%d)", int(volume));
+ if (int(type) == AudioTrack::VOICE_CALL) {
+ return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, float(volume) / 100.0));
+ } else {
+ return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
+ }
+}
+
+static int
+android_media_AudioSystem_getVolume(JNIEnv *env, jobject clazz, jint type)
+{
+ float v;
+ int v_int = -1;
+ if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
+ // voice call volume is converted to log scale in the hardware
+ if (int(type) == AudioTrack::VOICE_CALL) {
+ v_int = lrint(v * 100.0);
+ } else {
+ v_int = AudioSystem::logToLinear(v);
+ }
+ }
+ return v_int;
+}
+
+static int
+android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
+{
+ return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
+}
+
+static jboolean
+android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
+{
+ bool state = false;
+ AudioSystem::isMicrophoneMuted(&state);
+ return state;
+}
+
+static int
+android_media_AudioSystem_setRouting(JNIEnv *env, jobject clazz, jint mode, jint routes, jint mask)
+{
+ return check_AudioSystem_Command(AudioSystem::setRouting(mode, uint32_t(routes), uint32_t(mask)));
+}
+
+static jint
+android_media_AudioSystem_getRouting(JNIEnv *env, jobject clazz, jint mode)
+{
+ uint32_t routes = -1;
+ AudioSystem::getRouting(mode, &routes);
+ return jint(routes);
+}
+
+static int
+android_media_AudioSystem_setMode(JNIEnv *env, jobject clazz, jint mode)
+{
+ return check_AudioSystem_Command(AudioSystem::setMode(mode));
+}
+
+static jint
+android_media_AudioSystem_getMode(JNIEnv *env, jobject clazz)
+{
+ int mode = AudioSystem::MODE_INVALID;
+ AudioSystem::getMode(&mode);
+ return jint(mode);
+}
+
+static jboolean
+android_media_AudioSystem_isMusicActive(JNIEnv *env, jobject thiz)
+{
+ bool state = false;
+ AudioSystem::isMusicActive(&state);
+ return state;
+}
+
+// Temporary interface, do not use
+// TODO: Replace with a more generic key:value get/set mechanism
+static void
+android_media_AudioSystem_setParameter(JNIEnv *env, jobject thiz, jstring key, jstring value)
+{
+ const char *c_key = env->GetStringUTFChars(key, NULL);
+ const char *c_value = env->GetStringUTFChars(value, NULL);
+ AudioSystem::setParameter(c_key, c_value);
+ env->ReleaseStringUTFChars(key, c_key);
+ env->ReleaseStringUTFChars(value, c_value);
+}
+
+void android_media_AudioSystem_error_callback(status_t err)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass clazz = env->FindClass("android/media/AudioSystem");
+
+ int error;
+
+ switch (err) {
+ case DEAD_OBJECT:
+ error = kAudioStatusMediaServerDied;
+ break;
+ case NO_ERROR:
+ error = kAudioStatusOk;
+ break;
+ default:
+ error = kAudioStatusError;
+ break;
+ }
+
+ env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"setVolume", "(II)I", (void *)android_media_AudioSystem_setVolume},
+ {"getVolume", "(I)I", (void *)android_media_AudioSystem_getVolume},
+ {"setParameter", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)android_media_AudioSystem_setParameter},
+ {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
+ {"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
+ {"setRouting", "(III)I", (void *)android_media_AudioSystem_setRouting},
+ {"getRouting", "(I)I", (void *)android_media_AudioSystem_getRouting},
+ {"setMode", "(I)I", (void *)android_media_AudioSystem_setMode},
+ {"getMode", "()I", (void *)android_media_AudioSystem_getMode},
+ {"isMusicActive", "()Z", (void *)android_media_AudioSystem_isMusicActive},
+};
+
+const char* const kClassPathName = "android/media/AudioSystem";
+
+int register_android_media_AudioSystem(JNIEnv *env)
+{
+ AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/AudioSystem", gMethods, NELEM(gMethods));
+}
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
new file mode 100644
index 0000000..73c1283
--- /dev/null
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -0,0 +1,149 @@
+/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+ **
+ ** 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 "ToneGenerator"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "utils/Log.h"
+#include "media/AudioSystem.h"
+#include "media/ToneGenerator.h"
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+struct fields_t {
+ jfieldID context;
+};
+static fields_t fields;
+
+static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType) {
+ LOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz);
+
+ ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
+ fields.context);
+ if (lpToneGen == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
+ return false;
+ }
+
+ return lpToneGen->startTone(toneType);
+}
+
+static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) {
+ LOGV("android_media_ToneGenerator_stopTone: %x\n", (int)thiz);
+
+ ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
+ fields.context);
+
+ LOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+ if (lpToneGen == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
+ return;
+ }
+ lpToneGen->stopTone();
+}
+
+static void android_media_ToneGenerator_release(JNIEnv *env, jobject thiz) {
+ ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
+ fields.context);
+ LOGV("android_media_ToneGenerator_release lpToneGen: %x\n", (int)lpToneGen);
+
+ env->SetIntField(thiz, fields.context, 0);
+
+ if (lpToneGen) {
+ delete lpToneGen;
+ }
+}
+
+static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
+ jint streamType, jint volume) {
+ ToneGenerator *lpToneGen = new ToneGenerator(streamType, AudioSystem::linearToLog(volume));
+
+ env->SetIntField(thiz, fields.context, 0);
+
+ LOGV("android_media_ToneGenerator_native_setup jobject: %x\n", (int)thiz);
+
+ if (lpToneGen == NULL) {
+ LOGE("ToneGenerator creation failed \n");
+ jniThrowException(env, "java/lang/OutOfMemoryException", NULL);
+ return;
+ }
+ LOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+
+ if (!lpToneGen->isInited()) {
+ LOGE("ToneGenerator init failed \n");
+ jniThrowException(env, "java/lang/RuntimeException", "Init failed");
+ return;
+ }
+
+ // Stow our new C++ ToneGenerator in an opaque field in the Java object.
+ env->SetIntField(thiz, fields.context, (int)lpToneGen);
+
+ LOGV("ToneGenerator fields.context: %x\n", env->GetIntField(thiz, fields.context));
+}
+
+static void android_media_ToneGenerator_native_finalize(JNIEnv *env,
+ jobject thiz) {
+ LOGV("android_media_ToneGenerator_native_finalize jobject: %x\n", (int)thiz);
+
+ ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
+ fields.context);
+
+ if (lpToneGen) {
+ LOGV("delete lpToneGen: %x\n", (int)lpToneGen);
+ delete lpToneGen;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ { "startTone", "(I)Z", (void *)android_media_ToneGenerator_startTone },
+ { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone },
+ { "release", "()V", (void *)android_media_ToneGenerator_release },
+ { "native_setup", "(II)V", (void *)android_media_ToneGenerator_native_setup },
+ { "native_finalize", "()V", (void *)android_media_ToneGenerator_native_finalize }
+};
+
+
+int register_android_media_ToneGenerator(JNIEnv *env) {
+ jclass clazz;
+
+ clazz = env->FindClass("android/media/ToneGenerator");
+ if (clazz == NULL) {
+ LOGE("Can't find %s", "android/media/ToneGenerator");
+ return -1;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ LOGE("Can't find ToneGenerator.mNativeContext");
+ return -1;
+ }
+ LOGV("register_android_media_ToneGenerator ToneGenerator fields.context: %x", (unsigned int)fields.context);
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/ToneGenerator", gMethods, NELEM(gMethods));
+}
diff --git a/core/jni/android_message_digest_sha1.cpp b/core/jni/android_message_digest_sha1.cpp
new file mode 100644
index 0000000..480bbf8
--- /dev/null
+++ b/core/jni/android_message_digest_sha1.cpp
@@ -0,0 +1,146 @@
+/* //device/libs/android_runtime/android_message_digest_sha1.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include "jni.h"
+#include <JNIHelp.h>
+#include "android_runtime/AndroidRuntime.h"
+
+#include <openssl/sha.h>
+
+//#define _DEBUG 1
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+
+struct fields_t {
+ jfieldID context;
+};
+static fields_t fields;
+
+static void native_init(JNIEnv *env, jobject clazz)
+{
+ SHA_CTX* context;
+
+#ifdef _DEBUG
+ printf("sha1.native_init\n");
+#endif
+
+ context = (SHA_CTX *)malloc(sizeof(SHA_CTX));
+ SHA1_Init(context);
+
+ env->SetIntField(clazz, fields.context, (int)context);
+}
+
+static void native_reset(JNIEnv *env, jobject clazz)
+{
+ SHA_CTX *context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
+ if (context != NULL) {
+#ifdef _DEBUG
+ printf("sha1.native_reset: free context\n");
+#endif
+ free(context);
+ env->SetIntField(clazz, fields.context, 0 );
+ }
+}
+
+
+static void native_update(JNIEnv *env, jobject clazz, jbyteArray dataArray)
+{
+#ifdef _DEBUG
+ printf("sha1.native_update\n");
+#endif
+ jbyte * data;
+ jsize dataSize;
+ SHA_CTX *context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
+
+ if (context == NULL) {
+#ifdef _DEBUG
+ printf("sha1.native_update: context is NULL, call init...\n");
+#endif
+ native_init(env, clazz);
+ context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
+ }
+
+ data = env->GetByteArrayElements(dataArray, NULL);
+ if (data == NULL) {
+ LOGE("Unable to get byte array elements");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid data array when calling MessageDigest.update()");
+ return;
+ }
+ dataSize = env->GetArrayLength(dataArray);
+
+ SHA1_Update(context, data, dataSize);
+
+ env->ReleaseByteArrayElements(dataArray, data, 0);
+}
+
+static jbyteArray native_digest(JNIEnv *env, jobject clazz)
+{
+#ifdef _DEBUG
+ printf("sha1.native_digest\n");
+#endif
+ jbyteArray array;
+ jbyte md[SHA_DIGEST_LENGTH];
+ SHA_CTX *context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
+
+ SHA1_Final((uint8_t*)md, context);
+
+ array = env->NewByteArray(SHA_DIGEST_LENGTH);
+ LOG_ASSERT(array, "Native could not create new byte[]");
+
+ env->SetByteArrayRegion(array, 0, SHA_DIGEST_LENGTH, md);
+
+ native_reset(env, clazz);
+
+ return array;
+}
+
+
+static JNINativeMethod method_table[] =
+{
+ /* name, signature, funcPtr */
+ {"init", "()V", (void *)native_init},
+ {"update", "([B)V", (void *)native_update},
+ {"digest", "()[B", (void *)native_digest},
+ {"reset", "()V", (void *)native_reset},
+};
+
+int register_android_message_digest_sha1(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/security/Sha1MessageDigest");
+ if (clazz == NULL) {
+ LOGE("Can't find android/security/Sha1MessageDigest");
+ return -1;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeSha1Context", "I");
+ if (fields.context == NULL) {
+ LOGE("Can't find Sha1MessageDigest.mNativeSha1Context");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(
+ env, "android/security/Sha1MessageDigest",
+ method_table, NELEM(method_table));
+}
+
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
new file mode 100644
index 0000000..abd0961
--- /dev/null
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -0,0 +1,966 @@
+/*
+ * Copyright (C) 2006 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 "LocalSocketImpl"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <cutils/sockets.h>
+#include <netinet/tcp.h>
+#include <cutils/properties.h>
+#include <cutils/adb_networking.h>
+
+namespace android {
+
+static jfieldID field_inboundFileDescriptors;
+static jfieldID field_outboundFileDescriptors;
+static jclass class_Credentials;
+static jclass class_FileDescriptor;
+static jmethodID method_CredentialsInit;
+
+/*
+ * private native FileDescriptor
+ * create_native(boolean stream)
+ * throws IOException;
+ */
+static jobject
+socket_create (JNIEnv *env, jobject object, jboolean stream)
+{
+ int ret;
+
+ ret = socket(PF_LOCAL, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return NULL;
+ }
+
+ return jniCreateFileDescriptor(env,ret);
+}
+
+/* private native void connectLocal(FileDescriptor fd,
+ * String name, int namespace) throws IOException
+ */
+static void
+socket_connect_local(JNIEnv *env, jobject object,
+ jobject fileDescriptor, jstring name, jint namespaceId)
+{
+ int ret;
+ const char *nameUtf8;
+ int fd;
+
+ nameUtf8 = env->GetStringUTFChars(name, NULL);
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ ret = socket_local_client_connect(
+ fd,
+ nameUtf8,
+ namespaceId,
+ SOCK_STREAM);
+
+ env->ReleaseStringUTFChars(name, nameUtf8);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+#define DEFAULT_BACKLOG 4
+
+/* private native void bindLocal(FileDescriptor fd, String name, namespace)
+ * throws IOException;
+ */
+
+static void
+socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
+ jstring name, jint namespaceId)
+{
+ int ret;
+ int fd;
+ const char *nameUtf8;
+
+
+ if (name == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ nameUtf8 = env->GetStringUTFChars(name, NULL);
+
+ ret = socket_local_server_bind(fd, nameUtf8, namespaceId);
+
+ env->ReleaseStringUTFChars(name, nameUtf8);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+/* private native void listen_native(int fd, int backlog) throws IOException; */
+static void
+socket_listen (JNIEnv *env, jobject object, jobject fileDescriptor, int backlog)
+{
+ int ret;
+ int fd;
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ ret = listen(fd, backlog);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+/* private native FileDescriptor
+** accept (FileDescriptor fd, LocalSocketImpl s)
+** throws IOException;
+*/
+static jobject
+socket_accept (JNIEnv *env, jobject object, jobject fileDescriptor, jobject s)
+{
+ union {
+ struct sockaddr address;
+ struct sockaddr_un un_address;
+ } sa;
+
+ int ret;
+ int retFD;
+ int fd;
+ socklen_t addrlen;
+
+ if (s == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return NULL;
+ }
+
+ do {
+ addrlen = sizeof(sa);
+ ret = accept(fd, &(sa.address), &addrlen);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return NULL;
+ }
+
+ retFD = ret;
+
+ return jniCreateFileDescriptor(env, retFD);
+}
+
+/* private native void shutdown(FileDescriptor fd, boolean shutdownInput) */
+
+static void
+socket_shutdown (JNIEnv *env, jobject object, jobject fileDescriptor,
+ jboolean shutdownInput)
+{
+ int ret;
+ int fd;
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ ret = shutdown(fd, shutdownInput ? SHUT_RD : SHUT_WR);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+static bool
+java_opt_to_real(int optID, int* opt, int* level)
+{
+ switch (optID)
+ {
+ case 4098:
+ *opt = SO_RCVBUF;
+ *level = SOL_SOCKET;
+ return true;
+ case 4097:
+ *opt = SO_SNDBUF;
+ *level = SOL_SOCKET;
+ return true;
+ case 4102:
+ *opt = SO_SNDTIMEO;
+ *level = SOL_SOCKET;
+ return true;
+ case 128:
+ *opt = SO_LINGER;
+ *level = SOL_SOCKET;
+ return true;
+ case 1:
+ *opt = TCP_NODELAY;
+ *level = IPPROTO_TCP;
+ return true;
+ case 4:
+ *opt = SO_REUSEADDR;
+ *level = SOL_SOCKET;
+ return true;
+
+ }
+ return false;
+}
+
+static jint
+socket_getOption(JNIEnv *env, jobject object, jobject fileDescriptor, int optID)
+{
+ int ret, value;
+ int opt, level;
+ int fd;
+
+ socklen_t size = sizeof(int);
+
+ if (!java_opt_to_real(optID, &opt, &level)) {
+ jniThrowIOException(env, -1);
+ return 0;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return 0;
+ }
+
+ switch (opt)
+ {
+ case SO_LINGER:
+ {
+ struct linger lingr;
+ size = sizeof(lingr);
+ ret = getsockopt(fd, level, opt, &lingr, &size);
+ if (!lingr.l_onoff) {
+ value = -1;
+ } else {
+ value = lingr.l_linger;
+ }
+ break;
+ }
+ default:
+ ret = getsockopt(fd, level, opt, &value, &size);
+ break;
+ }
+
+
+ if (ret != 0) {
+ jniThrowIOException(env, errno);
+ return 0;
+ }
+
+ return value;
+}
+
+static void socket_setOption(
+ JNIEnv *env, jobject object, jobject fileDescriptor, int optID,
+ jint boolValue, jint intValue) {
+ int ret;
+ int optname;
+ int level;
+ int fd;
+
+ if (!java_opt_to_real(optID, &optname, &level)) {
+ jniThrowIOException(env, -1);
+ return;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ switch (optname) {
+ case SO_LINGER: {
+ /*
+ * SO_LINGER is special because it needs to use a special
+ * "linger" struct as well as use the incoming boolean
+ * argument specially.
+ */
+ struct linger lingr;
+ lingr.l_onoff = boolValue ? 1 : 0; // Force it to be 0 or 1.
+ lingr.l_linger = intValue;
+ ret = setsockopt(fd, level, optname, &lingr, sizeof(lingr));
+ break;
+ }
+ case SO_SNDTIMEO: {
+ /*
+ * SO_TIMEOUT from the core library gets converted to
+ * SO_SNDTIMEO, but the option is supposed to set both
+ * send and receive timeouts. Note: The incoming timeout
+ * value is in milliseconds.
+ */
+ struct timeval timeout;
+ timeout.tv_sec = intValue / 1000;
+ timeout.tv_usec = (intValue % 1000) * 1000;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
+ (void *)&timeout, sizeof(timeout));
+
+ if (ret == 0) {
+ ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
+ (void *)&timeout, sizeof(timeout));
+ }
+
+ break;
+ }
+ default: {
+ /*
+ * In all other cases, the translated option level and
+ * optname may be used directly for a call to setsockopt().
+ */
+ ret = setsockopt(fd, level, optname, &intValue, sizeof(intValue));
+ break;
+ }
+ }
+
+ if (ret != 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+static jint socket_available (JNIEnv *env, jobject object,
+ jobject fileDescriptor)
+{
+ int fd;
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return (jint)-1;
+ }
+
+#if 1
+ int avail;
+ int ret = ioctl(fd, FIONREAD, &avail);
+
+ // If this were a non-socket fd, there would be other cases to worry
+ // about...
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return (jint) 0;
+ }
+
+ return (jint)avail;
+#else
+// there appears to be a bionic bug that prevents this version from working.
+
+ ssize_t ret;
+ struct msghdr msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ do {
+ ret = recvmsg(fd, &msg, MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL);
+ } while (ret < 0 && errno == EINTR);
+
+
+ // MSG_PEEK returns 0 on EOF and EWOULDBLOCK on none available
+ if (ret < 0 && errno == EWOULDBLOCK) {
+ return 0;
+ } if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return -1;
+ }
+
+ return (jint)ret;
+#endif
+}
+
+static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor)
+{
+ int fd;
+ int err;
+
+ if (fileDescriptor == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ do {
+ err = close(fd);
+ } while (err < 0 && errno == EINTR);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+/**
+ * Processes ancillary data, handling only
+ * SCM_RIGHTS. Creates appropriate objects and sets appropriate
+ * fields in the LocalSocketImpl object. Returns 0 on success
+ * or -1 if an exception was thrown.
+ */
+static int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg)
+{
+ struct cmsghdr *cmsgptr;
+
+ for (cmsgptr = CMSG_FIRSTHDR(pMsg);
+ cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) {
+
+ if (cmsgptr->cmsg_level != SOL_SOCKET) {
+ continue;
+ }
+
+ if (cmsgptr->cmsg_type == SCM_RIGHTS) {
+ int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
+ jobjectArray fdArray;
+ int count
+ = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
+
+ if (count < 0) {
+ jniThrowException(env, "java/io/IOException",
+ "invalid cmsg length");
+ }
+
+ fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL);
+
+ if (fdArray == NULL) {
+ return -1;
+ }
+
+ for (int i = 0; i < count; i++) {
+ jobject fdObject
+ = jniCreateFileDescriptor(env, pDescriptors[i]);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+
+ env->SetObjectArrayElement(fdArray, i, fdObject);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+ }
+
+ env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Reads data from a socket into buf, processing any ancillary data
+ * and adding it to thisJ.
+ *
+ * Returns the length of normal data read, or -1 if an exception has
+ * been thrown in this function.
+ */
+static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
+ void *buffer, size_t len)
+{
+ ssize_t ret;
+ ssize_t bytesread = 0;
+ struct msghdr msg;
+ struct iovec iv;
+ unsigned char *buf = (unsigned char *)buffer;
+ // Enough buffer for a pile of fd's. We throw an exception if
+ // this buffer is too small.
+ struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100];
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&iv, 0, sizeof(iv));
+
+ iv.iov_base = buf;
+ iv.iov_len = len;
+
+ msg.msg_iov = &iv;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+
+ do {
+ ret = recvmsg(fd, &msg, MSG_NOSIGNAL);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0 && errno == EPIPE) {
+ // Treat this as an end of stream
+ return 0;
+ }
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return -1;
+ }
+
+ if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) {
+ // To us, any of the above flags are a fatal error
+
+ jniThrowException(env, "java/io/IOException",
+ "Unexpected error or truncation during recvmsg()");
+
+ return -1;
+ }
+
+ if (ret >= 0) {
+ socket_process_cmsg(env, thisJ, &msg);
+ }
+
+ return ret;
+}
+
+/**
+ * Writes all the data in the specified buffer to the specified socket.
+ *
+ * Returns 0 on success or -1 if an exception was thrown.
+ */
+static int socket_write_all(JNIEnv *env, jobject object, int fd,
+ void *buf, size_t len)
+{
+ ssize_t ret;
+ struct msghdr msg;
+ unsigned char *buffer = (unsigned char *)buf;
+ memset(&msg, 0, sizeof(msg));
+
+ jobjectArray outboundFds
+ = (jobjectArray)env->GetObjectField(
+ object, field_outboundFileDescriptors);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+
+ struct cmsghdr *cmsg;
+ int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
+ int fds[countFds];
+ char msgbuf[CMSG_SPACE(countFds)];
+
+ // Add any pending outbound file descriptors to the message
+ if (outboundFds != NULL) {
+
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+
+ for (int i = 0; i < countFds; i++) {
+ jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+
+ fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+ }
+
+ // See "man cmsg" really
+ msg.msg_control = msgbuf;
+ msg.msg_controllen = sizeof msgbuf;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof fds);
+ memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
+ }
+
+ // We only write our msg_control during the first write
+ while (len > 0) {
+ struct iovec iv;
+ memset(&iv, 0, sizeof(iv));
+
+ iv.iov_base = buffer;
+ iv.iov_len = len;
+
+ msg.msg_iov = &iv;
+ msg.msg_iovlen = 1;
+
+ do {
+ ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ return -1;
+ }
+
+ buffer += ret;
+ len -= ret;
+
+ // Wipes out any msg_control too
+ memset(&msg, 0, sizeof(msg));
+ }
+
+ return 0;
+}
+
+static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor)
+{
+ int fd;
+ int err;
+
+ if (fileDescriptor == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return (jint)-1;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return (jint)0;
+ }
+
+ unsigned char buf;
+
+ err = socket_read_all(env, object, fd, &buf, 1);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return (jint)0;
+ }
+
+ if (err == 0) {
+ // end of file
+ return (jint)-1;
+ }
+
+ return (jint)buf;
+}
+
+static jint socket_readba (JNIEnv *env, jobject object,
+ jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
+{
+ int fd;
+ jbyte* byteBuffer;
+ int ret;
+
+ if (fileDescriptor == NULL || buffer == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return (jint)-1;
+ }
+
+ if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
+ jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL);
+ return (jint)-1;
+ }
+
+ if (len == 0) {
+ // because socket_read_all returns 0 on EOF
+ return 0;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return (jint)-1;
+ }
+
+ byteBuffer = env->GetByteArrayElements(buffer, NULL);
+
+ if (NULL == byteBuffer) {
+ // an exception will have been thrown
+ return (jint)-1;
+ }
+
+ ret = socket_read_all(env, object,
+ fd, byteBuffer + off, len);
+
+ // A return of -1 above means an exception is pending
+
+ env->ReleaseByteArrayElements(buffer, byteBuffer, 0);
+
+ return (jint) ((ret == 0) ? -1 : ret);
+}
+
+static void socket_write (JNIEnv *env, jobject object,
+ jint b, jobject fileDescriptor)
+{
+ int fd;
+ int err;
+
+ if (fileDescriptor == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ err = socket_write_all(env, object, fd, &b, 1);
+
+ // A return of -1 above means an exception is pending
+}
+
+static void socket_writeba (JNIEnv *env, jobject object,
+ jbyteArray buffer, jint off, jint len, jobject fileDescriptor)
+{
+ int fd;
+ int err;
+ jbyte* byteBuffer;
+
+ if (fileDescriptor == NULL || buffer == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) {
+ jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL);
+ return;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ byteBuffer = env->GetByteArrayElements(buffer,NULL);
+
+ if (NULL == byteBuffer) {
+ // an exception will have been thrown
+ return;
+ }
+
+ err = socket_write_all(env, object, fd,
+ byteBuffer + off, len);
+
+ // A return of -1 above means an exception is pending
+
+ env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
+}
+
+static jobject socket_get_peer_credentials(JNIEnv *env,
+ jobject object, jobject fileDescriptor)
+{
+ int err;
+ int fd;
+
+ if (fileDescriptor == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return NULL;
+ }
+
+ struct ucred creds;
+
+ memset(&creds, 0, sizeof(creds));
+ socklen_t szCreds = sizeof(creds);
+
+ err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return NULL;
+ }
+
+ if (szCreds == 0) {
+ return NULL;
+ }
+
+ return env->NewObject(class_Credentials, method_CredentialsInit,
+ creds.pid, creds.uid, creds.gid);
+}
+
+#if 0
+//TODO change this to return an instance of LocalSocketAddress
+static jobject socket_getSockName(JNIEnv *env,
+ jobject object, jobject fileDescriptor)
+{
+ int err;
+ int fd;
+
+ if (fileDescriptor == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return NULL;
+ }
+
+ union {
+ struct sockaddr address;
+ struct sockaddr_un un_address;
+ } sa;
+
+ memset(&sa, 0, sizeof(sa));
+
+ socklen_t namelen = sizeof(sa);
+ err = getsockname(fd, &(sa.address), &namelen);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return NULL;
+ }
+
+ if (sa.address.sa_family != AF_UNIX) {
+ // We think we're an impl only for AF_UNIX, so this should never happen.
+
+ jniThrowIOException(env, EINVAL);
+ return NULL;
+ }
+
+ if (sa.un_address.sun_path[0] == '\0') {
+ } else {
+ }
+
+
+
+
+}
+#endif
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption},
+ {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption},
+ {"create_native", "(Z)Ljava/io/FileDescriptor;", (void*)socket_create},
+ {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
+ (void*)socket_connect_local},
+ {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local},
+ {"listen_native", "(Ljava/io/FileDescriptor;I)V", (void*)socket_listen},
+ {"accept", "(Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;", (void*)socket_accept},
+ {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown},
+ {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available},
+ {"close_native", "(Ljava/io/FileDescriptor;)V", (void*) socket_close},
+ {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read},
+ {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba},
+ {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba},
+ {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write},
+ {"getPeerCredentials_native",
+ "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;",
+ (void*) socket_get_peer_credentials}
+ //,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;",
+ // (void *) socket_getSockName}
+
+};
+
+int register_android_net_LocalSocketImpl(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/net/LocalSocketImpl");
+
+ if (clazz == NULL) {
+ goto error;
+ }
+
+ field_inboundFileDescriptors = env->GetFieldID(clazz,
+ "inboundFileDescriptors", "[Ljava/io/FileDescriptor;");
+
+ if (field_inboundFileDescriptors == NULL) {
+ goto error;
+ }
+
+ field_outboundFileDescriptors = env->GetFieldID(clazz,
+ "outboundFileDescriptors", "[Ljava/io/FileDescriptor;");
+
+ if (field_outboundFileDescriptors == NULL) {
+ goto error;
+ }
+
+ class_Credentials = env->FindClass("android/net/Credentials");
+
+ if (class_Credentials == NULL) {
+ goto error;
+ }
+
+ class_Credentials = (jclass)env->NewGlobalRef(class_Credentials);
+
+ class_FileDescriptor = env->FindClass("java/io/FileDescriptor");
+
+ if (class_FileDescriptor == NULL) {
+ goto error;
+ }
+
+ class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor);
+
+ method_CredentialsInit
+ = env->GetMethodID(class_Credentials, "<init>", "(III)V");
+
+ if (method_CredentialsInit == NULL) {
+ goto error;
+ }
+
+ return jniRegisterNativeMethods(env,
+ "android/net/LocalSocketImpl", gMethods, NELEM(gMethods));
+
+error:
+ LOGE("Error registering android.net.LocalSocketImpl");
+ return -1;
+}
+
+};
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
new file mode 100644
index 0000000..417ce54
--- /dev/null
+++ b/core/jni/android_net_NetUtils.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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 "NetUtils"
+
+#include "jni.h"
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+#include <arpa/inet.h>
+
+extern "C" {
+int ifc_disable(const char *ifname);
+int ifc_add_host_route(const char *ifname, uint32_t addr);
+int ifc_remove_host_routes(const char *ifname);
+int ifc_set_default_route(const char *ifname, uint32_t gateway);
+int ifc_get_default_route(const char *ifname);
+int ifc_remove_default_route(const char *ifname);
+int ifc_reset_connections(const char *ifname);
+int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2);
+
+int dhcp_do_request(const char *ifname,
+ in_addr_t *ipaddr,
+ in_addr_t *gateway,
+ in_addr_t *mask,
+ in_addr_t *dns1,
+ in_addr_t *dns2,
+ in_addr_t *server,
+ uint32_t *lease);
+int dhcp_stop(const char *ifname);
+char *dhcp_get_errmsg();
+}
+
+#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
+
+namespace android {
+
+/*
+ * The following remembers the jfieldID's of the fields
+ * of the DhcpInfo Java object, so that we don't have
+ * to look them up every time.
+ */
+static struct fieldIds {
+ jclass dhcpInfoClass;
+ jmethodID constructorId;
+ jfieldID ipaddress;
+ jfieldID gateway;
+ jfieldID netmask;
+ jfieldID dns1;
+ jfieldID dns2;
+ jfieldID serverAddress;
+ jfieldID leaseDuration;
+} dhcpInfoFieldIds;
+
+static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_disable(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
+static jint android_net_utils_addHostRoute(JNIEnv* env, jobject clazz, jstring ifname, jint addr)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_add_host_route(nameStr, addr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
+static jint android_net_utils_removeHostRoutes(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_remove_host_routes(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
+static jint android_net_utils_setDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname, jint gateway)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_set_default_route(nameStr, gateway);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
+static jint android_net_utils_getDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_get_default_route(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
+static jint android_net_utils_removeDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_remove_default_route(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
+static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_reset_connections(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
+static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ int result;
+ in_addr_t ipaddr, gateway, mask, dns1, dns2, server;
+ uint32_t lease;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::dhcp_do_request(nameStr, &ipaddr, &gateway, &mask,
+ &dns1, &dns2, &server, &lease);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ if (result == 0 && dhcpInfoFieldIds.dhcpInfoClass != NULL) {
+ env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr);
+ env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway);
+ env->SetIntField(info, dhcpInfoFieldIds.netmask, mask);
+ env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1);
+ env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2);
+ env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server);
+ env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease);
+ }
+ return (jboolean)(result == 0);
+}
+
+static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::dhcp_stop(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());
+}
+
+static jboolean android_net_utils_configureInterface(JNIEnv* env,
+ jobject clazz,
+ jstring ifname,
+ jint ipaddr,
+ jint mask,
+ jint gateway,
+ jint dns1,
+ jint dns2)
+{
+ int result;
+ uint32_t lease;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_configure(nameStr, ipaddr, mask, gateway, dns1, dns2);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jboolean)(result == 0);
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gNetworkUtilMethods[] = {
+ /* name, signature, funcPtr */
+
+ { "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
+ { "addHostRoute", "(Ljava/lang/String;I)I", (void *)android_net_utils_addHostRoute },
+ { "removeHostRoutes", "(Ljava/lang/String;)I", (void *)android_net_utils_removeHostRoutes },
+ { "setDefaultRoute", "(Ljava/lang/String;I)I", (void *)android_net_utils_setDefaultRoute },
+ { "getDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_getDefaultRoute },
+ { "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute },
+ { "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 },
+ { "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface },
+ { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
+};
+
+int register_android_net_NetworkUtils(JNIEnv* env)
+{
+ jclass netutils = env->FindClass(NETUTILS_PKG_NAME);
+ LOG_FATAL_IF(netutils == NULL, "Unable to find class " NETUTILS_PKG_NAME);
+
+ dhcpInfoFieldIds.dhcpInfoClass = env->FindClass("android/net/DhcpInfo");
+ if (dhcpInfoFieldIds.dhcpInfoClass != NULL) {
+ dhcpInfoFieldIds.constructorId = env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, "<init>", "()V");
+ dhcpInfoFieldIds.ipaddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "ipAddress", "I");
+ dhcpInfoFieldIds.gateway = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "gateway", "I");
+ dhcpInfoFieldIds.netmask = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "netmask", "I");
+ dhcpInfoFieldIds.dns1 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I");
+ dhcpInfoFieldIds.dns2 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I");
+ dhcpInfoFieldIds.serverAddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "serverAddress", "I");
+ dhcpInfoFieldIds.leaseDuration = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "leaseDuration", "I");
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
new file mode 100644
index 0000000..48af99e
--- /dev/null
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -0,0 +1,492 @@
+/*
+ * 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 "wifi"
+
+#include "jni.h"
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+
+#include "wifi.h"
+
+#define WIFI_PKG_NAME "android/net/wifi/WifiNative"
+
+namespace android {
+
+/*
+ * The following remembers the jfieldID's of the fields
+ * of the DhcpInfo Java object, so that we don't have
+ * to look them up every time.
+ */
+static struct fieldIds {
+ jclass dhcpInfoClass;
+ jmethodID constructorId;
+ jfieldID ipaddress;
+ jfieldID gateway;
+ jfieldID netmask;
+ jfieldID dns1;
+ jfieldID dns2;
+ jfieldID serverAddress;
+ jfieldID leaseDuration;
+} dhcpInfoFieldIds;
+
+static int doCommand(const char *cmd, char *replybuf, int replybuflen)
+{
+ size_t reply_len = replybuflen - 1;
+
+ if (::wifi_command(cmd, replybuf, &reply_len) != 0)
+ return -1;
+ else {
+ // Strip off trailing newline
+ if (reply_len > 0 && replybuf[reply_len-1] == '\n')
+ replybuf[reply_len-1] = '\0';
+ else
+ replybuf[reply_len] = '\0';
+ return 0;
+ }
+}
+
+static jint doIntCommand(const char *cmd)
+{
+ char reply[256];
+
+ if (doCommand(cmd, reply, sizeof(reply)) != 0) {
+ return (jint)-1;
+ } else {
+ return (jint)atoi(reply);
+ }
+}
+
+static jboolean doBooleanCommand(const char *cmd, const char *expect)
+{
+ char reply[256];
+
+ if (doCommand(cmd, reply, sizeof(reply)) != 0) {
+ return (jboolean)JNI_FALSE;
+ } else {
+ return (jboolean)(strcmp(reply, expect) == 0);
+ }
+}
+
+// Send a command to the supplicant, and return the reply as a String
+static jstring doStringCommand(JNIEnv *env, const char *cmd)
+{
+ char reply[4096];
+
+ if (doCommand(cmd, reply, sizeof(reply)) != 0) {
+ return env->NewStringUTF(NULL);
+ } else {
+ return env->NewStringUTF(reply);
+ }
+}
+
+static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject clazz)
+{
+ return (jboolean)(::wifi_load_driver() == 0);
+}
+
+static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject clazz)
+{
+ return (jboolean)(::wifi_unload_driver() == 0);
+}
+
+static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject clazz)
+{
+ return (jboolean)(::wifi_start_supplicant() == 0);
+}
+
+static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject clazz)
+{
+ return (jboolean)(::wifi_stop_supplicant() == 0);
+}
+
+static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject clazz)
+{
+ return (jboolean)(::wifi_connect_to_supplicant() == 0);
+}
+
+static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject clazz)
+{
+ ::wifi_close_supplicant_connection();
+}
+
+static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject clazz)
+{
+ char buf[256];
+
+ int nread = ::wifi_wait_for_event(buf, sizeof buf);
+ if (nread > 0) {
+ return env->NewStringUTF(buf);
+ } else {
+ return env->NewStringUTF(NULL);
+ }
+}
+
+static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject clazz)
+{
+ return doStringCommand(env, "LIST_NETWORKS");
+}
+
+static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject clazz)
+{
+ return doIntCommand("ADD_NETWORK");
+}
+
+static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env,
+ jobject clazz,
+ jint netId,
+ jstring name,
+ jstring value)
+{
+ char cmdstr[256];
+ jboolean isCopy;
+
+ const char *nameStr = env->GetStringUTFChars(name, &isCopy);
+ const char *valueStr = env->GetStringUTFChars(value, &isCopy);
+
+ if (nameStr == NULL || valueStr == NULL)
+ return JNI_FALSE;
+
+ int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s",
+ netId, nameStr, valueStr) >= (int)sizeof(cmdstr);
+
+ env->ReleaseStringUTFChars(name, nameStr);
+ env->ReleaseStringUTFChars(value, valueStr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jstring android_net_wifi_getNetworkVariableCommand(JNIEnv* env,
+ jobject clazz,
+ jint netId,
+ jstring name)
+{
+ char cmdstr[256];
+ jboolean isCopy;
+
+ const char *nameStr = env->GetStringUTFChars(name, &isCopy);
+
+ if (nameStr == NULL)
+ return env->NewStringUTF(NULL);
+
+ int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "GET_NETWORK %d %s",
+ netId, nameStr) >= (int)sizeof(cmdstr);
+
+ env->ReleaseStringUTFChars(name, nameStr);
+
+ return cmdTooLong ? env->NewStringUTF(NULL) : doStringCommand(env, cmdstr);
+}
+
+static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "REMOVE_NETWORK %d", netId);
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jboolean android_net_wifi_enableNetworkCommand(JNIEnv* env,
+ jobject clazz,
+ jint netId,
+ jboolean disableOthers)
+{
+ char cmdstr[256];
+ const char *cmd = disableOthers ? "SELECT_NETWORK" : "ENABLE_NETWORK";
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "%s %d", cmd, netId);
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DISABLE_NETWORK %d", netId);
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject clazz)
+{
+ return doStringCommand(env, "STATUS");
+}
+
+static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("PING", "PONG");
+}
+
+static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject clazz)
+{
+ return doStringCommand(env, "SCAN_RESULTS");
+}
+
+static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("DISCONNECT", "OK");
+}
+
+static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("RECONNECT", "OK");
+}
+static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("REASSOCIATE", "OK");
+}
+
+static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz)
+{
+ jboolean result;
+ // Ignore any error from setting the scan mode.
+ // The scan will still work.
+ (void)doBooleanCommand("DRIVER SCAN-ACTIVE", "OK");
+ result = doBooleanCommand("SCAN", "OK");
+ (void)doBooleanCommand("DRIVER SCAN-PASSIVE", "OK");
+ return result;
+}
+
+static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject clazz, jboolean setActive)
+{
+ jboolean result;
+ // Ignore any error from setting the scan mode.
+ // The scan will still work.
+ if (setActive) {
+ return doBooleanCommand("DRIVER SCAN-ACTIVE", "OK");
+ } else {
+ return doBooleanCommand("DRIVER SCAN-PASSIVE", "OK");
+ }
+}
+
+static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("DRIVER START", "OK");
+}
+
+static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("DRIVER STOP", "OK");
+}
+
+static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
+{
+ char reply[256];
+ int rssi = -200;
+
+ if (doCommand("DRIVER RSSI", reply, sizeof(reply)) != 0) {
+ return (jint)-1;
+ }
+ // reply comes back in the form "<SSID> rssi XX" where XX is the
+ // number we're interested in. if we're associating, it returns "OK".
+ if (strcmp(reply, "OK") != 0) {
+ sscanf(reply, "%*s %*s %d", &rssi);
+ }
+ return (jint)rssi;
+}
+
+static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz)
+{
+ char reply[256];
+ int linkspeed;
+
+ if (doCommand("DRIVER LINKSPEED", reply, sizeof(reply)) != 0) {
+ return (jint)-1;
+ }
+ // reply comes back in the form "LinkSpeed XX" where XX is the
+ // number we're interested in.
+ sscanf(reply, "%*s %u", &linkspeed);
+ return (jint)linkspeed;
+}
+
+static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject clazz)
+{
+ char reply[256];
+ char buf[256];
+
+ if (doCommand("DRIVER MACADDR", reply, sizeof(reply)) != 0) {
+ return env->NewStringUTF(NULL);
+ }
+ // reply comes back in the form "Macaddr = XX.XX.XX.XX.XX.XX" where XX
+ // is the part of the string we're interested in.
+ if (sscanf(reply, "%*s = %255s", buf) == 1)
+ return env->NewStringUTF(buf);
+ else
+ return env->NewStringUTF(NULL);
+}
+
+static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER POWERMODE %d", mode);
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXMODE %d", mode);
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject clazz)
+{
+ // Make sure we never write out a value for AP_SCAN other than 1
+ (void)doBooleanCommand("AP_SCAN 1", "OK");
+ return doBooleanCommand("SAVE_CONFIG", "OK");
+}
+
+static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("RECONFIGURE", "OK");
+}
+
+static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject clazz, jint mode)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "AP_SCAN %d", mode);
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject clazz, jstring bssid)
+{
+ char cmdstr[256];
+ jboolean isCopy;
+
+ const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
+
+ int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= sizeof(cmdstr);
+
+ env->ReleaseStringUTFChars(bssid, bssidStr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
+static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("BLACKLIST clear", "OK");
+}
+
+static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info)
+{
+ jint ipaddr, gateway, mask, dns1, dns2, server, lease;
+ jboolean succeeded = ((jboolean)::do_dhcp_request(&ipaddr, &gateway, &mask,
+ &dns1, &dns2, &server, &lease) == 0);
+ if (succeeded && dhcpInfoFieldIds.dhcpInfoClass != NULL) {
+ env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr);
+ env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway);
+ env->SetIntField(info, dhcpInfoFieldIds.netmask, mask);
+ env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1);
+ env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2);
+ env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server);
+ env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease);
+ }
+ return succeeded;
+}
+
+static jstring android_net_wifi_getDhcpError(JNIEnv* env, jobject clazz)
+{
+ return env->NewStringUTF(::get_dhcp_error_string());
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gWifiMethods[] = {
+ /* name, signature, funcPtr */
+
+ { "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },
+ { "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver },
+ { "startSupplicant", "()Z", (void *)android_net_wifi_startSupplicant },
+ { "stopSupplicant", "()Z", (void *)android_net_wifi_stopSupplicant },
+ { "connectToSupplicant", "()Z", (void *)android_net_wifi_connectToSupplicant },
+ { "closeSupplicantConnection", "()V", (void *)android_net_wifi_closeSupplicantConnection },
+
+ { "listNetworksCommand", "()Ljava/lang/String;",
+ (void*) android_net_wifi_listNetworksCommand },
+ { "addNetworkCommand", "()I", (void*) android_net_wifi_addNetworkCommand },
+ { "setNetworkVariableCommand", "(ILjava/lang/String;Ljava/lang/String;)Z",
+ (void*) android_net_wifi_setNetworkVariableCommand },
+ { "getNetworkVariableCommand", "(ILjava/lang/String;)Ljava/lang/String;",
+ (void*) android_net_wifi_getNetworkVariableCommand },
+ { "removeNetworkCommand", "(I)Z", (void*) android_net_wifi_removeNetworkCommand },
+ { "enableNetworkCommand", "(IZ)Z", (void*) android_net_wifi_enableNetworkCommand },
+ { "disableNetworkCommand", "(I)Z", (void*) android_net_wifi_disableNetworkCommand },
+ { "waitForEvent", "()Ljava/lang/String;", (void*) android_net_wifi_waitForEvent },
+ { "statusCommand", "()Ljava/lang/String;", (void*) android_net_wifi_statusCommand },
+ { "scanResultsCommand", "()Ljava/lang/String;", (void*) android_net_wifi_scanResultsCommand },
+ { "pingCommand", "()Z", (void *)android_net_wifi_pingCommand },
+ { "disconnectCommand", "()Z", (void *)android_net_wifi_disconnectCommand },
+ { "reconnectCommand", "()Z", (void *)android_net_wifi_reconnectCommand },
+ { "reassociateCommand", "()Z", (void *)android_net_wifi_reassociateCommand },
+ { "scanCommand", "()Z", (void*) android_net_wifi_scanCommand },
+ { "setScanModeCommand", "(Z)Z", (void*) android_net_wifi_setScanModeCommand },
+ { "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand },
+ { "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand },
+ { "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },
+ { "setBluetoothCoexistenceModeCommand", "(I)Z",
+ (void*) android_net_wifi_setBluetoothCoexistenceModeCommand },
+ { "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand },
+ { "getLinkSpeedCommand", "()I", (void*) android_net_wifi_getLinkSpeedCommand },
+ { "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand },
+ { "saveConfigCommand", "()Z", (void*) android_net_wifi_saveConfigCommand },
+ { "reloadConfigCommand", "()Z", (void*) android_net_wifi_reloadConfigCommand },
+ { "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand },
+ { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand },
+ { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand },
+
+ { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest },
+ { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError },
+};
+
+int register_android_net_wifi_WifiManager(JNIEnv* env)
+{
+ jclass wifi = env->FindClass(WIFI_PKG_NAME);
+ LOG_FATAL_IF(wifi == NULL, "Unable to find class " WIFI_PKG_NAME);
+
+ dhcpInfoFieldIds.dhcpInfoClass = env->FindClass("android/net/DhcpInfo");
+ if (dhcpInfoFieldIds.dhcpInfoClass != NULL) {
+ dhcpInfoFieldIds.constructorId = env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, "<init>", "()V");
+ dhcpInfoFieldIds.ipaddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "ipAddress", "I");
+ dhcpInfoFieldIds.gateway = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "gateway", "I");
+ dhcpInfoFieldIds.netmask = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "netmask", "I");
+ dhcpInfoFieldIds.dns1 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I");
+ dhcpInfoFieldIds.dns2 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I");
+ dhcpInfoFieldIds.serverAddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "serverAddress", "I");
+ dhcpInfoFieldIds.leaseDuration = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "leaseDuration", "I");
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp
new file mode 100644
index 0000000..584e7a4
--- /dev/null
+++ b/core/jni/android_nio_utils.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include "android_nio_utils.h"
+
+struct NioJNIData {
+ jclass nioAccessClass;
+
+ jmethodID getBasePointerID;
+ jmethodID getBaseArrayID;
+ jmethodID getBaseArrayOffsetID;
+};
+
+static NioJNIData gNioJNI;
+
+void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
+ assert(array);
+
+ jlong pointer;
+ jint offset;
+ void *data;
+
+ pointer = _env->CallStaticLongMethod(gNioJNI.nioAccessClass,
+ gNioJNI.getBasePointerID, buffer);
+ if (pointer != 0L) {
+ *array = NULL;
+ return (void *) (jint) pointer;
+ }
+
+ *array = (jarray) _env->CallStaticObjectMethod(gNioJNI.nioAccessClass,
+ gNioJNI.getBaseArrayID, buffer);
+ offset = _env->CallStaticIntMethod(gNioJNI.nioAccessClass,
+ gNioJNI.getBaseArrayOffsetID, buffer);
+ data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
+
+ return (void *) ((char *) data + offset);
+}
+
+
+void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data,
+ jboolean commit) {
+ _env->ReleasePrimitiveArrayCritical(array, data,
+ commit ? 0 : JNI_ABORT);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer,
+ jboolean commit) {
+ fEnv = env;
+ fCommit = commit;
+ fPointer = android::nio_getPointer(env, nioBuffer, &fArray);
+}
+
+android::AutoBufferPointer::~AutoBufferPointer() {
+ if (NULL != fArray) {
+ android::nio_releasePointer(fEnv, fArray, fPointer, fCommit);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jclass findClass(JNIEnv* env, const char name[]) {
+ jclass c = env->FindClass(name);
+ LOG_FATAL_IF(!c, "Unable to find class %s", name);
+ return c;
+}
+
+static jmethodID findStaticMethod(JNIEnv* env, jclass c, const char method[],
+ const char params[]) {
+ jmethodID m = env->GetStaticMethodID(c, method, params);
+ LOG_FATAL_IF(!m, "Unable to find method %s", method);
+ return m;
+}
+
+static jfieldID getFieldID(JNIEnv* env, jclass c, const char name[],
+ const char type[]) {
+ jfieldID f = env->GetFieldID(c, name, type);
+ LOG_FATAL_IF(!f, "Unable to find field %s", name);
+ return f;
+}
+
+namespace android {
+
+int register_android_nio_utils(JNIEnv* env);
+int register_android_nio_utils(JNIEnv* env) {
+ jclass localClass = findClass(env, "java/nio/NIOAccess");
+ gNioJNI.getBasePointerID = findStaticMethod(env, localClass,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ gNioJNI.getBaseArrayID = findStaticMethod(env, localClass,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ gNioJNI.getBaseArrayOffsetID = findStaticMethod(env, localClass,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+ // now record a permanent version of the class ID
+ gNioJNI.nioAccessClass = (jclass) env->NewGlobalRef(localClass);
+
+ return 0;
+}
+
+}
diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h
new file mode 100644
index 0000000..69c360c
--- /dev/null
+++ b/core/jni/android_nio_utils.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef android_nio_utils_DEFINED
+#define android_nio_utils_DEFINED
+
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+
+/**
+ * Given an nio.Buffer, return a pointer to it, beginning at its current
+ * position. The returned pointer is only valid for the current JNI stack-frame.
+ * For performance, it does not create any global references, so the getPointer
+ * (and releasePointer if array is returned non-null) must be done in the
+ * same JNI stack-frame.
+ *
+ * @param env The current JNI env
+ * @param buffer The nio.Buffer object
+ * @param array REQUIRED. Output. If on return it is set to non-null, then
+ * nio_releasePointer must be called with the array
+ * and the returned pointer when the caller is through with it.
+ * If on return it is set to null, do not call
+ * nio_releasePointer.
+ * @return The pointer to the memory in the buffer object
+ */
+void* nio_getPointer(JNIEnv *env, jobject buffer, jarray *array);
+
+/**
+ * Call this if android_nio_getPointer returned non-null in its array parameter.
+ * Pass that array and the returned pointer when you are done accessing the
+ * pointer. If called (i.e. array is non-null), it must be called in the same
+ * JNI stack-frame as getPointer
+ *
+ * @param env The current JNI env
+ * @param buffer The array returned from android_nio_getPointer (!= null)
+ * @param pointer The pointer returned by android_nio_getPointer
+ * @param commit JNI_FALSE if the pointer was just read, and JNI_TRUE if
+ * the pointer was written to.
+ */
+void nio_releasePointer(JNIEnv *env, jarray array, void *pointer,
+ jboolean commit);
+
+class AutoBufferPointer {
+public:
+ AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit);
+ ~AutoBufferPointer();
+
+ void* pointer() const { return fPointer; }
+
+private:
+ JNIEnv* fEnv;
+ void* fPointer;
+ jarray fArray;
+ jint fRemaining;
+ jboolean fCommit;
+};
+
+} /* namespace android */
+
+#endif
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
new file mode 100644
index 0000000..6ba949c
--- /dev/null
+++ b/core/jni/android_os_Debug.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/misc.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+namespace android
+{
+
+static jfieldID dalvikPss_field;
+static jfieldID dalvikPrivateDirty_field;
+static jfieldID dalvikSharedDirty_field;
+static jfieldID nativePss_field;
+static jfieldID nativePrivateDirty_field;
+static jfieldID nativeSharedDirty_field;
+static jfieldID otherPss_field;
+static jfieldID otherPrivateDirty_field;
+static jfieldID otherSharedDirty_field;
+
+struct stats_t {
+ int dalvikPss;
+ int dalvikPrivateDirty;
+ int dalvikSharedDirty;
+
+ int nativePss;
+ int nativePrivateDirty;
+ int nativeSharedDirty;
+
+ int otherPss;
+ int otherPrivateDirty;
+ int otherSharedDirty;
+};
+
+#define BINDER_STATS "/proc/binder/stats"
+
+static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
+{
+#ifdef HAVE_MALLOC_H
+ struct mallinfo info = mallinfo();
+ return (jlong) info.usmblks;
+#else
+ return -1;
+#endif
+}
+
+static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
+{
+#ifdef HAVE_MALLOC_H
+ struct mallinfo info = mallinfo();
+ return (jlong) info.uordblks;
+#else
+ return -1;
+#endif
+}
+
+static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
+{
+#ifdef HAVE_MALLOC_H
+ struct mallinfo info = mallinfo();
+ return (jlong) info.fordblks;
+#else
+ return -1;
+#endif
+}
+
+static int read_mapinfo(FILE *fp, stats_t* stats)
+{
+ char line[1024];
+ int len;
+ int skip;
+
+ unsigned start = 0, size = 0, resident = 0, pss = 0;
+ unsigned shared_clean = 0, shared_dirty = 0;
+ unsigned private_clean = 0, private_dirty = 0;
+ unsigned referenced = 0;
+
+ int isNativeHeap;
+ int isDalvikHeap;
+ int isSqliteHeap;
+
+again:
+ isNativeHeap = 0;
+ isDalvikHeap = 0;
+ isSqliteHeap = 0;
+ skip = 0;
+
+ if(fgets(line, 1024, fp) == 0) return 0;
+
+ len = strlen(line);
+ if (len < 1) return 0;
+ line[--len] = 0;
+
+ /* ignore guard pages */
+ if (line[18] == '-') skip = 1;
+
+ start = strtoul(line, 0, 16);
+
+ if (len >= 50) {
+ if (!strcmp(line + 49, "[heap]")) {
+ isNativeHeap = 1;
+ } else if (!strncmp(line + 49, "/dalvik-LinearAlloc", strlen("/dalvik-LinearAlloc"))) {
+ isDalvikHeap = 1;
+ } else if (!strncmp(line + 49, "/mspace/dalvik-heap", strlen("/mspace/dalvik-heap"))) {
+ isDalvikHeap = 1;
+ } else if (!strncmp(line + 49, "/dalvik-heap-bitmap/", strlen("/dalvik-heap-bitmap/"))) {
+ isDalvikHeap = 1;
+ } else if (!strncmp(line + 49, "/tmp/sqlite-heap", strlen("/tmp/sqlite-heap"))) {
+ isSqliteHeap = 1;
+ }
+ }
+
+ // TODO: This needs to be fixed to be less fragile. If the order of this file changes or a new
+ // line is add, this method will return without filling out any of the information.
+
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Size: %d kB", &size) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Rss: %d kB", &resident) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Pss: %d kB", &pss) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Shared_Clean: %d kB", &shared_clean) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Shared_Dirty: %d kB", &shared_dirty) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Private_Clean: %d kB", &private_clean) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Private_Dirty: %d kB", &private_dirty) != 1) return 0;
+ if (fgets(line, 1024, fp) == 0) return 0;
+ if (sscanf(line, "Referenced: %d kB", &referenced) != 1) return 0;
+
+ if (skip) {
+ goto again;
+ }
+
+ if (isNativeHeap) {
+ stats->nativePss += pss;
+ stats->nativePrivateDirty += private_dirty;
+ stats->nativeSharedDirty += shared_dirty;
+ } else if (isDalvikHeap) {
+ stats->dalvikPss += pss;
+ stats->dalvikPrivateDirty += private_dirty;
+ stats->dalvikSharedDirty += shared_dirty;
+ } else if (isSqliteHeap) {
+ // ignore
+ } else {
+ stats->otherPss += pss;
+ stats->otherPrivateDirty += shared_dirty;
+ stats->otherSharedDirty += private_dirty;
+ }
+
+ return 1;
+}
+
+static void load_maps(int pid, stats_t* stats)
+{
+ char tmp[128];
+ FILE *fp;
+
+ sprintf(tmp, "/proc/%d/smaps", pid);
+ fp = fopen(tmp, "r");
+ if (fp == 0) return;
+
+ while (read_mapinfo(fp, stats) != 0) {
+ // Do nothing
+ }
+ fclose(fp);
+}
+
+static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
+{
+ stats_t stats;
+ memset(&stats, 0, sizeof(stats_t));
+
+ load_maps(getpid(), &stats);
+
+ env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
+ env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
+ env->SetIntField(object, dalvikSharedDirty_field, stats.dalvikSharedDirty);
+
+ env->SetIntField(object, nativePss_field, stats.nativePss);
+ env->SetIntField(object, nativePrivateDirty_field, stats.nativePrivateDirty);
+ env->SetIntField(object, nativeSharedDirty_field, stats.nativeSharedDirty);
+
+ env->SetIntField(object, otherPss_field, stats.otherPss);
+ env->SetIntField(object, otherPrivateDirty_field, stats.otherPrivateDirty);
+ env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
+}
+
+static jint read_binder_stat(const char* stat)
+{
+ FILE* fp = fopen(BINDER_STATS, "r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ char line[1024];
+
+ char compare[128];
+ int len = snprintf(compare, 128, "proc %d", getpid());
+
+ // loop until we have the block that represents this process
+ do {
+ if (fgets(line, 1024, fp) == 0) {
+ return -1;
+ }
+ } while (strncmp(compare, line, len));
+
+ // now that we have this process, read until we find the stat that we are looking for
+ len = snprintf(compare, 128, " %s: ", stat);
+
+ do {
+ if (fgets(line, 1024, fp) == 0) {
+ return -1;
+ }
+ } while (strncmp(compare, line, len));
+
+ // we have the line, now increment the line ptr to the value
+ char* ptr = line + len;
+ return atoi(ptr);
+}
+
+static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
+{
+ return read_binder_stat("bcTRANSACTION");
+}
+
+static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz)
+{
+ return read_binder_stat("brTRANSACTION");
+}
+
+// these are implemented in android_util_Binder.cpp
+jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
+jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
+jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
+
+/*
+ * JNI registration.
+ */
+
+static JNINativeMethod gMethods[] = {
+ { "getNativeHeapSize", "()J",
+ (void*) android_os_Debug_getNativeHeapSize },
+ { "getNativeHeapAllocatedSize", "()J",
+ (void*) android_os_Debug_getNativeHeapAllocatedSize },
+ { "getNativeHeapFreeSize", "()J",
+ (void*) android_os_Debug_getNativeHeapFreeSize },
+ { "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V",
+ (void*) android_os_Debug_getDirtyPages },
+ { "getBinderSentTransactions", "()I",
+ (void*) android_os_Debug_getBinderSentTransactions },
+ { "getBinderReceivedTransactions", "()I",
+ (void*) android_os_getBinderReceivedTransactions },
+ { "getBinderLocalObjectCount", "()I",
+ (void*)android_os_Debug_getLocalObjectCount },
+ { "getBinderProxyObjectCount", "()I",
+ (void*)android_os_Debug_getProxyObjectCount },
+ { "getBinderDeathObjectCount", "()I",
+ (void*)android_os_Debug_getDeathObjectCount },
+};
+
+int register_android_os_Debug(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
+
+ dalvikPss_field = env->GetFieldID(clazz, "dalvikPss", "I");
+ dalvikPrivateDirty_field = env->GetFieldID(clazz, "dalvikPrivateDirty", "I");
+ dalvikSharedDirty_field = env->GetFieldID(clazz, "dalvikSharedDirty", "I");
+
+ nativePss_field = env->GetFieldID(clazz, "nativePss", "I");
+ nativePrivateDirty_field = env->GetFieldID(clazz, "nativePrivateDirty", "I");
+ nativeSharedDirty_field = env->GetFieldID(clazz, "nativeSharedDirty", "I");
+
+ otherPss_field = env->GetFieldID(clazz, "otherPss", "I");
+ otherPrivateDirty_field = env->GetFieldID(clazz, "otherPrivateDirty", "I");
+ otherSharedDirty_field = env->GetFieldID(clazz, "otherSharedDirty", "I");
+
+ return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_os_Exec.cpp b/core/jni/android_os_Exec.cpp
new file mode 100644
index 0000000..ca5e695
--- /dev/null
+++ b/core/jni/android_os_Exec.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2007 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 "Exec"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+
+namespace android
+{
+
+static jclass class_fileDescriptor;
+static jfieldID field_fileDescriptor_descriptor;
+static jmethodID method_fileDescriptor_init;
+
+
+static int create_subprocess(const char *cmd, const char *arg0, const char *arg1,
+ int* pProcessId)
+{
+ char *devname;
+ int ptm;
+ pid_t pid;
+
+ ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
+ if(ptm < 0){
+ LOGE("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
+ return -1;
+ }
+ fcntl(ptm, F_SETFD, FD_CLOEXEC);
+
+ if(grantpt(ptm) || unlockpt(ptm) ||
+ ((devname = (char*) ptsname(ptm)) == 0)){
+ LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
+ return -1;
+ }
+
+ pid = fork();
+ if(pid < 0) {
+ LOGE("- fork failed: %s -\n", strerror(errno));
+ return -1;
+ }
+
+ if(pid == 0){
+ int pts;
+
+ setsid();
+
+ pts = open(devname, O_RDWR);
+ if(pts < 0) exit(-1);
+
+ dup2(pts, 0);
+ dup2(pts, 1);
+ dup2(pts, 2);
+
+ close(ptm);
+
+ execl(cmd, cmd, arg0, arg1, NULL);
+ exit(-1);
+ } else {
+ *pProcessId = (int) pid;
+ return ptm;
+ }
+}
+
+
+static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
+ jstring cmd, jstring arg0, jstring arg1, jintArray processIdArray)
+{
+ const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0;
+ String8 cmd_8;
+ if (str) {
+ cmd_8 = String8(str, env->GetStringLength(cmd));
+ env->ReleaseStringCritical(cmd, str);
+ }
+
+ str = arg0 ? env->GetStringCritical(arg0, 0) : 0;
+ const char* arg0Str = 0;
+ String8 arg0_8;
+ if (str) {
+ arg0_8 = String8(str, env->GetStringLength(arg0));
+ env->ReleaseStringCritical(arg0, str);
+ arg0Str = arg0_8.string();
+ }
+
+ str = arg1 ? env->GetStringCritical(arg1, 0) : 0;
+ const char* arg1Str = 0;
+ String8 arg1_8;
+ if (str) {
+ arg1_8 = String8(str, env->GetStringLength(arg1));
+ env->ReleaseStringCritical(arg1, str);
+ arg1Str = arg1_8.string();
+ }
+
+ int procId;
+ int ptm = create_subprocess(cmd_8.string(), arg0Str, arg1Str, &procId);
+
+ if (processIdArray) {
+ int procIdLen = env->GetArrayLength(processIdArray);
+ if (procIdLen > 0) {
+ jboolean isCopy;
+
+ int* pProcId = (int*) env->GetPrimitiveArrayCritical(processIdArray, &isCopy);
+ if (pProcId) {
+ *pProcId = procId;
+ env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0);
+ }
+ }
+ }
+
+ jobject result = env->NewObject(class_fileDescriptor, method_fileDescriptor_init);
+
+ if (!result) {
+ LOGE("Couldn't create a FileDescriptor.");
+ }
+ else {
+ env->SetIntField(result, field_fileDescriptor_descriptor, ptm);
+ }
+
+ return result;
+}
+
+
+static void android_os_Exec_setPtyWindowSize(JNIEnv *env, jobject clazz,
+ jobject fileDescriptor, jint row, jint col, jint xpixel, jint ypixel)
+{
+ int fd;
+ struct winsize sz;
+
+ fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ sz.ws_row = row;
+ sz.ws_col = col;
+ sz.ws_xpixel = xpixel;
+ sz.ws_ypixel = ypixel;
+
+ ioctl(fd, TIOCSWINSZ, &sz);
+}
+
+static int android_os_Exec_waitFor(JNIEnv *env, jobject clazz,
+ jint procId) {
+ int status;
+ waitpid(procId, &status, 0);
+ int result = 0;
+ if (WIFEXITED(status)) {
+ result = WEXITSTATUS(status);
+ }
+ return result;
+}
+
+static JNINativeMethod method_table[] = {
+ { "createSubprocess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
+ (void*) android_os_Exec_createSubProcess },
+ { "setPtyWindowSize", "(Ljava/io/FileDescriptor;IIII)V",
+ (void*) android_os_Exec_setPtyWindowSize},
+ { "waitFor", "(I)I",
+ (void*) android_os_Exec_waitFor}
+};
+
+int register_android_os_Exec(JNIEnv *env)
+{
+ class_fileDescriptor = env->FindClass("java/io/FileDescriptor");
+
+ if (class_fileDescriptor == NULL) {
+ LOGE("Can't find java/io/FileDescriptor");
+ return -1;
+ }
+
+ field_fileDescriptor_descriptor = env->GetFieldID(class_fileDescriptor, "descriptor", "I");
+
+ if (field_fileDescriptor_descriptor == NULL) {
+ LOGE("Can't find FileDescriptor.descriptor");
+ return -1;
+ }
+
+ method_fileDescriptor_init = env->GetMethodID(class_fileDescriptor, "<init>", "()V");
+ if (method_fileDescriptor_init == NULL) {
+ LOGE("Can't find FileDescriptor.init");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(
+ env, "android/os/Exec",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
new file mode 100644
index 0000000..21cb919
--- /dev/null
+++ b/core/jni/android_os_FileUtils.cpp
@@ -0,0 +1,208 @@
+/* //device/libs/android_runtime/android_util_Process.cpp
+**
+** Copyright 2006, 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 "FileUtils"
+
+#include <utils/Log.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include "JNIHelp.h"
+
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#if HAVE_ANDROID_OS
+#include <sys/ioctl.h>
+#include <linux/msdos_fs.h>
+#endif
+
+namespace android {
+
+static jclass gFileStatusClass;
+static jfieldID gFileStatusDevFieldID;
+static jfieldID gFileStatusInoFieldID;
+static jfieldID gFileStatusModeFieldID;
+static jfieldID gFileStatusNlinkFieldID;
+static jfieldID gFileStatusUidFieldID;
+static jfieldID gFileStatusGidFieldID;
+static jfieldID gFileStatusSizeFieldID;
+static jfieldID gFileStatusBlksizeFieldID;
+static jfieldID gFileStatusBlocksFieldID;
+static jfieldID gFileStatusAtimeFieldID;
+static jfieldID gFileStatusMtimeFieldID;
+static jfieldID gFileStatusCtimeFieldID;
+
+jint android_os_FileUtils_setPermissions(JNIEnv* env, jobject clazz,
+ jstring file, jint mode,
+ jint uid, jint gid)
+{
+ #if HAVE_ANDROID_OS
+ const jchar* str = env->GetStringCritical(file, 0);
+ String8 file8;
+ if (str) {
+ file8 = String8(str, env->GetStringLength(file));
+ env->ReleaseStringCritical(file, str);
+ }
+ if (file8.size() <= 0) {
+ return ENOENT;
+ }
+ if (uid >= 0 || gid >= 0) {
+ int res = chown(file8.string(), uid, gid);
+ if (res != 0) {
+ return errno;
+ }
+ }
+ return chmod(file8.string(), mode) == 0 ? 0 : errno;
+ #else
+ return ENOSYS;
+ #endif
+}
+
+jint android_os_FileUtils_getPermissions(JNIEnv* env, jobject clazz,
+ jstring file, jintArray outArray)
+{
+ #if HAVE_ANDROID_OS
+ const jchar* str = env->GetStringCritical(file, 0);
+ String8 file8;
+ if (str) {
+ file8 = String8(str, env->GetStringLength(file));
+ env->ReleaseStringCritical(file, str);
+ }
+ if (file8.size() <= 0) {
+ return ENOENT;
+ }
+ struct stat st;
+ if (stat(file8.string(), &st) != 0) {
+ return errno;
+ }
+ jint* array = (jint*)env->GetPrimitiveArrayCritical(outArray, 0);
+ if (array) {
+ int len = env->GetArrayLength(outArray);
+ if (len >= 1) {
+ array[0] = st.st_mode;
+ }
+ if (len >= 2) {
+ array[1] = st.st_uid;
+ }
+ if (len >= 3) {
+ array[2] = st.st_gid;
+ }
+ }
+ env->ReleasePrimitiveArrayCritical(outArray, array, 0);
+ return 0;
+ #else
+ return ENOSYS;
+ #endif
+}
+
+jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path)
+{
+ #if HAVE_ANDROID_OS
+ if (path == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return -1;
+ }
+ const char *pathStr = env->GetStringUTFChars(path, NULL);
+ int result = -1;
+ // only if our system supports this ioctl
+ #ifdef VFAT_IOCTL_GET_VOLUME_ID
+ int fd = open(pathStr, O_RDONLY);
+ if (fd >= 0) {
+ result = ioctl(fd, VFAT_IOCTL_GET_VOLUME_ID);
+ close(fd);
+ }
+ #endif
+
+ env->ReleaseStringUTFChars(path, pathStr);
+ return result;
+ #else
+ return -1;
+ #endif
+}
+
+jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring path, jobject fileStatus) {
+ const char* pathStr = env->GetStringUTFChars(path, NULL);
+ jboolean ret = false;
+
+ struct stat s;
+ int res = stat(pathStr, &s);
+ if (res == 0) {
+ ret = true;
+ if (fileStatus != NULL) {
+ env->SetIntField(fileStatus, gFileStatusDevFieldID, s.st_dev);
+ env->SetIntField(fileStatus, gFileStatusInoFieldID, s.st_ino);
+ env->SetIntField(fileStatus, gFileStatusModeFieldID, s.st_mode);
+ env->SetIntField(fileStatus, gFileStatusNlinkFieldID, s.st_nlink);
+ env->SetIntField(fileStatus, gFileStatusUidFieldID, s.st_uid);
+ env->SetIntField(fileStatus, gFileStatusGidFieldID, s.st_gid);
+ env->SetLongField(fileStatus, gFileStatusSizeFieldID, s.st_size);
+ env->SetIntField(fileStatus, gFileStatusBlksizeFieldID, s.st_blksize);
+ env->SetLongField(fileStatus, gFileStatusBlocksFieldID, s.st_blocks);
+ env->SetLongField(fileStatus, gFileStatusAtimeFieldID, s.st_atime);
+ env->SetLongField(fileStatus, gFileStatusMtimeFieldID, s.st_mtime);
+ env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
+ }
+ }
+
+ env->ReleaseStringUTFChars(path, pathStr);
+
+ return ret;
+}
+
+static const JNINativeMethod methods[] = {
+ {"setPermissions", "(Ljava/lang/String;III)I", (void*)android_os_FileUtils_setPermissions},
+ {"getPermissions", "(Ljava/lang/String;[I)I", (void*)android_os_FileUtils_getPermissions},
+ {"getFatVolumeId", "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getFatVolumeId},
+ {"getFileStatus", "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z", (void*)android_os_FileUtils_getFileStatus},
+};
+
+static const char* const kFileUtilsPathName = "android/os/FileUtils";
+
+int register_android_os_FileUtils(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass(kFileUtilsPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils");
+
+ gFileStatusClass = env->FindClass("android/os/FileUtils$FileStatus");
+ LOG_FATAL_IF(gFileStatusClass == NULL, "Unable to find class android.os.FileUtils$FileStatus");
+
+ gFileStatusDevFieldID = env->GetFieldID(gFileStatusClass, "dev", "I");
+ gFileStatusInoFieldID = env->GetFieldID(gFileStatusClass, "ino", "I");
+ gFileStatusModeFieldID = env->GetFieldID(gFileStatusClass, "mode", "I");
+ gFileStatusNlinkFieldID = env->GetFieldID(gFileStatusClass, "nlink", "I");
+ gFileStatusUidFieldID = env->GetFieldID(gFileStatusClass, "uid", "I");
+ gFileStatusGidFieldID = env->GetFieldID(gFileStatusClass, "gid", "I");
+ gFileStatusSizeFieldID = env->GetFieldID(gFileStatusClass, "size", "J");
+ gFileStatusBlksizeFieldID = env->GetFieldID(gFileStatusClass, "blksize", "I");
+ gFileStatusBlocksFieldID = env->GetFieldID(gFileStatusClass, "blocks", "J");
+ gFileStatusAtimeFieldID = env->GetFieldID(gFileStatusClass, "atime", "J");
+ gFileStatusMtimeFieldID = env->GetFieldID(gFileStatusClass, "mtime", "J");
+ gFileStatusCtimeFieldID = env->GetFieldID(gFileStatusClass, "ctime", "J");
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kFileUtilsPathName,
+ methods, NELEM(methods));
+}
+
+}
+
diff --git a/core/jni/android_os_Hardware.cpp b/core/jni/android_os_Hardware.cpp
new file mode 100644
index 0000000..a302498
--- /dev/null
+++ b/core/jni/android_os_Hardware.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006, 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.
+*/
+
+#include <hardware/flashlight.h>
+#include <hardware/led.h>
+#include <hardware/power.h>
+
+#include <nativehelper/jni.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+
+static jboolean
+setLedState(JNIEnv *env, jobject clazz, jint colorARGB, jint onMS, jint offMS)
+{
+ return set_led_state(colorARGB, onMS, offMS);
+}
+
+static jint
+getFlashlightEnabled(JNIEnv *env, jobject clazz)
+{
+ return get_flashlight_enabled();
+}
+
+static void
+setFlashlightEnabled(JNIEnv *env, jobject clazz, jboolean on)
+{
+ set_flashlight_enabled(on);
+}
+
+static void
+enableCameraFlash(JNIEnv *env, jobject clazz, jint milliseconds)
+{
+ enable_camera_flash(milliseconds);
+}
+
+static void
+setScreenBacklight(JNIEnv *env, jobject clazz, jint brightness)
+{
+ set_light_brightness(SCREEN_LIGHT, brightness);
+}
+
+static void
+setKeyboardBacklight(JNIEnv *env, jobject clazz, jboolean on)
+{
+ set_light_brightness(KEYBOARD_LIGHT, (on ? 255 : 0));
+}
+
+static void
+setButtonBacklight(JNIEnv *env, jobject clazz, jboolean on)
+{
+ set_light_brightness(BUTTON_LIGHT, (on ? 255 : 0));
+}
+
+// ============================================================================
+/*
+ * JNI registration.
+ */
+
+static JNINativeMethod g_methods[] = {
+ /* name, signature, funcPtr */
+ { "setLedState", "(III)I", (void*)setLedState },
+ { "getFlashlightEnabled", "()Z", (void*)getFlashlightEnabled },
+ { "setFlashlightEnabled", "(Z)V", (void*)setFlashlightEnabled },
+ { "enableCameraFlash", "(I)V", (void*)enableCameraFlash },
+ { "setScreenBacklight", "(I)V", (void*)setScreenBacklight },
+ { "setKeyboardBacklight", "(Z)V", (void*)setKeyboardBacklight },
+ { "setButtonBacklight", "(Z)V", (void*)setButtonBacklight },
+};
+
+int register_android_os_Hardware(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/os/Hardware", g_methods, NELEM(g_methods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
new file mode 100644
index 0000000..edf7dc4
--- /dev/null
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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_TAG "MemoryFile"
+#include <utils/Log.h>
+
+#include <cutils/ashmem.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "JNIHelp.h"
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+namespace android {
+
+static jint android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)
+{
+ const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);
+
+ // round up length to page boundary
+ length = (((length - 1) / getpagesize()) + 1) * getpagesize();
+ int result = ashmem_create_region(namestr, length);
+
+ if (name)
+ env->ReleaseStringUTFChars(name, namestr);
+
+ if (result < 0)
+ jniThrowException(env, "java/io/IOException", "ashmem_create_region failed");
+ return result;
+}
+
+static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jint fd, jint length)
+{
+ jint result = (jint)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (!result)
+ jniThrowException(env, "java/io/IOException", "mmap failed");
+ return result;
+}
+
+static void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jint fd)
+{
+ close(fd);
+}
+
+static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz,
+ jint fd, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
+ jint count, jboolean unpinned)
+{
+ if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
+ ashmem_unpin_region(fd, 0, 0);
+ jniThrowException(env, "java/io/IOException", "ashmem region was purged");
+ return -1;
+ }
+
+ jbyte* bytes = env->GetByteArrayElements(buffer, 0);
+ memcpy(bytes + destOffset, (const char *)address + srcOffset, count);
+ env->ReleaseByteArrayElements(buffer, bytes, 0);
+
+ if (unpinned) {
+ ashmem_unpin_region(fd, 0, 0);
+ }
+ return count;
+}
+
+static jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz,
+ jint fd, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
+ jint count, jboolean unpinned)
+{
+ if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
+ ashmem_unpin_region(fd, 0, 0);
+ jniThrowException(env, "java/io/IOException", "ashmem region was purged");
+ return -1;
+ }
+
+ jbyte* bytes = env->GetByteArrayElements(buffer, 0);
+ memcpy((char *)address + destOffset, bytes + srcOffset, count);
+ env->ReleaseByteArrayElements(buffer, bytes, 0);
+
+ if (unpinned) {
+ ashmem_unpin_region(fd, 0, 0);
+ }
+ return count;
+}
+
+static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jint fd, jboolean pin)
+{
+ int result = (pin ? ashmem_pin_region(fd, 0, 0) : ashmem_unpin_region(fd, 0, 0));
+ if (result < 0) {
+ jniThrowException(env, "java/io/IOException", NULL);
+ }
+}
+
+static const JNINativeMethod methods[] = {
+ {"native_open", "(Ljava/lang/String;I)I", (void*)android_os_MemoryFile_open},
+ {"native_mmap", "(II)I", (void*)android_os_MemoryFile_mmap},
+ {"native_close", "(I)V", (void*)android_os_MemoryFile_close},
+ {"native_read", "(II[BIIIZ)I", (void*)android_os_MemoryFile_read},
+ {"native_write", "(II[BIIIZ)V", (void*)android_os_MemoryFile_write},
+ {"native_pin", "(IZ)V", (void*)android_os_MemoryFile_pin},
+};
+
+static const char* const kClassPathName = "android/os/MemoryFile";
+
+int register_android_os_MemoryFile(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass(kClassPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils");
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kClassPathName,
+ methods, NELEM(methods));
+}
+
+}
diff --git a/core/jni/android_os_NetStat.cpp b/core/jni/android_os_NetStat.cpp
new file mode 100644
index 0000000..983f719
--- /dev/null
+++ b/core/jni/android_os_NetStat.cpp
@@ -0,0 +1,158 @@
+/* //device/libs/android_runtime/android_os_Wifi.cpp
+**
+** Copyright 2007, 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 "NetStat"
+
+#include "jni.h"
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#if HAVE_ANDROID_OS
+#include <utils/Atomic.h>
+#endif
+
+namespace android {
+
+static jint android_os_netStatGetTxPkts(JNIEnv* env, jobject clazz)
+{
+ int ret = 0;
+ int fd = -1;
+ char input[50];
+
+ fd = open("/sys/class/net/rmnet0/statistics/tx_packets", O_RDONLY);
+ if (fd <= 0) {
+ fd = open("/sys/class/net/ppp0/statistics/tx_packets", O_RDONLY);
+ }
+
+ if (fd > 0) {
+ int size = read(fd, input, 50);
+ if (size > 0) {
+ ret = atoi(input);
+ }
+ close(fd);
+ }
+
+ return (jint)ret;
+}
+
+static jint android_os_netStatGetRxPkts(JNIEnv* env, jobject clazz)
+{
+ int ret = 0;
+ int fd = -1;
+ char input[50];
+
+ fd = open("/sys/class/net/rmnet0/statistics/rx_packets", O_RDONLY);
+ if (fd <= 0) {
+ fd = open("/sys/class/net/ppp0/statistics/rx_packets", O_RDONLY);
+ }
+
+ if (fd > 0) {
+ int size = read(fd, input, 50);
+ if (size > 0) {
+ ret = atoi(input);
+ }
+ close(fd);
+ }
+
+ return (jint)ret;
+}
+
+static jint android_os_netStatGetRxBytes(JNIEnv* env, jobject clazz)
+{
+ int ret = 0;
+ int fd = -1;
+ char input[50];
+
+ fd = open("/sys/class/net/rmnet0/statistics/rx_bytes", O_RDONLY);
+ if (fd <= 0) {
+ fd = open("/sys/class/net/ppp0/statistics/rx_bytes", O_RDONLY);
+ }
+
+ if (fd > 0) {
+ int size = read(fd, input, 50);
+ if (size > 0) {
+ ret = atoi(input);
+ }
+ close(fd);
+ }
+
+ return (jint)ret;
+}
+
+
+static jint android_os_netStatGetTxBytes(JNIEnv* env, jobject clazz)
+{
+ int ret = 0;
+ int fd = -1;
+ char input[50];
+
+ fd = open("/sys/class/net/rmnet0/statistics/tx_bytes", O_RDONLY);
+ if (fd <= 0) {
+ fd = open("/sys/class/net/ppp0/statistics/tx_bytes", O_RDONLY);
+ }
+
+ if (fd > 0) {
+ int size = read(fd, input, 50);
+ if (size > 0) {
+ ret = atoi(input);
+ }
+ close(fd);
+ }
+
+ return (jint)ret;
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+
+ { "netStatGetTxPkts", "()I",
+ (void*) android_os_netStatGetTxPkts },
+
+ { "netStatGetRxPkts", "()I",
+ (void*) android_os_netStatGetRxPkts },
+
+ { "netStatGetTxBytes", "()I",
+ (void*) android_os_netStatGetTxBytes },
+
+ { "netStatGetRxBytes", "()I",
+ (void*) android_os_netStatGetRxBytes },
+
+};
+
+int register_android_os_NetStat(JNIEnv* env)
+{
+ jclass netStat = env->FindClass("android/os/NetStat");
+ LOG_FATAL_IF(netStat == NULL, "Unable to find class android/os/NetStat");
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/os/NetStat", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
new file mode 100644
index 0000000..465e233
--- /dev/null
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -0,0 +1,102 @@
+/* //device/libs/android_runtime/android_os_ParcelFileDescriptor.cpp
+**
+** 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.
+*/
+
+#include "JNIHelp.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#include <utils/Log.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android
+{
+
+static struct file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+ jfieldID mDescriptor;
+} gFileDescriptorOffsets;
+
+static struct socket_offsets_t
+{
+ jfieldID mSocketImpl;
+} gSocketOffsets;
+
+static struct socket_impl_offsets_t
+{
+ jfieldID mFileDescriptor;
+} gSocketImplOffsets;
+
+
+static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
+ jobject clazz, jobject object)
+{
+ jobject socketImpl = env->GetObjectField(object, gSocketOffsets.mSocketImpl);
+ jobject fileDescriptor = env->GetObjectField(socketImpl, gSocketImplOffsets.mFileDescriptor);
+ jint fd = env->GetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor);
+ jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
+ gFileDescriptorOffsets.mConstructor);
+ if (fileDescriptorClone != NULL) {
+ env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, dup(fd));
+ }
+ return fileDescriptorClone;
+}
+
+static const JNINativeMethod gParcelFileDescriptorMethods[] = {
+ {"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
+ (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket}
+};
+
+const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
+
+int register_android_os_ParcelFileDescriptor(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("java/net/Socket");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.Socket");
+ gSocketOffsets.mSocketImpl = env->GetFieldID(clazz, "impl", "Ljava/net/SocketImpl;");
+ LOG_FATAL_IF(gSocketOffsets.mSocketImpl == NULL,
+ "Unable to find impl field in java.net.Socket");
+
+ clazz = env->FindClass("java/net/SocketImpl");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.SocketImpl");
+ gSocketImplOffsets.mFileDescriptor = env->GetFieldID(clazz, "fd", "Ljava/io/FileDescriptor;");
+ LOG_FATAL_IF(gSocketImplOffsets.mFileDescriptor == NULL,
+ "Unable to find fd field in java.net.SocketImpl");
+
+ clazz = env->FindClass("java/io/FileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
+ gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
+ gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
+ LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
+ "Unable to find descriptor field in java.io.FileDescriptor");
+
+ clazz = env->FindClass(kParcelFileDescriptorPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kParcelFileDescriptorPathName,
+ gParcelFileDescriptorMethods, NELEM(gParcelFileDescriptorMethods));
+}
+
+}
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
new file mode 100644
index 0000000..02a4083
--- /dev/null
+++ b/core/jni/android_os_Power.cpp
@@ -0,0 +1,123 @@
+/* //device/libs/android_runtime/android_os_Power.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include "jni.h"
+#include "android_runtime/AndroidRuntime.h"
+#include <utils/misc.h>
+#include <hardware/power.h>
+#include <sys/reboot.h>
+
+namespace android
+{
+
+static void throw_NullPointerException(JNIEnv *env, const char* msg)
+{
+ jclass clazz;
+ clazz = env->FindClass("java/lang/NullPointerException");
+ env->ThrowNew(clazz, msg);
+}
+
+static void
+acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj)
+{
+ if (idObj == NULL) {
+ throw_NullPointerException(env, "id is null");
+ return ;
+ }
+
+ const char *id = env->GetStringUTFChars(idObj, NULL);
+
+ acquire_wake_lock(lock, id);
+
+ env->ReleaseStringUTFChars(idObj, id);
+}
+
+static void
+releaseWakeLock(JNIEnv *env, jobject clazz, jstring idObj)
+{
+ if (idObj == NULL) {
+ throw_NullPointerException(env, "id is null");
+ return ;
+ }
+
+ const char *id = env->GetStringUTFChars(idObj, NULL);
+
+ release_wake_lock(id);
+
+ env->ReleaseStringUTFChars(idObj, id);
+
+}
+
+static int
+setLastUserActivityTimeout(JNIEnv *env, jobject clazz, jlong timeMS)
+{
+ return set_last_user_activity_timeout(timeMS/1000);
+}
+
+static int
+setLightBrightness(JNIEnv *env, jobject clazz, jint mask, jint brightness)
+{
+ return set_light_brightness(mask, brightness);
+}
+
+static int
+setScreenState(JNIEnv *env, jobject clazz, jboolean on)
+{
+ return set_screen_state(on);
+}
+
+static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
+{
+ sync();
+#ifdef HAVE_ANDROID_OS
+ reboot(RB_POWER_OFF);
+#endif
+}
+
+static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)
+{
+ sync();
+#ifdef HAVE_ANDROID_OS
+ if (reason == NULL) {
+ reboot(RB_AUTOBOOT);
+ } else {
+ const char *chars = env->GetStringUTFChars(reason, NULL);
+ __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, (char*) chars);
+ env->ReleaseStringUTFChars(reason, chars); // In case it fails.
+ }
+#endif
+}
+
+static JNINativeMethod method_table[] = {
+ { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },
+ { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },
+ { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },
+ { "setLightBrightness", "(II)I", (void*)setLightBrightness },
+ { "setScreenState", "(Z)I", (void*)setScreenState },
+ { "shutdown", "()V", (void*)android_os_Power_shutdown },
+ { "reboot", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },
+};
+
+int register_android_os_Power(JNIEnv *env)
+{
+ return AndroidRuntime::registerNativeMethods(
+ env, "android/os/Power",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/core/jni/android_os_StatFs.cpp b/core/jni/android_os_StatFs.cpp
new file mode 100644
index 0000000..c658aa5
--- /dev/null
+++ b/core/jni/android_os_StatFs.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2007, 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.
+ */
+
+#if INCLUDE_SYS_MOUNT_FOR_STATFS
+#include <sys/mount.h>
+#else
+#include <sys/statfs.h>
+#endif
+
+#include <errno.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+
+namespace android
+{
+
+// ----------------------------------------------------------------------------
+
+struct fields_t {
+ jfieldID context;
+};
+static fields_t fields;
+
+// ----------------------------------------------------------------------------
+
+static jint
+android_os_StatFs_getBlockSize(JNIEnv *env, jobject thiz)
+{
+ struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
+ return stat->f_bsize;
+}
+
+static jint
+android_os_StatFs_getBlockCount(JNIEnv *env, jobject thiz)
+{
+ struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
+ return stat->f_blocks;
+}
+
+static jint
+android_os_StatFs_getFreeBlocks(JNIEnv *env, jobject thiz)
+{
+ struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
+ return stat->f_bfree;
+}
+
+static jint
+android_os_StatFs_getAvailableBlocks(JNIEnv *env, jobject thiz)
+{
+ struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
+ return stat->f_bavail;
+}
+
+static void
+android_os_StatFs_native_restat(JNIEnv *env, jobject thiz, jstring path)
+{
+ if (path == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ // get the object handle
+ struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
+ if (stat == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldException", NULL);
+ return;
+ }
+
+ const char* pathstr = env->GetStringUTFChars(path, NULL);
+ if (pathstr == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ return;
+ }
+
+ // note that stat will contain the new file data corresponding to
+ // pathstr
+ if (statfs(pathstr, stat) != 0) {
+ LOGE("statfs %s failed, errno: %d", pathstr, errno);
+ delete stat;
+ env->SetIntField(thiz, fields.context, 0);
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ // Release pathstr
+ env->ReleaseStringUTFChars(path, pathstr);
+}
+
+static void
+android_os_StatFs_native_setup(JNIEnv *env, jobject thiz, jstring path)
+{
+ if (path == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ struct statfs* stat = new struct statfs;
+ if (stat == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ return;
+ }
+ env->SetIntField(thiz, fields.context, (int)stat);
+ android_os_StatFs_native_restat(env, thiz, path);
+}
+
+static void
+android_os_StatFs_native_finalize(JNIEnv *env, jobject thiz)
+{
+ struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
+ if (stat != NULL) {
+ delete stat;
+ env->SetIntField(thiz, fields.context, 0);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"getBlockSize", "()I", (void *)android_os_StatFs_getBlockSize},
+ {"getBlockCount", "()I", (void *)android_os_StatFs_getBlockCount},
+ {"getFreeBlocks", "()I", (void *)android_os_StatFs_getFreeBlocks},
+ {"getAvailableBlocks", "()I", (void *)android_os_StatFs_getAvailableBlocks},
+ {"native_setup", "(Ljava/lang/String;)V", (void *)android_os_StatFs_native_setup},
+ {"native_finalize", "()V", (void *)android_os_StatFs_native_finalize},
+ {"native_restat", "(Ljava/lang/String;)V", (void *)android_os_StatFs_native_restat},
+};
+
+
+int register_android_os_StatFs(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/os/StatFs");
+ if (clazz == NULL) {
+ LOGE("Can't find android/os/StatFs");
+ return -1;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ LOGE("Can't find StatFs.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/os/StatFs", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
new file mode 100644
index 0000000..ffd0c1e
--- /dev/null
+++ b/core/jni/android_os_SystemClock.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * System clock functions.
+ */
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "utils/SystemClock.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+namespace android {
+
+/*
+ * native public static void setCurrentTimeMillis(long millis)
+ *
+ * Set the current time. This only works when running as root.
+ */
+static jboolean android_os_SystemClock_setCurrentTimeMillis(JNIEnv* env,
+ jobject clazz, jlong millis)
+{
+ return (setCurrentTimeMillis(millis) == 0);
+}
+
+/*
+ * native public static long uptimeMillis();
+ */
+static jlong android_os_SystemClock_uptimeMillis(JNIEnv* env,
+ jobject clazz)
+{
+ return (jlong)uptimeMillis();
+}
+
+/*
+ * native public static long elapsedRealtime();
+ */
+static jlong android_os_SystemClock_elapsedRealtime(JNIEnv* env,
+ jobject clazz)
+{
+ return (jlong)elapsedRealtime();
+}
+
+/*
+ * native public static long currentThreadTimeMillis();
+ */
+static jlong android_os_SystemClock_currentThreadTimeMillis(JNIEnv* env,
+ jobject clazz)
+{
+#if defined(HAVE_POSIX_CLOCKS)
+ struct timespec tm;
+
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
+
+ return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
+#else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
+#endif
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "setCurrentTimeMillis", "(J)Z",
+ (void*) android_os_SystemClock_setCurrentTimeMillis },
+ { "uptimeMillis", "()J",
+ (void*) android_os_SystemClock_uptimeMillis },
+ { "elapsedRealtime", "()J",
+ (void*) android_os_SystemClock_elapsedRealtime },
+ { "currentThreadTimeMillis", "()J",
+ (void*) android_os_SystemClock_currentThreadTimeMillis },
+};
+int register_android_os_SystemClock(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/os/SystemClock", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
new file mode 100644
index 0000000..ca4fa11
--- /dev/null
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -0,0 +1,108 @@
+/* //device/libs/android_runtime/android_os_SystemProperties.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include "cutils/properties.h"
+#include "jni.h"
+#include "android_runtime/AndroidRuntime.h"
+#include <nativehelper/JNIHelp.h>
+
+namespace android
+{
+
+static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
+ jstring keyJ, jstring defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jstring rvJ = NULL;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if ((len <= 0) && (defJ != NULL)) {
+ rvJ = defJ;
+ } else if (len >= 0) {
+ rvJ = env->NewStringUTF(buf);
+ } else {
+ rvJ = env->NewStringUTF("");
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return rvJ;
+}
+
+static jstring SystemProperties_getS(JNIEnv *env, jobject clazz,
+ jstring keyJ)
+{
+ return SystemProperties_getSS(env, clazz, keyJ, NULL);
+}
+
+static void SystemProperties_set(JNIEnv *env, jobject clazz,
+ jstring keyJ, jstring valJ)
+{
+ int err;
+ const char* key;
+ const char* val;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ return ;
+ }
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ if (valJ == NULL) {
+ val = ""; /* NULL pointer not allowed here */
+ } else {
+ val = env->GetStringUTFChars(valJ, NULL);
+ }
+
+ err = property_set(key, val);
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+ if (valJ != NULL) {
+ env->ReleaseStringUTFChars(valJ, val);
+ }
+}
+
+static JNINativeMethod method_table[] = {
+ { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) SystemProperties_getS },
+ { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) SystemProperties_getSS },
+ { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
+ (void*) SystemProperties_set },
+};
+
+int register_android_os_SystemProperties(JNIEnv *env)
+{
+ return AndroidRuntime::registerNativeMethods(
+ env, "android/os/SystemProperties",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp
new file mode 100644
index 0000000..cac4372
--- /dev/null
+++ b/core/jni/android_os_UEventObserver.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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_TAG "UEventObserver"
+#include "utils/Log.h"
+
+#include "hardware/uevent.h"
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+namespace android
+{
+
+static void
+android_os_UEventObserver_native_setup(JNIEnv *env, jclass clazz)
+{
+ if (!uevent_init()) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Unable to open socket for UEventObserver");
+ }
+}
+
+static int
+android_os_UEventObserver_next_event(JNIEnv *env, jclass clazz, jbyteArray jbuffer)
+{
+ int buf_sz = env->GetArrayLength(jbuffer);
+ char *buffer = (char*)env->GetByteArrayElements(jbuffer, NULL);
+
+ int length = uevent_next_event(buffer, buf_sz - 1);
+
+ env->ReleaseByteArrayElements(jbuffer, (jbyte*)buffer, 0);
+
+ return length;
+}
+
+static JNINativeMethod gMethods[] = {
+ {"native_setup", "()V", (void *)android_os_UEventObserver_native_setup},
+ {"next_event", "([B)I", (void *)android_os_UEventObserver_next_event},
+};
+
+
+int register_android_os_UEventObserver(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/os/UEventObserver");
+ if (clazz == NULL) {
+ LOGE("Can't find android/os/UEventObserver");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/os/UEventObserver", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_pim_EventRecurrence.cpp b/core/jni/android_pim_EventRecurrence.cpp
new file mode 100644
index 0000000..cbe99bc
--- /dev/null
+++ b/core/jni/android_pim_EventRecurrence.cpp
@@ -0,0 +1,199 @@
+/* //device/libs/android_runtime/android_pim_EventRecurrence.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include <pim/EventRecurrence.h>
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+#include <utils/String8.h>
+
+namespace android {
+
+struct cached_array_fields_t
+{
+ jfieldID array;
+ jfieldID count;
+};
+
+static jclass clazz;
+static jfieldID freq_field;
+static jfieldID until_field;
+static jfieldID count_field;
+static jfieldID interval_field;
+static jfieldID wkst_field;
+static cached_array_fields_t bysecond_fields;
+static cached_array_fields_t byminute_fields;
+static cached_array_fields_t byhour_fields;
+static cached_array_fields_t byday_fields;
+static cached_array_fields_t bydayNum_fields;
+static cached_array_fields_t bymonthday_fields;
+static cached_array_fields_t byyearday_fields;
+static cached_array_fields_t byweekno_fields;
+static cached_array_fields_t bymonth_fields;
+static cached_array_fields_t bysetpos_fields;
+
+static status_t
+set_array(JNIEnv* env, int inCount, int* inArray,
+ jobject This, const cached_array_fields_t& fields)
+{
+ if (inCount > 0) {
+ jintArray array = (jintArray) env->GetObjectField(This, fields.array);
+ if (array == NULL || env->GetArrayLength(array) < inCount) {
+ // +4 because it's cheap to allocate a little extra here, and
+ // that reduces the chance that we'll come back here again
+ array = env->NewIntArray(inCount+4);
+ env->SetObjectField(This, fields.array, array);
+ }
+ if (array == NULL) {
+ return NO_MEMORY;
+ }
+ env->SetIntArrayRegion(array, 0, inCount, inArray);
+
+ }
+ env->SetIntField(This, fields.count, inCount);
+ return NO_ERROR;
+}
+
+/*
+ * In class android.pim.EventRecurrence
+ * public native int parse(String str);
+ */
+#define SET_ARRAY_AND_CHECK(name) \
+ /*printf("setting " #name " to %d elements\n", er.name##Count);*/ \
+ if (set_array(env, er.name##Count, er.name, This, name##_fields) \
+ != NO_ERROR) { \
+ jniThrowException(env, "java/lang/RuntimeException", \
+ "EventRecurrence.parse error setting field " #name " or " \
+ #name "Count."); \
+ return ; \
+ }
+static void
+EventRecurrence_parse(JNIEnv* env, jobject This, jstring jstr)
+{
+ if (jstr == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "EventRecurrence.parse str parameter null");
+ return ;
+ }
+ jboolean isCopy;
+ const jchar* jchars = env->GetStringChars(jstr, &isCopy);
+ jsize len = env->GetStringLength(jstr);
+ String16 str(jchars, len);
+ env->ReleaseStringChars(jstr, jchars);
+
+ //printf("the string was '%s'\n", String8(str).string());
+
+ EventRecurrence er;
+ if (NO_ERROR != er.parse(str)) {
+ String8 msg("Error parsing recurrence: '");
+ msg.append(String8(str));
+ msg.append("'");
+
+ jniThrowException(env,
+ "android/pim/EventRecurrence$InvalidFormatException",
+ msg.string());
+ return ;
+ }
+
+ jstring untilStr;
+ if (er.until.size() > 0) {
+ untilStr = env->NewString(er.until.string(), er.until.size());
+ if (untilStr == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "EventRecurrence.parse error setting field 'until'");
+ return ;
+ }
+ } else {
+ untilStr = NULL;
+ }
+ env->SetObjectField(This, until_field, untilStr);
+
+ env->SetIntField(This, freq_field, er.freq);
+ env->SetIntField(This, count_field, er.count);
+ env->SetIntField(This, interval_field, er.interval);
+ env->SetIntField(This, wkst_field, er.wkst);
+
+ SET_ARRAY_AND_CHECK(bysecond)
+ SET_ARRAY_AND_CHECK(byminute)
+ SET_ARRAY_AND_CHECK(byhour)
+ SET_ARRAY_AND_CHECK(byday)
+ // we'll just set the bydayCount field twice, it'll be less code total
+ if (set_array(env, er.bydayCount, er.bydayNum, This, bydayNum_fields)
+ != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "EventRecurrence.parse error setting field bydayNum or "
+ "bydayCount.");
+ return ;
+ }
+ SET_ARRAY_AND_CHECK(bymonthday)
+ SET_ARRAY_AND_CHECK(byyearday)
+ SET_ARRAY_AND_CHECK(byweekno)
+ SET_ARRAY_AND_CHECK(bymonth)
+ SET_ARRAY_AND_CHECK(bysetpos)
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod METHODS[] = {
+ /* name, signature, funcPtr */
+ { "parse", "(Ljava/lang/String;)V", (void*)EventRecurrence_parse }
+};
+
+static const char*const CLASS_NAME = "android/pim/EventRecurrence";
+
+int register_android_pim_EventRecurrence(JNIEnv* env)
+{
+ clazz = env->FindClass(CLASS_NAME);
+ if (clazz == NULL) {
+ LOGE("Field lookup unable to find class '%s'\n", CLASS_NAME);
+ return -1;
+ }
+
+ freq_field = env->GetFieldID(clazz, "freq", "I");
+ count_field = env->GetFieldID(clazz, "count", "I");
+ interval_field = env->GetFieldID(clazz, "interval", "I");
+ wkst_field = env->GetFieldID(clazz, "wkst", "I");
+
+ until_field = env->GetFieldID(clazz, "until", "Ljava/lang/String;");
+
+ bysecond_fields.array = env->GetFieldID(clazz, "bysecond", "[I");
+ bysecond_fields.count = env->GetFieldID(clazz, "bysecondCount", "I");
+ byminute_fields.array = env->GetFieldID(clazz, "byminute", "[I");
+ byminute_fields.count = env->GetFieldID(clazz, "byminuteCount", "I");
+ byhour_fields.array = env->GetFieldID(clazz, "byhour", "[I");
+ byhour_fields.count = env->GetFieldID(clazz, "byhourCount", "I");
+ byday_fields.array = env->GetFieldID(clazz, "byday", "[I");
+ byday_fields.count = env->GetFieldID(clazz, "bydayCount", "I");
+ bydayNum_fields.array = env->GetFieldID(clazz, "bydayNum", "[I");
+ bydayNum_fields.count = byday_fields.count;
+ bymonthday_fields.array = env->GetFieldID(clazz, "bymonthday", "[I");
+ bymonthday_fields.count = env->GetFieldID(clazz, "bymonthdayCount", "I");
+ byyearday_fields.array = env->GetFieldID(clazz, "byyearday", "[I");
+ byyearday_fields.count = env->GetFieldID(clazz, "byyeardayCount", "I");
+ byweekno_fields.array = env->GetFieldID(clazz, "byweekno", "[I");
+ byweekno_fields.count = env->GetFieldID(clazz, "byweeknoCount", "I");
+ bymonth_fields.array = env->GetFieldID(clazz, "bymonth", "[I");
+ bymonth_fields.count = env->GetFieldID(clazz, "bymonthCount", "I");
+ bysetpos_fields.array = env->GetFieldID(clazz, "bysetpos", "[I");
+ bysetpos_fields.count = env->GetFieldID(clazz, "bysetposCount", "I");
+
+ return jniRegisterNativeMethods(env, CLASS_NAME,
+ METHODS, sizeof(METHODS)/sizeof(METHODS[0]));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_pim_Time.cpp b/core/jni/android_pim_Time.cpp
new file mode 100644
index 0000000..c1dd499
--- /dev/null
+++ b/core/jni/android_pim_Time.cpp
@@ -0,0 +1,594 @@
+/*
+** Copyright 2006, 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 "Log_println"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <assert.h>
+
+#include "jni.h"
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+#include <utils/TimeUtils.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+
+static jfieldID g_allDayField = 0;
+static jfieldID g_secField = 0;
+static jfieldID g_minField = 0;
+static jfieldID g_hourField = 0;
+static jfieldID g_mdayField = 0;
+static jfieldID g_monField = 0;
+static jfieldID g_yearField = 0;
+static jfieldID g_wdayField = 0;
+static jfieldID g_ydayField = 0;
+static jfieldID g_isdstField = 0;
+static jfieldID g_gmtoffField = 0;
+static jfieldID g_timezoneField = 0;
+
+static inline bool java2time(JNIEnv* env, Time* t, jobject o)
+{
+ t->t.tm_sec = env->GetIntField(o, g_secField);
+ t->t.tm_min = env->GetIntField(o, g_minField);
+ t->t.tm_hour = env->GetIntField(o, g_hourField);
+ t->t.tm_mday = env->GetIntField(o, g_mdayField);
+ t->t.tm_mon = env->GetIntField(o, g_monField);
+ t->t.tm_year = (env->GetIntField(o, g_yearField))-1900;
+ t->t.tm_wday = env->GetIntField(o, g_wdayField);
+ t->t.tm_yday = env->GetIntField(o, g_ydayField);
+ t->t.tm_isdst = env->GetIntField(o, g_isdstField);
+ t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField);
+ bool allDay = env->GetIntField(o, g_allDayField);
+ if (allDay &&
+ ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
+ char msg[100];
+ sprintf(msg, "allDay is true but sec, min, hour are not 0.");
+ jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+ return false;
+ }
+ return true;
+}
+
+static inline void time2java(JNIEnv* env, jobject o, const Time &t)
+{
+ env->SetIntField(o, g_secField, t.t.tm_sec);
+ env->SetIntField(o, g_minField, t.t.tm_min);
+ env->SetIntField(o, g_hourField, t.t.tm_hour);
+ env->SetIntField(o, g_mdayField, t.t.tm_mday);
+ env->SetIntField(o, g_monField, t.t.tm_mon);
+ env->SetIntField(o, g_yearField, t.t.tm_year+1900);
+ env->SetIntField(o, g_wdayField, t.t.tm_wday);
+ env->SetIntField(o, g_ydayField, t.t.tm_yday);
+ env->SetIntField(o, g_isdstField, t.t.tm_isdst);
+ env->SetLongField(o, g_gmtoffField, t.t.tm_gmtoff);
+}
+
+#define ACQUIRE_TIMEZONE(This, t) \
+ jstring timezoneString_##This \
+ = (jstring) env->GetObjectField(This, g_timezoneField); \
+ t.timezone = env->GetStringUTFChars(timezoneString_##This, NULL);
+
+#define RELEASE_TIMEZONE(This, t) \
+ env->ReleaseStringUTFChars(timezoneString_##This, t.timezone);
+
+
+// ============================================================================
+
+static jlong android_pim_Time_normalize(JNIEnv* env, jobject This,
+ jboolean ignoreDst)
+{
+ Time t;
+ if (!java2time(env, &t, This)) return 0L;
+ ACQUIRE_TIMEZONE(This, t)
+
+ int64_t result = t.toMillis(ignoreDst != 0);
+
+ time2java(env, This, t);
+ RELEASE_TIMEZONE(This, t)
+
+ return result;
+}
+
+static void android_pim_Time_switchTimezone(JNIEnv* env, jobject This,
+ jstring timezoneObject)
+{
+ Time t;
+ if (!java2time(env, &t, This)) return;
+ ACQUIRE_TIMEZONE(This, t)
+
+ const char* timezone = env->GetStringUTFChars(timezoneObject, NULL);
+
+ t.switchTimezone(timezone);
+
+ time2java(env, This, t);
+ env->ReleaseStringUTFChars(timezoneObject, timezone);
+ RELEASE_TIMEZONE(This, t)
+
+ // we do this here because there's no point in reallocating the string
+ env->SetObjectField(This, g_timezoneField, timezoneObject);
+}
+
+static jint android_pim_Time_compare(JNIEnv* env, jobject clazz,
+ jobject aObject, jobject bObject)
+{
+ Time a, b;
+
+ if (!java2time(env, &a, aObject)) return 0;
+ ACQUIRE_TIMEZONE(aObject, a)
+
+ if (!java2time(env, &b, bObject)) return 0;
+ ACQUIRE_TIMEZONE(bObject, b)
+
+ int result = Time::compare(a, b);
+
+ RELEASE_TIMEZONE(aObject, a)
+ RELEASE_TIMEZONE(bObject, b)
+
+ return result;
+}
+
+static jstring android_pim_Time_format2445(JNIEnv* env, jobject This)
+{
+ Time t;
+ if (!java2time(env, &t, This)) return env->NewStringUTF("");
+ bool allDay = env->GetIntField(This, g_allDayField);
+
+ if (!allDay) {
+ ACQUIRE_TIMEZONE(This, t)
+ bool inUtc = strcmp("UTC", t.timezone) == 0;
+ short buf[16];
+ t.format2445(buf, true);
+ RELEASE_TIMEZONE(This, t)
+ if (inUtc) {
+ // The letter 'Z' is appended to the end so allow for one
+ // more character in the buffer.
+ return env->NewString((jchar*)buf, 16);
+ } else {
+ return env->NewString((jchar*)buf, 15);
+ }
+ } else {
+ short buf[8];
+ t.format2445(buf, false);
+ return env->NewString((jchar*)buf, 8);
+ }
+}
+
+static jstring android_pim_Time_format(JNIEnv* env, jobject This,
+ jstring formatObject)
+{
+ Time t;
+ if (!java2time(env, &t, This)) return env->NewStringUTF("");
+ ACQUIRE_TIMEZONE(This, t)
+
+ const char* format = env->GetStringUTFChars(formatObject, NULL);
+
+ String8 r = t.format(format);
+
+ env->ReleaseStringUTFChars(formatObject, format);
+ RELEASE_TIMEZONE(This, t)
+
+ return env->NewStringUTF(r.string());
+}
+
+
+static jstring android_pim_Time_toString(JNIEnv* env, jobject This)
+{
+ Time t;
+ if (!java2time(env, &t, This)) return env->NewStringUTF("");;
+ ACQUIRE_TIMEZONE(This, t)
+
+ String8 r = t.toString();
+
+ RELEASE_TIMEZONE(This, t)
+
+ return env->NewStringUTF(r.string());
+}
+
+static void android_pim_Time_setToNow(JNIEnv* env, jobject This)
+{
+ env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+ Time t;
+ ACQUIRE_TIMEZONE(This, t)
+
+ t.setToNow();
+
+ time2java(env, This, t);
+ RELEASE_TIMEZONE(This, t)
+}
+
+static jlong android_pim_Time_toMillis(JNIEnv* env, jobject This,
+ jboolean ignoreDst)
+{
+ Time t;
+ if (!java2time(env, &t, This)) return 0L;
+ ACQUIRE_TIMEZONE(This, t)
+
+ int64_t result = t.toMillis(ignoreDst != 0);
+
+ RELEASE_TIMEZONE(This, t)
+
+ return result;
+}
+
+static void android_pim_Time_set(JNIEnv* env, jobject This, jlong millis)
+{
+ env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+ Time t;
+ if (!java2time(env, &t, This)) return;
+ ACQUIRE_TIMEZONE(This, t)
+
+ t.set(millis);
+
+ time2java(env, This, t);
+ RELEASE_TIMEZONE(This, t)
+}
+
+
+// ============================================================================
+// Just do this here because it's not worth recreating the strings
+
+static int get_char(JNIEnv* env, const jchar *s, int spos, int mul,
+ bool *thrown)
+{
+ jchar c = s[spos];
+ if (c >= '0' && c <= '9') {
+ return (c - '0') * mul;
+ } else {
+ char msg[100];
+ sprintf(msg, "Parse error at pos=%d", spos);
+ jniThrowException(env, "android/util/TimeFormatException", msg);
+ *thrown = true;
+ return 0;
+ }
+}
+
+static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
+{
+ jchar c = s[spos];
+ if (c != expected) {
+ char msg[100];
+ sprintf(msg, "Unexpected %c at pos=%d. Expected %c.", c, spos,
+ expected);
+ jniThrowException(env, "android/util/TimeFormatException", msg);
+ return false;
+ }
+ return true;
+}
+
+
+static void android_pim_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;
+
+ 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;
+ env->SetIntField(This, g_yearField, n);
+
+ n = get_char(env, s, 4, 10, &thrown);
+ n += get_char(env, s, 5, 1, &thrown);
+ n--;
+ if (thrown) return;
+ env->SetIntField(This, g_monField, n);
+
+ n = get_char(env, s, 6, 10, &thrown);
+ n += get_char(env, s, 7, 1, &thrown);
+ if (thrown) return;
+ env->SetIntField(This, g_mdayField, n);
+
+ if (len >= 15) {
+ env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+ n = get_char(env, s, 9, 10, &thrown);
+ n += get_char(env, s, 10, 1, &thrown);
+ if (thrown) return;
+ env->SetIntField(This, g_hourField, n);
+
+ n = get_char(env, s, 11, 10, &thrown);
+ n += get_char(env, s, 12, 1, &thrown);
+ if (thrown) return;
+ env->SetIntField(This, g_minField, n);
+
+ n = get_char(env, s, 13, 10, &thrown);
+ n += get_char(env, s, 14, 1, &thrown);
+ if (thrown) return;
+ env->SetIntField(This, g_secField, n);
+ } else {
+ 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);
+}
+
+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,
+ jobject This,
+ jstring strObj)
+{
+ jsize len = env->GetStringLength(strObj);
+ const jchar *s = env->GetStringChars(strObj, NULL);
+
+ bool thrown = false;
+ int n;
+ jboolean inUtc = 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);
+
+ // -
+ if (!check_char(env, s, 4, '-')) return false;
+
+ // month
+ n = get_char(env, s, 5, 10, &thrown);
+ n += get_char(env, s, 6, 1, &thrown);
+ --n;
+ if (thrown) return false;
+ env->SetIntField(This, g_monField, n);
+
+ // -
+ if (!check_char(env, s, 7, '-')) return false;
+
+ // day
+ n = get_char(env, s, 8, 10, &thrown);
+ n += get_char(env, s, 9, 1, &thrown);
+ if (thrown) return false;
+ env->SetIntField(This, g_mdayField, n);
+
+ if (len >= 17) {
+ // T
+ if (!check_char(env, s, 10, 'T')) return false;
+
+ env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+ // hour
+ n = get_char(env, s, 11, 10, &thrown);
+ n += get_char(env, s, 12, 1, &thrown);
+ if (thrown) return false;
+ int hour = n;
+ // env->SetIntField(This, g_hourField, n);
+
+ // :
+ if (!check_char(env, s, 13, ':')) return false;
+
+ // minute
+ n = get_char(env, s, 14, 10, &thrown);
+ n += get_char(env, s, 15, 1, &thrown);
+ if (thrown) return false;
+ int minute = n;
+ // env->SetIntField(This, g_minField, n);
+
+ // :
+ if (!check_char(env, s, 16, ':')) return false;
+
+ // second
+ n = get_char(env, s, 17, 10, &thrown);
+ n += get_char(env, s, 18, 1, &thrown);
+ if (thrown) return false;
+ env->SetIntField(This, g_secField, n);
+
+ // skip the '.XYZ' -- we don't care about subsecond precision.
+ int offset = 0;
+ if (len >= 23) {
+ char c = s[23];
+
+ // NOTE: the offset is meant to be subtracted to get from local time
+ // to UTC. we therefore use 1 for '-' and -1 for '+'.
+ switch (c) {
+ case 'Z':
+ // Zulu time -- UTC
+ offset = 0;
+ break;
+ case '-':
+ offset = 1;
+ break;
+ case '+':
+ offset = -1;
+ break;
+ default:
+ char msg[100];
+ sprintf(msg, "Unexpected %c at position 19. Expected + or -",
+ c);
+ jniThrowException(env, "android/util/TimeFormatException", msg);
+ return false;
+ }
+ inUtc = true;
+
+ if (offset != 0) {
+ // hour
+ n = get_char(env, s, 24, 10, &thrown);
+ n += get_char(env, s, 25, 1, &thrown);
+ if (thrown) return false;
+ n *= offset;
+ hour += n;
+
+ // :
+ if (!check_char(env, s, 26, ':')) return false;
+
+ // minute
+ n = get_char(env, s, 27, 10, &thrown);
+ n += get_char(env, s, 28, 1, &thrown);
+ if (thrown) return false;
+ n *= offset;
+ minute += n;
+ }
+ }
+ env->SetIntField(This, g_hourField, hour);
+ env->SetIntField(This, g_minField, minute);
+
+ if (offset != 0) {
+ // we need to normalize after applying the hour and minute offsets
+ android_pim_Time_normalize(env, This, false /* use isdst */);
+ // The timezone is set to UTC in the calling Java code.
+ }
+ } else {
+ 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;
+}
+
+// ============================================================================
+/*
+ * JNI registration.
+ */
+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 }
+};
+
+int register_android_pim_Time(JNIEnv* env)
+{
+ jclass timeClass = env->FindClass("android/pim/Time");
+
+ g_allDayField = env->GetFieldID(timeClass, "allDay", "Z");
+ g_secField = env->GetFieldID(timeClass, "second", "I");
+ g_minField = env->GetFieldID(timeClass, "minute", "I");
+ g_hourField = env->GetFieldID(timeClass, "hour", "I");
+ g_mdayField = env->GetFieldID(timeClass, "monthDay", "I");
+ g_monField = env->GetFieldID(timeClass, "month", "I");
+ g_yearField = env->GetFieldID(timeClass, "year", "I");
+ g_wdayField = env->GetFieldID(timeClass, "weekDay", "I");
+ g_ydayField = env->GetFieldID(timeClass, "yearDay", "I");
+ g_isdstField = env->GetFieldID(timeClass, "isDst", "I");
+ 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));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_security_Md5MessageDigest.cpp b/core/jni/android_security_Md5MessageDigest.cpp
new file mode 100644
index 0000000..3533559
--- /dev/null
+++ b/core/jni/android_security_Md5MessageDigest.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#include "jni.h"
+#include <JNIHelp.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <openssl/md5.h>
+
+namespace android
+{
+
+struct fields_t {
+ jfieldID context;
+};
+static fields_t fields;
+
+static void native_init(JNIEnv *env, jobject clazz)
+{
+ MD5_CTX* context = (MD5_CTX *)malloc(sizeof(MD5_CTX));
+ MD5_Init(context);
+
+ env->SetIntField(clazz, fields.context, (int)context);
+}
+
+static void native_reset(JNIEnv *env, jobject clazz)
+{
+ MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
+ if (context != NULL) {
+ free(context);
+ env->SetIntField(clazz, fields.context, 0 );
+ }
+}
+
+static void native_update(JNIEnv *env, jobject clazz, jbyteArray dataArray)
+{
+ jbyte * data;
+ jsize dataSize;
+ MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
+
+ if (context == NULL) {
+ native_init(env, clazz);
+ context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
+ }
+
+ data = env->GetByteArrayElements(dataArray, NULL);
+ if (data == NULL) {
+ LOGE("Unable to get byte array elements");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid data array when calling MessageDigest.update()");
+ return;
+ }
+ dataSize = env->GetArrayLength(dataArray);
+
+ MD5_Update(context, data, dataSize);
+
+ env->ReleaseByteArrayElements(dataArray, data, 0);
+}
+
+static jbyteArray native_digest(JNIEnv *env, jobject clazz)
+{
+ jbyteArray array;
+ jbyte md[MD5_DIGEST_LENGTH];
+ MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
+
+ MD5_Final((uint8_t*)md, context);
+
+ array = env->NewByteArray(MD5_DIGEST_LENGTH);
+ LOG_ASSERT(array, "Native could not create new byte[]");
+
+ env->SetByteArrayRegion(array, 0, MD5_DIGEST_LENGTH, md);
+
+ native_reset(env, clazz);
+
+ return array;
+}
+
+
+/*
+ * JNI registration.
+ */
+
+static JNINativeMethod gMethods[] =
+{
+ /* name, signature, funcPtr */
+ {"init", "()V", (void *)native_init},
+ {"update", "([B)V", (void *)native_update},
+ {"digest", "()[B", (void *)native_digest},
+ {"reset", "()V", (void *)native_reset},
+};
+
+int register_android_security_Md5MessageDigest(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/security/Md5MessageDigest");
+ if (clazz == NULL) {
+ LOGE("Can't find android/security/Md5MessageDigest");
+ return -1;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeMd5Context", "I");
+ if (fields.context == NULL) {
+ LOGE("Can't find Md5MessageDigest.mNativeMd5Context");
+ return -1;
+ }
+
+ return jniRegisterNativeMethods(env, "android/security/Md5MessageDigest",
+ gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp
new file mode 100644
index 0000000..3ff6af1
--- /dev/null
+++ b/core/jni/android_server_BluetoothDeviceService.cpp
@@ -0,0 +1,1144 @@
+/*
+** Copyright 2006, 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 DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Adapter"
+#define LOG_TAG "BluetoothDeviceService.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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#include <bluedroid/bluetooth.h>
+#endif
+
+#include <cutils/properties.h>
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+// We initialize these variables when we load class
+// android.server.BluetoothDeviceService
+static jfieldID field_mNativeData;
+
+typedef struct {
+ JNIEnv *env;
+ DBusConnection *conn;
+ const char *adapter; // dbus object name of the local adapter
+} native_data_t;
+
+void onCreateBondingResult(DBusMessage *msg, void *user);
+void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user);
+
+/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
+ * Perform quick sanity check, if there are any problems return NULL
+ */
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ native_data_t *nat =
+ (native_data_t *)(env->GetIntField(object, field_mNativeData));
+ if (nat == NULL || nat->conn == NULL) {
+ LOGE("Uninitialized native data\n");
+ return NULL;
+ }
+ return nat;
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+#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 initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return false;
+ }
+ nat->env = env;
+
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ 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;
+ }
+
+ nat->adapter = BLUEZ_ADAPTER_OBJECT_NAME;
+#endif /*HAVE_BLUETOOTH*/
+ return true;
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ if (nat) {
+ free(nat);
+ nat = NULL;
+ }
+#endif
+}
+
+static jstring getNameNative(JNIEnv *env, jobject object){
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetName",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_string(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ return (env->NewStringUTF(nat->adapter));
+ }
+#endif
+ return NULL;
+}
+
+
+static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jboolean ret = JNI_FALSE;
+
+ native_data_t *nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ dbus_error_init(&err);
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
+ DBUS_CLASS_NAME, "DiscoverDevices");
+
+ if (msg == NULL) {
+ LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__);
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ /* We treat the in-progress error code as success. */
+ if(strcmp(err.message, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
+ LOGW("%s: D-Bus error: %s, treating as startDiscoveryNative success\n",
+ __FUNCTION__, err.message);
+ ret = JNI_TRUE;
+ goto done;
+ } else {
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ ret = JNI_FALSE;
+ goto done;
+ }
+ }
+
+ ret = JNI_TRUE;
+done:
+ if (reply) dbus_message_unref(reply);
+ if (msg) dbus_message_unref(msg);
+ return ret;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static void cancelDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jstring ret;
+ native_data_t *nat;
+
+ dbus_error_init(&err);
+
+ nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
+ DBUS_CLASS_NAME, "CancelDiscovery");
+
+ if (msg == NULL) {
+ LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__);
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized") == 0) {
+ // hcid sends this if there is no active discovery to cancel
+ LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
+ dbus_error_free(&err);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ }
+ }
+
+done:
+ if (msg) dbus_message_unref(msg);
+ if (reply) dbus_message_unref(reply);
+#endif
+}
+
+static jboolean startPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ jboolean ret = JNI_FALSE;
+
+ native_data_t *nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ dbus_error_init(&err);
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
+ DBUS_CLASS_NAME, "StartPeriodicDiscovery");
+ if (msg == NULL) {
+ LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__);
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ /* We treat the in-progress error code as success. */
+ if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
+ LOGW("%s: D-Bus error: %s (%s), treating as "
+ "startPeriodicDiscoveryNative success\n",
+ __FUNCTION__, err.name, err.message);
+ } else {
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ ret = JNI_FALSE;
+ goto done;
+ }
+ }
+
+ ret = JNI_TRUE;
+done:
+ if (reply) dbus_message_unref(reply);
+ if (msg) dbus_message_unref(msg);
+ return ret;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean stopPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jboolean ret = JNI_FALSE;
+
+ native_data_t *nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ dbus_error_init(&err);
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
+ DBUS_CLASS_NAME, "StopPeriodicDiscovery");
+ if (msg == NULL) {
+ LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__);
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ /* We treat the in-progress error code as success. */
+ if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
+ LOGW("%s: D-Bus error: %s (%s), treating as "
+ "stopPeriodicDiscoveryNative success\n",
+ __FUNCTION__, err.name, err.message);
+ } else {
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ ret = JNI_FALSE;
+ goto done;
+ }
+ }
+
+ ret = JNI_TRUE;
+done:
+ if (reply) dbus_message_unref(reply);
+ if (msg) dbus_message_unref(msg);
+ return ret;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean isPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "IsPeriodicDiscovery",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean setDiscoverableTimeoutNative(JNIEnv *env, jobject object, jint timeout_s) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ if (timeout_s < 0) {
+ return JNI_FALSE;
+ }
+
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "SetDiscoverableTimeout",
+ DBUS_TYPE_UINT32, &timeout_s,
+ DBUS_TYPE_INVALID);
+ if (reply != NULL) {
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jint getDiscoverableTimeoutNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetDiscoverableTimeout",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_uint32(env, reply) : -1;
+ }
+#endif
+ return -1;
+}
+
+static jboolean isConnectedNative(JNIEnv *env, jobject object, jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "IsConnected",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static void disconnectRemoteDeviceNative(JNIEnv *env, jobject object, jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ // Set a timeout of 5 seconds. Specifying the default timeout is
+ // not long enough, as a remote-device disconnect results in
+ // signal RemoteDisconnectRequested being sent, followed by a
+ // delay of 2 seconds, after which the actual disconnect takes
+ // place.
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, 60000, nat->adapter,
+ DBUS_CLASS_NAME, "DisconnectRemoteDevice",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ if (reply) dbus_message_unref(reply);
+ }
+#endif
+}
+
+static jboolean isConnectableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "IsConnectable",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean isDiscoverableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "IsDiscoverable",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jstring getModeNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetMode",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_string(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jboolean setModeNative(JNIEnv *env, jobject object, jstring mode) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_mode = env->GetStringUTFChars(mode, NULL);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "SetMode",
+ DBUS_TYPE_STRING, &c_mode,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(mode, c_mode);
+ if (reply) {
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static void common_Bonding(JNIEnv *env, jobject object, int timeout_ms,
+ const char *func, jstring address) {
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, timeout_ms, nat->adapter,
+ DBUS_CLASS_NAME, func,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ if (reply) {
+ dbus_message_unref(reply);
+ }
+ }
+#endif
+}
+
+static jboolean createBondingNative(JNIEnv *env, jobject object,
+ jstring address, jint timeout_ms) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+ strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
+ bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
+ onCreateBondingResult, // callback
+ context_address, // user data
+ nat->adapter,
+ DBUS_CLASS_NAME, "CreateBonding",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return ret ? JNI_TRUE : JNI_FALSE;
+
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static void cancelBondingProcessNative(JNIEnv *env, jobject object,
+ jstring address) {
+ LOGV(__FUNCTION__);
+ common_Bonding(env, object, -1, "CancelBondingProcess", address);
+}
+
+static void removeBondingNative(JNIEnv *env, jobject object, jstring address) {
+ LOGV(__FUNCTION__);
+ common_Bonding(env, object, -1, "RemoveBonding", address);
+}
+
+static jboolean hasBondingNative(JNIEnv *env, jobject object, jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "HasBonding",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jobjectArray listBondingsNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "ListBondings",
+ DBUS_TYPE_INVALID);
+ // return String[]
+ return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jobjectArray listConnectionsNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "ListConnections",
+ DBUS_TYPE_INVALID);
+ // return String[]
+ return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jobjectArray listRemoteDevicesNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "ListRemoteDevices",
+ DBUS_TYPE_INVALID);
+ return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jstring common_Get(JNIEnv *env, jobject object, const char *func) {
+ LOGV("%s:%s", __FUNCTION__, func);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusError err;
+ dbus_error_init(&err);
+ DBusMessage *reply =
+ dbus_func_args_error(env, nat->conn, &err, nat->adapter,
+ DBUS_CLASS_NAME, func,
+ DBUS_TYPE_INVALID);
+ if (reply) {
+ return dbus_returns_string(env, reply);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return NULL;
+ }
+ }
+#endif
+ return NULL;
+}
+
+static jstring getAddressNative(JNIEnv *env, jobject obj) {
+ return common_Get(env, obj, "GetAddress");
+}
+
+static jstring getVersionNative(JNIEnv *env, jobject obj) {
+ return common_Get(env, obj, "GetVersion");
+}
+
+static jstring getRevisionNative(JNIEnv *env, jobject obj) {
+ return common_Get(env, obj, "GetRevision");
+}
+
+static jstring getManufacturerNative(JNIEnv *env, jobject obj) {
+ return common_Get(env, obj, "GetManufacturer");
+}
+
+static jstring getCompanyNative(JNIEnv *env, jobject obj) {
+ return common_Get(env, obj, "GetCompany");
+}
+
+static jboolean setNameNative(JNIEnv *env, jobject obj, jstring name) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat) {
+ const char *c_name = env->GetStringUTFChars(name, NULL);
+ DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "SetName",
+ DBUS_TYPE_STRING, &c_name,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(name, c_name);
+ if (reply) {
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jstring getMajorClassNative(JNIEnv *env, jobject obj) {
+ return common_Get(env, obj, "GetMajorClass");
+}
+
+static jstring getMinorClassNative(JNIEnv *env, jobject obj) {
+ return common_Get(env, obj, "GetMinorClass");
+}
+
+static jstring common_getRemote(JNIEnv *env, jobject object, const char *func,
+ jstring address) {
+ LOGV("%s:%s", __FUNCTION__, func);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ DBusError err;
+ dbus_error_init(&err);
+
+ LOGV("... address = %s", c_address);
+
+ DBusMessage *reply =
+ dbus_func_args_error(env, nat->conn, &err, nat->adapter,
+ DBUS_CLASS_NAME, func,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ if (reply) {
+ return dbus_returns_string(env, reply);
+ } else if (!strcmp(func, "GetRemoteName") &&
+ dbus_error_has_name(&err, "org.bluez.Error.RequestDeferred")) {
+ // This error occurs if we request name during device discovery,
+ // its fine
+ LOGV("... %s: %s", func, err.message);
+ dbus_error_free(&err);
+ return NULL;
+ } else {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return NULL;
+ }
+ }
+#endif
+ return NULL;
+}
+
+static jstring getRemoteAliasNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteAlias", address);
+}
+
+static jboolean setRemoteAliasNative(JNIEnv *env, jobject obj,
+ jstring address, jstring alias) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ const char *c_alias = env->GetStringUTFChars(alias, NULL);
+
+ LOGV("... address = %s alias = %s", c_address, c_alias);
+
+ DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "SetRemoteAlias",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_STRING, &c_alias,
+ DBUS_TYPE_INVALID);
+
+ env->ReleaseStringUTFChars(address, c_address);
+ env->ReleaseStringUTFChars(alias, c_alias);
+ if (reply)
+ {
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean clearRemoteAliasNative(JNIEnv *env, jobject obj, jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, obj);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+
+ LOGV("... address = %s", c_address);
+
+ DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "ClearRemoteAlias",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+
+ env->ReleaseStringUTFChars(address, c_address);
+ if (reply)
+ {
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jstring getRemoteVersionNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteVersion", address);
+}
+
+static jstring getRemoteRevisionNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteRevision", address);
+}
+
+static jstring getRemoteManufacturerNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteManufacturer", address);
+}
+
+static jstring getRemoteCompanyNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteCompany", address);
+}
+
+static jstring getRemoteMajorClassNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteMajorClass", address);
+}
+
+static jstring getRemoteMinorClassNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteMinorClass", address);
+}
+
+static jstring getRemoteNameNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "GetRemoteName", address);
+}
+
+static jstring lastSeenNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "LastSeen", address);
+}
+
+static jstring lastUsedNative(JNIEnv *env, jobject obj, jstring address) {
+ return common_getRemote(env, obj, "LastUsed", address);
+}
+
+static jobjectArray getRemoteServiceClassesNative(JNIEnv *env, jobject object,
+ jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+
+ LOGV("... address = %s", c_address);
+
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetRemoteServiceClasses",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jint getRemoteClassNative(JNIEnv *env, jobject object, jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ jint ret = 0;
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+
+ LOGV("... address = %s", c_address);
+
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetRemoteClass",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ if (reply)
+ {
+ DBusError err;
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(reply, &err,
+ DBUS_TYPE_UINT32, &ret,
+ DBUS_TYPE_INVALID)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+ dbus_message_unref(reply);
+ }
+
+ return ret;
+ }
+#endif
+ return 0;
+}
+
+static jbyteArray getRemoteFeaturesNative(JNIEnv *env, jobject object,
+ jstring address) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+
+ LOGV("... address = %s", c_address);
+
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetRemoteFeatures",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ /* array of DBUS_TYPE_BYTE_AS_STRING */
+ return reply ? dbus_returns_array_of_bytes(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jintArray getRemoteServiceHandlesNative(JNIEnv *env, jobject object,
+ jstring address, jstring match) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ jintArray intArray = NULL;
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ const char *c_match = env->GetStringUTFChars(match, NULL);
+
+ LOGV("... address = %s match = %s", c_address, c_match);
+
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetRemoteServiceHandles",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_STRING, &c_match,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ env->ReleaseStringUTFChars(match, c_match);
+ if (reply)
+ {
+ DBusError err;
+ jint *list;
+ int i, len;
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args (reply, &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ &list, &len,
+ DBUS_TYPE_INVALID)) {
+ if (len) {
+ intArray = env->NewIntArray(len);
+ if (intArray)
+ env->SetIntArrayRegion(intArray, 0, len, list);
+ }
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+
+ dbus_message_unref(reply);
+ }
+ return intArray;
+ }
+#endif
+ return NULL;
+}
+
+static jbyteArray getRemoteServiceRecordNative(JNIEnv *env, jobject object,
+ jstring address, jint handle) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+
+ LOGV("... address = %s", c_address);
+
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, nat->adapter,
+ DBUS_CLASS_NAME, "GetRemoteServiceRecord",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return reply ? dbus_returns_array_of_bytes(env, reply) : NULL;
+ }
+#endif
+ return NULL;
+}
+
+static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object,
+ jstring address, jshort uuid16) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+ strlcpy(context_address, c_address, BTADDR_SIZE);
+
+ LOGV("... address = %s", c_address);
+ LOGV("... uuid16 = %#X", uuid16);
+
+ bool ret = dbus_func_args_async(env, nat->conn, 20000, // ms
+ onGetRemoteServiceChannelResult, context_address,
+ nat->adapter,
+ DBUS_CLASS_NAME, "GetRemoteServiceChannel",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_UINT16, &uuid16,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jint enableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ return bt_enable();
+#endif
+ return -1;
+}
+
+static jint disableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ return bt_disable();
+#endif
+ return -1;
+}
+
+static jint isEnabledNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ return bt_is_enabled();
+#endif
+ return -1;
+}
+
+static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
+ jstring pin, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return PIN code to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ const char *c_pin = env->GetStringUTFChars(pin, NULL);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ env->ReleaseStringUTFChars(pin, c_pin);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean cancelPinNative(JNIEnv *env, jobject object, jstring address,
+ int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_error(msg,
+ "org.bluez.Error.Canceled", "PIN Entry was canceled");
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return PIN cancel to "
+ "D-BUS\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+ {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
+
+ {"isEnabledNative", "()I", (void *)isEnabledNative},
+ {"enableNative", "()I", (void *)enableNative},
+ {"disableNative", "()I", (void *)disableNative},
+
+ {"getAddressNative", "()Ljava/lang/String;", (void *)getAddressNative},
+ {"getNameNative", "()Ljava/lang/String;", (void*)getNameNative},
+ {"setNameNative", "(Ljava/lang/String;)Z", (void *)setNameNative},
+ {"getMajorClassNative", "()Ljava/lang/String;", (void *)getMajorClassNative},
+ {"getMinorClassNative", "()Ljava/lang/String;", (void *)getMinorClassNative},
+ {"getVersionNative", "()Ljava/lang/String;", (void *)getVersionNative},
+ {"getRevisionNative", "()Ljava/lang/String;", (void *)getRevisionNative},
+ {"getManufacturerNative", "()Ljava/lang/String;", (void *)getManufacturerNative},
+ {"getCompanyNative", "()Ljava/lang/String;", (void *)getCompanyNative},
+
+ {"getModeNative", "()Ljava/lang/String;", (void *)getModeNative},
+ {"setModeNative", "(Ljava/lang/String;)Z", (void *)setModeNative},
+
+ {"getDiscoverableTimeoutNative", "()I", (void *)getDiscoverableTimeoutNative},
+ {"setDiscoverableTimeoutNative", "(I)Z", (void *)setDiscoverableTimeoutNative},
+
+ {"startDiscoveryNative", "(Z)Z", (void*)startDiscoveryNative},
+ {"cancelDiscoveryNative", "()Z", (void *)cancelDiscoveryNative},
+ {"startPeriodicDiscoveryNative", "()Z", (void *)startPeriodicDiscoveryNative},
+ {"stopPeriodicDiscoveryNative", "()Z", (void *)stopPeriodicDiscoveryNative},
+ {"isPeriodicDiscoveryNative", "()Z", (void *)isPeriodicDiscoveryNative},
+ {"listRemoteDevicesNative", "()[Ljava/lang/String;", (void *)listRemoteDevicesNative},
+
+ {"listConnectionsNative", "()[Ljava/lang/String;", (void *)listConnectionsNative},
+ {"isConnectedNative", "(Ljava/lang/String;)Z", (void *)isConnectedNative},
+ {"disconnectRemoteDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectRemoteDeviceNative},
+
+ {"createBondingNative", "(Ljava/lang/String;I)Z", (void *)createBondingNative},
+ {"cancelBondingProcessNative", "(Ljava/lang/String;)Z", (void *)cancelBondingProcessNative},
+ {"listBondingsNative", "()[Ljava/lang/String;", (void *)listBondingsNative},
+ {"hasBondingNative", "(Ljava/lang/String;)Z", (void *)hasBondingNative},
+ {"removeBondingNative", "(Ljava/lang/String;)Z", (void *)removeBondingNative},
+
+ {"getRemoteNameNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteNameNative},
+ {"getRemoteAliasNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteAliasNative},
+ {"setRemoteAliasNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)setRemoteAliasNative},
+ {"clearRemoteAliasNative", "(Ljava/lang/String;)Z", (void *)clearRemoteAliasNative},
+ {"getRemoteVersionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteVersionNative},
+ {"getRemoteRevisionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteRevisionNative},
+ {"getRemoteClassNative", "(Ljava/lang/String;)I", (void *)getRemoteClassNative},
+ {"getRemoteManufacturerNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteManufacturerNative},
+ {"getRemoteCompanyNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteCompanyNative},
+ {"getRemoteMajorClassNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteMajorClassNative},
+ {"getRemoteMinorClassNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteMinorClassNative},
+ {"getRemoteServiceClassesNative", "(Ljava/lang/String;)[Ljava/lang/String;", (void *)getRemoteServiceClassesNative},
+ {"getRemoteServiceChannelNative", "(Ljava/lang/String;S)Z", (void *)getRemoteServiceChannelNative},
+ {"getRemoteFeaturesNative", "(Ljava/lang/String;)[B", (void *)getRemoteFeaturesNative},
+ {"lastSeenNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastSeenNative},
+ {"lastUsedNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastUsedNative},
+ {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
+ {"cancelPinNative", "(Ljava/lang/String;I)Z", (void *)cancelPinNative},
+};
+
+int register_android_server_BluetoothDeviceService(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
new file mode 100644
index 0000000..395a45c
--- /dev/null
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -0,0 +1,642 @@
+/*
+** 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 "BluetoothEventLoop.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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jfieldID field_mNativeData;
+
+static jmethodID method_onModeChanged;
+static jmethodID method_onDiscoveryStarted;
+static jmethodID method_onDiscoveryCompleted;
+static jmethodID method_onRemoteDeviceFound;
+static jmethodID method_onRemoteDeviceDisappeared;
+static jmethodID method_onRemoteClassUpdated;
+static jmethodID method_onRemoteNameUpdated;
+static jmethodID method_onRemoteNameFailed;
+static jmethodID method_onRemoteAliasChanged;
+static jmethodID method_onRemoteAliasCleared;
+static jmethodID method_onRemoteDeviceConnected;
+static jmethodID method_onRemoteDeviceDisconnectRequested;
+static jmethodID method_onRemoteDeviceDisconnected;
+static jmethodID method_onBondingCreated;
+static jmethodID method_onBondingRemoved;
+
+static jmethodID method_onCreateBondingResult;
+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;
+};
+
+// Only valid during waitForAndDispatchEventNative()
+static 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,
+ field_mNativeData));
+}
+
+#endif
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+
+#ifdef HAVE_BLUETOOTH
+ method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(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");
+ method_onRemoteDeviceDisappeared = env->GetMethodID(clazz, "onRemoteDeviceDisappeared", "(Ljava/lang/String;)V");
+ method_onRemoteClassUpdated = env->GetMethodID(clazz, "onRemoteClassUpdated", "(Ljava/lang/String;I)V");
+ method_onRemoteNameUpdated = env->GetMethodID(clazz, "onRemoteNameUpdated", "(Ljava/lang/String;Ljava/lang/String;)V");
+ method_onRemoteNameFailed = env->GetMethodID(clazz, "onRemoteNameFailed", "(Ljava/lang/String;)V");
+ method_onRemoteAliasChanged = env->GetMethodID(clazz, "onRemoteAliasChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
+ method_onRemoteDeviceConnected = env->GetMethodID(clazz, "onRemoteDeviceConnected", "(Ljava/lang/String;)V");
+ method_onRemoteDeviceDisconnectRequested = env->GetMethodID(clazz, "onRemoteDeviceDisconnectRequested", "(Ljava/lang/String;)V");
+ method_onRemoteDeviceDisconnected = env->GetMethodID(clazz, "onRemoteDeviceDisconnected", "(Ljava/lang/String;)V");
+ method_onBondingCreated = env->GetMethodID(clazz, "onBondingCreated", "(Ljava/lang/String;)V");
+ method_onBondingRemoved = env->GetMethodID(clazz, "onBondingRemoved", "(Ljava/lang/String;)V");
+
+ method_onCreateBondingResult = env->GetMethodID(clazz, "onCreateBondingResult", "(Ljava/lang/String;Z)V");
+
+ method_onPasskeyAgentRequest = env->GetMethodID(clazz, "onPasskeyAgentRequest", "(Ljava/lang/String;I)V");
+ method_onPasskeyAgentCancel = env->GetMethodID(clazz, "onPasskeyAgentCancel", "(Ljava/lang/String;)V");
+ method_onGetRemoteServiceChannelResult = env->GetMethodID(clazz, "onGetRemoteServiceChannelResult", "(Ljava/lang/String;I)V");
+
+ field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return;
+ }
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+
+ {
+ 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("%s: Could not get onto the system bus!", __FUNCTION__);
+ dbus_error_free(&err);
+ }
+ }
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ if (nat) {
+ free(nat);
+ }
+#endif
+}
+
+#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,
+ DBusMessage *msg,
+ void *data);
+
+static const DBusObjectPathVTable passkey_agent_vtable = {
+ NULL, passkey_agent_event_filter, NULL, NULL, NULL, NULL
+};
+#endif
+
+static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ dbus_threads_init_default();
+ native_data_t *nat = get_native_data(env, object);
+ if (nat != NULL && nat->conn != NULL) {
+ if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
+ return JNI_FALSE;
+ }
+
+ if (add_adapter_event_match(env, nat) != JNI_TRUE) {
+ return JNI_FALSE;
+ }
+
+ const char *path = "/android/bluetooth/PasskeyAgent";
+ if (!dbus_connection_register_object_path(nat->conn, path,
+ &passkey_agent_vtable, NULL)) {
+ LOGE("%s: Can't register object path %s for agent!",
+ __FUNCTION__, path);
+ return JNI_FALSE;
+ }
+
+ DBusError err;
+ dbus_error_init(&err);
+
+ // RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep
+ // trying for 10 seconds.
+ int attempt;
+ for (attempt = 1000; attempt > 0; attempt--) {
+ DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err,
+ BLUEZ_DBUS_BASE_PATH,
+ "org.bluez.Security", "RegisterDefaultPasskeyAgent",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ if (reply) {
+ // Success
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ } else if (dbus_error_has_name(&err,
+ "org.freedesktop.DBus.Error.ServiceUnknown")) {
+ // hcid is still down, retry
+ dbus_error_free(&err);
+ usleep(10000); // 10 ms
+ } else {
+ // Some other error we weren't expecting
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+ }
+ LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), "
+ "is hcid running?");
+ return JNI_FALSE;
+ }
+
+#endif
+ return JNI_FALSE;
+}
+
+static void tearDownEventLoopNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat != NULL && nat->conn != NULL) {
+
+ const char *path = "/android/bluetooth/PasskeyAgent";
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH,
+ "org.bluez.Security", "UnregisterDefaultPasskeyAgent",
+ DBUS_TYPE_STRING, &path,
+ 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);
+ }
+#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);
+ }
+}
+
+// Called by dbus during WaitForAndDispatchEventNative()
+static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
+ void *data) {
+ native_data_t *nat;
+ JNIEnv *env;
+ DBusError err;
+
+ dbus_error_init(&err);
+
+ nat = (native_data_t *)data;
+ env = nat->env;
+ if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+ LOGV("%s: not interested (not a signal).", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("%s: Received signal %s:%s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg));
+
+ if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteDeviceFound")) {
+ char *c_address;
+ int n_class;
+ short n_rssi;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_UINT32, &n_class,
+ DBUS_TYPE_INT16, &n_rssi,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s class = %#X rssi = %hd", c_address, n_class,
+ n_rssi);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceFound,
+ env->NewStringUTF(c_address),
+ (jint)n_class,
+ (jshort)n_rssi);
+ } 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",
+ "DiscoveryStarted")) {
+ LOGI("DiscoveryStarted signal received");
+ env->CallVoidMethod(nat->me, method_onDiscoveryStarted);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "DiscoveryCompleted")) {
+ LOGI("DiscoveryCompleted signal received");
+ env->CallVoidMethod(nat->me, method_onDiscoveryCompleted);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteDeviceDisappeared")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me, method_onRemoteDeviceDisappeared,
+ env->NewStringUTF(c_address));
+ } 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",
+ "RemoteClassUpdated")) {
+ char *c_address;
+ int n_class;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_UINT32, &n_class,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me, method_onRemoteClassUpdated,
+ env->NewStringUTF(c_address), (jint)n_class);
+ } 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",
+ "RemoteNameUpdated")) {
+ char *c_address;
+ char *c_name;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_STRING, &c_name,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s, name = %s", c_address, c_name);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteNameUpdated,
+ env->NewStringUTF(c_address),
+ env->NewStringUTF(c_name));
+ } 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",
+ "RemoteNameFailed")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteNameFailed,
+ env->NewStringUTF(c_address));
+ } 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",
+ "RemoteAliasChanged")) {
+ char *c_address, *c_alias;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_STRING, &c_alias,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s, alias = %s", c_address, c_alias);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteAliasChanged,
+ env->NewStringUTF(c_address),
+ env->NewStringUTF(c_alias));
+ } 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",
+ "RemoteAliasCleared")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteAliasCleared,
+ env->NewStringUTF(c_address));
+ } 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",
+ "RemoteDeviceConnected")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceConnected,
+ env->NewStringUTF(c_address));
+ } 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",
+ "RemoteDeviceDisconnectRequested")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceDisconnectRequested,
+ env->NewStringUTF(c_address));
+ } 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",
+ "RemoteDeviceDisconnected")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceDisconnected,
+ env->NewStringUTF(c_address));
+ } 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",
+ "BondingCreated")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onBondingCreated,
+ env->NewStringUTF(c_address));
+ } 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",
+ "BondingRemoved")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onBondingRemoved,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ LOGV("... ignored");
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+// Called by dbus during WaitForAndDispatchEventNative()
+static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data) {
+ native_data_t *nat = event_loop_nat;
+ JNIEnv *env;
+
+
+ env = nat->env;
+ if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
+ LOGV("%s: not interested (not a method call).", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ LOGV("%s: Received method %s:%s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg));
+
+ if (dbus_message_is_method_call(msg,
+ "org.bluez.PasskeyAgent", "Request")) {
+
+ const char *adapter;
+ const char *address;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for Request() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("... address = %s", address);
+
+ dbus_message_ref(msg); // increment refcount because we pass to java
+
+ env->CallVoidMethod(nat->me, method_onPasskeyAgentRequest,
+ env->NewStringUTF(address), (int)msg);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.PasskeyAgent", "Cancel")) {
+
+ const char *adapter;
+ const char *address;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("... address = %s", address);
+
+ env->CallVoidMethod(nat->me, method_onPasskeyAgentCancel,
+ env->NewStringUTF(address));
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.PasskeyAgent", "Release")) {
+ LOGE("We are no longer the passkey agent!");
+ } else {
+ LOGV("... ignored");
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+#endif
+
+static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object,
+ jint timeout_ms) {
+#ifdef HAVE_BLUETOOTH
+ //LOGV("%s: %8d (pid %d tid %d)",__FUNCTION__, time(NULL), getpid(), gettid()); // too chatty
+ native_data_t *nat = get_native_data(env, object);
+ if (nat != NULL && nat->conn != NULL) {
+ jboolean ret;
+ 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;
+ event_loop_nat = NULL;
+ nat->me = NULL;
+ nat->env = NULL;
+ return ret;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+#ifdef HAVE_BLUETOOTH
+void onCreateBondingResult(DBusMessage *msg, void *user) {
+ LOGV(__FUNCTION__);
+
+ const char *address = (const char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env = event_loop_nat->env;
+
+ LOGV("... address = %s", address);
+
+ jboolean result = JNI_TRUE;
+ 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);
+ result = JNI_FALSE;
+ dbus_error_free(&err);
+ }
+
+ env->CallVoidMethod(event_loop_nat->me,
+ method_onCreateBondingResult,
+ env->NewStringUTF(address),
+ result);
+ free(user);
+}
+
+void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) {
+ LOGV(__FUNCTION__);
+
+ const char *address = (const char *) user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env = event_loop_nat->env;
+ jint channel = -2;
+
+ LOGV("... address = %s", context->address);
+
+ if (dbus_set_error_from_message(&err, msg) ||
+ !dbus_message_get_args(msg, &err,
+ DBUS_TYPE_INT32, &channel,
+ DBUS_TYPE_INVALID)) {
+ /* 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);
+ }
+
+done:
+ env->CallVoidMethod(event_loop_nat->me,
+ method_onGetRemoteServiceChannelResult,
+ env->NewStringUTF(address),
+ channel);
+ free(user);
+}
+#endif
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void *)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+ {"setUpEventLoopNative", "()Z", (void *)setUpEventLoopNative},
+ {"tearDownEventLoopNative", "()V", (void *)tearDownEventLoopNative},
+ {"waitForAndDispatchEventNative", "(I)Z", (void *)waitForAndDispatchEventNative}
+};
+
+int register_android_server_BluetoothEventLoop(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
new file mode 100644
index 0000000..97daed3
--- /dev/null
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -0,0 +1,128 @@
+/* //device/libs/android_runtime/android_text_AndroidCharacter.cpp
+**
+** Copyright 2006, 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 "AndroidUnicode"
+
+#include <jni.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "utils/misc.h"
+#include "utils/AndroidUnicode.h"
+#include "utils/Log.h"
+
+namespace android {
+
+static void jniThrowException(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass excClazz = env->FindClass(exc);
+ LOG_ASSERT(excClazz, "Unable to find class %s", exc);
+
+ env->ThrowNew(excClazz, msg);
+}
+
+static void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, jbyteArray destArray, int count)
+{
+ jchar* src = env->GetCharArrayElements(srcArray, NULL);
+ jbyte* dest = env->GetByteArrayElements(destArray, NULL);
+ if (src == NULL || dest == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ goto DIRECTION_END;
+ }
+
+ if (env->GetArrayLength(srcArray) < count || env->GetArrayLength(destArray) < count) {
+ jniThrowException(env, "java/lang/ArrayIndexException", NULL);
+ goto DIRECTION_END;
+ }
+
+ for (int i = 0; i < count; i++) {
+ if (src[i] >= 0xD800 && src[i] <= 0xDBFF &&
+ i + 1 < count &&
+ src[i + 1] >= 0xDC00 && src[i + 1] <= 0xDFFF) {
+ int c = 0x00010000 + ((src[i] - 0xD800) << 10) +
+ (src[i + 1] & 0x3FF);
+ int dir = android::Unicode::getDirectionality(c);
+
+ dest[i++] = dir;
+ dest[i] = dir;
+ } else {
+ int c = src[i];
+ int dir = android::Unicode::getDirectionality(c);
+
+ dest[i] = dir;
+ }
+ }
+
+DIRECTION_END:
+ env->ReleaseCharArrayElements(srcArray, src, JNI_ABORT);
+ env->ReleaseByteArrayElements(destArray, dest, JNI_ABORT);
+}
+
+static jboolean mirror(JNIEnv* env, jobject obj, jcharArray charArray, int start, int count)
+{
+ jchar* data = env->GetCharArrayElements(charArray, NULL);
+ bool ret = false;
+
+ if (data == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ goto MIRROR_END;
+ }
+
+ if (start > start + count || env->GetArrayLength(charArray) < count) {
+ jniThrowException(env, "java/lang/ArrayIndexException", NULL);
+ goto MIRROR_END;
+ }
+
+ for (int i = start; i < start + count; i++) {
+ // XXX this thinks it knows that surrogates are never mirrored
+
+ int c1 = data[i];
+ int c2 = android::Unicode::toMirror(c1);
+
+ if (c1 != c2) {
+ data[i] = c2;
+ ret = true;
+ }
+ }
+
+MIRROR_END:
+ env->ReleaseCharArrayElements(charArray, data, JNI_ABORT);
+ return ret;
+}
+
+static jchar getMirror(JNIEnv* env, jobject obj, jchar c)
+{
+ return android::Unicode::toMirror(c);
+}
+
+static JNINativeMethod gMethods[] = {
+ { "getDirectionalities", "([C[BI)V",
+ (void*) getDirectionalities },
+ { "mirror", "([CII)Z",
+ (void*) mirror },
+ { "getMirror", "(C)C",
+ (void*) getMirror }
+};
+
+int register_android_text_AndroidCharacter(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/text/AndroidCharacter");
+ LOG_ASSERT(clazz, "Cannot find android/text/AndroidCharacter");
+
+ return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidCharacter",
+ gMethods, NELEM(gMethods));
+}
+
+}
diff --git a/core/jni/android_text_KeyCharacterMap.cpp b/core/jni/android_text_KeyCharacterMap.cpp
new file mode 100644
index 0000000..2a23a71
--- /dev/null
+++ b/core/jni/android_text_KeyCharacterMap.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2006, 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.
+*/
+
+#include <ui/KeyCharacterMap.h>
+
+#include <nativehelper/jni.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+
+static jint
+ctor(JNIEnv *env, jobject clazz, jint id)
+{
+ return reinterpret_cast<int>(KeyCharacterMap::load(id));
+}
+
+static void
+dtor(JNIEnv *env, jobject clazz, jint ptr)
+{
+ delete reinterpret_cast<KeyCharacterMap*>(ptr);
+}
+
+static jchar
+get(JNIEnv *env, jobject clazz, jint ptr, jint keycode, jint meta)
+{
+ return reinterpret_cast<KeyCharacterMap*>(ptr)->get(keycode, meta);
+}
+
+static jchar
+getNumber(JNIEnv *env, jobject clazz, jint ptr, jint keycode)
+{
+ return reinterpret_cast<KeyCharacterMap*>(ptr)->getNumber(keycode);
+}
+
+static jchar
+getMatch(JNIEnv *env, jobject clazz, jint ptr, jint keycode, jcharArray chars, jint modifiers)
+{
+ jchar rv;
+ jchar* ch = env->GetCharArrayElements(chars, NULL);
+ jsize chsize = env->GetArrayLength(chars);
+
+ rv = reinterpret_cast<KeyCharacterMap*>(ptr)->getMatch(keycode, ch, chsize, modifiers);
+
+ env->ReleaseCharArrayElements(chars, ch, JNI_ABORT);
+ return rv;
+}
+
+static jchar
+getDisplayLabel(JNIEnv *env, jobject clazz, jint ptr, jint keycode)
+{
+ return reinterpret_cast<KeyCharacterMap*>(ptr)->getDisplayLabel(keycode);
+}
+
+static jfieldID gKeyDataMetaField;
+static jfieldID gKeyDataNumberField;
+static jfieldID gKeyDataDisplayLabelField;
+
+static jboolean
+getKeyData(JNIEnv *env, jobject clazz, jint ptr, jint keycode, jobject keydata)
+{
+ jboolean rv;
+
+ unsigned short displayLabel = env->GetCharField(keydata, gKeyDataDisplayLabelField);
+ unsigned short number = env->GetCharField(keydata, gKeyDataNumberField);
+
+ jcharArray chars = (jcharArray) env->GetObjectField(keydata, gKeyDataMetaField);
+ jchar* ch = env->GetCharArrayElements(chars, NULL);
+
+ KeyCharacterMap* kmap = reinterpret_cast<KeyCharacterMap*>(ptr);
+ rv = kmap->getKeyData(keycode, &displayLabel, &number, ch);
+
+ env->SetCharField(keydata, gKeyDataDisplayLabelField, displayLabel);
+ env->SetCharField(keydata, gKeyDataNumberField, number);
+
+ env->ReleaseCharArrayElements(chars, ch, 0);
+ return rv;
+}
+
+static jint
+getKeyboardType(JNIEnv *env, jobject clazz, jint ptr)
+{
+ return reinterpret_cast<KeyCharacterMap*>(ptr)->getKeyboardType();
+}
+
+static jlongArray
+getEvents(JNIEnv *env, jobject clazz, jint ptr, jcharArray jchars)
+{
+ KeyCharacterMap* kmap = reinterpret_cast<KeyCharacterMap*>(ptr);
+
+ uint16_t* chars = env->GetCharArrayElements(jchars, NULL);
+ size_t len = env->GetArrayLength(jchars);
+
+ Vector<int32_t> keys;
+ Vector<uint32_t> modifiers;
+ bool success = kmap->getEvents(chars, len, &keys, &modifiers);
+
+ env->ReleaseCharArrayElements(jchars, chars, JNI_ABORT);
+
+ if (success) {
+ size_t N = keys.size();
+
+ jlongArray rv = env->NewLongArray(N);
+ uint64_t* results = (uint64_t*)env->GetLongArrayElements(rv, NULL);
+
+ for (size_t i=0; i<N; i++) {
+ uint64_t v = modifiers[i];
+ v <<= 32;
+ v |= keys[i];
+ results[i] = v;
+ }
+
+ env->ReleaseLongArrayElements(rv, (jlong*)results, 0);
+ return rv;
+ } else {
+ return NULL;
+ }
+}
+
+// ============================================================================
+/*
+ * JNI registration.
+ */
+
+static JNINativeMethod g_methods[] = {
+ /* name, signature, funcPtr */
+ { "ctor_native", "(I)I", (void*)ctor },
+ { "dtor_native", "(I)V", (void*)dtor },
+ { "get_native", "(III)C", (void*)get },
+ { "getNumber_native", "(II)C", (void*)getNumber },
+ { "getMatch_native", "(II[CI)C", (void*)getMatch },
+ { "getDisplayLabel_native", "(II)C", (void*)getDisplayLabel },
+ { "getKeyData_native", "(IILandroid/view/KeyCharacterMap$KeyData;)Z",
+ (void*)getKeyData },
+ { "getKeyboardType_native", "(I)I", (void*)getKeyboardType },
+ { "getEvents_native", "(I[C)[J", (void*)getEvents }
+};
+
+int register_android_text_KeyCharacterMap(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/view/KeyCharacterMap$KeyData");
+ if (clazz == NULL) {
+ LOGE("Can't find android/view/KeyCharacterMap$KeyData");
+ return -1;
+ }
+
+ gKeyDataMetaField = env->GetFieldID(clazz, "meta", "[C");
+ gKeyDataNumberField = env->GetFieldID(clazz, "number", "C");
+ gKeyDataDisplayLabelField = env->GetFieldID(clazz, "displayLabel", "C");
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/view/KeyCharacterMap", g_methods, NELEM(g_methods));
+}
+
+}; // namespace android
+
+
+
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
new file mode 100644
index 0000000..8a62159
--- /dev/null
+++ b/core/jni/android_util_AssetManager.cpp
@@ -0,0 +1,1673 @@
+/* //device/libs/android_runtime/android_util_AssetManager.cpp
+**
+** Copyright 2006, 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 "asset"
+
+#include <android_runtime/android_util_AssetManager.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_util_Binder.h"
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+
+#include <utils/Asset.h>
+#include <utils/AssetManager.h>
+#include <utils/ResourceTypes.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct typedvalue_offsets_t
+{
+ jfieldID mType;
+ jfieldID mData;
+ jfieldID mString;
+ jfieldID mAssetCookie;
+ jfieldID mResourceId;
+ jfieldID mChangingConfigurations;
+} gTypedValueOffsets;
+
+static struct assetfiledescriptor_offsets_t
+{
+ jfieldID mFd;
+ jfieldID mStartOffset;
+ jfieldID mLength;
+} gAssetFileDescriptorOffsets;
+
+static struct assetmanager_offsets_t
+{
+ jfieldID mObject;
+} gAssetManagerOffsets;
+
+jclass g_stringClass = NULL;
+
+// ----------------------------------------------------------------------------
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz;
+
+ npeClazz = env->FindClass(exc);
+ LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
+
+ env->ThrowNew(npeClazz, msg);
+}
+
+enum {
+ STYLE_NUM_ENTRIES = 5,
+ STYLE_TYPE = 0,
+ STYLE_DATA = 1,
+ STYLE_ASSET_COOKIE = 2,
+ STYLE_RESOURCE_ID = 3,
+ STYLE_CHANGING_CONFIGURATIONS = 4
+};
+
+static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+ const Res_value& value, uint32_t ref, ssize_t block,
+ uint32_t typeSpecFlags)
+{
+ env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
+ env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
+ (jint)table->getTableCookie(block));
+ env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
+ env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
+ env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
+ env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
+ typeSpecFlags);
+ return block;
+}
+
+// ----------------------------------------------------------------------------
+
+// this guy is exported to other jni routines
+AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
+{
+ AssetManager* am = (AssetManager*)env->GetIntField(obj, gAssetManagerOffsets.mObject);
+ if (am != NULL) {
+ return am;
+ }
+ jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
+ return NULL;
+}
+
+static jint android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
+ jstring fileName, jint mode)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ LOGV("openAsset in %p (Java object %p)\n", am, clazz);
+
+ if (fileName == NULL || am == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -1;
+ }
+
+ if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+ && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+ doThrow(env, "java/lang/IllegalArgumentException");
+ return -1;
+ }
+
+ const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
+ Asset* a = am->open(fileName8, (Asset::AccessMode)mode);
+
+ if (a == NULL) {
+ doThrow(env, "java/io/FileNotFoundException", fileName8);
+ env->ReleaseStringUTFChars(fileName, fileName8);
+ return -1;
+ }
+ env->ReleaseStringUTFChars(fileName, fileName8);
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return (jint)a;
+}
+
+static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
+{
+ off_t startOffset, length;
+ int fd = a->openFileDescriptor(&startOffset, &length);
+ delete a;
+
+ if (fd < 0) {
+ doThrow(env, "java/io/FileNotFoundException",
+ "This file can not be opened as a file descriptor; it is probably compressed");
+ return NULL;
+ }
+
+ jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
+ if (offsets == NULL) {
+ close(fd);
+ return NULL;
+ }
+
+ offsets[0] = startOffset;
+ offsets[1] = length;
+
+ env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
+
+ jobject fileDesc = newFileDescriptor(env, fd);
+ if (fileDesc == NULL) {
+ close(fd);
+ return NULL;
+ }
+
+ return newParcelFileDescriptor(env, fileDesc);
+}
+
+static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
+ jstring fileName, jlongArray outOffsets)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ LOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
+
+ if (fileName == NULL || am == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return NULL;
+ }
+
+ const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
+ Asset* a = am->open(fileName8, Asset::ACCESS_RANDOM);
+
+ if (a == NULL) {
+ doThrow(env, "java/io/FileNotFoundException", fileName8);
+ env->ReleaseStringUTFChars(fileName, fileName8);
+ return NULL;
+ }
+ env->ReleaseStringUTFChars(fileName, fileName8);
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return returnParcelFileDescriptor(env, a, outOffsets);
+}
+
+static jint android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
+ jint cookie,
+ jstring fileName,
+ jint mode)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ LOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
+
+ if (fileName == NULL || am == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -1;
+ }
+
+ if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+ && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+ doThrow(env, "java/lang/IllegalArgumentException");
+ return -1;
+ }
+
+ const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
+ Asset* a = cookie
+ ? am->openNonAsset((void*)cookie, fileName8, (Asset::AccessMode)mode)
+ : am->openNonAsset(fileName8, (Asset::AccessMode)mode);
+
+ if (a == NULL) {
+ doThrow(env, "java/io/FileNotFoundException", fileName8);
+ env->ReleaseStringUTFChars(fileName, fileName8);
+ return -1;
+ }
+ env->ReleaseStringUTFChars(fileName, fileName8);
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return (jint)a;
+}
+
+static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
+ jint cookie,
+ jstring fileName,
+ jlongArray outOffsets)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ LOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
+
+ if (fileName == NULL || am == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return NULL;
+ }
+
+ const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
+ Asset* a = cookie
+ ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_RANDOM)
+ : am->openNonAsset(fileName8, Asset::ACCESS_RANDOM);
+
+ if (a == NULL) {
+ doThrow(env, "java/io/FileNotFoundException", fileName8);
+ env->ReleaseStringUTFChars(fileName, fileName8);
+ return NULL;
+ }
+ env->ReleaseStringUTFChars(fileName, fileName8);
+
+ //printf("Created Asset Stream: %p\n", a);
+
+ return returnParcelFileDescriptor(env, a, outOffsets);
+}
+
+static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
+ jstring fileName)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ if (fileName == NULL || am == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return NULL;
+ }
+
+ const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
+
+ AssetDir* dir = am->openDir(fileName8);
+
+ env->ReleaseStringUTFChars(fileName, fileName8);
+
+ if (dir == NULL) {
+ doThrow(env, "java/io/FileNotFoundException", fileName8);
+ return NULL;
+ }
+
+ jclass cls = env->FindClass("java/lang/String");
+ LOG_FATAL_IF(cls == NULL, "No string class?!?");
+ if (cls == NULL) {
+ delete dir;
+ return NULL;
+ }
+
+ size_t N = dir->getFileCount();
+
+ jobjectArray array = env->NewObjectArray(dir->getFileCount(),
+ cls, NULL);
+ if (array == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ delete dir;
+ return NULL;
+ }
+
+ for (size_t i=0; i<N; i++) {
+ const String8& name = dir->getFileName(i);
+ jstring str = env->NewStringUTF(name.string());
+ if (str == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ delete dir;
+ return NULL;
+ }
+ env->SetObjectArrayElement(array, i, str);
+ }
+
+ delete dir;
+
+ return array;
+}
+
+static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
+ jint asset)
+{
+ Asset* a = (Asset*)asset;
+
+ //printf("Destroying Asset Stream: %p\n", a);
+
+ if (a == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return;
+ }
+
+ delete a;
+}
+
+static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
+ jint asset)
+{
+ Asset* a = (Asset*)asset;
+
+ if (a == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -1;
+ }
+
+ uint8_t b;
+ ssize_t res = a->read(&b, 1);
+ return res == 1 ? b : -1;
+}
+
+static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
+ jint asset, jbyteArray bArray,
+ jint off, jint len)
+{
+ Asset* a = (Asset*)asset;
+
+ if (a == NULL || bArray == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -1;
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+
+ jsize bLen = env->GetArrayLength(bArray);
+ if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
+ return -1;
+ }
+
+ jbyte* b = env->GetByteArrayElements(bArray, NULL);
+ ssize_t res = a->read(b+off, len);
+ env->ReleaseByteArrayElements(bArray, b, 0);
+
+ if (res > 0) return res;
+
+ if (res < 0) {
+ doThrow(env, "java/io/IOException");
+ }
+ return -1;
+}
+
+static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
+ jint asset,
+ jlong offset, jint whence)
+{
+ Asset* a = (Asset*)asset;
+
+ if (a == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -1;
+ }
+
+ return a->seek(
+ offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
+}
+
+static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
+ jint asset)
+{
+ Asset* a = (Asset*)asset;
+
+ if (a == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -1;
+ }
+
+ return a->getLength();
+}
+
+static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
+ jint asset)
+{
+ Asset* a = (Asset*)asset;
+
+ if (a == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return -1;
+ }
+
+ return a->getRemainingLength();
+}
+
+static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
+ jstring path)
+{
+ if (path == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ const char* path8 = env->GetStringUTFChars(path, NULL);
+
+ void* cookie;
+ bool res = am->addAssetPath(String8(path8), &cookie);
+
+ env->ReleaseStringUTFChars(path, path8);
+
+ return (res) ? (jint)cookie : 0;
+}
+
+static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_TRUE;
+ }
+ return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
+ jstring locale)
+{
+ if (locale == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return;
+ }
+
+ const char* locale8 = env->GetStringUTFChars(locale, NULL);
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return;
+ }
+
+ am->setLocale(locale8);
+
+ env->ReleaseStringUTFChars(locale, locale8);
+}
+
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+ Vector<String8> locales;
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ am->getLocales(&locales);
+
+ const int N = locales.size();
+
+ jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ for (int i=0; i<N; i++) {
+ LOGD("locale %2d: '%s'", i, locales[i].string());
+ env->SetObjectArrayElement(result, i, env->NewStringUTF(locales[i].string()));
+ }
+
+ return result;
+}
+
+static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
+ jint mcc, jint mnc,
+ jstring locale, jint orientation,
+ jint touchscreen, jint density,
+ jint keyboard, jint keyboardHidden,
+ jint navigation,
+ jint screenWidth, jint screenHeight,
+ jint sdkVersion)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return;
+ }
+
+ ResTable_config config;
+ memset(&config, 0, sizeof(config));
+
+ const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
+
+ config.mcc = (uint16_t)mcc;
+ config.mnc = (uint16_t)mnc;
+ config.orientation = (uint8_t)orientation;
+ config.touchscreen = (uint8_t)touchscreen;
+ config.density = (uint16_t)density;
+ config.keyboard = (uint8_t)keyboard;
+ config.inputFlags = (uint8_t)keyboardHidden<<ResTable_config::SHIFT_KEYSHIDDEN;
+ config.navigation = (uint8_t)navigation;
+ config.screenWidth = (uint16_t)screenWidth;
+ config.screenHeight = (uint16_t)screenHeight;
+ config.sdkVersion = (uint16_t)sdkVersion;
+ config.minorVersion = 0;
+ am->setConfiguration(config, locale8);
+
+ if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
+}
+
+static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
+ jstring name,
+ jstring defType,
+ jstring defPackage)
+{
+ if (name == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ const char16_t* name16 = env->GetStringChars(name, NULL);
+ jsize nameLen = env->GetStringLength(name);
+ const char16_t* defType16 = defType
+ ? env->GetStringChars(defType, NULL) : NULL;
+ jsize defTypeLen = defType
+ ? env->GetStringLength(defType) : 0;
+ const char16_t* defPackage16 = defPackage
+ ? env->GetStringChars(defPackage, NULL) : NULL;
+ jsize defPackageLen = defPackage
+ ? env->GetStringLength(defPackage) : 0;
+
+ jint ident = am->getResources().identifierForName(
+ name16, nameLen, defType16, defTypeLen, defPackage16, defPackageLen);
+
+ if (defPackage16) {
+ env->ReleaseStringChars(defPackage, defPackage16);
+ }
+ if (defType16) {
+ env->ReleaseStringChars(defType, defType16);
+ }
+ env->ReleaseStringChars(name, name16);
+
+ return ident;
+}
+
+static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, &name)) {
+ return NULL;
+ }
+
+ String16 str;
+ if (name.package != NULL) {
+ str.setTo(name.package, name.packageLen);
+ }
+ if (name.type != NULL) {
+ if (str.size() > 0) {
+ char16_t div = ':';
+ str.append(&div, 1);
+ }
+ str.append(name.type, name.typeLen);
+ }
+ if (name.name != NULL) {
+ if (str.size() > 0) {
+ char16_t div = '/';
+ str.append(&div, 1);
+ }
+ str.append(name.name, name.nameLen);
+ }
+
+ return env->NewString((const jchar*)str.string(), str.size());
+}
+
+static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, &name)) {
+ return NULL;
+ }
+
+ if (name.package != NULL) {
+ return env->NewString((const jchar*)name.package, name.packageLen);
+ }
+
+ return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, &name)) {
+ return NULL;
+ }
+
+ if (name.type != NULL) {
+ return env->NewString((const jchar*)name.type, name.typeLen);
+ }
+
+ return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
+ jint resid)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+
+ ResTable::resource_name name;
+ if (!am->getResources().getResourceName(resid, &name)) {
+ return NULL;
+ }
+
+ if (name.name != NULL) {
+ return env->NewString((const jchar*)name.name, name.nameLen);
+ }
+
+ return NULL;
+}
+
+static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
+ jint ident,
+ jobject outValue,
+ jboolean resolve)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ const ResTable& res(am->getResources());
+
+ Res_value value;
+ uint32_t typeSpecFlags;
+ ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags);
+ uint32_t ref = ident;
+ if (resolve) {
+ block = res.resolveReference(&value, block, &ref);
+ }
+ return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+}
+
+static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
+ jint ident, jint bagEntryId,
+ jobject outValue, jboolean resolve)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ const ResTable& res(am->getResources());
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
+
+ ssize_t block = -1;
+ Res_value value;
+
+ const ResTable::bag_entry* entry = NULL;
+ uint32_t typeSpecFlags;
+ ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
+
+ for (ssize_t i=0; i<entryCount; i++) {
+ if (((uint32_t)bagEntryId) == entry->map.name.ident) {
+ block = entry->stringBlock;
+ value = entry->map.value;
+ }
+ entry++;
+ }
+
+ res.unlock();
+
+ if (block < 0) {
+ return block;
+ }
+
+ uint32_t ref = ident;
+ if (resolve) {
+ block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+ }
+ return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+}
+
+static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ return am->getResources().getTableCount();
+}
+
+static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
+ jint block)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ return (jint)am->getResources().getTableStringBlock(block);
+}
+
+static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
+ jint cookie)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ String8 name(am->getAssetPath((void*)cookie));
+ if (name.length() == 0) {
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
+ return NULL;
+ }
+ jstring str = env->NewStringUTF(name.string());
+ if (str == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return NULL;
+ }
+ return str;
+}
+
+static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+ return (jint)(new ResTable::Theme(am->getResources()));
+}
+
+static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
+ jint themeInt)
+{
+ ResTable::Theme* theme = (ResTable::Theme*)themeInt;
+ delete theme;
+}
+
+static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
+ jint themeInt,
+ jint styleRes,
+ jboolean force)
+{
+ ResTable::Theme* theme = (ResTable::Theme*)themeInt;
+ theme->applyStyle(styleRes, force ? true : false);
+}
+
+static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
+ jint destInt, jint srcInt)
+{
+ ResTable::Theme* dest = (ResTable::Theme*)destInt;
+ ResTable::Theme* src = (ResTable::Theme*)srcInt;
+ dest->setTo(*src);
+}
+
+static jint android_content_AssetManager_loadThemeAttributeValue(
+ JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
+{
+ ResTable::Theme* theme = (ResTable::Theme*)themeInt;
+ const ResTable& res(theme->getResTable());
+
+ Res_value value;
+ // XXX value could be different in different configs!
+ uint32_t typeSpecFlags = 0;
+ ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
+ uint32_t ref = 0;
+ if (resolve) {
+ block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+ }
+ return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+}
+
+static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
+ jint themeInt, jint pri,
+ jstring tag, jstring prefix)
+{
+ ResTable::Theme* theme = (ResTable::Theme*)themeInt;
+ const ResTable& res(theme->getResTable());
+
+ if (tag == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return;
+ }
+
+ const char* tag8 = env->GetStringUTFChars(tag, NULL);
+ const char* prefix8 = NULL;
+ if (prefix != NULL) {
+ prefix8 = env->GetStringUTFChars(prefix, NULL);
+ }
+
+ // XXX Need to use params.
+ theme->dumpToLog();
+
+ if (prefix8 != NULL) {
+ env->ReleaseStringUTFChars(prefix, prefix8);
+ }
+ env->ReleaseStringUTFChars(tag, tag8);
+}
+
+static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
+ jint themeToken,
+ jint defStyleAttr,
+ jint defStyleRes,
+ jint xmlParserToken,
+ jintArray attrs,
+ jintArray outValues,
+ jintArray outIndices)
+{
+ if (themeToken == 0 || attrs == NULL || outValues == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+
+ ResTable::Theme* theme = (ResTable::Theme*)themeToken;
+ const ResTable& res = theme->getResTable();
+ ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+ Res_value value;
+
+ const jsize NI = env->GetArrayLength(attrs);
+ const jsize NV = env->GetArrayLength(outValues);
+ if (NV < (NI*STYLE_NUM_ENTRIES)) {
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
+ return JNI_FALSE;
+ }
+
+ jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+ if (src == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return JNI_FALSE;
+ }
+
+ jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ if (dest == NULL) {
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return JNI_FALSE;
+ }
+
+ jint* indices = NULL;
+ int indicesIdx = 0;
+ if (outIndices != NULL) {
+ if (env->GetArrayLength(outIndices) > NI) {
+ indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+ }
+ }
+
+ // Load default style from attribute, if specified...
+ uint32_t defStyleBagTypeSetFlags = 0;
+ if (defStyleAttr != 0) {
+ Res_value value;
+ if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
+ if (value.dataType == Res_value::TYPE_REFERENCE) {
+ defStyleRes = value.data;
+ }
+ }
+ }
+
+ // Retrieve the style class associated with the current XML tag.
+ int style = 0;
+ uint32_t styleBagTypeSetFlags = 0;
+ if (xmlParser != NULL) {
+ ssize_t idx = xmlParser->indexOfStyle();
+ if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
+ if (value.dataType == value.TYPE_ATTRIBUTE) {
+ if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ }
+ }
+ if (value.dataType == value.TYPE_REFERENCE) {
+ style = value.data;
+ }
+ }
+ }
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
+
+ // Retrieve the default style bag, if requested.
+ const ResTable::bag_entry* defStyleEnt = NULL;
+ uint32_t defStyleTypeSetFlags = 0;
+ ssize_t bagOff = defStyleRes != 0
+ ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
+ defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
+ const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
+ (bagOff >= 0 ? bagOff : 0);
+
+ // Retrieve the style class bag, if requested.
+ const ResTable::bag_entry* styleEnt = NULL;
+ uint32_t styleTypeSetFlags = 0;
+ bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
+ styleTypeSetFlags |= styleBagTypeSetFlags;
+ const ResTable::bag_entry* endStyleEnt = styleEnt +
+ (bagOff >= 0 ? bagOff : 0);
+
+ // Retrieve the XML attributes, if requested.
+ const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
+ jsize ix=0;
+ uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
+
+ static const ssize_t kXmlBlock = 0x10000000;
+
+ // Now iterate through all of the attributes that the client has requested,
+ // filling in each with whatever data we can find.
+ ssize_t block = 0;
+ uint32_t typeSetFlags;
+ for (jsize ii=0; ii<NI; ii++) {
+ const uint32_t curIdent = (uint32_t)src[ii];
+
+ // Try to find a value for this attribute... we prioritize values
+ // coming from, first XML attributes, then XML style, then default
+ // style, and finally the theme.
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = 0;
+ typeSetFlags = 0;
+
+ // Skip through XML attributes until the end or the next possible match.
+ while (ix < NX && curIdent > curXmlAttr) {
+ ix++;
+ curXmlAttr = xmlParser->getAttributeNameResID(ix);
+ }
+ // Retrieve the current XML attribute if it matches, and step to next.
+ if (ix < NX && curIdent == curXmlAttr) {
+ block = kXmlBlock;
+ xmlParser->getAttributeValue(ix, &value);
+ ix++;
+ curXmlAttr = xmlParser->getAttributeNameResID(ix);
+ }
+
+ // Skip through the style values until the end or the next possible match.
+ while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
+ styleEnt++;
+ }
+ // Retrieve the current style attribute if it matches, and step to next.
+ if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
+ if (value.dataType == Res_value::TYPE_NULL) {
+ block = styleEnt->stringBlock;
+ typeSetFlags = styleTypeSetFlags;
+ value = styleEnt->map.value;
+ }
+ styleEnt++;
+ }
+
+ // Skip through the default style values until the end or the next possible match.
+ while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
+ defStyleEnt++;
+ }
+ // Retrieve the current default style attribute if it matches, and step to next.
+ if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
+ if (value.dataType == Res_value::TYPE_NULL) {
+ block = defStyleEnt->stringBlock;
+ typeSetFlags = defStyleTypeSetFlags;
+ value = defStyleEnt->map.value;
+ }
+ defStyleEnt++;
+ }
+
+ //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+ uint32_t resid = 0;
+ if (value.dataType != Res_value::TYPE_NULL) {
+ // Take care of resolving the found resource to its final value.
+ //printf("Resolving attribute reference\n");
+ ssize_t newBlock = theme->resolveAttributeReference(&value, block, &resid, &typeSetFlags);
+ if (newBlock >= 0) block = newBlock;
+ } else {
+ // If we still don't have a value for this attribute, try to find
+ // it in the theme!
+ //printf("Looking up in theme\n");
+ ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
+ if (newBlock >= 0) {
+ //printf("Resolving resource reference\n");
+ newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
+ if (newBlock >= 0) block = newBlock;
+ }
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ }
+
+ //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+ // Write the final value back to Java.
+ dest[STYLE_TYPE] = value.dataType;
+ dest[STYLE_DATA] = value.data;
+ dest[STYLE_ASSET_COOKIE] =
+ block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
+ dest[STYLE_RESOURCE_ID] = resid;
+ dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+
+ if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
+ indicesIdx++;
+ indices[indicesIdx] = ii;
+ }
+
+ dest += STYLE_NUM_ENTRIES;
+ }
+
+ res.unlock();
+
+ if (indices != NULL) {
+ indices[0] = indicesIdx;
+ env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+ }
+ env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+
+ return JNI_TRUE;
+}
+
+static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
+ jint xmlParserToken,
+ jintArray attrs,
+ jintArray outValues,
+ jintArray outIndices)
+{
+ if (xmlParserToken == 0 || attrs == NULL || outValues == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+ const ResTable& res(am->getResources());
+ ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+ Res_value value;
+
+ const jsize NI = env->GetArrayLength(attrs);
+ const jsize NV = env->GetArrayLength(outValues);
+ if (NV < (NI*STYLE_NUM_ENTRIES)) {
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
+ return JNI_FALSE;
+ }
+
+ jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+ if (src == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return JNI_FALSE;
+ }
+
+ jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ if (dest == NULL) {
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return JNI_FALSE;
+ }
+
+ jint* indices = NULL;
+ int indicesIdx = 0;
+ if (outIndices != NULL) {
+ if (env->GetArrayLength(outIndices) > NI) {
+ indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+ }
+ }
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
+
+ // Retrieve the XML attributes, if requested.
+ const jsize NX = xmlParser->getAttributeCount();
+ jsize ix=0;
+ uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
+
+ static const ssize_t kXmlBlock = 0x10000000;
+
+ // Now iterate through all of the attributes that the client has requested,
+ // filling in each with whatever data we can find.
+ ssize_t block = 0;
+ uint32_t typeSetFlags;
+ for (jsize ii=0; ii<NI; ii++) {
+ const uint32_t curIdent = (uint32_t)src[ii];
+
+ // Try to find a value for this attribute...
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = 0;
+ typeSetFlags = 0;
+
+ // Skip through XML attributes until the end or the next possible match.
+ while (ix < NX && curIdent > curXmlAttr) {
+ ix++;
+ curXmlAttr = xmlParser->getAttributeNameResID(ix);
+ }
+ // Retrieve the current XML attribute if it matches, and step to next.
+ if (ix < NX && curIdent == curXmlAttr) {
+ block = kXmlBlock;
+ xmlParser->getAttributeValue(ix, &value);
+ ix++;
+ curXmlAttr = xmlParser->getAttributeNameResID(ix);
+ }
+
+ //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+ uint32_t resid = 0;
+ if (value.dataType != Res_value::TYPE_NULL) {
+ // Take care of resolving the found resource to its final value.
+ //printf("Resolving attribute reference\n");
+ ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
+ if (newBlock >= 0) block = newBlock;
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ }
+
+ //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+ // Write the final value back to Java.
+ dest[STYLE_TYPE] = value.dataType;
+ dest[STYLE_DATA] = value.data;
+ dest[STYLE_ASSET_COOKIE] =
+ block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
+ dest[STYLE_RESOURCE_ID] = resid;
+ dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+
+ if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
+ indicesIdx++;
+ indices[indicesIdx] = ii;
+ }
+
+ dest += STYLE_NUM_ENTRIES;
+ }
+
+ res.unlock();
+
+ if (indices != NULL) {
+ indices[0] = indicesIdx;
+ env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+ }
+
+ env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+ env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+
+ return JNI_TRUE;
+}
+
+static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
+ jint id)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
+
+ res.lock();
+ const ResTable::bag_entry* defStyleEnt = NULL;
+ ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
+ res.unlock();
+
+ return bagOff;
+}
+
+static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
+ jint id,
+ jintArray outValues)
+{
+ if (outValues == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+ const ResTable& res(am->getResources());
+ Res_value value;
+ ssize_t block;
+
+ const jsize NV = env->GetArrayLength(outValues);
+
+ jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+ if (dest == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return JNI_FALSE;
+ }
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
+
+ const ResTable::bag_entry* arrayEnt = NULL;
+ uint32_t arrayTypeSetFlags = 0;
+ ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
+ const ResTable::bag_entry* endArrayEnt = arrayEnt +
+ (bagOff >= 0 ? bagOff : 0);
+
+ int i = 0;
+ uint32_t typeSetFlags;
+ while (i < NV && arrayEnt < endArrayEnt) {
+ block = arrayEnt->stringBlock;
+ typeSetFlags = arrayTypeSetFlags;
+ value = arrayEnt->map.value;
+
+ uint32_t resid = 0;
+ if (value.dataType != Res_value::TYPE_NULL) {
+ // Take care of resolving the found resource to its final value.
+ //printf("Resolving attribute reference\n");
+ ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
+ if (newBlock >= 0) block = newBlock;
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ }
+
+ //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+ // Write the final value back to Java.
+ dest[STYLE_TYPE] = value.dataType;
+ dest[STYLE_DATA] = value.data;
+ dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
+ dest[STYLE_RESOURCE_ID] = resid;
+ dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+ dest += STYLE_NUM_ENTRIES;
+ i+= STYLE_NUM_ENTRIES;
+ arrayEnt++;
+ }
+
+ i /= STYLE_NUM_ENTRIES;
+
+ res.unlock();
+
+ env->ReleasePrimitiveArrayCritical(outValues, dest, 0);
+
+ return i;
+}
+
+static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
+ jint cookie,
+ jstring fileName)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
+
+ if (fileName == NULL || am == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
+ Asset* a = cookie
+ ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
+ : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
+
+ if (a == NULL) {
+ doThrow(env, "java/io/FileNotFoundException", fileName8);
+ env->ReleaseStringUTFChars(fileName, fileName8);
+ return 0;
+ }
+ env->ReleaseStringUTFChars(fileName, fileName8);
+
+ ResXMLTree* block = new ResXMLTree();
+ status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
+ a->close();
+ delete a;
+
+ if (err != NO_ERROR) {
+ doThrow(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+ return 0;
+ }
+
+ return (jint)block;
+}
+
+static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
+ jint arrayResId)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
+
+ const ResTable::bag_entry* startOfBag;
+ const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+ if (N < 0) {
+ return NULL;
+ }
+
+ jintArray array = env->NewIntArray(N * 2);
+ if (array == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+
+ Res_value value;
+ const ResTable::bag_entry* bag = startOfBag;
+ for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
+ jint stringIndex = -1;
+ jint stringBlock = 0;
+ value = bag->map.value;
+
+ // Take care of resolving the found resource to its final value.
+ stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
+ if (value.dataType == Res_value::TYPE_STRING) {
+ stringIndex = value.data;
+ }
+
+ //todo: It might be faster to allocate a C array to contain
+ // the blocknums and indices, put them in there and then
+ // do just one SetIntArrayRegion()
+ env->SetIntArrayRegion(array, j, 1, &stringBlock);
+ env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
+ j = j + 2;
+ }
+ res.unlockBag(startOfBag);
+ return array;
+}
+
+static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
+ jint arrayResId)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
+
+ jclass cls = env->FindClass("java/lang/String");
+ LOG_FATAL_IF(cls == NULL, "No string class?!?");
+ if (cls == NULL) {
+ return NULL;
+ }
+
+ const ResTable::bag_entry* startOfBag;
+ const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+ if (N < 0) {
+ return NULL;
+ }
+
+ jobjectArray array = env->NewObjectArray(N, cls, NULL);
+ if (array == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+
+ Res_value value;
+ const ResTable::bag_entry* bag = startOfBag;
+ size_t strLen = 0;
+ for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+ value = bag->map.value;
+ jstring str = NULL;
+
+ // Take care of resolving the found resource to its final value.
+ ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+ if (value.dataType == Res_value::TYPE_STRING) {
+ const char16_t* str16 = res.getTableStringBlock(block)->stringAt(value.data, &strLen);
+ str = env->NewString(str16, strLen);
+ if (str == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+ }
+
+ env->SetObjectArrayElement(array, i, str);
+ }
+ res.unlockBag(startOfBag);
+ return array;
+}
+
+static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
+ jint arrayResId)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return NULL;
+ }
+ const ResTable& res(am->getResources());
+
+ const ResTable::bag_entry* startOfBag;
+ const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+ if (N < 0) {
+ return NULL;
+ }
+
+ jintArray array = env->NewIntArray(N);
+ if (array == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
+
+ Res_value value;
+ const ResTable::bag_entry* bag = startOfBag;
+ for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+ value = bag->map.value;
+
+ // Take care of resolving the found resource to its final value.
+ ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+ if (value.dataType >= Res_value::TYPE_FIRST_INT
+ && value.dataType <= Res_value::TYPE_LAST_INT) {
+ int intVal = value.data;
+ env->SetIntArrayRegion(array, i, 1, &intVal);
+ }
+ }
+ res.unlockBag(startOfBag);
+ return array;
+}
+
+static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = new AssetManager();
+ if (am == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return;
+ }
+
+ am->addDefaultAssets();
+
+ LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
+ env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
+}
+
+static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = (AssetManager*)
+ (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
+ LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
+ if (am != NULL) {
+ delete am;
+ env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
+ }
+}
+
+static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
+{
+ return Asset::getGlobalCount();
+}
+
+static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
+{
+ return AssetManager::getGlobalCount();
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gAssetManagerMethods[] = {
+ /* name, signature, funcPtr */
+
+ // Basic asset stuff.
+ { "openAsset", "(Ljava/lang/String;I)I",
+ (void*) android_content_AssetManager_openAsset },
+ { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+ (void*) android_content_AssetManager_openAssetFd },
+ { "openNonAssetNative", "(ILjava/lang/String;I)I",
+ (void*) android_content_AssetManager_openNonAssetNative },
+ { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+ (void*) android_content_AssetManager_openNonAssetFdNative },
+ { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
+ (void*) android_content_AssetManager_list },
+ { "destroyAsset", "(I)V",
+ (void*) android_content_AssetManager_destroyAsset },
+ { "readAssetChar", "(I)I",
+ (void*) android_content_AssetManager_readAssetChar },
+ { "readAsset", "(I[BII)I",
+ (void*) android_content_AssetManager_readAsset },
+ { "seekAsset", "(IJI)J",
+ (void*) android_content_AssetManager_seekAsset },
+ { "getAssetLength", "(I)J",
+ (void*) android_content_AssetManager_getAssetLength },
+ { "getAssetRemainingLength", "(I)J",
+ (void*) android_content_AssetManager_getAssetRemainingLength },
+ { "addAssetPath", "(Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_addAssetPath },
+ { "isUpToDate", "()Z",
+ (void*) android_content_AssetManager_isUpToDate },
+
+ // Resources.
+ { "setLocale", "(Ljava/lang/String;)V",
+ (void*) android_content_AssetManager_setLocale },
+ { "getLocales", "()[Ljava/lang/String;",
+ (void*) android_content_AssetManager_getLocales },
+ { "setConfiguration", "(IILjava/lang/String;IIIIIIIII)V",
+ (void*) android_content_AssetManager_setConfiguration },
+ { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_getResourceIdentifier },
+ { "getResourceName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourceName },
+ { "getResourcePackageName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourcePackageName },
+ { "getResourceTypeName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourceTypeName },
+ { "getResourceEntryName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getResourceEntryName },
+ { "loadResourceValue","(ILandroid/util/TypedValue;Z)I",
+ (void*) android_content_AssetManager_loadResourceValue },
+ { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
+ (void*) android_content_AssetManager_loadResourceBagValue },
+ { "getStringBlockCount","()I",
+ (void*) android_content_AssetManager_getStringBlockCount },
+ { "getNativeStringBlock","(I)I",
+ (void*) android_content_AssetManager_getNativeStringBlock },
+ { "getCookieName","(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getCookieName },
+
+ // Themes.
+ { "newTheme", "()I",
+ (void*) android_content_AssetManager_newTheme },
+ { "deleteTheme", "(I)V",
+ (void*) android_content_AssetManager_deleteTheme },
+ { "applyThemeStyle", "(IIZ)V",
+ (void*) android_content_AssetManager_applyThemeStyle },
+ { "copyTheme", "(II)V",
+ (void*) android_content_AssetManager_copyTheme },
+ { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
+ (void*) android_content_AssetManager_loadThemeAttributeValue },
+ { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
+ (void*) android_content_AssetManager_dumpTheme },
+ { "applyStyle","(IIII[I[I[I)Z",
+ (void*) android_content_AssetManager_applyStyle },
+ { "retrieveAttributes","(I[I[I[I)Z",
+ (void*) android_content_AssetManager_retrieveAttributes },
+ { "getArraySize","(I)I",
+ (void*) android_content_AssetManager_getArraySize },
+ { "retrieveArray","(I[I)I",
+ (void*) android_content_AssetManager_retrieveArray },
+
+ // XML files.
+ { "openXmlAssetNative", "(ILjava/lang/String;)I",
+ (void*) android_content_AssetManager_openXmlAssetNative },
+
+ // Arrays.
+ { "getArrayStringResource","(I)[Ljava/lang/String;",
+ (void*) android_content_AssetManager_getArrayStringResource },
+ { "getArrayStringInfo","(I)[I",
+ (void*) android_content_AssetManager_getArrayStringInfo },
+ { "getArrayIntResource","(I)[I",
+ (void*) android_content_AssetManager_getArrayIntResource },
+
+ // Bookkeeping.
+ { "init", "()V",
+ (void*) android_content_AssetManager_init },
+ { "destroy", "()V",
+ (void*) android_content_AssetManager_destroy },
+ { "getGlobalAssetCount", "()I",
+ (void*) android_content_AssetManager_getGlobalAssetCount },
+ { "getGlobalAssetManagerCount", "()I",
+ (void*) android_content_AssetManager_getGlobalAssetCount },
+};
+
+int register_android_content_AssetManager(JNIEnv* env)
+{
+ jclass typedValue = env->FindClass("android/util/TypedValue");
+ LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
+ gTypedValueOffsets.mType
+ = env->GetFieldID(typedValue, "type", "I");
+ LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
+ gTypedValueOffsets.mData
+ = env->GetFieldID(typedValue, "data", "I");
+ LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
+ gTypedValueOffsets.mString
+ = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
+ LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
+ gTypedValueOffsets.mAssetCookie
+ = env->GetFieldID(typedValue, "assetCookie", "I");
+ LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
+ gTypedValueOffsets.mResourceId
+ = env->GetFieldID(typedValue, "resourceId", "I");
+ LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
+ gTypedValueOffsets.mChangingConfigurations
+ = env->GetFieldID(typedValue, "changingConfigurations", "I");
+ LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
+
+ jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
+ LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
+ gAssetFileDescriptorOffsets.mFd
+ = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
+ LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
+ gAssetFileDescriptorOffsets.mStartOffset
+ = env->GetFieldID(assetFd, "mStartOffset", "J");
+ LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
+ gAssetFileDescriptorOffsets.mLength
+ = env->GetFieldID(assetFd, "mLength", "J");
+ LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
+
+ jclass assetManager = env->FindClass("android/content/res/AssetManager");
+ LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
+ gAssetManagerOffsets.mObject
+ = env->GetFieldID(assetManager, "mObject", "I");
+ LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
+
+ g_stringClass = env->FindClass("java/lang/String");
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_util_Base64.cpp b/core/jni/android_util_Base64.cpp
new file mode 100644
index 0000000..bc69747
--- /dev/null
+++ b/core/jni/android_util_Base64.cpp
@@ -0,0 +1,160 @@
+/* //device/libs/android_runtime/android_util_Base64.cpp
+**
+** 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.
+*/
+
+/*********************************************************
+*
+* This code was copied from
+* system/extra/ssh/dropbear-0.49/libtomcrypt/src/misc/base64/base64_decode.c
+*
+*********************************************************/
+
+#define LOG_TAG "Base64"
+
+#include <utils/Log.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include "JNIHelp.h"
+
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+
+namespace android {
+
+static const unsigned char map[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255 };
+
+/**
+ base64 decode a block of memory
+ @param in The base64 data to decode
+ @param inlen The length of the base64 data
+ @param out [out] The destination of the binary decoded data
+ @param outlen [in/out] The max size and resulting size of the decoded data
+ @return 0 if successful
+*/
+int base64_decode(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen)
+{
+ unsigned long t, x, y, z;
+ unsigned char c;
+ int g;
+
+ g = 3;
+ for (x = y = z = t = 0; x < inlen; x++) {
+ c = map[in[x]&0xFF];
+ if (c == 255) continue;
+ /* the final = symbols are read and used to trim the remaining bytes */
+ if (c == 254) {
+ c = 0;
+ /* prevent g < 0 which would potentially allow an overflow later */
+ if (--g < 0) {
+ return -3;
+ }
+ } else if (g != 3) {
+ /* we only allow = to be at the end */
+ return -4;
+ }
+
+ t = (t<<6)|c;
+
+ if (++y == 4) {
+ if (z + g > *outlen) {
+ return -2;
+ }
+ out[z++] = (unsigned char)((t>>16)&255);
+ if (g > 1) out[z++] = (unsigned char)((t>>8)&255);
+ if (g > 2) out[z++] = (unsigned char)(t&255);
+ y = t = 0;
+ }
+ }
+ if (y != 0) {
+ return -5;
+ }
+ *outlen = z;
+ return 0;
+}
+
+static jbyteArray decodeBase64(JNIEnv *env, jobject jobj, jstring jdata)
+{
+ const char * rawData = env->GetStringUTFChars(jdata, NULL);
+ int stringLength = env->GetStringUTFLength(jdata);
+
+ int resultLength = stringLength / 4 * 3;
+ if (rawData[stringLength-1] == '=') {
+ resultLength -= 1;
+ if (rawData[stringLength-2] == '=') {
+ resultLength -= 1;
+ }
+ }
+
+ jbyteArray byteArray = env->NewByteArray(resultLength);
+ jbyte* byteArrayData = env->GetByteArrayElements(byteArray, NULL);
+
+ unsigned long outlen = resultLength;
+ int result = base64_decode((const unsigned char*)rawData, stringLength, (unsigned char *)byteArrayData, &outlen);
+ if (result != 0)
+ memset((unsigned char *)byteArrayData, -result, resultLength);
+
+ env->ReleaseStringUTFChars(jdata, rawData);
+ env->ReleaseByteArrayElements(byteArray, byteArrayData, 0);
+
+ return byteArray;
+}
+
+static const JNINativeMethod methods[] = {
+ {"decodeBase64Native", "(Ljava/lang/String;)[B", (void*)decodeBase64 }
+};
+
+static const char* const kBase64PathName = "android/os/Base64Utils";
+
+int register_android_util_Base64(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass(kBase64PathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Base64Utils");
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kBase64PathName,
+ methods, NELEM(methods));
+}
+
+}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
new file mode 100644
index 0000000..24404a8
--- /dev/null
+++ b/core/jni/android_util_Binder.cpp
@@ -0,0 +1,1510 @@
+/*
+ * Copyright (C) 2006 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 "JavaBinder"
+//#define LOG_NDEBUG 0
+
+#include "android_util_Binder.h"
+#include "JNIHelp.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#include <utils/Atomic.h>
+#include <utils/IInterface.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+//#undef LOGV
+//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+
+static struct bindernative_offsets_t
+{
+ // Class state.
+ jclass mClass;
+ jmethodID mExecTransact;
+
+ // Object state.
+ jfieldID mObject;
+
+} gBinderOffsets;
+
+// ----------------------------------------------------------------------------
+
+static struct binderinternal_offsets_t
+{
+ // Class state.
+ jclass mClass;
+ jmethodID mForceGc;
+
+} gBinderInternalOffsets;
+
+// ----------------------------------------------------------------------------
+
+static struct debug_offsets_t
+{
+ // Class state.
+ jclass mClass;
+
+} gDebugOffsets;
+
+// ----------------------------------------------------------------------------
+
+static struct weakreference_offsets_t
+{
+ // Class state.
+ jclass mClass;
+ jmethodID mGet;
+
+} gWeakReferenceOffsets;
+
+static struct error_offsets_t
+{
+ jclass mClass;
+} gErrorOffsets;
+
+// ----------------------------------------------------------------------------
+
+static struct binderproxy_offsets_t
+{
+ // Class state.
+ jclass mClass;
+ jmethodID mConstructor;
+ jmethodID mSendDeathNotice;
+
+ // Object state.
+ jfieldID mObject;
+ jfieldID mSelf;
+
+} gBinderProxyOffsets;
+
+// ----------------------------------------------------------------------------
+
+static struct parcel_offsets_t
+{
+ jfieldID mObject;
+ jfieldID mOwnObject;
+} gParcelOffsets;
+
+static struct log_offsets_t
+{
+ // Class state.
+ jclass mClass;
+ jmethodID mLogE;
+} gLogOffsets;
+
+static struct file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+ jfieldID mDescriptor;
+} gFileDescriptorOffsets;
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+// ****************************************************************************
+// ****************************************************************************
+// ****************************************************************************
+
+static volatile int32_t gNumRefsCreated = 0;
+static volatile int32_t gNumProxyRefs = 0;
+static volatile int32_t gNumLocalRefs = 0;
+static volatile int32_t gNumDeathRefs = 0;
+
+static void incRefsCreated(JNIEnv* env)
+{
+ int old = android_atomic_inc(&gNumRefsCreated);
+ if (old == 200) {
+ android_atomic_and(0, &gNumRefsCreated);
+ env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
+ gBinderInternalOffsets.mForceGc);
+ } else {
+ LOGV("Now have %d binder ops", old);
+ }
+}
+
+static JavaVM* jnienv_to_javavm(JNIEnv* env)
+{
+ JavaVM* vm;
+ return env->GetJavaVM(&vm) >= 0 ? vm : NULL;
+}
+
+static JNIEnv* javavm_to_jnienv(JavaVM* vm)
+{
+ JNIEnv* env;
+ return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
+}
+
+static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
+{
+ env->ExceptionClear();
+
+ jstring tagstr = env->NewStringUTF(LOG_TAG);
+ jstring msgstr = env->NewStringUTF(msg);
+
+ if ((tagstr == NULL) || (msgstr == NULL)) {
+ env->ExceptionClear(); /* assume exception (OOM?) was thrown */
+ LOGE("Unable to call Log.e()\n");
+ LOGE("%s", msg);
+ goto bail;
+ }
+
+ env->CallStaticIntMethod(
+ gLogOffsets.mClass, gLogOffsets.mLogE, tagstr, msgstr, excep);
+ if (env->ExceptionCheck()) {
+ /* attempting to log the failure has failed */
+ LOGW("Failed trying to log exception, msg='%s'\n", msg);
+ env->ExceptionClear();
+ }
+
+ if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
+ /*
+ * It's an Error: Reraise the exception, detach this thread, and
+ * wait for the fireworks. Die even more blatantly after a minute
+ * if the gentler attempt doesn't do the trick.
+ *
+ * The GetJavaVM function isn't on the "approved" list of JNI calls
+ * that can be made while an exception is pending, so we want to
+ * get the VM ptr, throw the exception, and then detach the thread.
+ */
+ JavaVM* vm = jnienv_to_javavm(env);
+ env->Throw(excep);
+ vm->DetachCurrentThread();
+ sleep(60);
+ LOGE("Forcefully exiting");
+ exit(1);
+ *((int *) 1) = 1;
+ }
+
+bail:
+ /* discard local refs created for us by VM */
+ env->DeleteLocalRef(tagstr);
+ env->DeleteLocalRef(msgstr);
+}
+
+class JavaBBinderHolder;
+
+class JavaBBinder : public BBinder
+{
+public:
+ JavaBBinder(JNIEnv* env, jobject object)
+ : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
+ {
+ LOGV("Creating JavaBBinder %p\n", this);
+ android_atomic_inc(&gNumLocalRefs);
+ incRefsCreated(env);
+ }
+
+ bool checkSubclass(const void* subclassID) const
+ {
+ return subclassID == &gBinderOffsets;
+ }
+
+ jobject object() const
+ {
+ return mObject;
+ }
+
+protected:
+ virtual ~JavaBBinder()
+ {
+ LOGV("Destroying JavaBBinder %p\n", this);
+ android_atomic_dec(&gNumLocalRefs);
+ JNIEnv* env = javavm_to_jnienv(mVM);
+ env->DeleteGlobalRef(mObject);
+ }
+
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
+ {
+ JNIEnv* env = javavm_to_jnienv(mVM);
+
+ LOGV("onTransact() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
+
+ //printf("Transact from %p to Java code sending: ", this);
+ //data.print();
+ //printf("\n");
+ jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
+ code, (int32_t)&data, (int32_t)reply, flags);
+ jthrowable excep = env->ExceptionOccurred();
+ if (excep) {
+ report_exception(env, excep,
+ "*** Uncaught remote exception! "
+ "(Exceptions are not yet supported across processes.)");
+ res = JNI_FALSE;
+
+ /* clean up JNI local ref -- we don't return to Java code */
+ env->DeleteLocalRef(excep);
+ }
+
+ //aout << "onTransact to Java code; result=" << res << endl
+ // << "Transact from " << this << " to Java code returning "
+ // << reply << ": " << *reply << endl;
+ return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
+ }
+
+ virtual status_t dump(int fd, const Vector<String16>& args)
+ {
+ return 0;
+ }
+
+private:
+ JavaVM* const mVM;
+ jobject const mObject;
+};
+
+// ----------------------------------------------------------------------------
+
+class JavaBBinderHolder : public RefBase
+{
+public:
+ JavaBBinderHolder(JNIEnv* env, jobject object)
+ : mObject(object)
+ {
+ LOGV("Creating JavaBBinderHolder for Object %p\n", object);
+ }
+ ~JavaBBinderHolder()
+ {
+ LOGV("Destroying JavaBBinderHolder for Object %p\n", mObject);
+ }
+
+ sp<JavaBBinder> get(JNIEnv* env)
+ {
+ AutoMutex _l(mLock);
+ sp<JavaBBinder> b = mBinder.promote();
+ if (b == NULL) {
+ b = new JavaBBinder(env, mObject);
+ mBinder = b;
+ LOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",
+ b.get(), b->getWeakRefs(), mObject, b->getWeakRefs()->getWeakCount());
+ }
+
+ return b;
+ }
+
+ sp<JavaBBinder> getExisting()
+ {
+ AutoMutex _l(mLock);
+ return mBinder.promote();
+ }
+
+private:
+ Mutex mLock;
+ jobject mObject;
+ wp<JavaBBinder> mBinder;
+};
+
+// ----------------------------------------------------------------------------
+
+class JavaDeathRecipient : public IBinder::DeathRecipient
+{
+public:
+ JavaDeathRecipient(JNIEnv* env, jobject object)
+ : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
+ mHoldsRef(true)
+ {
+ incStrong(this);
+ android_atomic_inc(&gNumDeathRefs);
+ incRefsCreated(env);
+ }
+
+ void binderDied(const wp<IBinder>& who)
+ {
+ JNIEnv* env = javavm_to_jnienv(mVM);
+
+ LOGV("Receiving binderDied() on JavaDeathRecipient %p\n", this);
+
+ env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
+ gBinderProxyOffsets.mSendDeathNotice, mObject);
+ jthrowable excep = env->ExceptionOccurred();
+ if (excep) {
+ report_exception(env, excep,
+ "*** Uncaught exception returned from death notification!");
+ }
+
+ clearReference();
+ }
+
+ void clearReference()
+ {
+ bool release = false;
+ mLock.lock();
+ if (mHoldsRef) {
+ mHoldsRef = false;
+ release = true;
+ }
+ mLock.unlock();
+ if (release) {
+ decStrong(this);
+ }
+ }
+
+protected:
+ virtual ~JavaDeathRecipient()
+ {
+ //LOGI("Removing death ref: recipient=%p\n", mObject);
+ android_atomic_dec(&gNumDeathRefs);
+ JNIEnv* env = javavm_to_jnienv(mVM);
+ env->DeleteGlobalRef(mObject);
+ }
+
+private:
+ JavaVM* const mVM;
+ jobject const mObject;
+ Mutex mLock;
+ bool mHoldsRef;
+};
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie)
+{
+ android_atomic_dec(&gNumProxyRefs);
+ JNIEnv* env = javavm_to_jnienv((JavaVM*)cleanupCookie);
+ env->DeleteGlobalRef((jobject)obj);
+}
+
+static Mutex mProxyLock;
+
+jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
+{
+ if (val == NULL) return NULL;
+
+ if (val->checkSubclass(&gBinderOffsets)) {
+ // One of our own!
+ jobject object = static_cast<JavaBBinder*>(val.get())->object();
+ //printf("objectForBinder %p: it's our own %p!\n", val.get(), object);
+ return object;
+ }
+
+ // For the rest of the function we will hold this lock, to serialize
+ // looking/creation of Java proxies for native Binder proxies.
+ AutoMutex _l(mProxyLock);
+
+ // Someone else's... do we know about it?
+ jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
+ if (object != NULL) {
+ jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet);
+ if (res != NULL) {
+ LOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
+ return res;
+ }
+ LOGV("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
+ android_atomic_dec(&gNumProxyRefs);
+ val->detachObject(&gBinderProxyOffsets);
+ env->DeleteGlobalRef(object);
+ }
+
+ object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
+ if (object != NULL) {
+ LOGV("objectForBinder %p: created new %p!\n", val.get(), object);
+ // The proxy holds a reference to the native object.
+ env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
+ val->incStrong(object);
+
+ // The native object needs to hold a weak reference back to the
+ // proxy, so we can retrieve the same proxy if it is still active.
+ jobject refObject = env->NewGlobalRef(
+ env->GetObjectField(object, gBinderProxyOffsets.mSelf));
+ val->attachObject(&gBinderProxyOffsets, refObject,
+ jnienv_to_javavm(env), proxy_cleanup);
+
+ // Note that a new object reference has been created.
+ android_atomic_inc(&gNumProxyRefs);
+ incRefsCreated(env);
+ }
+
+ return object;
+}
+
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
+{
+ if (obj == NULL) return NULL;
+
+ if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
+ JavaBBinderHolder* jbh = (JavaBBinderHolder*)
+ env->GetIntField(obj, gBinderOffsets.mObject);
+ return jbh != NULL ? jbh->get(env) : NULL;
+ }
+
+ if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
+ return (IBinder*)
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ }
+
+ LOGW("ibinderForJavaObject: %p is not a Binder object", obj);
+ return NULL;
+}
+
+Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
+{
+ if (obj) {
+ Parcel* p = (Parcel*)env->GetIntField(obj, gParcelOffsets.mObject);
+ if (p != NULL) {
+ return p;
+ }
+ jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
+ }
+ return NULL;
+}
+
+jobject newFileDescriptor(JNIEnv* env, int fd)
+{
+ jobject object = env->NewObject(
+ gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
+ if (object != NULL) {
+ //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
+ env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
+ }
+ return object;
+}
+
+jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc)
+{
+ return env->NewObject(
+ gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fileDesc);
+}
+
+void signalExceptionForError(JNIEnv* env, jobject obj, status_t err)
+{
+ switch (err) {
+ case UNKNOWN_ERROR:
+ jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
+ break;
+ case NO_MEMORY:
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ break;
+ case INVALID_OPERATION:
+ jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
+ break;
+ case BAD_VALUE:
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ break;
+ case BAD_INDEX:
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
+ break;
+ case BAD_TYPE:
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ break;
+ case NAME_NOT_FOUND:
+ jniThrowException(env, "java/util/NoSuchElementException", NULL);
+ break;
+ case PERMISSION_DENIED:
+ jniThrowException(env, "java/lang/SecurityException", NULL);
+ break;
+ case NOT_ENOUGH_DATA:
+ jniThrowException(env, "android/os/ParcelFormatException", "Not enough data");
+ break;
+ case NO_INIT:
+ jniThrowException(env, "java/lang/RuntimeException", "Not initialized");
+ break;
+ case ALREADY_EXISTS:
+ jniThrowException(env, "java/lang/RuntimeException", "Item already exists");
+ break;
+ case DEAD_OBJECT:
+ jniThrowException(env, "android/os/DeadObjectException", NULL);
+ break;
+ case UNKNOWN_TRANSACTION:
+ jniThrowException(env, "java/lang/RuntimeException", "Unknown transaction code");
+ break;
+ case FAILED_TRANSACTION:
+ LOGE("!!! FAILED BINDER TRANSACTION !!!");
+ //jniThrowException(env, "java/lang/OutOfMemoryError", "Binder transaction too large");
+ break;
+ default:
+ LOGE("Unknown binder error code. 0x%x", err);
+ }
+}
+
+}
+
+// ----------------------------------------------------------------------------
+
+static jint android_os_Binder_getCallingPid(JNIEnv* env, jobject clazz)
+{
+ return IPCThreadState::self()->getCallingPid();
+}
+
+static jint android_os_Binder_getCallingUid(JNIEnv* env, jobject clazz)
+{
+ return IPCThreadState::self()->getCallingUid();
+}
+
+static jlong android_os_Binder_clearCallingIdentity(JNIEnv* env, jobject clazz)
+{
+ return IPCThreadState::self()->clearCallingIdentity();
+}
+
+static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
+{
+ IPCThreadState::self()->restoreCallingIdentity(token);
+}
+
+static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
+{
+ IPCThreadState::self()->flushCommands();
+}
+
+static void android_os_Binder_init(JNIEnv* env, jobject clazz)
+{
+ JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz);
+ if (jbh == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return;
+ }
+ LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh);
+ jbh->incStrong(clazz);
+ env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);
+}
+
+static void android_os_Binder_destroy(JNIEnv* env, jobject clazz)
+{
+ JavaBBinderHolder* jbh = (JavaBBinderHolder*)
+ env->GetIntField(clazz, gBinderOffsets.mObject);
+ env->SetIntField(clazz, gBinderOffsets.mObject, 0);
+ LOGV("Java Binder %p: removing ref on holder %p", clazz, jbh);
+ jbh->decStrong(clazz);
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gBinderMethods[] = {
+ /* name, signature, funcPtr */
+ { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
+ { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
+ { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
+ { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
+ { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
+ { "init", "()V", (void*)android_os_Binder_init },
+ { "destroy", "()V", (void*)android_os_Binder_destroy }
+};
+
+const char* const kBinderPathName = "android/os/Binder";
+
+static int int_register_android_os_Binder(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass(kBinderPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Binder");
+
+ gBinderOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gBinderOffsets.mExecTransact
+ = env->GetMethodID(clazz, "execTransact", "(IIII)Z");
+ assert(gBinderOffsets.mExecTransact);
+
+ gBinderOffsets.mObject
+ = env->GetFieldID(clazz, "mObject", "I");
+ assert(gBinderOffsets.mObject);
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kBinderPathName,
+ gBinderMethods, NELEM(gBinderMethods));
+}
+
+// ****************************************************************************
+// ****************************************************************************
+// ****************************************************************************
+
+namespace android {
+
+jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz)
+{
+ return gNumLocalRefs;
+}
+
+jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz)
+{
+ return gNumProxyRefs;
+}
+
+jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz)
+{
+ return gNumDeathRefs;
+}
+
+}
+
+// ****************************************************************************
+// ****************************************************************************
+// ****************************************************************************
+
+static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
+{
+ sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
+ return javaObjectForIBinder(env, b);
+}
+
+static void android_os_BinderInternal_joinThreadPool(JNIEnv* env, jobject clazz)
+{
+ sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
+ android::IPCThreadState::self()->joinThreadPool();
+}
+
+static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
+{
+ LOGV("Gc has executed, clearing binder ops");
+ android_atomic_and(0, &gNumRefsCreated);
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gBinderInternalMethods[] = {
+ /* name, signature, funcPtr */
+ { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
+ { "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
+ { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
+};
+
+const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
+
+static int int_register_android_os_BinderInternal(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass(kBinderInternalPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class com.android.internal.os.BinderInternal");
+
+ gBinderInternalOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gBinderInternalOffsets.mForceGc
+ = env->GetStaticMethodID(clazz, "forceBinderGc", "()V");
+ assert(gBinderInternalOffsets.mForceGc);
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kBinderInternalPathName,
+ gBinderInternalMethods, NELEM(gBinderInternalMethods));
+}
+
+// ****************************************************************************
+// ****************************************************************************
+// ****************************************************************************
+
+static jboolean android_os_BinderProxy_pingBinder(JNIEnv* env, jobject obj)
+{
+ IBinder* target = (IBinder*)
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ if (target == NULL) {
+ return JNI_FALSE;
+ }
+ status_t err = target->pingBinder();
+ return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
+}
+
+static jstring android_os_BinderProxy_getInterfaceDescriptor(JNIEnv* env, jobject obj)
+{
+ IBinder* target = (IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ if (target != NULL) {
+ String16 desc = target->getInterfaceDescriptor();
+ return env->NewString(desc.string(), desc.size());
+ }
+ jniThrowException(env, "java/lang/RuntimeException",
+ "No binder found for object");
+ return NULL;
+}
+
+static jboolean android_os_BinderProxy_isBinderAlive(JNIEnv* env, jobject obj)
+{
+ IBinder* target = (IBinder*)
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ if (target == NULL) {
+ return JNI_FALSE;
+ }
+ bool alive = target->isBinderAlive();
+ return alive ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
+ jint code, jobject dataObj,
+ jobject replyObj, jint flags)
+{
+ if (dataObj == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return JNI_FALSE;
+ }
+
+ Parcel* data = parcelForJavaObject(env, dataObj);
+ if (data == NULL) {
+ return JNI_FALSE;
+ }
+ Parcel* reply = parcelForJavaObject(env, replyObj);
+ if (reply == NULL && replyObj != NULL) {
+ return JNI_FALSE;
+ }
+
+ IBinder* target = (IBinder*)
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ if (target == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
+ return JNI_FALSE;
+ }
+
+ LOGV("Java code calling transact on %p in Java object %p with code %d\n",
+ target, obj, code);
+ //printf("Transact from Java code to %p sending: ", target); data->print();
+ status_t err = target->transact(code, *data, reply, flags);
+ //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
+ if (err == NO_ERROR) {
+ return JNI_TRUE;
+ } else if (err == UNKNOWN_TRANSACTION) {
+ return JNI_FALSE;
+ }
+
+ signalExceptionForError(env, obj, err);
+ return JNI_FALSE;
+}
+
+static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
+ jobject recipient, jint flags)
+{
+ if (recipient == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ IBinder* target = (IBinder*)
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ if (target == NULL) {
+ LOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient);
+ assert(false);
+ }
+
+ LOGV("linkToDeath: binder=%p recipient=%p\n", target, recipient);
+
+ if (!target->localBinder()) {
+ sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient);
+ status_t err = target->linkToDeath(jdr, recipient, flags);
+ if (err != NO_ERROR) {
+ // Failure adding the death recipient, so clear its reference
+ // now.
+ jdr->clearReference();
+ signalExceptionForError(env, obj, err);
+ }
+ }
+}
+
+static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
+ jobject recipient, jint flags)
+{
+ jboolean res = JNI_FALSE;
+ if (recipient == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return res;
+ }
+
+ IBinder* target = (IBinder*)
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ if (target == NULL) {
+ LOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient);
+ return JNI_FALSE;
+ }
+
+ LOGV("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
+
+ if (!target->localBinder()) {
+ wp<IBinder::DeathRecipient> dr;
+ status_t err = target->unlinkToDeath(NULL, recipient, flags, &dr);
+ if (err == NO_ERROR && dr != NULL) {
+ sp<IBinder::DeathRecipient> sdr = dr.promote();
+ JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
+ if (jdr != NULL) {
+ jdr->clearReference();
+ }
+ }
+ if (err == NO_ERROR || err == DEAD_OBJECT) {
+ res = JNI_TRUE;
+ } else {
+ jniThrowException(env, "java/util/NoSuchElementException",
+ "Death link does not exist");
+ }
+ }
+
+ return res;
+}
+
+static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
+{
+ IBinder* b = (IBinder*)
+ env->GetIntField(obj, gBinderProxyOffsets.mObject);
+ LOGV("Destroying BinderProxy %p: binder=%p\n", obj, b);
+ env->SetIntField(obj, gBinderProxyOffsets.mObject, 0);
+ b->decStrong(obj);
+ IPCThreadState::self()->flushCommands();
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gBinderProxyMethods[] = {
+ /* name, signature, funcPtr */
+ {"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
+ {"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
+ {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
+ {"transact", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
+ {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
+ {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
+ {"destroy", "()V", (void*)android_os_BinderProxy_destroy},
+};
+
+const char* const kBinderProxyPathName = "android/os/BinderProxy";
+
+static int int_register_android_os_BinderProxy(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("java/lang/ref/WeakReference");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.lang.ref.WeakReference");
+ gWeakReferenceOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gWeakReferenceOffsets.mGet
+ = env->GetMethodID(clazz, "get", "()Ljava/lang/Object;");
+ assert(gWeakReferenceOffsets.mGet);
+
+ clazz = env->FindClass("java/lang/Error");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.lang.Error");
+ gErrorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+
+ clazz = env->FindClass(kBinderProxyPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.BinderProxy");
+
+ gBinderProxyOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gBinderProxyOffsets.mConstructor
+ = env->GetMethodID(clazz, "<init>", "()V");
+ assert(gBinderProxyOffsets.mConstructor);
+ gBinderProxyOffsets.mSendDeathNotice
+ = env->GetStaticMethodID(clazz, "sendDeathNotice", "(Landroid/os/IBinder$DeathRecipient;)V");
+ assert(gBinderProxyOffsets.mSendDeathNotice);
+
+ gBinderProxyOffsets.mObject
+ = env->GetFieldID(clazz, "mObject", "I");
+ assert(gBinderProxyOffsets.mObject);
+ gBinderProxyOffsets.mSelf
+ = env->GetFieldID(clazz, "mSelf", "Ljava/lang/ref/WeakReference;");
+ assert(gBinderProxyOffsets.mSelf);
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kBinderProxyPathName,
+ gBinderProxyMethods, NELEM(gBinderProxyMethods));
+}
+
+// ****************************************************************************
+// ****************************************************************************
+// ****************************************************************************
+
+static jint android_os_Parcel_dataSize(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ return parcel ? parcel->dataSize() : 0;
+}
+
+static jint android_os_Parcel_dataAvail(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ return parcel ? parcel->dataAvail() : 0;
+}
+
+static jint android_os_Parcel_dataPosition(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ return parcel ? parcel->dataPosition() : 0;
+}
+
+static jint android_os_Parcel_dataCapacity(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ return parcel ? parcel->dataCapacity() : 0;
+}
+
+static void android_os_Parcel_setDataSize(JNIEnv* env, jobject clazz, jint size)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->setDataSize(size);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_setDataPosition(JNIEnv* env, jobject clazz, jint pos)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ parcel->setDataPosition(pos);
+ }
+}
+
+static void android_os_Parcel_setDataCapacity(JNIEnv* env, jobject clazz, jint size)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->setDataCapacity(size);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz,
+ jobject data, jint offset,
+ jint length)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel == NULL) {
+ return;
+ }
+ void *dest;
+
+ const status_t err = parcel->writeInt32(length);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+
+ dest = parcel->writeInplace(length);
+
+ if (dest == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return;
+ }
+
+ jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
+ if (ar) {
+ memcpy(dest, ar, length);
+ env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
+ }
+}
+
+
+static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->writeInt32(val);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_writeLong(JNIEnv* env, jobject clazz, jlong val)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->writeInt64(val);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_writeFloat(JNIEnv* env, jobject clazz, jfloat val)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->writeFloat(val);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_writeDouble(JNIEnv* env, jobject clazz, jdouble val)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->writeDouble(val);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_writeString(JNIEnv* env, jobject clazz, jstring val)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ status_t err = NO_MEMORY;
+ if (val) {
+ const jchar* str = env->GetStringCritical(val, 0);
+ if (str) {
+ err = parcel->writeString16(str, env->GetStringLength(val));
+ env->ReleaseStringCritical(val, str);
+ }
+ } else {
+ err = parcel->writeString16(NULL, 0);
+ }
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jobject clazz, jobject object)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const status_t err = parcel->writeDupFileDescriptor(
+ env->GetIntField(object, gFileDescriptorOffsets.mDescriptor));
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ }
+ }
+}
+
+static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jobject clazz)
+{
+ jbyteArray ret = NULL;
+
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ int32_t len = parcel->readInt32();
+
+ // sanity check the stored length against the true data size
+ if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
+ ret = env->NewByteArray(len);
+
+ if (ret != NULL) {
+ jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
+ if (a2) {
+ const void* data = parcel->readInplace(len);
+ memcpy(a2, data, len);
+ env->ReleasePrimitiveArrayCritical(ret, a2, 0);
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ return parcel->readInt32();
+ }
+ return 0;
+}
+
+static jlong android_os_Parcel_readLong(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ return parcel->readInt64();
+ }
+ return 0;
+}
+
+static jfloat android_os_Parcel_readFloat(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ return parcel->readFloat();
+ }
+ return 0;
+}
+
+static jdouble android_os_Parcel_readDouble(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ return parcel->readDouble();
+ }
+ return 0;
+}
+
+static jstring android_os_Parcel_readString(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ size_t len;
+ const char16_t* str = parcel->readString16Inplace(&len);
+ if (str) {
+ return env->NewString(str, len);
+ }
+ return NULL;
+ }
+ return NULL;
+}
+
+static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ return javaObjectForIBinder(env, parcel->readStrongBinder());
+ }
+ return NULL;
+}
+
+static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ int fd = parcel->readFileDescriptor();
+ if (fd < 0) return NULL;
+ fd = dup(fd);
+ if (fd < 0) return NULL;
+ jobject object = env->NewObject(
+ gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
+ if (object != NULL) {
+ //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
+ env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
+ }
+ return object;
+ }
+ return NULL;
+}
+
+static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
+ jstring name, jint mode)
+{
+ if (name == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
+ const jchar* str = env->GetStringCritical(name, 0);
+ if (str == NULL) {
+ // Whatever, whatever.
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+ String8 name8(str, env->GetStringLength(name));
+ env->ReleaseStringCritical(name, str);
+ int flags=0;
+ switch (mode&0x30000000) {
+ case 0:
+ case 0x10000000:
+ flags = O_RDONLY;
+ break;
+ case 0x20000000:
+ flags = O_WRONLY;
+ break;
+ case 0x30000000:
+ flags = O_RDWR;
+ break;
+ }
+
+ if (mode&0x08000000) flags |= O_CREAT;
+ if (mode&0x04000000) flags |= O_TRUNC;
+
+ int realMode = S_IRWXU|S_IRWXG;
+ if (mode&0x00000001) realMode |= S_IROTH;
+ if (mode&0x00000002) realMode |= S_IWOTH;
+
+ int fd = open(name8.string(), flags, realMode);
+ if (fd < 0) {
+ jniThrowException(env, "java/io/FileNotFoundException", NULL);
+ return NULL;
+ }
+ jobject object = newFileDescriptor(env, fd);
+ if (object == NULL) {
+ close(fd);
+ }
+ return object;
+}
+
+static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
+{
+ int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+ if (fd >= 0) {
+ env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
+ //LOGI("Closing ParcelFileDescriptor %d\n", fd);
+ close(fd);
+ }
+}
+
+static void android_os_Parcel_freeBuffer(JNIEnv* env, jobject clazz)
+{
+ int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
+ if (own) {
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ //LOGI("Parcel.freeBuffer() called for C++ Parcel %p\n", parcel);
+ parcel->freeData();
+ }
+ }
+}
+
+static void android_os_Parcel_init(JNIEnv* env, jobject clazz, jint parcelInt)
+{
+ Parcel* parcel = (Parcel*)parcelInt;
+ int own = 0;
+ if (!parcel) {
+ //LOGI("Initializing obj %p: creating new Parcel\n", clazz);
+ own = 1;
+ parcel = new Parcel;
+ } else {
+ //LOGI("Initializing obj %p: given existing Parcel %p\n", clazz, parcel);
+ }
+ if (parcel == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return;
+ }
+ //LOGI("Initializing obj %p from C++ Parcel %p, own=%d\n", clazz, parcel, own);
+ env->SetIntField(clazz, gParcelOffsets.mOwnObject, own);
+ env->SetIntField(clazz, gParcelOffsets.mObject, (int)parcel);
+}
+
+static void android_os_Parcel_destroy(JNIEnv* env, jobject clazz)
+{
+ int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
+ if (own) {
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ env->SetIntField(clazz, gParcelOffsets.mObject, 0);
+ //LOGI("Destroying obj %p: deleting C++ Parcel %p\n", clazz, parcel);
+ delete parcel;
+ } else {
+ env->SetIntField(clazz, gParcelOffsets.mObject, 0);
+ //LOGI("Destroying obj %p: leaving C++ Parcel %p\n", clazz);
+ }
+}
+
+static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jobject clazz)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel == NULL) {
+ return NULL;
+ }
+
+ // do not marshall if there are binder objects in the parcel
+ if (parcel->objectsCount())
+ {
+ jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
+ return NULL;
+ }
+
+ jbyteArray ret = env->NewByteArray(parcel->dataSize());
+
+ if (ret != NULL)
+ {
+ jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
+ if (array != NULL)
+ {
+ memcpy(array, parcel->data(), parcel->dataSize());
+ env->ReleasePrimitiveArrayCritical(ret, array, 0);
+ }
+ }
+
+ return ret;
+}
+
+static void android_os_Parcel_unmarshall(JNIEnv* env, jobject clazz, jbyteArray data, jint offset, jint length)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel == NULL || length < 0) {
+ return;
+ }
+
+ jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
+ if (array)
+ {
+ parcel->setDataSize(length);
+ parcel->setDataPosition(0);
+
+ void* raw = parcel->writeInplace(length);
+ memcpy(raw, (array + offset), length);
+
+ env->ReleasePrimitiveArrayCritical(data, array, 0);
+ }
+}
+
+static void android_os_Parcel_appendFrom(JNIEnv* env, jobject clazz, jobject parcel, jint offset, jint length)
+{
+ Parcel* thisParcel = parcelForJavaObject(env, clazz);
+ if (thisParcel == NULL) {
+ return;
+ }
+ Parcel* otherParcel = parcelForJavaObject(env, parcel);
+ if (otherParcel == NULL) {
+ return;
+ }
+
+ (void) thisParcel->appendFrom(otherParcel, offset, length);
+}
+
+static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jobject clazz)
+{
+ jboolean ret = JNI_FALSE;
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ if (parcel->hasFileDescriptors()) {
+ ret = JNI_TRUE;
+ }
+ }
+ return ret;
+}
+
+static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jobject clazz, jstring name)
+{
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ // In the current implementation, the token is just the serialized interface name that
+ // the caller expects to be invoking
+ const jchar* str = env->GetStringCritical(name, 0);
+ if (str != NULL) {
+ parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
+ env->ReleaseStringCritical(name, str);
+ }
+ }
+}
+
+static void android_os_Parcel_enforceInterface(JNIEnv* env, jobject clazz, jstring name)
+{
+ jboolean ret = JNI_FALSE;
+
+ Parcel* parcel = parcelForJavaObject(env, clazz);
+ if (parcel != NULL) {
+ const jchar* str = env->GetStringCritical(name, 0);
+ if (str) {
+ bool isValid = parcel->enforceInterface(String16(str, env->GetStringLength(name)));
+ env->ReleaseStringCritical(name, str);
+ if (isValid) {
+ return; // everything was correct -> return silently
+ }
+ }
+ }
+
+ // all error conditions wind up here
+ jniThrowException(env, "java/lang/SecurityException",
+ "Binder invocation to an incorrect interface");
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gParcelMethods[] = {
+ {"dataSize", "()I", (void*)android_os_Parcel_dataSize},
+ {"dataAvail", "()I", (void*)android_os_Parcel_dataAvail},
+ {"dataPosition", "()I", (void*)android_os_Parcel_dataPosition},
+ {"dataCapacity", "()I", (void*)android_os_Parcel_dataCapacity},
+ {"setDataSize", "(I)V", (void*)android_os_Parcel_setDataSize},
+ {"setDataPosition", "(I)V", (void*)android_os_Parcel_setDataPosition},
+ {"setDataCapacity", "(I)V", (void*)android_os_Parcel_setDataCapacity},
+ {"writeNative", "([BII)V", (void*)android_os_Parcel_writeNative},
+ {"writeInt", "(I)V", (void*)android_os_Parcel_writeInt},
+ {"writeLong", "(J)V", (void*)android_os_Parcel_writeLong},
+ {"writeFloat", "(F)V", (void*)android_os_Parcel_writeFloat},
+ {"writeDouble", "(D)V", (void*)android_os_Parcel_writeDouble},
+ {"writeString", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeString},
+ {"writeStrongBinder", "(Landroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
+ {"writeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
+ {"createByteArray", "()[B", (void*)android_os_Parcel_createByteArray},
+ {"readInt", "()I", (void*)android_os_Parcel_readInt},
+ {"readLong", "()J", (void*)android_os_Parcel_readLong},
+ {"readFloat", "()F", (void*)android_os_Parcel_readFloat},
+ {"readDouble", "()D", (void*)android_os_Parcel_readDouble},
+ {"readString", "()Ljava/lang/String;", (void*)android_os_Parcel_readString},
+ {"readStrongBinder", "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
+ {"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
+ {"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
+ {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
+ {"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer},
+ {"init", "(I)V", (void*)android_os_Parcel_init},
+ {"destroy", "()V", (void*)android_os_Parcel_destroy},
+ {"marshall", "()[B", (void*)android_os_Parcel_marshall},
+ {"unmarshall", "([BII)V", (void*)android_os_Parcel_unmarshall},
+ {"appendFrom", "(Landroid/os/Parcel;II)V", (void*)android_os_Parcel_appendFrom},
+ {"hasFileDescriptors", "()Z", (void*)android_os_Parcel_hasFileDescriptors},
+ {"writeInterfaceToken", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
+ {"enforceInterface", "(Ljava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
+};
+
+const char* const kParcelPathName = "android/os/Parcel";
+
+static int int_register_android_os_Parcel(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/util/Log");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.util.Log");
+ gLogOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gLogOffsets.mLogE = env->GetStaticMethodID(
+ clazz, "e", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
+ assert(gLogOffsets.mLogE);
+
+ clazz = env->FindClass("java/io/FileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
+ gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gFileDescriptorOffsets.mConstructor
+ = env->GetMethodID(clazz, "<init>", "()V");
+ gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
+ LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
+ "Unable to find descriptor field in java.io.FileDescriptor");
+
+ clazz = env->FindClass("android/os/ParcelFileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+ gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gParcelFileDescriptorOffsets.mConstructor
+ = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+
+ clazz = env->FindClass(kParcelPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
+
+ gParcelOffsets.mObject
+ = env->GetFieldID(clazz, "mObject", "I");
+ gParcelOffsets.mOwnObject
+ = env->GetFieldID(clazz, "mOwnObject", "I");
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kParcelPathName,
+ gParcelMethods, NELEM(gParcelMethods));
+}
+
+int register_android_os_Binder(JNIEnv* env)
+{
+ if (int_register_android_os_Binder(env) < 0)
+ return -1;
+ if (int_register_android_os_BinderInternal(env) < 0)
+ return -1;
+ if (int_register_android_os_BinderProxy(env) < 0)
+ return -1;
+ if (int_register_android_os_Parcel(env) < 0)
+ return -1;
+ return 0;
+}
+
+namespace android {
+
+// Returns the Unix file descriptor for a ParcelFileDescriptor object
+int getParcelFileDescriptorFD(JNIEnv* env, jobject object)
+{
+ return env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+}
+
+}
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
new file mode 100644
index 0000000..16d993d
--- /dev/null
+++ b/core/jni/android_util_Binder.h
@@ -0,0 +1,35 @@
+/* //device/libs/android_runtime/android_util_Binder.h
+**
+** Copyright 2006, 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.
+*/
+
+#include <utils/IBinder.h>
+
+#include "jni.h"
+
+namespace android {
+
+// Converstion to/from Java IBinder Object and C++ IBinder instance.
+extern jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val);
+extern sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
+
+// Conversion from Java Parcel Object to C++ Parcel instance.
+// Note: does not type checking; must guarantee jobject is a Java Parcel
+extern Parcel* parcelForJavaObject(JNIEnv* env, jobject obj);
+
+extern jobject newFileDescriptor(JNIEnv* env, int fd);
+extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc);
+
+}
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
new file mode 100644
index 0000000..d0cac18
--- /dev/null
+++ b/core/jni/android_util_EventLog.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <fcntl.h>
+
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "jni.h"
+#include "utils/logger.h"
+
+#define END_DELIMITER '\n'
+#define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER))
+#define LONG_BUFFER_SIZE (sizeof(jbyte)+sizeof(jlong)+sizeof(END_DELIMITER))
+#define INITAL_BUFFER_CAPACITY 256
+
+#define MAX(a,b) ((a>b)?a:b)
+
+namespace android {
+
+static jclass gCollectionClass;
+static jmethodID gCollectionAddID;
+
+static jclass gEventClass;
+static jmethodID gEventInitID;
+
+static jclass gIntegerClass;
+static jfieldID gIntegerValueID;
+
+static jclass gListClass;
+static jfieldID gListItemsID;
+
+static jclass gLongClass;
+static jfieldID gLongValueID;
+
+static jclass gStringClass;
+
+struct ByteBuf {
+ size_t len;
+ size_t capacity;
+ uint8_t* buf;
+
+ ByteBuf(size_t initSize) {
+ buf = (uint8_t*)malloc(initSize);
+ len = 0;
+ capacity = initSize;
+ }
+
+ ~ByteBuf() {
+ free(buf);
+ }
+
+ bool ensureExtraCapacity(size_t extra) {
+ size_t spaceNeeded = len + extra;
+ if (spaceNeeded > capacity) {
+ size_t newCapacity = MAX(spaceNeeded, 2 * capacity);
+ void* newBuf = realloc(buf, newCapacity);
+ if (newBuf == NULL) {
+ return false;
+ }
+ capacity = newCapacity;
+ buf = (uint8_t*)newBuf;
+ return true;
+ } else {
+ return true;
+ }
+ }
+
+ void putIntEvent(jint value) {
+ bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
+ buf[len++] = EVENT_TYPE_INT;
+ memcpy(buf+len, &value, sizeof(jint));
+ len += sizeof(jint);
+ }
+
+ void putByte(uint8_t value) {
+ bool succeeded = ensureExtraCapacity(sizeof(uint8_t));
+ buf[len++] = value;
+ }
+
+ void putLongEvent(jlong value) {
+ bool succeeded = ensureExtraCapacity(LONG_BUFFER_SIZE);
+ buf[len++] = EVENT_TYPE_LONG;
+ memcpy(buf+len, &value, sizeof(jlong));
+ len += sizeof(jlong);
+ }
+
+
+ void putStringEvent(JNIEnv* env, jstring value) {
+ const char* strValue = env->GetStringUTFChars(value, NULL);
+ uint32_t strLen = strlen(strValue); //env->GetStringUTFLength(value);
+ bool succeeded = ensureExtraCapacity(1 + sizeof(uint32_t) + strLen);
+ buf[len++] = EVENT_TYPE_STRING;
+ memcpy(buf+len, &strLen, sizeof(uint32_t));
+ len += sizeof(uint32_t);
+ memcpy(buf+len, strValue, strLen);
+ env->ReleaseStringUTFChars(value, strValue);
+ len += strLen;
+ }
+
+ void putList(JNIEnv* env, jobject list) {
+ jobjectArray items = (jobjectArray) env->GetObjectField(list, gListItemsID);
+ if (items == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ jsize numItems = env->GetArrayLength(items);
+ putByte(EVENT_TYPE_LIST);
+ putByte(numItems);
+ // We'd like to call GetPrimitveArrayCritical() but that might
+ // not be safe since we're going to be doing some I/O
+ for (int i = 0; i < numItems; i++) {
+ jobject item = env->GetObjectArrayElement(items, i);
+ if (env->IsInstanceOf(item, gIntegerClass)) {
+ jint intVal = env->GetIntField(item, gIntegerValueID);
+ putIntEvent(intVal);
+ } else if (env->IsInstanceOf(item, gLongClass)) {
+ jlong longVal = env->GetLongField(item, gLongValueID);
+ putLongEvent(longVal);
+ } else if (env->IsInstanceOf(item, gStringClass)) {
+ putStringEvent(env, (jstring)item);
+ } else if (env->IsInstanceOf(item, gListClass)) {
+ putList(env, item);
+ } else {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ "Attempt to log an illegal item type.");
+ return;
+ }
+ env->DeleteLocalRef(item);
+ }
+
+ env->DeleteLocalRef(items);
+ }
+};
+
+/*
+ * In class android.util.EventLog:
+ * static native int writeEvent(int tag, int value)
+ */
+static jint android_util_EventLog_writeEvent_Integer(JNIEnv* env, jobject clazz,
+ jint tag, jint value)
+{
+ return android_btWriteLog(tag, EVENT_TYPE_INT, &value, sizeof(value));
+}
+
+/*
+ * In class android.util.EventLog:
+ * static native int writeEvent(long tag, long value)
+ */
+static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
+ jint tag, jlong value)
+{
+ return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
+}
+
+/*
+ * In class android.util.EventLog:
+ * static native int writeEvent(long tag, List value)
+ */
+static jint android_util_EventLog_writeEvent_List(JNIEnv* env, jobject clazz,
+ jint tag, jobject value) {
+ if (value == NULL) {
+ jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
+ env->ThrowNew(clazz, "writeEvent needs a value.");
+ return -1;
+ }
+ ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
+ byteBuf.putList(env, value);
+ byteBuf.putByte((uint8_t)END_DELIMITER);
+ int numBytesPut = byteBuf.len;
+ int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
+ return bytesWritten;
+}
+
+/*
+ * In class android.util.EventLog:
+ * static native int writeEvent(int tag, String value)
+ */
+static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
+ jint tag, jstring value) {
+ if (value == NULL) {
+ jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
+ env->ThrowNew(clazz, "logEvent needs a value.");
+ return -1;
+ }
+
+ ByteBuf byteBuf(INITAL_BUFFER_CAPACITY);
+ byteBuf.putStringEvent(env, value);
+ byteBuf.putByte((uint8_t)END_DELIMITER);
+ int numBytesPut = byteBuf.len;
+ int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut);
+ return bytesWritten;
+}
+
+/*
+ * In class android.util.EventLog:
+ * static native void readEvents(int[] tags, Collection<Event> output)
+ */
+static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
+ jintArray tags,
+ jobject out) {
+ if (tags == NULL || out == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ int fd = open("/dev/" LOGGER_LOG_EVENTS, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ jsize tagLength = env->GetArrayLength(tags);
+ jint *tagValues = env->GetIntArrayElements(tags, NULL);
+
+ uint8_t buf[LOGGER_ENTRY_MAX_LEN];
+ for (;;) {
+ int len = read(fd, buf, sizeof(buf));
+ if (len == 0 || (len < 0 && errno == EAGAIN)) {
+ break;
+ } else if (len < 0) {
+ // This calls env->ThrowNew(), which doesn't throw an exception
+ // now, but sets a flag to trigger an exception after we return.
+ jniThrowIOException(env, errno);
+ break;
+ } else if ((size_t) len < sizeof(logger_entry) + sizeof(int32_t)) {
+ jniThrowException(env, "java/io/IOException", "Event too short");
+ break;
+ }
+
+ logger_entry* entry = (logger_entry*) buf;
+ int32_t tag = * (int32_t*) (buf + sizeof(*entry));
+
+ int found = 0;
+ for (int i = 0; !found && i < tagLength; ++i) {
+ found = (tag == tagValues[i]);
+ }
+
+ if (found) {
+ jsize len = sizeof(*entry) + entry->len;
+ jbyteArray array = env->NewByteArray(len);
+ if (array == NULL) break;
+
+ jbyte *bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, buf, len);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+ jobject event = env->NewObject(gEventClass, gEventInitID, array);
+ if (event == NULL) break;
+
+ env->CallBooleanMethod(out, gCollectionAddID, event);
+ env->DeleteLocalRef(event);
+ env->DeleteLocalRef(array);
+ }
+ }
+
+ close(fd);
+ env->ReleaseIntArrayElements(tags, tagValues, 0);
+}
+
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gRegisterMethods[] = {
+ /* name, signature, funcPtr */
+ { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
+ { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
+ { "writeEvent",
+ "(ILjava/lang/String;)I",
+ (void*) android_util_EventLog_writeEvent_String
+ },
+ { "writeEvent",
+ "(ILandroid/util/EventLog$List;)I",
+ (void*) android_util_EventLog_writeEvent_List
+ },
+ { "readEvents",
+ "([ILjava/util/Collection;)V",
+ (void*) android_util_EventLog_readEvents
+ }
+};
+
+static struct { const char *name; jclass *clazz; } gClasses[] = {
+ { "android/util/EventLog$Event", &gEventClass },
+ { "android/util/EventLog$List", &gListClass },
+ { "java/lang/Integer", &gIntegerClass },
+ { "java/lang/Long", &gLongClass },
+ { "java/lang/String", &gStringClass },
+ { "java/util/Collection", &gCollectionClass },
+};
+
+static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
+ { &gIntegerClass, "value", "I", &gIntegerValueID },
+ { &gListClass, "mItems", "[Ljava/lang/Object;", &gListItemsID },
+ { &gLongClass, "value", "J", &gLongValueID },
+};
+
+static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
+ { &gEventClass, "<init>", "([B)V", &gEventInitID },
+ { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
+};
+
+int register_android_util_EventLog(JNIEnv* env) {
+ for (int i = 0; i < NELEM(gClasses); ++i) {
+ jclass clazz = env->FindClass(gClasses[i].name);
+ if (clazz == NULL) {
+ LOGE("Can't find class: %s\n", gClasses[i].name);
+ return -1;
+ }
+ *gClasses[i].clazz = (jclass) env->NewGlobalRef(clazz);
+ }
+
+ for (int i = 0; i < NELEM(gFields); ++i) {
+ *gFields[i].id = env->GetFieldID(
+ *gFields[i].c, gFields[i].name, gFields[i].ft);
+ if (*gFields[i].id == NULL) {
+ LOGE("Can't find field: %s\n", gFields[i].name);
+ return -1;
+ }
+ }
+
+ for (int i = 0; i < NELEM(gMethods); ++i) {
+ *gMethods[i].id = env->GetMethodID(
+ *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
+ if (*gMethods[i].id == NULL) {
+ LOGE("Can't find method: %s\n", gMethods[i].name);
+ return -1;
+ }
+ }
+
+ return AndroidRuntime::registerNativeMethods(
+ env,
+ "android/util/EventLog",
+ gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
new file mode 100644
index 0000000..794478a
--- /dev/null
+++ b/core/jni/android_util_FileObserver.cpp
@@ -0,0 +1,157 @@
+/* //device/libs/android_runtime/android_util_FileObserver.cpp
+**
+** Copyright 2006, 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.
+*/
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#ifdef HAVE_INOTIFY
+#include <sys/inotify.h>
+#endif
+
+namespace android {
+
+static jmethodID method_onEvent;
+
+static jint android_os_fileobserver_init(JNIEnv* env, jobject object)
+{
+#ifdef HAVE_INOTIFY
+
+ return (jint)inotify_init();
+
+#else // HAVE_INOTIFY
+
+ return -1;
+
+#endif // HAVE_INOTIFY
+}
+
+static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd)
+{
+#ifdef HAVE_INOTIFY
+
+ char event_buf[512];
+ struct inotify_event* event;
+
+ while (1)
+ {
+ int event_pos = 0;
+ int num_bytes = read(fd, event_buf, sizeof(event_buf));
+
+ if (num_bytes < (int)sizeof(*event))
+ {
+ if (errno == EINTR)
+ continue;
+
+ LOGE("***** ERROR! android_os_fileobserver_observe() got a short event!");
+ return;
+ }
+
+ while (num_bytes >= (int)sizeof(*event))
+ {
+ int event_size;
+ event = (struct inotify_event *)(event_buf + event_pos);
+
+ jstring path = NULL;
+
+ if (event->len > 0)
+ {
+ path = env->NewStringUTF(event->name);
+ }
+
+ env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
+
+ event_size = sizeof(*event) + event->len;
+ num_bytes -= event_size;
+ event_pos += event_size;
+ }
+ }
+
+#endif // HAVE_INOTIFY
+}
+
+static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask)
+{
+ int res = -1;
+
+#ifdef HAVE_INOTIFY
+
+ if (fd >= 0)
+ {
+ const char* path = env->GetStringUTFChars(pathString, NULL);
+
+ res = inotify_add_watch(fd, path, mask);
+
+ env->ReleaseStringUTFChars(pathString, path);
+ }
+
+#endif // HAVE_INOTIFY
+
+ return res;
+}
+
+static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd)
+{
+#ifdef HAVE_INOTIFY
+
+ inotify_rm_watch((int)fd, (uint32_t)wfd);
+
+#endif // HAVE_INOTIFY
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ { "init", "()I", (void*)android_os_fileobserver_init },
+ { "observe", "(I)V", (void*)android_os_fileobserver_observe },
+ { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching },
+ { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching }
+
+};
+
+int register_android_os_FileObserver(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/os/FileObserver$ObserverThread");
+
+ if (clazz == NULL)
+ {
+ LOGE("Can't find android/os/FileObserver$ObserverThread");
+ return -1;
+ }
+
+ method_onEvent = env->GetMethodID(clazz, "onEvent", "(IILjava/lang/String;)V");
+ if (method_onEvent == NULL)
+ {
+ LOGE("Can't find FileObserver.onEvent(int, int, String)");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/os/FileObserver$ObserverThread", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_util_FloatMath.cpp b/core/jni/android_util_FloatMath.cpp
new file mode 100644
index 0000000..f38faa9
--- /dev/null
+++ b/core/jni/android_util_FloatMath.cpp
@@ -0,0 +1,46 @@
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <math.h>
+#include <float.h>
+#include "SkTypes.h"
+
+class MathUtilsGlue {
+public:
+ static float FloorF(JNIEnv* env, jobject clazz, float x) {
+ return floorf(x);
+ }
+
+ static float CeilF(JNIEnv* env, jobject clazz, float x) {
+ return ceilf(x);
+ }
+
+ static float SinF(JNIEnv* env, jobject clazz, float x) {
+ return sinf(x);
+ }
+
+ static float CosF(JNIEnv* env, jobject clazz, float x) {
+ return cosf(x);
+ }
+
+ static float SqrtF(JNIEnv* env, jobject clazz, float x) {
+ return sqrtf(x);
+ }
+};
+
+static JNINativeMethod gMathUtilsMethods[] = {
+ {"floor", "(F)F", (void*) MathUtilsGlue::FloorF},
+ {"ceil", "(F)F", (void*) MathUtilsGlue::CeilF},
+ {"sin", "(F)F", (void*) MathUtilsGlue::SinF},
+ {"cos", "(F)F", (void*) MathUtilsGlue::CosF},
+ {"sqrt", "(F)F", (void*) MathUtilsGlue::SqrtF}
+};
+
+int register_android_util_FloatMath(JNIEnv* env)
+{
+ int result = android::AndroidRuntime::registerNativeMethods(env,
+ "android/util/FloatMath",
+ gMathUtilsMethods,
+ SK_ARRAY_COUNT(gMathUtilsMethods));
+ return result;
+}
+
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
new file mode 100644
index 0000000..8316b03
--- /dev/null
+++ b/core/jni/android_util_Log.cpp
@@ -0,0 +1,161 @@
+/* //device/libs/android_runtime/android_util_Log.cpp
+**
+** Copyright 2006, 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_NAMESPACE "log.tag."
+#define LOG_TAG "Log_println"
+
+#include <assert.h>
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "jni.h"
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#define MIN(a,b) ((a<b)?a:b)
+
+namespace android {
+
+struct levels_t {
+ jint verbose;
+ jint debug;
+ jint info;
+ jint warn;
+ jint error;
+ jint assert;
+};
+static levels_t levels;
+
+static int toLevel(const char* value)
+{
+ switch (value[0]) {
+ case 'V': return levels.verbose;
+ case 'D': return levels.debug;
+ case 'I': return levels.info;
+ case 'W': return levels.warn;
+ case 'E': return levels.error;
+ case 'A': return levels.assert;
+ case 'S': return -1; // SUPPRESS
+ }
+ return levels.info;
+}
+
+static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
+{
+#ifndef HAVE_ANDROID_OS
+ return false;
+#else /* HAVE_ANDROID_OS */
+ int len;
+ char key[PROPERTY_KEY_MAX];
+ char buf[PROPERTY_VALUE_MAX];
+
+ if (tag == NULL) {
+ return false;
+ }
+
+ jboolean result = false;
+
+ const char* chars = env->GetStringUTFChars(tag, NULL);
+
+ if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {
+ jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
+ char buf2[200];
+ snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n",
+ chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));
+
+ // release the chars!
+ env->ReleaseStringUTFChars(tag, chars);
+
+ env->ThrowNew(clazz, buf2);
+ return false;
+ } else {
+ strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1);
+ strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars);
+ }
+
+ env->ReleaseStringUTFChars(tag, chars);
+
+ len = property_get(key, buf, "");
+ int logLevel = toLevel(buf);
+ return (logLevel >= 0 && level >= logLevel) ? true : false;
+#endif /* HAVE_ANDROID_OS */
+}
+
+/*
+ * In class android.util.Log:
+ * public static native int println(int priority, String tag, String msg)
+ */
+static jint android_util_Log_println(JNIEnv* env, jobject clazz,
+ jint priority, jstring tagObj, jstring msgObj)
+{
+ const char* tag = NULL;
+ const char* msg = NULL;
+
+ if (msgObj == NULL) {
+ jclass npeClazz;
+
+ npeClazz = env->FindClass("java/lang/NullPointerException");
+ assert(npeClazz != NULL);
+
+ env->ThrowNew(npeClazz, "println needs a message");
+ return -1;
+ }
+
+ if (tagObj != NULL)
+ tag = env->GetStringUTFChars(tagObj, NULL);
+ msg = env->GetStringUTFChars(msgObj, NULL);
+
+ int res = android_writeLog((android_LogPriority) priority, tag, msg);
+
+ if (tag != NULL)
+ env->ReleaseStringUTFChars(tagObj, tag);
+ env->ReleaseStringUTFChars(msgObj, msg);
+
+ return res;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
+ { "println", "(ILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println },
+};
+
+int register_android_util_Log(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/util/Log");
+
+ if (clazz == NULL) {
+ LOGE("Can't find android/util/Log");
+ return -1;
+ }
+
+ levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I"));
+ levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I"));
+ levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I"));
+ levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I"));
+ levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I"));
+ levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I"));
+
+ return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
new file mode 100644
index 0000000..08c4f1c
--- /dev/null
+++ b/core/jni/android_util_Process.cpp
@@ -0,0 +1,743 @@
+/* //device/libs/android_runtime/android_util_Process.cpp
+**
+** Copyright 2006, 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 "Process"
+
+#include <utils/Log.h>
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include "android_util_Binder.h"
+#include "JNIHelp.h"
+
+#include <sys/errno.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+
+/* desktop Linux needs a little help with gettid() */
+#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
+#define __KERNEL__
+# include <linux/unistd.h>
+#ifdef _syscall0
+_syscall0(pid_t,gettid)
+#else
+pid_t gettid() { return syscall(__NR_gettid);}
+#endif
+#undef __KERNEL__
+#endif
+
+using namespace android;
+
+static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err)
+{
+ switch (err) {
+ case EINVAL:
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ break;
+ case ESRCH:
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist");
+ break;
+ case EPERM:
+ jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread");
+ break;
+ case EACCES:
+ jniThrowException(env, "java/lang/SecurityException", "No permission to set to given priority");
+ break;
+ default:
+ jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
+ break;
+ }
+}
+
+static void fakeProcessEntry(void* arg)
+{
+ String8* cls = (String8*)arg;
+
+ AndroidRuntime* jr = AndroidRuntime::getRuntime();
+ jr->callMain(cls->string(), 0, NULL);
+
+ delete cls;
+}
+
+jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
+{
+ return getpid();
+}
+
+jint android_os_Process_myTid(JNIEnv* env, jobject clazz)
+{
+#ifdef HAVE_GETTID
+ return gettid();
+#else
+ return getpid();
+#endif
+}
+
+jint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name)
+{
+ if (name == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return -1;
+ }
+
+ const jchar* str16 = env->GetStringCritical(name, 0);
+ String8 name8;
+ if (str16) {
+ name8 = String8(str16, env->GetStringLength(name));
+ env->ReleaseStringCritical(name, str16);
+ }
+
+ const size_t N = name8.size();
+ if (N > 0) {
+ const char* str = name8.string();
+ for (size_t i=0; i<N; i++) {
+ if (str[i] < '0' || str[i] > '9') {
+ struct passwd* pwd = getpwnam(str);
+ if (pwd == NULL) {
+ return -1;
+ }
+ return pwd->pw_uid;
+ }
+ }
+ return atoi(str);
+ }
+ return -1;
+}
+
+jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name)
+{
+ if (name == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return -1;
+ }
+
+ const jchar* str16 = env->GetStringCritical(name, 0);
+ String8 name8;
+ if (str16) {
+ name8 = String8(str16, env->GetStringLength(name));
+ env->ReleaseStringCritical(name, str16);
+ }
+
+ const size_t N = name8.size();
+ if (N > 0) {
+ const char* str = name8.string();
+ for (size_t i=0; i<N; i++) {
+ if (str[i] < '0' || str[i] > '9') {
+ struct group* grp = getgrnam(str);
+ if (grp == NULL) {
+ return -1;
+ }
+ return grp->gr_gid;
+ }
+ }
+ return atoi(str);
+ }
+ return -1;
+}
+
+void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
+ jint pid, jint pri)
+{
+ if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
+ signalExceptionForPriorityError(env, clazz, errno);
+ }
+ //LOGI("Setting priority of %d: %d, getpriority returns %d\n",
+ // pid, pri, getpriority(PRIO_PROCESS, pid));
+}
+
+void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
+ jint pri)
+{
+ jint tid = android_os_Process_myTid(env, clazz);
+ android_os_Process_setThreadPriority(env, clazz, tid, pri);
+}
+
+jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
+ jint pid)
+{
+ errno = 0;
+ jint pri = getpriority(PRIO_PROCESS, pid);
+ if (errno != 0) {
+ signalExceptionForPriorityError(env, clazz, errno);
+ }
+ //LOGI("Returning priority of %d: %d\n", pid, pri);
+ return pri;
+}
+
+jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
+ jint pid, jint adj)
+{
+#ifdef HAVE_OOM_ADJ
+ if (ProcessState::self()->supportsProcesses()) {
+ char text[64];
+ sprintf(text, "/proc/%d/oom_adj", pid);
+ int fd = open(text, O_WRONLY);
+ if (fd >= 0) {
+ sprintf(text, "%d", adj);
+ write(fd, text, strlen(text));
+ close(fd);
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
+{
+ if (name == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const jchar* str = env->GetStringCritical(name, 0);
+ String8 name8;
+ if (str) {
+ name8 = String8(str, env->GetStringLength(name));
+ env->ReleaseStringCritical(name, str);
+ }
+
+ if (name8.size() > 0) {
+ ProcessState::self()->setArgV0(name8.string());
+ }
+}
+
+jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
+{
+ #if HAVE_ANDROID_OS
+ return setuid(uid) == 0 ? 0 : errno;
+ #else
+ return ENOSYS;
+ #endif
+}
+
+jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
+{
+ #if HAVE_ANDROID_OS
+ return setgid(uid) == 0 ? 0 : errno;
+ #else
+ return ENOSYS;
+ #endif
+}
+
+jboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)
+{
+ return ProcessState::self()->supportsProcesses();
+}
+
+static int pid_compare(const void* v1, const void* v2)
+{
+ //LOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
+ return *((const jint*)v1) - *((const jint*)v2);
+}
+
+jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
+{
+ int fd = open("/proc/meminfo", O_RDONLY);
+
+ if (fd < 0) {
+ LOGW("Unable to open /proc/meminfo");
+ return -1;
+ }
+
+ char buffer[256];
+ const int len = read(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+
+ if (len < 0) {
+ LOGW("Unable to read /proc/meminfo");
+ return -1;
+ }
+ buffer[len] = 0;
+
+ int numFound = 0;
+ int mem = 0;
+
+ static const char* const sums[] = { "MemFree:", "Cached:", NULL };
+ static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), NULL };
+
+ char* p = buffer;
+ while (*p && numFound < 2) {
+ int i = 0;
+ while (sums[i]) {
+ if (strncmp(p, sums[i], sumsLen[i]) == 0) {
+ p += sumsLen[i];
+ while (*p == ' ') p++;
+ char* num = p;
+ while (*p >= '0' && *p <= '9') p++;
+ if (*p != 0) {
+ *p = 0;
+ p++;
+ if (*p == 0) p--;
+ }
+ mem += atoi(num) * 1024;
+ numFound++;
+ break;
+ }
+ i++;
+ }
+ p++;
+ }
+
+ return numFound > 0 ? mem : -1;
+}
+
+void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr,
+ jobjectArray reqFields, jlongArray outFields)
+{
+ //LOGI("getMemInfo: %p %p", reqFields, outFields);
+
+ if (fileStr == NULL || reqFields == NULL || outFields == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const char* file8 = env->GetStringUTFChars(fileStr, NULL);
+ if (file8 == NULL) {
+ return;
+ }
+ String8 file(file8);
+ env->ReleaseStringUTFChars(fileStr, file8);
+
+ jsize count = env->GetArrayLength(reqFields);
+ if (count > env->GetArrayLength(outFields)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ");
+ return;
+ }
+
+ Vector<String8> fields;
+ int i;
+
+ for (i=0; i<count; i++) {
+ jobject obj = env->GetObjectArrayElement(reqFields, i);
+ if (obj != NULL) {
+ const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
+ //LOGI("String at %d: %p = %s", i, obj, str8);
+ if (str8 == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
+ return;
+ }
+ fields.add(String8(str8));
+ env->ReleaseStringUTFChars((jstring)obj, str8);
+ } else {
+ jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
+ return;
+ }
+ }
+
+ jlong* sizesArray = env->GetLongArrayElements(outFields, 0);
+ if (sizesArray == NULL) {
+ return;
+ }
+
+ //LOGI("Clearing %d sizes", count);
+ for (i=0; i<count; i++) {
+ sizesArray[i] = 0;
+ }
+
+ int fd = open(file.string(), O_RDONLY);
+
+ if (fd >= 0) {
+ const size_t BUFFER_SIZE = 2048;
+ char* buffer = (char*)malloc(BUFFER_SIZE);
+ int len = read(fd, buffer, BUFFER_SIZE-1);
+ close(fd);
+
+ if (len < 0) {
+ LOGW("Unable to read %s", file.string());
+ len = 0;
+ }
+ buffer[len] = 0;
+
+ int foundCount = 0;
+
+ char* p = buffer;
+ while (*p && foundCount < count) {
+ bool skipToEol = true;
+ //LOGI("Parsing at: %s", p);
+ for (i=0; i<count; i++) {
+ const String8& field = fields[i];
+ if (strncmp(p, field.string(), field.length()) == 0) {
+ p += field.length();
+ while (*p == ' ') p++;
+ char* num = p;
+ while (*p >= '0' && *p <= '9') p++;
+ skipToEol = *p != '\n';
+ if (*p != 0) {
+ *p = 0;
+ p++;
+ }
+ char* end;
+ sizesArray[i] = strtoll(num, &end, 10);
+ //LOGI("Field %s = %d", field.string(), sizesArray[i]);
+ foundCount++;
+ break;
+ }
+ }
+ if (skipToEol) {
+ while (*p && *p != '\n') {
+ p++;
+ }
+ if (*p == '\n') {
+ p++;
+ }
+ }
+ }
+
+ free(buffer);
+ } else {
+ LOGW("Unable to open %s", file.string());
+ }
+
+ //LOGI("Done!");
+ env->ReleaseLongArrayElements(outFields, sizesArray, 0);
+}
+
+jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
+ jstring file, jintArray lastArray)
+{
+ if (file == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
+
+ const char* file8 = env->GetStringUTFChars(file, NULL);
+ if (file8 == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return NULL;
+ }
+
+ DIR* dirp = opendir(file8);
+
+ env->ReleaseStringUTFChars(file, file8);
+
+ if(dirp == NULL) {
+ return NULL;
+ }
+
+ jsize curCount = 0;
+ jint* curData = NULL;
+ if (lastArray != NULL) {
+ curCount = env->GetArrayLength(lastArray);
+ curData = env->GetIntArrayElements(lastArray, 0);
+ }
+
+ jint curPos = 0;
+
+ struct dirent* entry;
+ while ((entry=readdir(dirp)) != NULL) {
+ const char* p = entry->d_name;
+ while (*p) {
+ if (*p < '0' || *p > '9') break;
+ p++;
+ }
+ if (*p != 0) continue;
+
+ char* end;
+ int pid = strtol(entry->d_name, &end, 10);
+ //LOGI("File %s pid=%d\n", entry->d_name, pid);
+ if (curPos >= curCount) {
+ jsize newCount = (curCount == 0) ? 10 : (curCount*2);
+ jintArray newArray = env->NewIntArray(newCount);
+ if (newArray == NULL) {
+ closedir(dirp);
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return NULL;
+ }
+ jint* newData = env->GetIntArrayElements(newArray, 0);
+ if (curData != NULL) {
+ memcpy(newData, curData, sizeof(jint)*curCount);
+ env->ReleaseIntArrayElements(lastArray, curData, 0);
+ }
+ lastArray = newArray;
+ curCount = newCount;
+ curData = newData;
+ }
+
+ curData[curPos] = pid;
+ curPos++;
+ }
+
+ closedir(dirp);
+
+ if (curData != NULL && curPos > 0) {
+ qsort(curData, curPos, sizeof(jint), pid_compare);
+ }
+
+ while (curPos < curCount) {
+ curData[curPos] = -1;
+ curPos++;
+ }
+
+ if (curData != NULL) {
+ env->ReleaseIntArrayElements(lastArray, curData, 0);
+ }
+
+ return lastArray;
+}
+
+enum {
+ PROC_TERM_MASK = 0xff,
+ PROC_ZERO_TERM = 0,
+ PROC_SPACE_TERM = ' ',
+ PROC_COMBINE = 0x100,
+ PROC_PARENS = 0x200,
+ PROC_OUT_STRING = 0x1000,
+ PROC_OUT_LONG = 0x2000,
+ PROC_OUT_FLOAT = 0x4000,
+};
+
+jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
+ jstring file, jintArray format, jobjectArray outStrings,
+ jlongArray outLongs, jfloatArray outFloats)
+{
+ if (file == NULL || format == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return JNI_FALSE;
+ }
+
+ const char* file8 = env->GetStringUTFChars(file, NULL);
+ if (file8 == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return JNI_FALSE;
+ }
+ int fd = open(file8, O_RDONLY);
+ env->ReleaseStringUTFChars(file, file8);
+
+ if (fd < 0) {
+ //LOGW("Unable to open process file: %s\n", file8);
+ return JNI_FALSE;
+ }
+
+ char buffer[256];
+ const int len = read(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+
+ if (len < 0) {
+ //LOGW("Unable to open process file: %s fd=%d\n", file8, fd);
+ return JNI_FALSE;
+ }
+ buffer[len] = 0;
+
+ //LOGI("Process file %s: %s\n", file8, buffer);
+
+ const jsize NF = env->GetArrayLength(format);
+ const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0;
+ const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0;
+ const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0;
+
+ jint* formatData = env->GetIntArrayElements(format, 0);
+ jlong* longsData = outLongs ?
+ env->GetLongArrayElements(outLongs, 0) : NULL;
+ jfloat* floatsData = outFloats ?
+ env->GetFloatArrayElements(outFloats, 0) : NULL;
+ if (formatData == NULL || (NL > 0 && longsData == NULL)
+ || (NR > 0 && floatsData == NULL)) {
+ if (formatData != NULL) {
+ env->ReleaseIntArrayElements(format, formatData, 0);
+ }
+ if (longsData != NULL) {
+ env->ReleaseLongArrayElements(outLongs, longsData, 0);
+ }
+ if (floatsData != NULL) {
+ env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
+ }
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return JNI_FALSE;
+ }
+
+ jsize i = 0;
+ jsize di = 0;
+
+ jboolean res = JNI_TRUE;
+
+ for (jsize fi=0; fi<NF; fi++) {
+ const jint mode = formatData[fi];
+ if ((mode&PROC_PARENS) != 0) {
+ i++;
+ }
+ const char term = (char)(mode&PROC_TERM_MASK);
+ const jsize start = i;
+ if (i >= len) {
+ res = JNI_FALSE;
+ break;
+ }
+
+ jsize end = -1;
+ if ((mode&PROC_PARENS) != 0) {
+ while (buffer[i] != ')' && i < len) {
+ i++;
+ }
+ end = i;
+ i++;
+ }
+ while (buffer[i] != term && i < len) {
+ i++;
+ }
+ if (end < 0) {
+ end = i;
+ }
+
+ if (i < len) {
+ i++;
+ if ((mode&PROC_COMBINE) != 0) {
+ while (buffer[i] == term && i < len) {
+ i++;
+ }
+ }
+ }
+
+ //LOGI("Field %d: %d-%d dest=%d mode=0x%x\n", i, start, end, di, mode);
+
+ if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
+ char c = buffer[end];
+ buffer[end] = 0;
+ if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) {
+ char* end;
+ floatsData[di] = strtof(buffer+start, &end);
+ }
+ if ((mode&PROC_OUT_LONG) != 0 && di < NL) {
+ char* end;
+ longsData[di] = strtoll(buffer+start, &end, 10);
+ }
+ if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
+ jstring str = env->NewStringUTF(buffer+start);
+ env->SetObjectArrayElement(outStrings, di, str);
+ }
+ buffer[end] = c;
+ di++;
+ }
+ }
+
+ env->ReleaseIntArrayElements(format, formatData, 0);
+ if (longsData != NULL) {
+ env->ReleaseLongArrayElements(outLongs, longsData, 0);
+ }
+ if (floatsData != NULL) {
+ env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
+ }
+
+ return res;
+}
+
+void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
+ jobject binderObject)
+{
+ if (binderObject == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ sp<IBinder> binder = ibinderForJavaObject(env, binderObject);
+}
+
+void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
+{
+ if (pid > 0) {
+ LOGI("Sending signal. PID: %d SIG: %d", pid, sig);
+ kill(pid, sig);
+ }
+}
+
+static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
+{
+ struct timespec ts;
+
+ int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
+
+ if (res != 0) {
+ return (jlong) 0;
+ }
+
+ nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ return (jlong) nanoseconds_to_milliseconds(when);
+}
+
+static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
+{
+ char filename[64];
+
+ snprintf(filename, sizeof(filename), "/proc/%d/smaps", pid);
+
+ FILE * file = fopen(filename, "r");
+ if (!file) {
+ return (jlong) -1;
+ }
+
+ // Tally up all of the Pss from the various maps
+ char line[256];
+ jlong pss = 0;
+ while (fgets(line, sizeof(line), file)) {
+ jlong v;
+ if (sscanf(line, "Pss: %lld kB", &v) == 1) {
+ pss += v;
+ }
+ }
+
+ fclose(file);
+
+ // Return the Pss value in bytes, not kilobytes
+ return pss * 1024;
+}
+
+static const JNINativeMethod methods[] = {
+ {"myPid", "()I", (void*)android_os_Process_myPid},
+ {"myTid", "()I", (void*)android_os_Process_myTid},
+ {"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},
+ {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority},
+ {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority},
+ {"setOomAdj", "(II)Z", (void*)android_os_Process_setOomAdj},
+ {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
+ {"setUid", "(I)I", (void*)android_os_Process_setUid},
+ {"setGid", "(I)I", (void*)android_os_Process_setGid},
+ {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
+ {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
+ {"getFreeMemory", "()I", (void*)android_os_Process_getFreeMemory},
+ {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
+ {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
+ {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
+ {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
+ {"getPss", "(I)J", (void*)android_os_Process_getPss},
+ //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
+};
+
+const char* const kProcessPathName = "android/os/Process";
+
+int register_android_os_Process(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass(kProcessPathName);
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Process");
+
+ return AndroidRuntime::registerNativeMethods(
+ env, kProcessPathName,
+ methods, NELEM(methods));
+}
+
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
new file mode 100644
index 0000000..ffb271c
--- /dev/null
+++ b/core/jni/android_util_StringBlock.cpp
@@ -0,0 +1,204 @@
+/* //device/libs/android_runtime/android_util_StringBlock.cpp
+**
+** Copyright 2006, 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 "StringBlock"
+
+#include "jni.h"
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+
+#include <utils/ResourceTypes.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz;
+
+ npeClazz = env->FindClass(exc);
+ LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
+
+ env->ThrowNew(npeClazz, msg);
+}
+
+static jint android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz,
+ jbyteArray bArray,
+ jint off, jint len)
+{
+ if (bArray == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ jsize bLen = env->GetArrayLength(bArray);
+ if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
+ return 0;
+ }
+
+ jbyte* b = env->GetByteArrayElements(bArray, NULL);
+ ResStringPool* osb = new ResStringPool(b+off, len, true);
+ env->ReleaseByteArrayElements(bArray, b, 0);
+
+ if (osb == NULL || osb->getError() != NO_ERROR) {
+ doThrow(env, "java/lang/IllegalArgumentException");
+ return 0;
+ }
+
+ return (jint)osb;
+}
+
+static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResStringPool* osb = (ResStringPool*)token;
+ if (osb == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return osb->size();
+}
+
+static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResStringPool* osb = (ResStringPool*)token;
+ if (osb == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ size_t len;
+ const char16_t* str = osb->stringAt(idx, &len);
+ if (str == NULL) {
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
+ return 0;
+ }
+
+ return env->NewString((const jchar*)str, len);
+}
+
+static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResStringPool* osb = (ResStringPool*)token;
+ if (osb == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return NULL;
+ }
+
+ const ResStringPool_span* spans = osb->styleAt(idx);
+ if (spans == NULL) {
+ return NULL;
+ }
+
+ const ResStringPool_span* pos = spans;
+ int num = 0;
+ while (pos->name.index != ResStringPool_span::END) {
+ num++;
+ pos++;
+ }
+
+ if (num == 0) {
+ return NULL;
+ }
+
+ jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
+ if (array == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return NULL;
+ }
+
+ num = 0;
+ static const int numInts = sizeof(ResStringPool_span)/sizeof(jint);
+ while (spans->name.index != ResStringPool_span::END) {
+ env->SetIntArrayRegion(array,
+ num*numInts, numInts,
+ (jint*)spans);
+ spans++;
+ num++;
+ }
+
+ return array;
+}
+
+static jint android_content_StringBlock_nativeIndexOfString(JNIEnv* env, jobject clazz,
+ jint token, jstring str)
+{
+ ResStringPool* osb = (ResStringPool*)token;
+ if (osb == NULL || str == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ const char16_t* str16 = env->GetStringChars(str, NULL);
+ jsize strLen = env->GetStringLength(str);
+
+ ssize_t idx = osb->indexOfString(str16, strLen);
+
+ env->ReleaseStringChars(str, str16);
+
+ return idx;
+}
+
+static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResStringPool* osb = (ResStringPool*)token;
+ if (osb == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return;
+ }
+
+ delete osb;
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gStringBlockMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeCreate", "([BII)I",
+ (void*) android_content_StringBlock_nativeCreate },
+ { "nativeGetSize", "(I)I",
+ (void*) android_content_StringBlock_nativeGetSize },
+ { "nativeGetString", "(II)Ljava/lang/String;",
+ (void*) android_content_StringBlock_nativeGetString },
+ { "nativeGetStyle", "(II)[I",
+ (void*) android_content_StringBlock_nativeGetStyle },
+ { "nativeIndexOfString","(ILjava/lang/String;)I",
+ (void*) android_content_StringBlock_nativeIndexOfString },
+ { "nativeDestroy", "(I)V",
+ (void*) android_content_StringBlock_nativeDestroy },
+};
+
+int register_android_content_StringBlock(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/content/res/StringBlock", gStringBlockMethods, NELEM(gStringBlockMethods));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
new file mode 100644
index 0000000..8887fdc
--- /dev/null
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -0,0 +1,426 @@
+/* //device/libs/android_runtime/android_util_XmlBlock.cpp
+**
+** Copyright 2006, 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 "XmlBlock"
+
+#include "jni.h"
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/AssetManager.h>
+#include <utils/Log.h>
+
+#include <utils/ResourceTypes.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz;
+
+ npeClazz = env->FindClass(exc);
+ LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
+
+ env->ThrowNew(npeClazz, msg);
+}
+
+static jint android_content_XmlBlock_nativeCreate(JNIEnv* env, jobject clazz,
+ jbyteArray bArray,
+ jint off, jint len)
+{
+ if (bArray == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ jsize bLen = env->GetArrayLength(bArray);
+ if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
+ doThrow(env, "java/lang/IndexOutOfBoundsException");
+ return 0;
+ }
+
+ jbyte* b = env->GetByteArrayElements(bArray, NULL);
+ ResXMLTree* osb = new ResXMLTree(b+off, len, true);
+ env->ReleaseByteArrayElements(bArray, b, 0);
+
+ if (osb == NULL || osb->getError() != NO_ERROR) {
+ doThrow(env, "java/lang/IllegalArgumentException");
+ return 0;
+ }
+
+ return (jint)osb;
+}
+
+static jint android_content_XmlBlock_nativeGetStringBlock(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLTree* osb = (ResXMLTree*)token;
+ if (osb == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)&osb->getStrings();
+}
+
+static jint android_content_XmlBlock_nativeCreateParseState(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLTree* osb = (ResXMLTree*)token;
+ if (osb == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ ResXMLParser* st = new ResXMLParser(*osb);
+ if (st == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return 0;
+ }
+
+ st->restart();
+
+ return (jint)st;
+}
+
+static jint android_content_XmlBlock_nativeNext(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ return ResXMLParser::END_DOCUMENT;
+ }
+
+ do {
+ jint code = (jint)st->next();
+ switch (code) {
+ case ResXMLParser::START_TAG:
+ return 2;
+ case ResXMLParser::END_TAG:
+ return 3;
+ case ResXMLParser::TEXT:
+ return 4;
+ case ResXMLParser::START_DOCUMENT:
+ return 0;
+ case ResXMLParser::END_DOCUMENT:
+ return 1;
+ case ResXMLParser::BAD_DOCUMENT:
+ goto bad;
+ }
+ } while (true);
+
+bad:
+ doThrow(env, "org/xmlpull/v1/XmlPullParserException",
+ "Corrupt XML binary file");
+ return ResXMLParser::BAD_DOCUMENT;
+}
+
+static jint android_content_XmlBlock_nativeGetNamespace(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ return -1;
+ }
+
+ return (jint)st->getElementNamespaceID();
+}
+
+static jint android_content_XmlBlock_nativeGetName(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ return -1;
+ }
+
+ return (jint)st->getElementNameID();
+}
+
+static jint android_content_XmlBlock_nativeGetText(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ return -1;
+ }
+
+ return (jint)st->getTextID();
+}
+
+static jint android_content_XmlBlock_nativeGetLineNumber(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getLineNumber();
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeCount(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getAttributeCount();
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeNamespace(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getAttributeNamespaceID(idx);
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeName(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getAttributeNameID(idx);
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeResource(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getAttributeNameResID(idx);
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeDataType(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getAttributeDataType(idx);
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeData(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getAttributeData(idx);
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeStringValue(JNIEnv* env, jobject clazz,
+ jint token, jint idx)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ return (jint)st->getAttributeValueStringID(idx);
+}
+
+static jint android_content_XmlBlock_nativeGetAttributeIndex(JNIEnv* env, jobject clazz,
+ jint token,
+ jstring ns, jstring name)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL || name == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ const char16_t* ns16 = NULL;
+ jsize nsLen = 0;
+ if (ns) {
+ ns16 = env->GetStringChars(ns, NULL);
+ nsLen = env->GetStringLength(ns);
+ }
+
+ const char16_t* name16 = env->GetStringChars(name, NULL);
+ jsize nameLen = env->GetStringLength(name);
+
+ jint idx = (jint)st->indexOfAttribute(ns16, nsLen, name16, nameLen);
+
+ if (ns) {
+ env->ReleaseStringChars(ns, ns16);
+ }
+ env->ReleaseStringChars(name, name16);
+
+ return idx;
+}
+
+static jint android_content_XmlBlock_nativeGetIdAttribute(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ ssize_t idx = st->indexOfID();
+ return idx >= 0 ? (jint)st->getAttributeValueStringID(idx) : -1;
+}
+
+static jint android_content_XmlBlock_nativeGetClassAttribute(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ ssize_t idx = st->indexOfClass();
+ return idx >= 0 ? (jint)st->getAttributeValueStringID(idx) : -1;
+}
+
+static jint android_content_XmlBlock_nativeGetStyleAttribute(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return 0;
+ }
+
+ ssize_t idx = st->indexOfStyle();
+ if (idx < 0) {
+ return 0;
+ }
+
+ Res_value value;
+ if (st->getAttributeValue(idx, &value) < 0) {
+ return 0;
+ }
+
+ return value.dataType == value.TYPE_REFERENCE
+ || value.dataType == value.TYPE_ATTRIBUTE
+ ? value.data : 0;
+}
+
+static void android_content_XmlBlock_nativeDestroyParseState(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLParser* st = (ResXMLParser*)token;
+ if (st == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return;
+ }
+
+ delete st;
+}
+
+static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz,
+ jint token)
+{
+ ResXMLTree* osb = (ResXMLTree*)token;
+ if (osb == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return;
+ }
+
+ delete osb;
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gXmlBlockMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeCreate", "([BII)I",
+ (void*) android_content_XmlBlock_nativeCreate },
+ { "nativeGetStringBlock", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetStringBlock },
+ { "nativeCreateParseState", "(I)I",
+ (void*) android_content_XmlBlock_nativeCreateParseState },
+ { "nativeNext", "(I)I",
+ (void*) android_content_XmlBlock_nativeNext },
+ { "nativeGetNamespace", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetNamespace },
+ { "nativeGetName", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetName },
+ { "nativeGetText", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetText },
+ { "nativeGetLineNumber", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetLineNumber },
+ { "nativeGetAttributeCount", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeCount },
+ { "nativeGetAttributeNamespace","(II)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeNamespace },
+ { "nativeGetAttributeName", "(II)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeName },
+ { "nativeGetAttributeResource", "(II)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeResource },
+ { "nativeGetAttributeDataType", "(II)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeDataType },
+ { "nativeGetAttributeData", "(II)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeData },
+ { "nativeGetAttributeStringValue", "(II)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeStringValue },
+ { "nativeGetAttributeIndex", "(ILjava/lang/String;Ljava/lang/String;)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeIndex },
+ { "nativeGetIdAttribute", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetIdAttribute },
+ { "nativeGetClassAttribute", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetClassAttribute },
+ { "nativeGetStyleAttribute", "(I)I",
+ (void*) android_content_XmlBlock_nativeGetStyleAttribute },
+ { "nativeDestroyParseState", "(I)V",
+ (void*) android_content_XmlBlock_nativeDestroyParseState },
+ { "nativeDestroy", "(I)V",
+ (void*) android_content_XmlBlock_nativeDestroy },
+};
+
+int register_android_content_XmlBlock(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/content/res/XmlBlock", gXmlBlockMethods, NELEM(gXmlBlockMethods));
+}
+
+}; // namespace android
+
diff --git a/core/jni/android_view_Display.cpp b/core/jni/android_view_Display.cpp
new file mode 100644
index 0000000..bb7b5ef
--- /dev/null
+++ b/core/jni/android_view_Display.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/PixelFormat.h>
+#include <ui/DisplayInfo.h>
+
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+struct offsets_t {
+ jfieldID display;
+ jfieldID pixelFormat;
+ jfieldID fps;
+ jfieldID density;
+ jfieldID xdpi;
+ jfieldID ydpi;
+};
+static offsets_t offsets;
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz = env->FindClass(exc);
+ env->ThrowNew(npeClazz, msg);
+}
+
+// ----------------------------------------------------------------------------
+
+static void android_view_Display_init(
+ JNIEnv* env, jobject clazz, jint dpy)
+{
+ DisplayInfo info;
+ status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
+ if (err < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException");
+ return;
+ }
+ env->SetIntField(clazz, offsets.pixelFormat,info.pixelFormatInfo.format);
+ env->SetFloatField(clazz, offsets.fps, info.fps);
+ env->SetFloatField(clazz, offsets.density, info.density);
+ env->SetFloatField(clazz, offsets.xdpi, info.xdpi);
+ env->SetFloatField(clazz, offsets.ydpi, info.ydpi);
+}
+
+static jint android_view_Display_getWidth(
+ JNIEnv* env, jobject clazz)
+{
+ DisplayID dpy = env->GetIntField(clazz, offsets.display);
+ return SurfaceComposerClient::getDisplayWidth(dpy);
+}
+
+static jint android_view_Display_getHeight(
+ JNIEnv* env, jobject clazz)
+{
+ DisplayID dpy = env->GetIntField(clazz, offsets.display);
+ return SurfaceComposerClient::getDisplayHeight(dpy);
+}
+
+static jint android_view_Display_getOrientation(
+ JNIEnv* env, jobject clazz)
+{
+ DisplayID dpy = env->GetIntField(clazz, offsets.display);
+ return SurfaceComposerClient::getDisplayOrientation(dpy);
+}
+
+static jint android_view_Display_getDisplayCount(
+ JNIEnv* env, jclass clazz)
+{
+ return SurfaceComposerClient::getNumberOfDisplays();
+}
+
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/Display";
+
+static void nativeClassInit(JNIEnv* env, jclass clazz);
+
+static JNINativeMethod gMethods[] = {
+ { "nativeClassInit", "()V",
+ (void*)nativeClassInit },
+ { "getDisplayCount", "()I",
+ (void*)android_view_Display_getDisplayCount },
+ { "init", "(I)V",
+ (void*)android_view_Display_init },
+ { "getWidth", "()I",
+ (void*)android_view_Display_getWidth },
+ { "getHeight", "()I",
+ (void*)android_view_Display_getHeight },
+ { "getOrientation", "()I",
+ (void*)android_view_Display_getOrientation }
+};
+
+void nativeClassInit(JNIEnv* env, jclass clazz)
+{
+ offsets.display = env->GetFieldID(clazz, "mDisplay", "I");
+ offsets.pixelFormat = env->GetFieldID(clazz, "mPixelFormat", "I");
+ offsets.fps = env->GetFieldID(clazz, "mRefreshRate", "F");
+ offsets.density = env->GetFieldID(clazz, "mDensity", "F");
+ offsets.xdpi = env->GetFieldID(clazz, "mDpiX", "F");
+ offsets.ydpi = env->GetFieldID(clazz, "mDpiY", "F");
+}
+
+int register_android_view_Display(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
+
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
new file mode 100644
index 0000000..f09bd4c
--- /dev/null
+++ b/core/jni/android_view_Surface.cpp
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdio.h>
+
+#include "android_util_Binder.h"
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static const char* const OutOfResourcesException =
+ "android/view/Surface$OutOfResourcesException";
+
+struct sso_t {
+ jfieldID client;
+};
+static sso_t sso;
+
+struct so_t {
+ jfieldID surface;
+ jfieldID saveCount;
+ jfieldID canvas;
+};
+static so_t so;
+
+struct ro_t {
+ jfieldID l;
+ jfieldID t;
+ jfieldID r;
+ jfieldID b;
+};
+static ro_t ro;
+
+struct po_t {
+ jfieldID x;
+ jfieldID y;
+};
+static po_t po;
+
+struct co_t {
+ jfieldID surfaceFormat;
+};
+static co_t co;
+
+struct no_t {
+ jfieldID native_canvas;
+ jfieldID native_region;
+ jfieldID native_parcel;
+};
+static no_t no;
+
+
+static __attribute__((noinline))
+void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ if (!env->ExceptionOccurred()) {
+ jclass npeClazz = env->FindClass(exc);
+ env->ThrowNew(npeClazz, msg);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+
+static void SurfaceSession_init(JNIEnv* env, jobject clazz)
+{
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+ client->incStrong(clazz);
+ env->SetIntField(clazz, sso.client, (int)client.get());
+}
+
+static void SurfaceSession_destroy(JNIEnv* env, jobject clazz)
+{
+ SurfaceComposerClient* client =
+ (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
+ if (client != 0) {
+ client->decStrong(clazz);
+ env->SetIntField(clazz, sso.client, 0);
+ }
+}
+
+static void SurfaceSession_kill(JNIEnv* env, jobject clazz)
+{
+ SurfaceComposerClient* client =
+ (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
+ if (client != 0) {
+ client->dispose();
+ client->decStrong(clazz);
+ env->SetIntField(clazz, sso.client, 0);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
+{
+ Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
+ return sp<Surface>(p);
+}
+
+static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
+{
+ Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
+ if (surface.get()) {
+ surface->incStrong(clazz);
+ }
+ if (p) {
+ p->decStrong(clazz);
+ }
+ env->SetIntField(clazz, so.surface, (int)surface.get());
+}
+
+// ----------------------------------------------------------------------------
+
+static void Surface_init(
+ JNIEnv* env, jobject clazz,
+ jobject session, jint pid, jint dpy, jint w, jint h, jint format, jint flags)
+{
+ if (session == NULL) {
+ doThrow(env, "java/lang/NullPointerException");
+ return;
+ }
+
+ SurfaceComposerClient* client =
+ (SurfaceComposerClient*)env->GetIntField(session, sso.client);
+
+ sp<Surface> surface(client->createSurface(pid, dpy, w, h, format, flags));
+ if (surface == 0) {
+ doThrow(env, OutOfResourcesException);
+ return;
+ }
+ setSurface(env, clazz, surface);
+}
+
+static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
+{
+ Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);
+ if (parcel == NULL) {
+ doThrow(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+ const sp<Surface>& rhs = Surface::readFromParcel(parcel);
+ setSurface(env, clazz, rhs);
+}
+
+static void Surface_clear(JNIEnv* env, jobject clazz, uintptr_t *ostack)
+{
+ setSurface(env, clazz, 0);
+}
+
+static jboolean Surface_isValid(JNIEnv* env, jobject clazz)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ return surface->isValid() ? JNI_TRUE : JNI_FALSE;
+}
+
+static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
+{
+ /* note: if PIXEL_FORMAT_XRGB_8888 means that all alpha bytes are 0xFF, then
+ we can map to SkBitmap::kARGB_8888_Config, and optionally call
+ bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
+ */
+ switch (format) {
+ case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
+ case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config;
+ case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
+ case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config;
+ default: return SkBitmap::kNo_Config;
+ }
+}
+
+static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (!surface->isValid())
+ return 0;
+
+ // get dirty region
+ Region dirtyRegion;
+ if (dirtyRect) {
+ Rect dirty;
+ dirty.left = env->GetIntField(dirtyRect, ro.l);
+ dirty.top = env->GetIntField(dirtyRect, ro.t);
+ dirty.right = env->GetIntField(dirtyRect, ro.r);
+ dirty.bottom= env->GetIntField(dirtyRect, ro.b);
+ dirtyRegion.set(dirty);
+ } else {
+ dirtyRegion.set(Rect(0x3FFF,0x3FFF));
+ }
+
+ Surface::SurfaceInfo info;
+ status_t err = surface->lock(&info, &dirtyRegion);
+ if (err < 0) {
+ const char* const exception = (err == NO_MEMORY) ?
+ OutOfResourcesException :
+ "java/lang/IllegalArgumentException";
+ doThrow(env, exception, NULL);
+ return 0;
+ }
+
+ // Associate a SkCanvas object to this surface
+ jobject canvas = env->GetObjectField(clazz, so.canvas);
+ env->SetIntField(canvas, co.surfaceFormat, info.format);
+
+ SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
+ SkBitmap bitmap;
+ bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, info.bpr);
+ if (info.w > 0 && info.h > 0) {
+ bitmap.setPixels(info.bits);
+ } else {
+ // be safe with an empty bitmap.
+ bitmap.setPixels(NULL);
+ }
+ nativeCanvas->setBitmapDevice(bitmap);
+ nativeCanvas->clipRegion(dirtyRegion.toSkRegion());
+
+ int saveCount = nativeCanvas->save();
+ env->SetIntField(clazz, so.saveCount, saveCount);
+
+ return canvas;
+}
+
+static void Surface_unlockCanvasAndPost(
+ JNIEnv* env, jobject clazz, jobject argCanvas)
+{
+ jobject canvas = env->GetObjectField(clazz, so.canvas);
+ if (canvas != argCanvas) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (!surface->isValid())
+ return;
+
+ // detach the canvas from the surface
+ SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
+ int saveCount = env->GetIntField(clazz, so.saveCount);
+ nativeCanvas->restoreToCount(saveCount);
+ nativeCanvas->setBitmapDevice(SkBitmap());
+ env->SetIntField(clazz, so.saveCount, 0);
+
+ // unlock surface
+ status_t err = surface->unlockAndPost();
+ if (err < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+}
+
+static void Surface_unlockCanvas(
+ JNIEnv* env, jobject clazz, jobject argCanvas)
+{
+ jobject canvas = env->GetObjectField(clazz, so.canvas);
+ if (canvas != argCanvas) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (!surface->isValid())
+ return;
+
+ status_t err = surface->unlock();
+ if (err < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+ SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
+ int saveCount = env->GetIntField(clazz, so.saveCount);
+ nativeCanvas->restoreToCount(saveCount);
+ nativeCanvas->setBitmapDevice(SkBitmap());
+ env->SetIntField(clazz, so.saveCount, 0);
+}
+
+static void Surface_openTransaction(
+ JNIEnv* env, jobject clazz)
+{
+ SurfaceComposerClient::openGlobalTransaction();
+}
+
+static void Surface_closeTransaction(
+ JNIEnv* env, jobject clazz)
+{
+ SurfaceComposerClient::closeGlobalTransaction();
+}
+
+static void Surface_setOrientation(
+ JNIEnv* env, jobject clazz, jint display, jint orientation)
+{
+ int err = SurfaceComposerClient::setOrientation(display, orientation);
+ if (err < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+}
+
+static void Surface_freezeDisplay(
+ JNIEnv* env, jobject clazz, jint display)
+{
+ int err = SurfaceComposerClient::freezeDisplay(display, 0);
+ if (err < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+}
+
+static void Surface_unfreezeDisplay(
+ JNIEnv* env, jobject clazz, jint display)
+{
+ int err = SurfaceComposerClient::unfreezeDisplay(display, 0);
+ if (err < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+}
+
+static void Surface_setLayer(
+ JNIEnv* env, jobject clazz, jint zorder)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->setLayer(zorder) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_setPosition(
+ JNIEnv* env, jobject clazz, jint x, jint y)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->setPosition(x, y) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_setSize(
+ JNIEnv* env, jobject clazz, jint w, jint h)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->setSize(w, h) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_hide(
+ JNIEnv* env, jobject clazz)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->hide() < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_show(
+ JNIEnv* env, jobject clazz)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->show() < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_freeze(
+ JNIEnv* env, jobject clazz)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->freeze() < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_unfreeze(
+ JNIEnv* env, jobject clazz)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->unfreeze() < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_setFlags(
+ JNIEnv* env, jobject clazz, jint flags, jint mask)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->setFlags(flags, mask) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_setTransparentRegion(
+ JNIEnv* env, jobject clazz, jobject argRegion)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
+ if (surface->setTransparentRegionHint(Region(*nativeRegion)) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_setAlpha(
+ JNIEnv* env, jobject clazz, jfloat alpha)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->setAlpha(alpha) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_setMatrix(
+ JNIEnv* env, jobject clazz,
+ jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->setMatrix(dsdx, dtdx, dsdy, dtdy) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_setFreezeTint(
+ JNIEnv* env, jobject clazz,
+ jint tint)
+{
+ const sp<Surface>& surface = getSurface(env, clazz);
+ if (surface->isValid()) {
+ if (surface->setFreezeTint(tint) < 0) {
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ }
+}
+
+static void Surface_copyFrom(
+ JNIEnv* env, jobject clazz, jobject other)
+{
+ if (clazz == other)
+ return;
+
+ if (other == NULL) {
+ doThrow(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const sp<Surface>& surface = getSurface(env, clazz);
+ const sp<Surface>& rhs = getSurface(env, other);
+ if (!Surface::isSameSurface(surface, rhs)) {
+ // we reassign the surface only if it's a different one
+ // otherwise we would loose our client-side state.
+ setSurface(env, clazz, rhs->dup());
+ }
+}
+
+
+static void Surface_readFromParcel(
+ JNIEnv* env, jobject clazz, jobject argParcel)
+{
+ Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);
+ if (parcel == NULL) {
+ doThrow(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const sp<Surface>& surface = getSurface(env, clazz);
+ const sp<Surface>& rhs = Surface::readFromParcel(parcel);
+ if (!Surface::isSameSurface(surface, rhs)) {
+ // we reassign the surface only if it's a different one
+ // otherwise we would loose our client-side state.
+ setSurface(env, clazz, rhs);
+ }
+}
+
+static void Surface_writeToParcel(
+ JNIEnv* env, jobject clazz, jobject argParcel, jint flags)
+{
+ Parcel* parcel = (Parcel*)env->GetIntField(
+ argParcel, no.native_parcel);
+
+ if (parcel == NULL) {
+ doThrow(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const sp<Surface>& surface = getSurface(env, clazz);
+ Surface::writeToParcel(surface, parcel);
+}
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+
+const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession";
+const char* const kSurfaceClassPathName = "android/view/Surface";
+static void nativeClassInit(JNIEnv* env, jclass clazz);
+
+static JNINativeMethod gSurfaceSessionMethods[] = {
+ {"init", "()V", (void*)SurfaceSession_init },
+ {"destroy", "()V", (void*)SurfaceSession_destroy },
+ {"kill", "()V", (void*)SurfaceSession_kill },
+};
+
+static JNINativeMethod gSurfaceMethods[] = {
+ {"nativeClassInit", "()V", (void*)nativeClassInit },
+ {"init", "(Landroid/view/SurfaceSession;IIIIII)V", (void*)Surface_init },
+ {"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel },
+ {"clear", "()V", (void*)Surface_clear },
+ {"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom },
+ {"isValid", "()Z", (void*)Surface_isValid },
+ {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
+ {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost },
+ {"unlockCanvas", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvas },
+ {"openTransaction", "()V", (void*)Surface_openTransaction },
+ {"closeTransaction", "()V", (void*)Surface_closeTransaction },
+ {"setOrientation", "(II)V", (void*)Surface_setOrientation },
+ {"freezeDisplay", "(I)V", (void*)Surface_freezeDisplay },
+ {"unfreezeDisplay", "(I)V", (void*)Surface_unfreezeDisplay },
+ {"setLayer", "(I)V", (void*)Surface_setLayer },
+ {"setPosition", "(II)V",(void*)Surface_setPosition },
+ {"setSize", "(II)V",(void*)Surface_setSize },
+ {"hide", "()V", (void*)Surface_hide },
+ {"show", "()V", (void*)Surface_show },
+ {"freeze", "()V", (void*)Surface_freeze },
+ {"unfreeze", "()V", (void*)Surface_unfreeze },
+ {"setFlags", "(II)V",(void*)Surface_setFlags },
+ {"setTransparentRegionHint","(Landroid/graphics/Region;)V", (void*)Surface_setTransparentRegion },
+ {"setAlpha", "(F)V", (void*)Surface_setAlpha },
+ {"setMatrix", "(FFFF)V", (void*)Surface_setMatrix },
+ {"setFreezeTint", "(I)V", (void*)Surface_setFreezeTint },
+ {"readFromParcel", "(Landroid/os/Parcel;)V", (void*)Surface_readFromParcel },
+ {"writeToParcel", "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel },
+};
+
+void nativeClassInit(JNIEnv* env, jclass clazz)
+{
+ so.surface = env->GetFieldID(clazz, "mSurface", "I");
+ so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
+ so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
+
+ jclass surfaceSession = env->FindClass("android/view/SurfaceSession");
+ sso.client = env->GetFieldID(surfaceSession, "mClient", "I");
+
+ jclass canvas = env->FindClass("android/graphics/Canvas");
+ no.native_canvas = env->GetFieldID(canvas, "mNativeCanvas", "I");
+ co.surfaceFormat = env->GetFieldID(canvas, "mSurfaceFormat", "I");
+
+ jclass region = env->FindClass("android/graphics/Region");
+ no.native_region = env->GetFieldID(region, "mNativeRegion", "I");
+
+ jclass parcel = env->FindClass("android/os/Parcel");
+ no.native_parcel = env->GetFieldID(parcel, "mObject", "I");
+
+ jclass rect = env->FindClass("android/graphics/Rect");
+ ro.l = env->GetFieldID(rect, "left", "I");
+ ro.t = env->GetFieldID(rect, "top", "I");
+ ro.r = env->GetFieldID(rect, "right", "I");
+ ro.b = env->GetFieldID(rect, "bottom", "I");
+
+ jclass point = env->FindClass("android/graphics/Point");
+ po.x = env->GetFieldID(point, "x", "I");
+ po.y = env->GetFieldID(point, "y", "I");
+}
+
+int register_android_view_Surface(JNIEnv* env)
+{
+ int err;
+ err = AndroidRuntime::registerNativeMethods(env, kSurfaceSessionClassPathName,
+ gSurfaceSessionMethods, NELEM(gSurfaceSessionMethods));
+
+ err |= AndroidRuntime::registerNativeMethods(env, kSurfaceClassPathName,
+ gSurfaceMethods, NELEM(gSurfaceMethods));
+ return err;
+}
+
+};
+
diff --git a/core/jni/android_view_ViewRoot.cpp b/core/jni/android_view_ViewRoot.cpp
new file mode 100644
index 0000000..843d293
--- /dev/null
+++ b/core/jni/android_view_ViewRoot.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <graphics/SkCanvas.h>
+#include <graphics/SkDevice.h>
+#include <graphics/SkGLCanvas.h>
+#include <graphics/SkPaint.h>
+#include "GraphicsJNI.h"
+
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static int gPrevDur;
+
+static void android_view_ViewRoot_showFPS(JNIEnv* env, jobject, jobject jcanvas,
+ jint dur) {
+ NPE_CHECK_RETURN_VOID(env, jcanvas);
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
+ const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
+ int height = bm.height();
+ SkScalar bot = SkIntToScalar(height);
+
+ if (height < 200) {
+ return;
+ }
+
+ SkMatrix m;
+ SkRect r;
+ SkPaint p;
+ char str[4];
+
+ dur = (gPrevDur + dur) >> 1;
+ gPrevDur = dur;
+
+ dur = 1000 / dur;
+ str[3] = (char)('0' + dur % 10); dur /= 10;
+ str[2] = (char)('0' + dur % 10); dur /= 10;
+ str[1] = (char)('0' + dur % 10); dur /= 10;
+ str[0] = (char)('0' + dur % 10);
+
+ m.reset();
+ r.set(0, bot-SkIntToScalar(10), SkIntToScalar(26), bot);
+ p.setAntiAlias(true);
+ p.setTextSize(SkIntToScalar(10));
+
+ canvas->save();
+ canvas->setMatrix(m);
+ canvas->clipRect(r, SkRegion::kReplace_Op);
+ p.setColor(SK_ColorWHITE);
+ canvas->drawPaint(p);
+ p.setColor(SK_ColorBLACK);
+ canvas->drawText(str, 4, SkIntToScalar(1), bot - SK_Scalar1, p);
+ canvas->restore();
+}
+
+static void android_view_ViewRoot_abandonGlCaches(JNIEnv* env, jobject) {
+ SkGLCanvas::AbandonAllTextures();
+}
+
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/ViewRoot";
+
+static JNINativeMethod gMethods[] = {
+ { "nativeShowFPS", "(Landroid/graphics/Canvas;I)V",
+ (void*)android_view_ViewRoot_showFPS },
+ { "nativeAbandonGlCaches", "()V",
+ (void*)android_view_ViewRoot_abandonGlCaches }
+};
+
+int register_android_view_ViewRoot(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
+
diff --git a/core/jni/com_android_internal_graphics_NativeUtils.cpp b/core/jni/com_android_internal_graphics_NativeUtils.cpp
new file mode 100644
index 0000000..0829532
--- /dev/null
+++ b/core/jni/com_android_internal_graphics_NativeUtils.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 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 "AWT"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPicture.h"
+#include "SkTemplates.h"
+
+namespace android
+{
+
+static jclass class_fileDescriptor;
+static jfieldID field_fileDescriptor_descriptor;
+static jmethodID method_fileDescriptor_init;
+
+
+static jboolean scrollRect(JNIEnv* env, jobject graphics2D, jobject canvas, jobject rect, int dx, int dy) {
+ if (canvas == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return false;
+ }
+
+ SkIRect src, *srcPtr = NULL;
+ if (NULL != rect) {
+ GraphicsJNI::jrect_to_irect(env, rect, &src);
+ srcPtr = &src;
+ }
+ SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
+ const SkBitmap& bitmap = c->getDevice()->accessBitmap(true);
+ return bitmap.scrollRect(srcPtr, dx, dy, NULL);
+}
+
+static JNINativeMethod method_table[] = {
+ { "nativeScrollRect",
+ "(Landroid/graphics/Canvas;Landroid/graphics/Rect;II)Z",
+ (void*)scrollRect}
+};
+
+int register_com_android_internal_graphics_NativeUtils(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(
+ env, "com/android/internal/graphics/NativeUtils",
+ method_table, NELEM(method_table));
+}
+
+}
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
new file mode 100644
index 0000000..ada4dd3
--- /dev/null
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2007 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 "Zygote"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utils/misc.h>
+#include <errno.h>
+#include <sys/select.h>
+
+#include "jni.h"
+#include <JNIHelp.h>
+#include "android_runtime/AndroidRuntime.h"
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/capability.h>
+#include <linux/prctl.h>
+#include <sys/prctl.h>
+extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
+extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+#endif
+
+
+namespace android {
+
+/*
+ * In class com.android.internal.os.ZygoteInit:
+ * private static native boolean setreuid(int ruid, int euid)
+ */
+static jint com_android_internal_os_ZygoteInit_setreuid(
+ JNIEnv* env, jobject clazz, jint ruid, jint euid)
+{
+ int err;
+
+ errno = 0;
+ err = setreuid(ruid, euid);
+
+ //LOGI("setreuid(%d,%d) err %d errno %d", ruid, euid, err, errno);
+
+ return errno;
+}
+
+/*
+ * In class com.android.internal.os.ZygoteInit:
+ * private static native int setregid(int rgid, int egid)
+ */
+static jint com_android_internal_os_ZygoteInit_setregid(
+ JNIEnv* env, jobject clazz, jint rgid, jint egid)
+{
+ int err;
+
+ errno = 0;
+ err = setregid(rgid, egid);
+
+ //LOGI("setregid(%d,%d) err %d errno %d", rgid, egid, err, errno);
+
+ return errno;
+}
+
+/*
+ * In class com.android.internal.os.ZygoteInit:
+ * private static native int setpgid(int rgid, int egid)
+ */
+static jint com_android_internal_os_ZygoteInit_setpgid(
+ JNIEnv* env, jobject clazz, jint pid, jint pgid)
+{
+ int err;
+
+ errno = 0;
+
+ err = setpgid(pid, pgid);
+
+ return errno;
+}
+
+/*
+ * In class com.android.internal.os.ZygoteInit:
+ * private static native int getpgid(int pid)
+ */
+static jint com_android_internal_os_ZygoteInit_getpgid(
+ JNIEnv* env, jobject clazz, jint pid)
+{
+ pid_t ret;
+ ret = getpgid(pid);
+
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ }
+
+ return ret;
+}
+
+static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
+ jobject clazz, jobject in, jobject out, jobject errfd)
+{
+ int fd;
+ int err;
+
+ fd = jniGetFDFromFileDescriptor(env, in);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ do {
+ err = dup2(fd, STDIN_FILENO);
+ } while (err < 0 && errno == EINTR);
+
+ fd = jniGetFDFromFileDescriptor(env, out);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ do {
+ err = dup2(fd, STDOUT_FILENO);
+ } while (err < 0 && errno == EINTR);
+
+ fd = jniGetFDFromFileDescriptor(env, errfd);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ do {
+ err = dup2(fd, STDERR_FILENO);
+ } while (err < 0 && errno == EINTR);
+}
+
+static void com_android_internal_os_ZygoteInit_closeDescriptor(JNIEnv* env,
+ jobject clazz, jobject descriptor)
+{
+ int fd;
+ int err;
+
+ fd = jniGetFDFromFileDescriptor(env, descriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ do {
+ err = close(fd);
+ } while (err < 0 && errno == EINTR);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env,
+ jobject clazz, jobject descriptor, jboolean flag)
+{
+ int fd;
+ int err;
+ int fdFlags;
+
+ fd = jniGetFDFromFileDescriptor(env, descriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ return;
+ }
+
+ fdFlags = fcntl(fd, F_GETFD);
+
+ if (fdFlags < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ if (flag) {
+ fdFlags |= FD_CLOEXEC;
+ } else {
+ fdFlags &= ~FD_CLOEXEC;
+ }
+
+ err = fcntl(fd, F_SETFD, fdFlags);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+}
+
+static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
+ jobject clazz, jlong permitted, jlong effective)
+{
+#ifdef HAVE_ANDROID_OS
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata;
+ int err;
+
+ memset (&capheader, 0, sizeof(capheader));
+ memset (&capdata, 0, sizeof(capdata));
+
+ capheader.version = _LINUX_CAPABILITY_VERSION;
+ capheader.pid = 0;
+
+ // As of this writing, capdata is __u32, but that's expected
+ // to change...
+ capdata.effective = effective;
+ capdata.permitted = permitted;
+
+ err = capset (&capheader, &capdata);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+#endif /* HAVE_ANDROID_OS */
+}
+
+static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
+ jobject clazz, jint pid)
+{
+#ifndef HAVE_ANDROID_OS
+ return (jlong)0;
+#else
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata;
+ int err;
+
+ memset (&capheader, 0, sizeof(capheader));
+ memset (&capdata, 0, sizeof(capdata));
+
+ capheader.version = _LINUX_CAPABILITY_VERSION;
+ capheader.pid = pid;
+
+ err = capget (&capheader, &capdata);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return 0;
+ }
+
+ return (jlong) capdata.permitted;
+#endif /* HAVE_ANDROID_OS */
+}
+
+static jint com_android_internal_os_ZygoteInit_selectReadable (
+ JNIEnv *env, jobject clazz, jobjectArray fds)
+{
+ if (fds == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "fds == null");
+ return -1;
+ }
+
+ jsize length = env->GetArrayLength(fds);
+ fd_set fdset;
+
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+
+ FD_ZERO(&fdset);
+
+ int nfds = 0;
+ for (jsize i = 0; i < length; i++) {
+ jobject fdObj = env->GetObjectArrayElement(fds, i);
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+ if (fdObj == NULL) {
+ continue;
+ }
+ int fd = jniGetFDFromFileDescriptor(env, fdObj);
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+
+ FD_SET(fd, &fdset);
+
+ if (fd >= nfds) {
+ nfds = fd + 1;
+ }
+ }
+
+ int err;
+ do {
+ err = select (nfds, &fdset, NULL, NULL, NULL);
+ } while (err < 0 && errno == EINTR);
+
+ if (err < 0) {
+ jniThrowIOException(env, errno);
+ return -1;
+ }
+
+ for (jsize i = 0; i < length; i++) {
+ jobject fdObj = env->GetObjectArrayElement(fds, i);
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+ if (fdObj == NULL) {
+ continue;
+ }
+ int fd = jniGetFDFromFileDescriptor(env, fdObj);
+ if (env->ExceptionOccurred() != NULL) {
+ return -1;
+ }
+ if (FD_ISSET(fd, &fdset)) {
+ return (jint)i;
+ }
+ }
+ return -1;
+}
+
+static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
+ JNIEnv *env, jobject clazz, jint fd)
+{
+ return jniCreateFileDescriptor(env, fd);
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "setreuid", "(II)I",
+ (void*) com_android_internal_os_ZygoteInit_setreuid },
+ { "setregid", "(II)I",
+ (void*) com_android_internal_os_ZygoteInit_setregid },
+ { "setpgid", "(II)I",
+ (void *) com_android_internal_os_ZygoteInit_setpgid },
+ { "getpgid", "(I)I",
+ (void *) com_android_internal_os_ZygoteInit_getpgid },
+ { "reopenStdio",
+ "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
+ "Ljava/io/FileDescriptor;)V",
+ (void *) com_android_internal_os_ZygoteInit_reopenStdio},
+ { "closeDescriptor", "(Ljava/io/FileDescriptor;)V",
+ (void *) com_android_internal_os_ZygoteInit_closeDescriptor},
+ { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
+ (void *) com_android_internal_os_ZygoteInit_setCloseOnExec},
+ { "setCapabilities", "(JJ)V",
+ (void *) com_android_internal_os_ZygoteInit_setCapabilities },
+ { "capgetPermitted", "(I)J",
+ (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
+ { "selectReadable", "([Ljava/io/FileDescriptor;)I",
+ (void *) com_android_internal_os_ZygoteInit_selectReadable },
+ { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
+ (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
+};
+int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
+
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
new file mode 100644
index 0000000..af03016
--- /dev/null
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -0,0 +1,475 @@
+/*
+**
+** Copyright 2006, 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.
+*/
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+#include <GLES/egl.h>
+#include <GLES/gl.h>
+
+#include <ui/EGLNativeWindowSurface.h>
+#include <ui/Surface.h>
+#include <graphics/SkBitmap.h>
+#include <graphics/SkPixelRef.h>
+
+namespace android {
+
+static jclass gDisplay_class;
+static jclass gContext_class;
+static jclass gSurface_class;
+static jclass gConfig_class;
+
+static jmethodID gConfig_ctorID;
+
+static jfieldID gDisplay_EGLDisplayFieldID;
+static jfieldID gContext_EGLContextFieldID;
+static jfieldID gSurface_EGLSurfaceFieldID;
+static jfieldID gSurface_NativePixelRefFieldID;
+static jfieldID gConfig_EGLConfigFieldID;
+static jfieldID gSurface_SurfaceFieldID;
+static jfieldID gBitmap_NativeBitmapFieldID;
+
+static __attribute__((noinline))
+void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz = env->FindClass(exc);
+ env->ThrowNew(npeClazz, msg);
+}
+
+static __attribute__((noinline))
+bool hasException(JNIEnv *env) {
+ if (env->ExceptionCheck() != 0) {
+ env->ExceptionDescribe();
+ return true;
+ }
+ return false;
+}
+
+static __attribute__((noinline))
+jclass make_globalref(JNIEnv* env, const char classname[]) {
+ jclass c = env->FindClass(classname);
+ return (jclass)env->NewGlobalRef(c);
+}
+
+static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
+ if (!o) return EGL_NO_DISPLAY;
+ return (EGLDisplay)env->GetIntField(o, gDisplay_EGLDisplayFieldID);
+}
+static inline EGLSurface getSurface(JNIEnv* env, jobject o) {
+ if (!o) return EGL_NO_SURFACE;
+ return (EGLSurface)env->GetIntField(o, gSurface_EGLSurfaceFieldID);
+}
+static inline EGLContext getContext(JNIEnv* env, jobject o) {
+ if (!o) return EGL_NO_CONTEXT;
+ return (EGLContext)env->GetIntField(o, gContext_EGLContextFieldID);
+}
+static inline EGLConfig getConfig(JNIEnv* env, jobject o) {
+ if (!o) return 0;
+ return (EGLConfig)env->GetIntField(o, gConfig_EGLConfigFieldID);
+}
+static void nativeClassInit(JNIEnv *_env, jclass eglImplClass)
+{
+ gDisplay_class = make_globalref(_env, "com/google/android/gles_jni/EGLDisplayImpl");
+ gContext_class = make_globalref(_env, "com/google/android/gles_jni/EGLContextImpl");
+ gSurface_class = make_globalref(_env, "com/google/android/gles_jni/EGLSurfaceImpl");
+ gConfig_class = make_globalref(_env, "com/google/android/gles_jni/EGLConfigImpl");
+
+ gConfig_ctorID = _env->GetMethodID(gConfig_class, "<init>", "(I)V");
+
+ gDisplay_EGLDisplayFieldID = _env->GetFieldID(gDisplay_class, "mEGLDisplay", "I");
+ gContext_EGLContextFieldID = _env->GetFieldID(gContext_class, "mEGLContext", "I");
+ gSurface_EGLSurfaceFieldID = _env->GetFieldID(gSurface_class, "mEGLSurface", "I");
+ gSurface_NativePixelRefFieldID = _env->GetFieldID(gSurface_class, "mNativePixelRef", "I");
+ gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class, "mEGLConfig", "I");
+
+ jclass surface_class = _env->FindClass("android/view/Surface");
+ gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I");
+
+ jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
+ gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "I");
+}
+
+jboolean jni_eglInitialize(JNIEnv *_env, jobject _this, jobject display,
+ jintArray major_minor) {
+
+ EGLDisplay dpy = getDisplay(_env, display);
+ jboolean success = eglInitialize(dpy, NULL, NULL);
+ if (success && major_minor) {
+ int len = _env->GetArrayLength(major_minor);
+ if (len) {
+ // we're exposing only EGL 1.0
+ jint* base = (jint *)_env->GetPrimitiveArrayCritical(major_minor, (jboolean *)0);
+ if (len >= 1) base[0] = 1;
+ if (len >= 2) base[1] = 0;
+ _env->ReleasePrimitiveArrayCritical(major_minor, base, JNI_ABORT);
+ }
+ }
+ return success;
+}
+
+jboolean jni_eglQueryContext(JNIEnv *_env, jobject _this, jobject display,
+ jobject context, jint attribute, jintArray value) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLContext ctx = getContext(_env, context);
+ if (value == NULL) {
+ doThrow(_env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+ jboolean success = JNI_FALSE;
+ int len = _env->GetArrayLength(value);
+ if (len) {
+ jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
+ success = eglQueryContext(dpy, ctx, attribute, base);
+ _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
+ }
+ return success;
+}
+
+jboolean jni_eglQuerySurface(JNIEnv *_env, jobject _this, jobject display,
+ jobject surface, jint attribute, jintArray value) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLContext sur = getSurface(_env, surface);
+ if (value == NULL) {
+ doThrow(_env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+ jboolean success = JNI_FALSE;
+ int len = _env->GetArrayLength(value);
+ if (len) {
+ jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
+ success = eglQuerySurface(dpy, sur, attribute, base);
+ _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
+ }
+ return success;
+}
+
+jboolean jni_eglChooseConfig(JNIEnv *_env, jobject _this, jobject display,
+ jintArray attrib_list, jobjectArray configs, jint config_size, jintArray num_config) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ if (attrib_list==NULL || configs==NULL || num_config==NULL) {
+ doThrow(_env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+ jboolean success = JNI_FALSE;
+ jint* attrib_base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
+ jint* num_base = (jint *)_env->GetPrimitiveArrayCritical(num_config, (jboolean *)0);
+ EGLConfig nativeConfigs[config_size];
+ success = eglChooseConfig(dpy, attrib_base, nativeConfigs, config_size, num_base);
+ int num = num_base[0];
+ _env->ReleasePrimitiveArrayCritical(num_config, num_base, JNI_ABORT);
+ _env->ReleasePrimitiveArrayCritical(attrib_list, attrib_base, JNI_ABORT);
+ if (success) {
+ for (int i=0 ; i<num ; i++) {
+ jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]);
+ _env->SetObjectArrayElement(configs, i, obj);
+ }
+ }
+ return success;
+}
+
+jint jni_eglCreateContext(JNIEnv *_env, jobject _this, jobject display,
+ jobject config, jobject share_context, jintArray attrib_list) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLConfig cnf = getConfig(_env, config);
+ EGLContext shr = getContext(_env, share_context);
+ jint* base = 0;
+ if (attrib_list) {
+ // XXX: if array is malformed, we should return an NPE instead of segfault
+ base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
+ }
+ EGLContext ctx = eglCreateContext(dpy, cnf, shr, base);
+ if (attrib_list) {
+ _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
+ }
+ return (jint)ctx;
+}
+
+jint jni_eglCreatePbufferSurface(JNIEnv *_env, jobject _this, jobject display,
+ jobject config, jintArray attrib_list) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLConfig cnf = getConfig(_env, config);
+ jint* base = 0;
+ if (attrib_list) {
+ // XXX: if array is malformed, we should return an NPE instead of segfault
+ base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
+ }
+ EGLSurface sur = eglCreatePbufferSurface(dpy, cnf, base);
+ if (attrib_list) {
+ _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
+ }
+ return (jint)sur;
+}
+
+static PixelFormat convertPixelFormat(SkBitmap::Config format)
+{
+ switch (format) {
+ case SkBitmap::kARGB_8888_Config: return PIXEL_FORMAT_RGBA_8888;
+ case SkBitmap::kARGB_4444_Config: return PIXEL_FORMAT_RGBA_4444;
+ case SkBitmap::kRGB_565_Config: return PIXEL_FORMAT_RGB_565;
+ case SkBitmap::kA8_Config: return PIXEL_FORMAT_A_8;
+ default: return PIXEL_FORMAT_NONE;
+ }
+}
+
+void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_sur,
+ jobject display, jobject config, jobject native_pixmap,
+ jintArray attrib_list)
+{
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLConfig cnf = getConfig(_env, config);
+ jint* base = 0;
+
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)_env->GetIntField(native_pixmap,
+ gBitmap_NativeBitmapFieldID);
+ SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0;
+ if (ref == NULL) {
+ doThrow(_env, "java/lang/NullPointerException", "Bitmap has no PixelRef");
+ return;
+ }
+
+ ref->safeRef();
+ ref->lockPixels();
+
+ egl_native_pixmap_t pixmap;
+ pixmap.version = sizeof(pixmap);
+ pixmap.width = nativeBitmap->width();
+ pixmap.height = nativeBitmap->height();
+ pixmap.stride = nativeBitmap->rowBytes() / nativeBitmap->bytesPerPixel();
+ pixmap.format = convertPixelFormat(nativeBitmap->config());
+ pixmap.data = (uint8_t*)ref->pixels();
+
+ if (attrib_list) {
+ // XXX: if array is malformed, we should return an NPE instead of segfault
+ base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
+ }
+ EGLSurface sur = eglCreatePixmapSurface(dpy, cnf, &pixmap, base);
+ if (attrib_list) {
+ _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
+ }
+
+ if (sur != EGL_NO_SURFACE) {
+ _env->SetIntField(out_sur, gSurface_EGLSurfaceFieldID, (int)sur);
+ _env->SetIntField(out_sur, gSurface_NativePixelRefFieldID, (int)ref);
+ } else {
+ ref->unlockPixels();
+ ref->safeUnref();
+ }
+}
+
+jint jni_eglCreateWindowSurface(JNIEnv *_env, jobject _this, jobject display,
+ jobject config, jobject native_window, jintArray attrib_list) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLContext cnf = getConfig(_env, config);
+ Surface* window = 0;
+ if (native_window == NULL) {
+not_valid_surface:
+ doThrow(_env, "java/lang/NullPointerException",
+ "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface");
+ return 0;
+ }
+ window = (Surface*)_env->GetIntField(native_window, gSurface_SurfaceFieldID);
+ if (window == NULL)
+ goto not_valid_surface;
+
+ jint* base = 0;
+ if (attrib_list) {
+ // XXX: if array is malformed, we should return an NPE instead of segfault
+ base = (jint *)_env->GetPrimitiveArrayCritical(attrib_list, (jboolean *)0);
+ }
+ EGLSurface sur = eglCreateWindowSurface(dpy, cnf, new EGLNativeWindowSurface(window), base);
+ if (attrib_list) {
+ _env->ReleasePrimitiveArrayCritical(attrib_list, base, JNI_ABORT);
+ }
+ return (jint)sur;
+}
+
+jboolean jni_eglGetConfigAttrib(JNIEnv *_env, jobject _this, jobject display,
+ jobject config, jint attribute, jintArray value) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLContext cnf = getConfig(_env, config);
+ if (value == NULL) {
+ doThrow(_env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+ jboolean success = JNI_FALSE;
+ int len = _env->GetArrayLength(value);
+ if (len) {
+ jint* base = (jint *)_env->GetPrimitiveArrayCritical(value, (jboolean *)0);
+ success = eglGetConfigAttrib(dpy, cnf, attribute, base);
+ _env->ReleasePrimitiveArrayCritical(value, base, JNI_ABORT);
+ }
+ return success;
+}
+
+jboolean jni_eglGetConfigs(JNIEnv *_env, jobject _this, jobject display,
+ jobjectArray configs, jint config_size, jintArray num_config) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ jboolean success = JNI_FALSE;
+ if (num_config == NULL) {
+ doThrow(_env, "java/lang/NullPointerException");
+ return JNI_FALSE;
+ }
+ jint* num_base = (jint *)_env->GetPrimitiveArrayCritical(num_config, (jboolean *)0);
+ EGLConfig nativeConfigs[config_size];
+ success = eglGetConfigs(dpy, configs ? nativeConfigs : 0, config_size, num_base);
+ int num = num_base[0];
+ _env->ReleasePrimitiveArrayCritical(num_config, num_base, JNI_ABORT);
+
+ 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]);
+ }
+ }
+ return success;
+}
+
+jint jni_eglGetError(JNIEnv *_env, jobject _this) {
+ EGLint error = eglGetError();
+ return error;
+}
+
+jint jni_eglGetCurrentContext(JNIEnv *_env, jobject _this) {
+ return (jint)eglGetCurrentContext();
+}
+
+jint jni_eglGetCurrentDisplay(JNIEnv *_env, jobject _this) {
+ return (jint)eglGetCurrentDisplay();
+}
+
+jint jni_eglGetCurrentSurface(JNIEnv *_env, jobject _this, jint readdraw) {
+ return (jint)eglGetCurrentSurface(readdraw);
+}
+
+jboolean jni_eglDestroyContext(JNIEnv *_env, jobject _this, jobject display, jobject context) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLContext ctx = getContext(_env, context);
+ return eglDestroyContext(dpy, ctx);
+}
+
+jboolean jni_eglDestroySurface(JNIEnv *_env, jobject _this, jobject display, jobject surface) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLSurface sur = getSurface(_env, surface);
+
+ if (sur) {
+ SkPixelRef* ref = (SkPixelRef*)(_env->GetIntField(surface,
+ gSurface_NativePixelRefFieldID));
+ if (ref) {
+ ref->unlockPixels();
+ ref->safeUnref();
+ }
+ }
+ return eglDestroySurface(dpy, sur);
+}
+
+jint jni_eglGetDisplay(JNIEnv *_env, jobject _this, jobject native_display) {
+ return (jint)eglGetDisplay(EGL_DEFAULT_DISPLAY);
+}
+
+jboolean jni_eglMakeCurrent(JNIEnv *_env, jobject _this, jobject display, jobject draw, jobject read, jobject context) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLSurface sdr = getSurface(_env, draw);
+ EGLSurface srd = getSurface(_env, read);
+ EGLContext ctx = getContext(_env, context);
+ return eglMakeCurrent(dpy, sdr, srd, ctx);
+}
+
+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));
+}
+
+jboolean jni_eglSwapBuffers(JNIEnv *_env, jobject _this, jobject display, jobject surface) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLSurface sur = getSurface(_env, surface);
+ return eglSwapBuffers(dpy, sur);
+}
+
+jboolean jni_eglTerminate(JNIEnv *_env, jobject _this, jobject display) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ return eglTerminate(dpy);
+}
+
+jboolean jni_eglCopyBuffers(JNIEnv *_env, jobject _this, jobject display,
+ jobject surface, jobject native_pixmap) {
+ // TODO: implement me
+ return JNI_FALSE;
+}
+
+jboolean jni_eglWaitGL(JNIEnv *_env, jobject _this) {
+ return eglWaitGL();
+}
+
+jboolean jni_eglWaitNative(JNIEnv *_env, jobject _this, jint engine, jobject bindTarget) {
+ return eglWaitNative(engine);
+}
+
+
+static const char *classPathName = "com/google/android/gles_jni/EGLImpl";
+
+#define DISPLAY "Ljavax/microedition/khronos/egl/EGLDisplay;"
+#define CONTEXT "Ljavax/microedition/khronos/egl/EGLContext;"
+#define CONFIG "Ljavax/microedition/khronos/egl/EGLConfig;"
+#define SURFACE "Ljavax/microedition/khronos/egl/EGLSurface;"
+#define OBJECT "Ljava/lang/Object;"
+#define STRING "Ljava/lang/String;"
+
+static JNINativeMethod methods[] = {
+{"_nativeClassInit","()V", (void*)nativeClassInit },
+{"eglWaitGL", "()Z", (void*)jni_eglWaitGL },
+{"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
+{"eglQueryContext", "(" DISPLAY CONTEXT "I[I)Z", (void*)jni_eglQueryContext },
+{"eglQuerySurface", "(" DISPLAY SURFACE "I[I)Z", (void*)jni_eglQuerySurface },
+{"eglChooseConfig", "(" DISPLAY "[I[" CONFIG "I[I)Z", (void*)jni_eglChooseConfig },
+{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)I", (void*)jni_eglCreateContext },
+{"eglGetConfigs", "(" DISPLAY "[" CONFIG "I[I)Z", (void*)jni_eglGetConfigs },
+{"eglTerminate", "(" DISPLAY ")Z", (void*)jni_eglTerminate },
+{"eglCopyBuffers", "(" DISPLAY SURFACE OBJECT ")Z", (void*)jni_eglCopyBuffers },
+{"eglWaitNative", "(I" OBJECT ")Z", (void*)jni_eglWaitNative },
+{"eglGetError", "()I", (void*)jni_eglGetError },
+{"eglGetConfigAttrib", "(" DISPLAY CONFIG "I[I)Z", (void*)jni_eglGetConfigAttrib },
+{"_eglGetDisplay", "(" OBJECT ")I", (void*)jni_eglGetDisplay },
+{"_eglGetCurrentContext", "()I", (void*)jni_eglGetCurrentContext },
+{"_eglGetCurrentDisplay", "()I", (void*)jni_eglGetCurrentDisplay },
+{"_eglGetCurrentSurface", "(I)I", (void*)jni_eglGetCurrentSurface },
+{"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface },
+{"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface },
+{"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface },
+{"eglDestroyContext", "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext },
+{"eglDestroySurface", "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface },
+{"eglMakeCurrent", "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent },
+{"eglQueryString", "(" DISPLAY "I)" STRING, (void*)jni_eglQueryString },
+{"eglSwapBuffers", "(" DISPLAY SURFACE ")Z", (void*)jni_eglSwapBuffers },
+};
+
+} // namespace android
+
+int register_com_google_android_gles_jni_EGLImpl(JNIEnv *_env)
+{
+ int err;
+ err = android::AndroidRuntime::registerNativeMethods(_env,
+ android::classPathName, android::methods, NELEM(android::methods));
+ return err;
+}
+
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
new file mode 100644
index 0000000..1cd23b0
--- /dev/null
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -0,0 +1,6571 @@
+/* //device/libs/android_runtime/com_google_android_gles_jni_GLImpl.cpp
+**
+** Copyright 2006, 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.
+*/
+
+// This source file is automatically generated
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+#include <assert.h>
+#include <GLES/gl.h>
+
+#include <private/opengles/gl_context.h>
+
+#define _NUM_COMPRESSED_TEXTURE_FORMATS \
+ (::android::OGLES_NUM_COMPRESSED_TEXTURE_FORMATS)
+
+static int initialized = 0;
+
+static jclass nioAccessClass;
+static jclass bufferClass;
+static jclass OOMEClass;
+static jclass UOEClass;
+static jclass IAEClass;
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+/* Cache method IDs each time the class is loaded. */
+
+void
+nativeClassInitBuffer(JNIEnv *_env)
+{
+ jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+ nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+ jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+ bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+ getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+ positionID = _env->GetFieldID(bufferClass, "position", "I");
+ limitID = _env->GetFieldID(bufferClass, "limit", "I");
+ elementSizeShiftID =
+ _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+}
+
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+ nativeClassInitBuffer(_env);
+
+ jclass IAEClassLocal =
+ _env->FindClass("java/lang/IllegalArgumentException");
+ jclass OOMEClassLocal =
+ _env->FindClass("java/lang/OutOfMemoryError");
+ jclass UOEClassLocal =
+ _env->FindClass("java/lang/UnsupportedOperationException");
+
+ IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
+ OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
+ UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
+{
+ jint position;
+ jint limit;
+ jint elementSizeShift;
+ jlong pointer;
+ jint offset;
+ void *data;
+
+ position = _env->GetIntField(buffer, positionID);
+ limit = _env->GetIntField(buffer, limitID);
+ elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ *remaining = (limit - position) << elementSizeShift;
+ pointer = _env->CallStaticLongMethod(nioAccessClass,
+ getBasePointerID, buffer);
+ if (pointer != 0L) {
+ *array = NULL;
+ return (void *) (jint) pointer;
+ }
+
+ *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+ getBaseArrayID, buffer);
+ offset = _env->CallStaticIntMethod(nioAccessClass,
+ getBaseArrayOffsetID, buffer);
+ data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
+
+ return (void *) ((char *) data + offset);
+}
+
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+ _env->ReleasePrimitiveArrayCritical(array, data,
+ commit ? 0 : JNI_ABORT);
+}
+
+// --------------------------------------------------------------------------
+
+/* void glActiveTexture ( GLenum texture ) */
+static void
+android_glActiveTexture__I
+ (JNIEnv *_env, jobject _this, jint texture) {
+ glActiveTexture(
+ (GLenum)texture
+ );
+}
+
+/* void glAlphaFunc ( GLenum func, GLclampf ref ) */
+static void
+android_glAlphaFunc__IF
+ (JNIEnv *_env, jobject _this, jint func, jfloat ref) {
+ glAlphaFunc(
+ (GLenum)func,
+ (GLclampf)ref
+ );
+}
+
+/* void glAlphaFuncx ( GLenum func, GLclampx ref ) */
+static void
+android_glAlphaFuncx__II
+ (JNIEnv *_env, jobject _this, jint func, jint ref) {
+ glAlphaFuncx(
+ (GLenum)func,
+ (GLclampx)ref
+ );
+}
+
+/* void glBindTexture ( GLenum target, GLuint texture ) */
+static void
+android_glBindTexture__II
+ (JNIEnv *_env, jobject _this, jint target, jint texture) {
+ glBindTexture(
+ (GLenum)target,
+ (GLuint)texture
+ );
+}
+
+/* void glBlendFunc ( GLenum sfactor, GLenum dfactor ) */
+static void
+android_glBlendFunc__II
+ (JNIEnv *_env, jobject _this, jint sfactor, jint dfactor) {
+ glBlendFunc(
+ (GLenum)sfactor,
+ (GLenum)dfactor
+ );
+}
+
+/* void glClear ( GLbitfield mask ) */
+static void
+android_glClear__I
+ (JNIEnv *_env, jobject _this, jint mask) {
+ glClear(
+ (GLbitfield)mask
+ );
+}
+
+/* void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) */
+static void
+android_glClearColor__FFFF
+ (JNIEnv *_env, jobject _this, jfloat red, jfloat green, jfloat blue, jfloat alpha) {
+ glClearColor(
+ (GLclampf)red,
+ (GLclampf)green,
+ (GLclampf)blue,
+ (GLclampf)alpha
+ );
+}
+
+/* void glClearColorx ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) */
+static void
+android_glClearColorx__IIII
+ (JNIEnv *_env, jobject _this, jint red, jint green, jint blue, jint alpha) {
+ glClearColorx(
+ (GLclampx)red,
+ (GLclampx)green,
+ (GLclampx)blue,
+ (GLclampx)alpha
+ );
+}
+
+/* void glClearDepthf ( GLclampf depth ) */
+static void
+android_glClearDepthf__F
+ (JNIEnv *_env, jobject _this, jfloat depth) {
+ glClearDepthf(
+ (GLclampf)depth
+ );
+}
+
+/* void glClearDepthx ( GLclampx depth ) */
+static void
+android_glClearDepthx__I
+ (JNIEnv *_env, jobject _this, jint depth) {
+ glClearDepthx(
+ (GLclampx)depth
+ );
+}
+
+/* void glClearStencil ( GLint s ) */
+static void
+android_glClearStencil__I
+ (JNIEnv *_env, jobject _this, jint s) {
+ glClearStencil(
+ (GLint)s
+ );
+}
+
+/* void glClientActiveTexture ( GLenum texture ) */
+static void
+android_glClientActiveTexture__I
+ (JNIEnv *_env, jobject _this, jint texture) {
+ glClientActiveTexture(
+ (GLenum)texture
+ );
+}
+
+/* void glColor4f ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) */
+static void
+android_glColor4f__FFFF
+ (JNIEnv *_env, jobject _this, jfloat red, jfloat green, jfloat blue, jfloat alpha) {
+ glColor4f(
+ (GLfloat)red,
+ (GLfloat)green,
+ (GLfloat)blue,
+ (GLfloat)alpha
+ );
+}
+
+/* void glColor4x ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) */
+static void
+android_glColor4x__IIII
+ (JNIEnv *_env, jobject _this, jint red, jint green, jint blue, jint alpha) {
+ glColor4x(
+ (GLfixed)red,
+ (GLfixed)green,
+ (GLfixed)blue,
+ (GLfixed)alpha
+ );
+}
+
+/* void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ) */
+static void
+android_glColorMask__ZZZZ
+ (JNIEnv *_env, jobject _this, jboolean red, jboolean green, jboolean blue, jboolean alpha) {
+ glColorMask(
+ (GLboolean)red,
+ (GLboolean)green,
+ (GLboolean)blue,
+ (GLboolean)alpha
+ );
+}
+
+/* void glColorPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glColorPointerBounds__IIILjava_nio_Buffer_2I
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pointer = (GLvoid *) 0;
+
+ pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining);
+ glColorPointerBounds(
+ (GLint)size,
+ (GLenum)type,
+ (GLsizei)stride,
+ (GLvoid *)pointer,
+ (GLsizei)remaining
+ );
+ if (_array) {
+ releasePointer(_env, _array, pointer, JNI_FALSE);
+ }
+}
+
+/* void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) */
+static void
+android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint imageSize, jobject data_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *data = (GLvoid *) 0;
+
+ data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ glCompressedTexImage2D(
+ (GLenum)target,
+ (GLint)level,
+ (GLenum)internalformat,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLint)border,
+ (GLsizei)imageSize,
+ (GLvoid *)data
+ );
+ if (_array) {
+ releasePointer(_env, _array, data, JNI_FALSE);
+ }
+}
+
+/* void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) */
+static void
+android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint imageSize, jobject data_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *data = (GLvoid *) 0;
+
+ data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ glCompressedTexSubImage2D(
+ (GLenum)target,
+ (GLint)level,
+ (GLint)xoffset,
+ (GLint)yoffset,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLenum)format,
+ (GLsizei)imageSize,
+ (GLvoid *)data
+ );
+ if (_array) {
+ releasePointer(_env, _array, data, JNI_FALSE);
+ }
+}
+
+/* void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) */
+static void
+android_glCopyTexImage2D__IIIIIIII
+ (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint x, jint y, jint width, jint height, jint border) {
+ glCopyTexImage2D(
+ (GLenum)target,
+ (GLint)level,
+ (GLenum)internalformat,
+ (GLint)x,
+ (GLint)y,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLint)border
+ );
+}
+
+/* void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) */
+static void
+android_glCopyTexSubImage2D__IIIIIIII
+ (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint x, jint y, jint width, jint height) {
+ glCopyTexSubImage2D(
+ (GLenum)target,
+ (GLint)level,
+ (GLint)xoffset,
+ (GLint)yoffset,
+ (GLint)x,
+ (GLint)y,
+ (GLsizei)width,
+ (GLsizei)height
+ );
+}
+
+/* void glCullFace ( GLenum mode ) */
+static void
+android_glCullFace__I
+ (JNIEnv *_env, jobject _this, jint mode) {
+ glCullFace(
+ (GLenum)mode
+ );
+}
+
+/* void glDeleteTextures ( GLsizei n, const GLuint *textures ) */
+static void
+android_glDeleteTextures__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray textures_ref, jint offset) {
+ GLuint *textures_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *textures = (GLuint *) 0;
+
+ if (!textures_ref) {
+ _env->ThrowNew(IAEClass, "textures == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(textures_ref) - offset;
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ textures_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(textures_ref, (jboolean *)0);
+ textures = textures_base + offset;
+
+ glDeleteTextures(
+ (GLsizei)n,
+ (GLuint *)textures
+ );
+
+exit:
+ if (textures_base) {
+ _env->ReleasePrimitiveArrayCritical(textures_ref, textures_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glDeleteTextures ( GLsizei n, const GLuint *textures ) */
+static void
+android_glDeleteTextures__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject textures_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *textures = (GLuint *) 0;
+
+ textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glDeleteTextures(
+ (GLsizei)n,
+ (GLuint *)textures
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, textures, JNI_FALSE);
+ }
+}
+
+/* void glDepthFunc ( GLenum func ) */
+static void
+android_glDepthFunc__I
+ (JNIEnv *_env, jobject _this, jint func) {
+ glDepthFunc(
+ (GLenum)func
+ );
+}
+
+/* void glDepthMask ( GLboolean flag ) */
+static void
+android_glDepthMask__Z
+ (JNIEnv *_env, jobject _this, jboolean flag) {
+ glDepthMask(
+ (GLboolean)flag
+ );
+}
+
+/* void glDepthRangef ( GLclampf zNear, GLclampf zFar ) */
+static void
+android_glDepthRangef__FF
+ (JNIEnv *_env, jobject _this, jfloat zNear, jfloat zFar) {
+ glDepthRangef(
+ (GLclampf)zNear,
+ (GLclampf)zFar
+ );
+}
+
+/* void glDepthRangex ( GLclampx zNear, GLclampx zFar ) */
+static void
+android_glDepthRangex__II
+ (JNIEnv *_env, jobject _this, jint zNear, jint zFar) {
+ glDepthRangex(
+ (GLclampx)zNear,
+ (GLclampx)zFar
+ );
+}
+
+/* void glDisable ( GLenum cap ) */
+static void
+android_glDisable__I
+ (JNIEnv *_env, jobject _this, jint cap) {
+ glDisable(
+ (GLenum)cap
+ );
+}
+
+/* void glDisableClientState ( GLenum array ) */
+static void
+android_glDisableClientState__I
+ (JNIEnv *_env, jobject _this, jint array) {
+ glDisableClientState(
+ (GLenum)array
+ );
+}
+
+/* void glDrawArrays ( GLenum mode, GLint first, GLsizei count ) */
+static void
+android_glDrawArrays__III
+ (JNIEnv *_env, jobject _this, jint mode, jint first, jint count) {
+ glDrawArrays(
+ (GLenum)mode,
+ (GLint)first,
+ (GLsizei)count
+ );
+}
+
+/* void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) */
+static void
+android_glDrawElements__IIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *indices = (GLvoid *) 0;
+
+ indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
+ glDrawElements(
+ (GLenum)mode,
+ (GLsizei)count,
+ (GLenum)type,
+ (GLvoid *)indices
+ );
+ if (_array) {
+ releasePointer(_env, _array, indices, JNI_FALSE);
+ }
+}
+
+/* void glEnable ( GLenum cap ) */
+static void
+android_glEnable__I
+ (JNIEnv *_env, jobject _this, jint cap) {
+ glEnable(
+ (GLenum)cap
+ );
+}
+
+/* void glEnableClientState ( GLenum array ) */
+static void
+android_glEnableClientState__I
+ (JNIEnv *_env, jobject _this, jint array) {
+ glEnableClientState(
+ (GLenum)array
+ );
+}
+
+/* void glFinish ( void ) */
+static void
+android_glFinish__
+ (JNIEnv *_env, jobject _this) {
+ glFinish();
+}
+
+/* void glFlush ( void ) */
+static void
+android_glFlush__
+ (JNIEnv *_env, jobject _this) {
+ glFlush();
+}
+
+/* void glFogf ( GLenum pname, GLfloat param ) */
+static void
+android_glFogf__IF
+ (JNIEnv *_env, jobject _this, jint pname, jfloat param) {
+ glFogf(
+ (GLenum)pname,
+ (GLfloat)param
+ );
+}
+
+/* void glFogfv ( GLenum pname, const GLfloat *params ) */
+static void
+android_glFogfv__I_3FI
+ (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) {
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_FOG_MODE)
+ case GL_FOG_MODE:
+#endif // defined(GL_FOG_MODE)
+#if defined(GL_FOG_DENSITY)
+ case GL_FOG_DENSITY:
+#endif // defined(GL_FOG_DENSITY)
+#if defined(GL_FOG_START)
+ case GL_FOG_START:
+#endif // defined(GL_FOG_START)
+#if defined(GL_FOG_END)
+ case GL_FOG_END:
+#endif // defined(GL_FOG_END)
+ _needed = 1;
+ break;
+#if defined(GL_FOG_COLOR)
+ case GL_FOG_COLOR:
+#endif // defined(GL_FOG_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glFogfv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glFogfv ( GLenum pname, const GLfloat *params ) */
+static void
+android_glFogfv__ILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_FOG_MODE)
+ case GL_FOG_MODE:
+#endif // defined(GL_FOG_MODE)
+#if defined(GL_FOG_DENSITY)
+ case GL_FOG_DENSITY:
+#endif // defined(GL_FOG_DENSITY)
+#if defined(GL_FOG_START)
+ case GL_FOG_START:
+#endif // defined(GL_FOG_START)
+#if defined(GL_FOG_END)
+ case GL_FOG_END:
+#endif // defined(GL_FOG_END)
+ _needed = 1;
+ break;
+#if defined(GL_FOG_COLOR)
+ case GL_FOG_COLOR:
+#endif // defined(GL_FOG_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glFogfv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glFogx ( GLenum pname, GLfixed param ) */
+static void
+android_glFogx__II
+ (JNIEnv *_env, jobject _this, jint pname, jint param) {
+ glFogx(
+ (GLenum)pname,
+ (GLfixed)param
+ );
+}
+
+/* void glFogxv ( GLenum pname, const GLfixed *params ) */
+static void
+android_glFogxv__I_3II
+ (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) {
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_FOG_MODE)
+ case GL_FOG_MODE:
+#endif // defined(GL_FOG_MODE)
+#if defined(GL_FOG_DENSITY)
+ case GL_FOG_DENSITY:
+#endif // defined(GL_FOG_DENSITY)
+#if defined(GL_FOG_START)
+ case GL_FOG_START:
+#endif // defined(GL_FOG_START)
+#if defined(GL_FOG_END)
+ case GL_FOG_END:
+#endif // defined(GL_FOG_END)
+ _needed = 1;
+ break;
+#if defined(GL_FOG_COLOR)
+ case GL_FOG_COLOR:
+#endif // defined(GL_FOG_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glFogxv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glFogxv ( GLenum pname, const GLfixed *params ) */
+static void
+android_glFogxv__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_FOG_MODE)
+ case GL_FOG_MODE:
+#endif // defined(GL_FOG_MODE)
+#if defined(GL_FOG_DENSITY)
+ case GL_FOG_DENSITY:
+#endif // defined(GL_FOG_DENSITY)
+#if defined(GL_FOG_START)
+ case GL_FOG_START:
+#endif // defined(GL_FOG_START)
+#if defined(GL_FOG_END)
+ case GL_FOG_END:
+#endif // defined(GL_FOG_END)
+ _needed = 1;
+ break;
+#if defined(GL_FOG_COLOR)
+ case GL_FOG_COLOR:
+#endif // defined(GL_FOG_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glFogxv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glFrontFace ( GLenum mode ) */
+static void
+android_glFrontFace__I
+ (JNIEnv *_env, jobject _this, jint mode) {
+ glFrontFace(
+ (GLenum)mode
+ );
+}
+
+/* void glFrustumf ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */
+static void
+android_glFrustumf__FFFFFF
+ (JNIEnv *_env, jobject _this, jfloat left, jfloat right, jfloat bottom, jfloat top, jfloat zNear, jfloat zFar) {
+ glFrustumf(
+ (GLfloat)left,
+ (GLfloat)right,
+ (GLfloat)bottom,
+ (GLfloat)top,
+ (GLfloat)zNear,
+ (GLfloat)zFar
+ );
+}
+
+/* void glFrustumx ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) */
+static void
+android_glFrustumx__IIIIII
+ (JNIEnv *_env, jobject _this, jint left, jint right, jint bottom, jint top, jint zNear, jint zFar) {
+ glFrustumx(
+ (GLfixed)left,
+ (GLfixed)right,
+ (GLfixed)bottom,
+ (GLfixed)top,
+ (GLfixed)zNear,
+ (GLfixed)zFar
+ );
+}
+
+/* void glGenTextures ( GLsizei n, GLuint *textures ) */
+static void
+android_glGenTextures__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray textures_ref, jint offset) {
+ jint _exception = 0;
+ GLuint *textures_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *textures = (GLuint *) 0;
+
+ if (!textures_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "textures == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(textures_ref) - offset;
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ textures_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(textures_ref, (jboolean *)0);
+ textures = textures_base + offset;
+
+ glGenTextures(
+ (GLsizei)n,
+ (GLuint *)textures
+ );
+
+exit:
+ if (textures_base) {
+ _env->ReleasePrimitiveArrayCritical(textures_ref, textures_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGenTextures ( GLsizei n, GLuint *textures ) */
+static void
+android_glGenTextures__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject textures_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *textures = (GLuint *) 0;
+
+ textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glGenTextures(
+ (GLsizei)n,
+ (GLuint *)textures
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, textures, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* GLenum glGetError ( void ) */
+static jint
+android_glGetError__
+ (JNIEnv *_env, jobject _this) {
+ GLenum _returnValue;
+ _returnValue = glGetError();
+ return _returnValue;
+}
+
+/* void glGetIntegerv ( GLenum pname, GLint *params ) */
+static void
+android_glGetIntegerv__I_3II
+ (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_ALPHA_BITS)
+ case GL_ALPHA_BITS:
+#endif // defined(GL_ALPHA_BITS)
+#if defined(GL_ALPHA_TEST_FUNC)
+ case GL_ALPHA_TEST_FUNC:
+#endif // defined(GL_ALPHA_TEST_FUNC)
+#if defined(GL_ALPHA_TEST_REF)
+ case GL_ALPHA_TEST_REF:
+#endif // defined(GL_ALPHA_TEST_REF)
+#if defined(GL_BLEND_DST)
+ case GL_BLEND_DST:
+#endif // defined(GL_BLEND_DST)
+#if defined(GL_BLUE_BITS)
+ case GL_BLUE_BITS:
+#endif // defined(GL_BLUE_BITS)
+#if defined(GL_COLOR_ARRAY_BUFFER_BINDING)
+ case GL_COLOR_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_COLOR_ARRAY_BUFFER_BINDING)
+#if defined(GL_COLOR_ARRAY_SIZE)
+ case GL_COLOR_ARRAY_SIZE:
+#endif // defined(GL_COLOR_ARRAY_SIZE)
+#if defined(GL_COLOR_ARRAY_STRIDE)
+ case GL_COLOR_ARRAY_STRIDE:
+#endif // defined(GL_COLOR_ARRAY_STRIDE)
+#if defined(GL_COLOR_ARRAY_TYPE)
+ case GL_COLOR_ARRAY_TYPE:
+#endif // defined(GL_COLOR_ARRAY_TYPE)
+#if defined(GL_CULL_FACE)
+ case GL_CULL_FACE:
+#endif // defined(GL_CULL_FACE)
+#if defined(GL_DEPTH_BITS)
+ case GL_DEPTH_BITS:
+#endif // defined(GL_DEPTH_BITS)
+#if defined(GL_DEPTH_CLEAR_VALUE)
+ case GL_DEPTH_CLEAR_VALUE:
+#endif // defined(GL_DEPTH_CLEAR_VALUE)
+#if defined(GL_DEPTH_FUNC)
+ case GL_DEPTH_FUNC:
+#endif // defined(GL_DEPTH_FUNC)
+#if defined(GL_DEPTH_WRITEMASK)
+ case GL_DEPTH_WRITEMASK:
+#endif // defined(GL_DEPTH_WRITEMASK)
+#if defined(GL_FOG_DENSITY)
+ case GL_FOG_DENSITY:
+#endif // defined(GL_FOG_DENSITY)
+#if defined(GL_FOG_END)
+ case GL_FOG_END:
+#endif // defined(GL_FOG_END)
+#if defined(GL_FOG_MODE)
+ case GL_FOG_MODE:
+#endif // defined(GL_FOG_MODE)
+#if defined(GL_FOG_START)
+ case GL_FOG_START:
+#endif // defined(GL_FOG_START)
+#if defined(GL_FRONT_FACE)
+ case GL_FRONT_FACE:
+#endif // defined(GL_FRONT_FACE)
+#if defined(GL_GREEN_BITS)
+ case GL_GREEN_BITS:
+#endif // defined(GL_GREEN_BITS)
+#if defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES)
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+#endif // defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES)
+#if defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES)
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+#endif // defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES)
+#if defined(GL_LIGHT_MODEL_TWO_SIDE)
+ case GL_LIGHT_MODEL_TWO_SIDE:
+#endif // defined(GL_LIGHT_MODEL_TWO_SIDE)
+#if defined(GL_LINE_SMOOTH_HINT)
+ case GL_LINE_SMOOTH_HINT:
+#endif // defined(GL_LINE_SMOOTH_HINT)
+#if defined(GL_LINE_WIDTH)
+ case GL_LINE_WIDTH:
+#endif // defined(GL_LINE_WIDTH)
+#if defined(GL_LOGIC_OP_MODE)
+ case GL_LOGIC_OP_MODE:
+#endif // defined(GL_LOGIC_OP_MODE)
+#if defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES)
+ case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES)
+#if defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES)
+ case GL_MATRIX_INDEX_ARRAY_SIZE_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES)
+#if defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES)
+ case GL_MATRIX_INDEX_ARRAY_STRIDE_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES)
+#if defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES)
+ case GL_MATRIX_INDEX_ARRAY_TYPE_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES)
+#if defined(GL_MATRIX_MODE)
+ case GL_MATRIX_MODE:
+#endif // defined(GL_MATRIX_MODE)
+#if defined(GL_MAX_CLIP_PLANES)
+ case GL_MAX_CLIP_PLANES:
+#endif // defined(GL_MAX_CLIP_PLANES)
+#if defined(GL_MAX_ELEMENTS_INDICES)
+ case GL_MAX_ELEMENTS_INDICES:
+#endif // defined(GL_MAX_ELEMENTS_INDICES)
+#if defined(GL_MAX_ELEMENTS_VERTICES)
+ case GL_MAX_ELEMENTS_VERTICES:
+#endif // defined(GL_MAX_ELEMENTS_VERTICES)
+#if defined(GL_MAX_LIGHTS)
+ case GL_MAX_LIGHTS:
+#endif // defined(GL_MAX_LIGHTS)
+#if defined(GL_MAX_MODELVIEW_STACK_DEPTH)
+ case GL_MAX_MODELVIEW_STACK_DEPTH:
+#endif // defined(GL_MAX_MODELVIEW_STACK_DEPTH)
+#if defined(GL_MAX_PALETTE_MATRICES_OES)
+ case GL_MAX_PALETTE_MATRICES_OES:
+#endif // defined(GL_MAX_PALETTE_MATRICES_OES)
+#if defined(GL_MAX_PROJECTION_STACK_DEPTH)
+ case GL_MAX_PROJECTION_STACK_DEPTH:
+#endif // defined(GL_MAX_PROJECTION_STACK_DEPTH)
+#if defined(GL_MAX_TEXTURE_SIZE)
+ case GL_MAX_TEXTURE_SIZE:
+#endif // defined(GL_MAX_TEXTURE_SIZE)
+#if defined(GL_MAX_TEXTURE_STACK_DEPTH)
+ case GL_MAX_TEXTURE_STACK_DEPTH:
+#endif // defined(GL_MAX_TEXTURE_STACK_DEPTH)
+#if defined(GL_MAX_TEXTURE_UNITS)
+ case GL_MAX_TEXTURE_UNITS:
+#endif // defined(GL_MAX_TEXTURE_UNITS)
+#if defined(GL_MAX_VERTEX_UNITS_OES)
+ case GL_MAX_VERTEX_UNITS_OES:
+#endif // defined(GL_MAX_VERTEX_UNITS_OES)
+#if defined(GL_MODELVIEW_STACK_DEPTH)
+ case GL_MODELVIEW_STACK_DEPTH:
+#endif // defined(GL_MODELVIEW_STACK_DEPTH)
+#if defined(GL_NORMAL_ARRAY_BUFFER_BINDING)
+ case GL_NORMAL_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_NORMAL_ARRAY_BUFFER_BINDING)
+#if defined(GL_NORMAL_ARRAY_STRIDE)
+ case GL_NORMAL_ARRAY_STRIDE:
+#endif // defined(GL_NORMAL_ARRAY_STRIDE)
+#if defined(GL_NORMAL_ARRAY_TYPE)
+ case GL_NORMAL_ARRAY_TYPE:
+#endif // defined(GL_NORMAL_ARRAY_TYPE)
+#if defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS)
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+#endif // defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS)
+#if defined(GL_PACK_ALIGNMENT)
+ case GL_PACK_ALIGNMENT:
+#endif // defined(GL_PACK_ALIGNMENT)
+#if defined(GL_PERSPECTIVE_CORRECTION_HINT)
+ case GL_PERSPECTIVE_CORRECTION_HINT:
+#endif // defined(GL_PERSPECTIVE_CORRECTION_HINT)
+#if defined(GL_POINT_SIZE)
+ case GL_POINT_SIZE:
+#endif // defined(GL_POINT_SIZE)
+#if defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES)
+ case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
+#endif // defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES)
+#if defined(GL_POINT_SIZE_ARRAY_STRIDE_OES)
+ case GL_POINT_SIZE_ARRAY_STRIDE_OES:
+#endif // defined(GL_POINT_SIZE_ARRAY_STRIDE_OES)
+#if defined(GL_POINT_SIZE_ARRAY_TYPE_OES)
+ case GL_POINT_SIZE_ARRAY_TYPE_OES:
+#endif // defined(GL_POINT_SIZE_ARRAY_TYPE_OES)
+#if defined(GL_POINT_SMOOTH_HINT)
+ case GL_POINT_SMOOTH_HINT:
+#endif // defined(GL_POINT_SMOOTH_HINT)
+#if defined(GL_POLYGON_OFFSET_FACTOR)
+ case GL_POLYGON_OFFSET_FACTOR:
+#endif // defined(GL_POLYGON_OFFSET_FACTOR)
+#if defined(GL_POLYGON_OFFSET_UNITS)
+ case GL_POLYGON_OFFSET_UNITS:
+#endif // defined(GL_POLYGON_OFFSET_UNITS)
+#if defined(GL_PROJECTION_STACK_DEPTH)
+ case GL_PROJECTION_STACK_DEPTH:
+#endif // defined(GL_PROJECTION_STACK_DEPTH)
+#if defined(GL_RED_BITS)
+ case GL_RED_BITS:
+#endif // defined(GL_RED_BITS)
+#if defined(GL_SHADE_MODEL)
+ case GL_SHADE_MODEL:
+#endif // defined(GL_SHADE_MODEL)
+#if defined(GL_STENCIL_BITS)
+ case GL_STENCIL_BITS:
+#endif // defined(GL_STENCIL_BITS)
+#if defined(GL_STENCIL_CLEAR_VALUE)
+ case GL_STENCIL_CLEAR_VALUE:
+#endif // defined(GL_STENCIL_CLEAR_VALUE)
+#if defined(GL_STENCIL_FAIL)
+ case GL_STENCIL_FAIL:
+#endif // defined(GL_STENCIL_FAIL)
+#if defined(GL_STENCIL_FUNC)
+ case GL_STENCIL_FUNC:
+#endif // defined(GL_STENCIL_FUNC)
+#if defined(GL_STENCIL_PASS_DEPTH_FAIL)
+ case GL_STENCIL_PASS_DEPTH_FAIL:
+#endif // defined(GL_STENCIL_PASS_DEPTH_FAIL)
+#if defined(GL_STENCIL_PASS_DEPTH_PASS)
+ case GL_STENCIL_PASS_DEPTH_PASS:
+#endif // defined(GL_STENCIL_PASS_DEPTH_PASS)
+#if defined(GL_STENCIL_REF)
+ case GL_STENCIL_REF:
+#endif // defined(GL_STENCIL_REF)
+#if defined(GL_STENCIL_VALUE_MASK)
+ case GL_STENCIL_VALUE_MASK:
+#endif // defined(GL_STENCIL_VALUE_MASK)
+#if defined(GL_STENCIL_WRITEMASK)
+ case GL_STENCIL_WRITEMASK:
+#endif // defined(GL_STENCIL_WRITEMASK)
+#if defined(GL_SUBPIXEL_BITS)
+ case GL_SUBPIXEL_BITS:
+#endif // defined(GL_SUBPIXEL_BITS)
+#if defined(GL_TEXTURE_BINDING_2D)
+ case GL_TEXTURE_BINDING_2D:
+#endif // defined(GL_TEXTURE_BINDING_2D)
+#if defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING)
+ case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING)
+#if defined(GL_TEXTURE_COORD_ARRAY_SIZE)
+ case GL_TEXTURE_COORD_ARRAY_SIZE:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_SIZE)
+#if defined(GL_TEXTURE_COORD_ARRAY_STRIDE)
+ case GL_TEXTURE_COORD_ARRAY_STRIDE:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_STRIDE)
+#if defined(GL_TEXTURE_COORD_ARRAY_TYPE)
+ case GL_TEXTURE_COORD_ARRAY_TYPE:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_TYPE)
+#if defined(GL_TEXTURE_STACK_DEPTH)
+ case GL_TEXTURE_STACK_DEPTH:
+#endif // defined(GL_TEXTURE_STACK_DEPTH)
+#if defined(GL_UNPACK_ALIGNMENT)
+ case GL_UNPACK_ALIGNMENT:
+#endif // defined(GL_UNPACK_ALIGNMENT)
+#if defined(GL_VERTEX_ARRAY_BUFFER_BINDING)
+ case GL_VERTEX_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_VERTEX_ARRAY_BUFFER_BINDING)
+#if defined(GL_VERTEX_ARRAY_SIZE)
+ case GL_VERTEX_ARRAY_SIZE:
+#endif // defined(GL_VERTEX_ARRAY_SIZE)
+#if defined(GL_VERTEX_ARRAY_STRIDE)
+ case GL_VERTEX_ARRAY_STRIDE:
+#endif // defined(GL_VERTEX_ARRAY_STRIDE)
+#if defined(GL_VERTEX_ARRAY_TYPE)
+ case GL_VERTEX_ARRAY_TYPE:
+#endif // defined(GL_VERTEX_ARRAY_TYPE)
+#if defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES)
+ case GL_WEIGHT_ARRAY_BUFFER_BINDING_OES:
+#endif // defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES)
+#if defined(GL_WEIGHT_ARRAY_SIZE_OES)
+ case GL_WEIGHT_ARRAY_SIZE_OES:
+#endif // defined(GL_WEIGHT_ARRAY_SIZE_OES)
+#if defined(GL_WEIGHT_ARRAY_STRIDE_OES)
+ case GL_WEIGHT_ARRAY_STRIDE_OES:
+#endif // defined(GL_WEIGHT_ARRAY_STRIDE_OES)
+#if defined(GL_WEIGHT_ARRAY_TYPE_OES)
+ case GL_WEIGHT_ARRAY_TYPE_OES:
+#endif // defined(GL_WEIGHT_ARRAY_TYPE_OES)
+ _needed = 1;
+ break;
+#if defined(GL_ALIASED_POINT_SIZE_RANGE)
+ case GL_ALIASED_POINT_SIZE_RANGE:
+#endif // defined(GL_ALIASED_POINT_SIZE_RANGE)
+#if defined(GL_ALIASED_LINE_WIDTH_RANGE)
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+#endif // defined(GL_ALIASED_LINE_WIDTH_RANGE)
+#if defined(GL_DEPTH_RANGE)
+ case GL_DEPTH_RANGE:
+#endif // defined(GL_DEPTH_RANGE)
+#if defined(GL_MAX_VIEWPORT_DIMS)
+ case GL_MAX_VIEWPORT_DIMS:
+#endif // defined(GL_MAX_VIEWPORT_DIMS)
+#if defined(GL_SMOOTH_LINE_WIDTH_RANGE)
+ case GL_SMOOTH_LINE_WIDTH_RANGE:
+#endif // defined(GL_SMOOTH_LINE_WIDTH_RANGE)
+#if defined(GL_SMOOTH_POINT_SIZE_RANGE)
+ case GL_SMOOTH_POINT_SIZE_RANGE:
+#endif // defined(GL_SMOOTH_POINT_SIZE_RANGE)
+ _needed = 2;
+ break;
+#if defined(GL_COLOR_CLEAR_VALUE)
+ case GL_COLOR_CLEAR_VALUE:
+#endif // defined(GL_COLOR_CLEAR_VALUE)
+#if defined(GL_COLOR_WRITEMASK)
+ case GL_COLOR_WRITEMASK:
+#endif // defined(GL_COLOR_WRITEMASK)
+#if defined(GL_SCISSOR_BOX)
+ case GL_SCISSOR_BOX:
+#endif // defined(GL_SCISSOR_BOX)
+#if defined(GL_VIEWPORT)
+ case GL_VIEWPORT:
+#endif // defined(GL_VIEWPORT)
+ _needed = 4;
+ break;
+#if defined(GL_MODELVIEW_MATRIX)
+ case GL_MODELVIEW_MATRIX:
+#endif // defined(GL_MODELVIEW_MATRIX)
+#if defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES)
+ case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
+#endif // defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES)
+#if defined(GL_PROJECTION_MATRIX)
+ case GL_PROJECTION_MATRIX:
+#endif // defined(GL_PROJECTION_MATRIX)
+#if defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES)
+ case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
+#endif // defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES)
+#if defined(GL_TEXTURE_MATRIX)
+ case GL_TEXTURE_MATRIX:
+#endif // defined(GL_TEXTURE_MATRIX)
+#if defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES)
+ case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
+#endif // defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES)
+ _needed = 16;
+ break;
+#if defined(GL_COMPRESSED_TEXTURE_FORMATS)
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+#endif // defined(GL_COMPRESSED_TEXTURE_FORMATS)
+#if defined(GL_FOG_COLOR)
+ case GL_FOG_COLOR:
+#endif // defined(GL_FOG_COLOR)
+#if defined(GL_LIGHT_MODEL_AMBIENT)
+ case GL_LIGHT_MODEL_AMBIENT:
+#endif // defined(GL_LIGHT_MODEL_AMBIENT)
+ _needed = _NUM_COMPRESSED_TEXTURE_FORMATS;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetIntegerv(
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetIntegerv ( GLenum pname, GLint *params ) */
+static void
+android_glGetIntegerv__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_ALPHA_BITS)
+ case GL_ALPHA_BITS:
+#endif // defined(GL_ALPHA_BITS)
+#if defined(GL_ALPHA_TEST_FUNC)
+ case GL_ALPHA_TEST_FUNC:
+#endif // defined(GL_ALPHA_TEST_FUNC)
+#if defined(GL_ALPHA_TEST_REF)
+ case GL_ALPHA_TEST_REF:
+#endif // defined(GL_ALPHA_TEST_REF)
+#if defined(GL_BLEND_DST)
+ case GL_BLEND_DST:
+#endif // defined(GL_BLEND_DST)
+#if defined(GL_BLUE_BITS)
+ case GL_BLUE_BITS:
+#endif // defined(GL_BLUE_BITS)
+#if defined(GL_COLOR_ARRAY_BUFFER_BINDING)
+ case GL_COLOR_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_COLOR_ARRAY_BUFFER_BINDING)
+#if defined(GL_COLOR_ARRAY_SIZE)
+ case GL_COLOR_ARRAY_SIZE:
+#endif // defined(GL_COLOR_ARRAY_SIZE)
+#if defined(GL_COLOR_ARRAY_STRIDE)
+ case GL_COLOR_ARRAY_STRIDE:
+#endif // defined(GL_COLOR_ARRAY_STRIDE)
+#if defined(GL_COLOR_ARRAY_TYPE)
+ case GL_COLOR_ARRAY_TYPE:
+#endif // defined(GL_COLOR_ARRAY_TYPE)
+#if defined(GL_CULL_FACE)
+ case GL_CULL_FACE:
+#endif // defined(GL_CULL_FACE)
+#if defined(GL_DEPTH_BITS)
+ case GL_DEPTH_BITS:
+#endif // defined(GL_DEPTH_BITS)
+#if defined(GL_DEPTH_CLEAR_VALUE)
+ case GL_DEPTH_CLEAR_VALUE:
+#endif // defined(GL_DEPTH_CLEAR_VALUE)
+#if defined(GL_DEPTH_FUNC)
+ case GL_DEPTH_FUNC:
+#endif // defined(GL_DEPTH_FUNC)
+#if defined(GL_DEPTH_WRITEMASK)
+ case GL_DEPTH_WRITEMASK:
+#endif // defined(GL_DEPTH_WRITEMASK)
+#if defined(GL_FOG_DENSITY)
+ case GL_FOG_DENSITY:
+#endif // defined(GL_FOG_DENSITY)
+#if defined(GL_FOG_END)
+ case GL_FOG_END:
+#endif // defined(GL_FOG_END)
+#if defined(GL_FOG_MODE)
+ case GL_FOG_MODE:
+#endif // defined(GL_FOG_MODE)
+#if defined(GL_FOG_START)
+ case GL_FOG_START:
+#endif // defined(GL_FOG_START)
+#if defined(GL_FRONT_FACE)
+ case GL_FRONT_FACE:
+#endif // defined(GL_FRONT_FACE)
+#if defined(GL_GREEN_BITS)
+ case GL_GREEN_BITS:
+#endif // defined(GL_GREEN_BITS)
+#if defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES)
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+#endif // defined(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES)
+#if defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES)
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+#endif // defined(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES)
+#if defined(GL_LIGHT_MODEL_TWO_SIDE)
+ case GL_LIGHT_MODEL_TWO_SIDE:
+#endif // defined(GL_LIGHT_MODEL_TWO_SIDE)
+#if defined(GL_LINE_SMOOTH_HINT)
+ case GL_LINE_SMOOTH_HINT:
+#endif // defined(GL_LINE_SMOOTH_HINT)
+#if defined(GL_LINE_WIDTH)
+ case GL_LINE_WIDTH:
+#endif // defined(GL_LINE_WIDTH)
+#if defined(GL_LOGIC_OP_MODE)
+ case GL_LOGIC_OP_MODE:
+#endif // defined(GL_LOGIC_OP_MODE)
+#if defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES)
+ case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES)
+#if defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES)
+ case GL_MATRIX_INDEX_ARRAY_SIZE_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_SIZE_OES)
+#if defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES)
+ case GL_MATRIX_INDEX_ARRAY_STRIDE_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_STRIDE_OES)
+#if defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES)
+ case GL_MATRIX_INDEX_ARRAY_TYPE_OES:
+#endif // defined(GL_MATRIX_INDEX_ARRAY_TYPE_OES)
+#if defined(GL_MATRIX_MODE)
+ case GL_MATRIX_MODE:
+#endif // defined(GL_MATRIX_MODE)
+#if defined(GL_MAX_CLIP_PLANES)
+ case GL_MAX_CLIP_PLANES:
+#endif // defined(GL_MAX_CLIP_PLANES)
+#if defined(GL_MAX_ELEMENTS_INDICES)
+ case GL_MAX_ELEMENTS_INDICES:
+#endif // defined(GL_MAX_ELEMENTS_INDICES)
+#if defined(GL_MAX_ELEMENTS_VERTICES)
+ case GL_MAX_ELEMENTS_VERTICES:
+#endif // defined(GL_MAX_ELEMENTS_VERTICES)
+#if defined(GL_MAX_LIGHTS)
+ case GL_MAX_LIGHTS:
+#endif // defined(GL_MAX_LIGHTS)
+#if defined(GL_MAX_MODELVIEW_STACK_DEPTH)
+ case GL_MAX_MODELVIEW_STACK_DEPTH:
+#endif // defined(GL_MAX_MODELVIEW_STACK_DEPTH)
+#if defined(GL_MAX_PALETTE_MATRICES_OES)
+ case GL_MAX_PALETTE_MATRICES_OES:
+#endif // defined(GL_MAX_PALETTE_MATRICES_OES)
+#if defined(GL_MAX_PROJECTION_STACK_DEPTH)
+ case GL_MAX_PROJECTION_STACK_DEPTH:
+#endif // defined(GL_MAX_PROJECTION_STACK_DEPTH)
+#if defined(GL_MAX_TEXTURE_SIZE)
+ case GL_MAX_TEXTURE_SIZE:
+#endif // defined(GL_MAX_TEXTURE_SIZE)
+#if defined(GL_MAX_TEXTURE_STACK_DEPTH)
+ case GL_MAX_TEXTURE_STACK_DEPTH:
+#endif // defined(GL_MAX_TEXTURE_STACK_DEPTH)
+#if defined(GL_MAX_TEXTURE_UNITS)
+ case GL_MAX_TEXTURE_UNITS:
+#endif // defined(GL_MAX_TEXTURE_UNITS)
+#if defined(GL_MAX_VERTEX_UNITS_OES)
+ case GL_MAX_VERTEX_UNITS_OES:
+#endif // defined(GL_MAX_VERTEX_UNITS_OES)
+#if defined(GL_MODELVIEW_STACK_DEPTH)
+ case GL_MODELVIEW_STACK_DEPTH:
+#endif // defined(GL_MODELVIEW_STACK_DEPTH)
+#if defined(GL_NORMAL_ARRAY_BUFFER_BINDING)
+ case GL_NORMAL_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_NORMAL_ARRAY_BUFFER_BINDING)
+#if defined(GL_NORMAL_ARRAY_STRIDE)
+ case GL_NORMAL_ARRAY_STRIDE:
+#endif // defined(GL_NORMAL_ARRAY_STRIDE)
+#if defined(GL_NORMAL_ARRAY_TYPE)
+ case GL_NORMAL_ARRAY_TYPE:
+#endif // defined(GL_NORMAL_ARRAY_TYPE)
+#if defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS)
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+#endif // defined(GL_NUM_COMPRESSED_TEXTURE_FORMATS)
+#if defined(GL_PACK_ALIGNMENT)
+ case GL_PACK_ALIGNMENT:
+#endif // defined(GL_PACK_ALIGNMENT)
+#if defined(GL_PERSPECTIVE_CORRECTION_HINT)
+ case GL_PERSPECTIVE_CORRECTION_HINT:
+#endif // defined(GL_PERSPECTIVE_CORRECTION_HINT)
+#if defined(GL_POINT_SIZE)
+ case GL_POINT_SIZE:
+#endif // defined(GL_POINT_SIZE)
+#if defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES)
+ case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
+#endif // defined(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES)
+#if defined(GL_POINT_SIZE_ARRAY_STRIDE_OES)
+ case GL_POINT_SIZE_ARRAY_STRIDE_OES:
+#endif // defined(GL_POINT_SIZE_ARRAY_STRIDE_OES)
+#if defined(GL_POINT_SIZE_ARRAY_TYPE_OES)
+ case GL_POINT_SIZE_ARRAY_TYPE_OES:
+#endif // defined(GL_POINT_SIZE_ARRAY_TYPE_OES)
+#if defined(GL_POINT_SMOOTH_HINT)
+ case GL_POINT_SMOOTH_HINT:
+#endif // defined(GL_POINT_SMOOTH_HINT)
+#if defined(GL_POLYGON_OFFSET_FACTOR)
+ case GL_POLYGON_OFFSET_FACTOR:
+#endif // defined(GL_POLYGON_OFFSET_FACTOR)
+#if defined(GL_POLYGON_OFFSET_UNITS)
+ case GL_POLYGON_OFFSET_UNITS:
+#endif // defined(GL_POLYGON_OFFSET_UNITS)
+#if defined(GL_PROJECTION_STACK_DEPTH)
+ case GL_PROJECTION_STACK_DEPTH:
+#endif // defined(GL_PROJECTION_STACK_DEPTH)
+#if defined(GL_RED_BITS)
+ case GL_RED_BITS:
+#endif // defined(GL_RED_BITS)
+#if defined(GL_SHADE_MODEL)
+ case GL_SHADE_MODEL:
+#endif // defined(GL_SHADE_MODEL)
+#if defined(GL_STENCIL_BITS)
+ case GL_STENCIL_BITS:
+#endif // defined(GL_STENCIL_BITS)
+#if defined(GL_STENCIL_CLEAR_VALUE)
+ case GL_STENCIL_CLEAR_VALUE:
+#endif // defined(GL_STENCIL_CLEAR_VALUE)
+#if defined(GL_STENCIL_FAIL)
+ case GL_STENCIL_FAIL:
+#endif // defined(GL_STENCIL_FAIL)
+#if defined(GL_STENCIL_FUNC)
+ case GL_STENCIL_FUNC:
+#endif // defined(GL_STENCIL_FUNC)
+#if defined(GL_STENCIL_PASS_DEPTH_FAIL)
+ case GL_STENCIL_PASS_DEPTH_FAIL:
+#endif // defined(GL_STENCIL_PASS_DEPTH_FAIL)
+#if defined(GL_STENCIL_PASS_DEPTH_PASS)
+ case GL_STENCIL_PASS_DEPTH_PASS:
+#endif // defined(GL_STENCIL_PASS_DEPTH_PASS)
+#if defined(GL_STENCIL_REF)
+ case GL_STENCIL_REF:
+#endif // defined(GL_STENCIL_REF)
+#if defined(GL_STENCIL_VALUE_MASK)
+ case GL_STENCIL_VALUE_MASK:
+#endif // defined(GL_STENCIL_VALUE_MASK)
+#if defined(GL_STENCIL_WRITEMASK)
+ case GL_STENCIL_WRITEMASK:
+#endif // defined(GL_STENCIL_WRITEMASK)
+#if defined(GL_SUBPIXEL_BITS)
+ case GL_SUBPIXEL_BITS:
+#endif // defined(GL_SUBPIXEL_BITS)
+#if defined(GL_TEXTURE_BINDING_2D)
+ case GL_TEXTURE_BINDING_2D:
+#endif // defined(GL_TEXTURE_BINDING_2D)
+#if defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING)
+ case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING)
+#if defined(GL_TEXTURE_COORD_ARRAY_SIZE)
+ case GL_TEXTURE_COORD_ARRAY_SIZE:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_SIZE)
+#if defined(GL_TEXTURE_COORD_ARRAY_STRIDE)
+ case GL_TEXTURE_COORD_ARRAY_STRIDE:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_STRIDE)
+#if defined(GL_TEXTURE_COORD_ARRAY_TYPE)
+ case GL_TEXTURE_COORD_ARRAY_TYPE:
+#endif // defined(GL_TEXTURE_COORD_ARRAY_TYPE)
+#if defined(GL_TEXTURE_STACK_DEPTH)
+ case GL_TEXTURE_STACK_DEPTH:
+#endif // defined(GL_TEXTURE_STACK_DEPTH)
+#if defined(GL_UNPACK_ALIGNMENT)
+ case GL_UNPACK_ALIGNMENT:
+#endif // defined(GL_UNPACK_ALIGNMENT)
+#if defined(GL_VERTEX_ARRAY_BUFFER_BINDING)
+ case GL_VERTEX_ARRAY_BUFFER_BINDING:
+#endif // defined(GL_VERTEX_ARRAY_BUFFER_BINDING)
+#if defined(GL_VERTEX_ARRAY_SIZE)
+ case GL_VERTEX_ARRAY_SIZE:
+#endif // defined(GL_VERTEX_ARRAY_SIZE)
+#if defined(GL_VERTEX_ARRAY_STRIDE)
+ case GL_VERTEX_ARRAY_STRIDE:
+#endif // defined(GL_VERTEX_ARRAY_STRIDE)
+#if defined(GL_VERTEX_ARRAY_TYPE)
+ case GL_VERTEX_ARRAY_TYPE:
+#endif // defined(GL_VERTEX_ARRAY_TYPE)
+#if defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES)
+ case GL_WEIGHT_ARRAY_BUFFER_BINDING_OES:
+#endif // defined(GL_WEIGHT_ARRAY_BUFFER_BINDING_OES)
+#if defined(GL_WEIGHT_ARRAY_SIZE_OES)
+ case GL_WEIGHT_ARRAY_SIZE_OES:
+#endif // defined(GL_WEIGHT_ARRAY_SIZE_OES)
+#if defined(GL_WEIGHT_ARRAY_STRIDE_OES)
+ case GL_WEIGHT_ARRAY_STRIDE_OES:
+#endif // defined(GL_WEIGHT_ARRAY_STRIDE_OES)
+#if defined(GL_WEIGHT_ARRAY_TYPE_OES)
+ case GL_WEIGHT_ARRAY_TYPE_OES:
+#endif // defined(GL_WEIGHT_ARRAY_TYPE_OES)
+ _needed = 1;
+ break;
+#if defined(GL_ALIASED_POINT_SIZE_RANGE)
+ case GL_ALIASED_POINT_SIZE_RANGE:
+#endif // defined(GL_ALIASED_POINT_SIZE_RANGE)
+#if defined(GL_ALIASED_LINE_WIDTH_RANGE)
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+#endif // defined(GL_ALIASED_LINE_WIDTH_RANGE)
+#if defined(GL_DEPTH_RANGE)
+ case GL_DEPTH_RANGE:
+#endif // defined(GL_DEPTH_RANGE)
+#if defined(GL_MAX_VIEWPORT_DIMS)
+ case GL_MAX_VIEWPORT_DIMS:
+#endif // defined(GL_MAX_VIEWPORT_DIMS)
+#if defined(GL_SMOOTH_LINE_WIDTH_RANGE)
+ case GL_SMOOTH_LINE_WIDTH_RANGE:
+#endif // defined(GL_SMOOTH_LINE_WIDTH_RANGE)
+#if defined(GL_SMOOTH_POINT_SIZE_RANGE)
+ case GL_SMOOTH_POINT_SIZE_RANGE:
+#endif // defined(GL_SMOOTH_POINT_SIZE_RANGE)
+ _needed = 2;
+ break;
+#if defined(GL_COLOR_CLEAR_VALUE)
+ case GL_COLOR_CLEAR_VALUE:
+#endif // defined(GL_COLOR_CLEAR_VALUE)
+#if defined(GL_COLOR_WRITEMASK)
+ case GL_COLOR_WRITEMASK:
+#endif // defined(GL_COLOR_WRITEMASK)
+#if defined(GL_SCISSOR_BOX)
+ case GL_SCISSOR_BOX:
+#endif // defined(GL_SCISSOR_BOX)
+#if defined(GL_VIEWPORT)
+ case GL_VIEWPORT:
+#endif // defined(GL_VIEWPORT)
+ _needed = 4;
+ break;
+#if defined(GL_MODELVIEW_MATRIX)
+ case GL_MODELVIEW_MATRIX:
+#endif // defined(GL_MODELVIEW_MATRIX)
+#if defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES)
+ case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
+#endif // defined(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES)
+#if defined(GL_PROJECTION_MATRIX)
+ case GL_PROJECTION_MATRIX:
+#endif // defined(GL_PROJECTION_MATRIX)
+#if defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES)
+ case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
+#endif // defined(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES)
+#if defined(GL_TEXTURE_MATRIX)
+ case GL_TEXTURE_MATRIX:
+#endif // defined(GL_TEXTURE_MATRIX)
+#if defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES)
+ case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
+#endif // defined(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES)
+ _needed = 16;
+ break;
+#if defined(GL_COMPRESSED_TEXTURE_FORMATS)
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+#endif // defined(GL_COMPRESSED_TEXTURE_FORMATS)
+#if defined(GL_FOG_COLOR)
+ case GL_FOG_COLOR:
+#endif // defined(GL_FOG_COLOR)
+#if defined(GL_LIGHT_MODEL_AMBIENT)
+ case GL_LIGHT_MODEL_AMBIENT:
+#endif // defined(GL_LIGHT_MODEL_AMBIENT)
+ _needed = _NUM_COMPRESSED_TEXTURE_FORMATS;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glGetIntegerv(
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+#include <string.h>
+
+/* const GLubyte * glGetString ( GLenum name ) */
+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);
+ return output;
+}
+/* void glHint ( GLenum target, GLenum mode ) */
+static void
+android_glHint__II
+ (JNIEnv *_env, jobject _this, jint target, jint mode) {
+ glHint(
+ (GLenum)target,
+ (GLenum)mode
+ );
+}
+
+/* void glLightModelf ( GLenum pname, GLfloat param ) */
+static void
+android_glLightModelf__IF
+ (JNIEnv *_env, jobject _this, jint pname, jfloat param) {
+ glLightModelf(
+ (GLenum)pname,
+ (GLfloat)param
+ );
+}
+
+/* void glLightModelfv ( GLenum pname, const GLfloat *params ) */
+static void
+android_glLightModelfv__I_3FI
+ (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) {
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_LIGHT_MODEL_TWO_SIDE)
+ case GL_LIGHT_MODEL_TWO_SIDE:
+#endif // defined(GL_LIGHT_MODEL_TWO_SIDE)
+ _needed = 1;
+ break;
+#if defined(GL_LIGHT_MODEL_AMBIENT)
+ case GL_LIGHT_MODEL_AMBIENT:
+#endif // defined(GL_LIGHT_MODEL_AMBIENT)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glLightModelfv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glLightModelfv ( GLenum pname, const GLfloat *params ) */
+static void
+android_glLightModelfv__ILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_LIGHT_MODEL_TWO_SIDE)
+ case GL_LIGHT_MODEL_TWO_SIDE:
+#endif // defined(GL_LIGHT_MODEL_TWO_SIDE)
+ _needed = 1;
+ break;
+#if defined(GL_LIGHT_MODEL_AMBIENT)
+ case GL_LIGHT_MODEL_AMBIENT:
+#endif // defined(GL_LIGHT_MODEL_AMBIENT)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glLightModelfv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glLightModelx ( GLenum pname, GLfixed param ) */
+static void
+android_glLightModelx__II
+ (JNIEnv *_env, jobject _this, jint pname, jint param) {
+ glLightModelx(
+ (GLenum)pname,
+ (GLfixed)param
+ );
+}
+
+/* void glLightModelxv ( GLenum pname, const GLfixed *params ) */
+static void
+android_glLightModelxv__I_3II
+ (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) {
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_LIGHT_MODEL_TWO_SIDE)
+ case GL_LIGHT_MODEL_TWO_SIDE:
+#endif // defined(GL_LIGHT_MODEL_TWO_SIDE)
+ _needed = 1;
+ break;
+#if defined(GL_LIGHT_MODEL_AMBIENT)
+ case GL_LIGHT_MODEL_AMBIENT:
+#endif // defined(GL_LIGHT_MODEL_AMBIENT)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glLightModelxv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glLightModelxv ( GLenum pname, const GLfixed *params ) */
+static void
+android_glLightModelxv__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_LIGHT_MODEL_TWO_SIDE)
+ case GL_LIGHT_MODEL_TWO_SIDE:
+#endif // defined(GL_LIGHT_MODEL_TWO_SIDE)
+ _needed = 1;
+ break;
+#if defined(GL_LIGHT_MODEL_AMBIENT)
+ case GL_LIGHT_MODEL_AMBIENT:
+#endif // defined(GL_LIGHT_MODEL_AMBIENT)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glLightModelxv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glLightf ( GLenum light, GLenum pname, GLfloat param ) */
+static void
+android_glLightf__IIF
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jfloat param) {
+ glLightf(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfloat)param
+ );
+}
+
+/* void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) */
+static void
+android_glLightfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jfloatArray params_ref, jint offset) {
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glLightfv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) */
+static void
+android_glLightfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glLightfv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glLightx ( GLenum light, GLenum pname, GLfixed param ) */
+static void
+android_glLightx__III
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jint param) {
+ glLightx(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfixed)param
+ );
+}
+
+/* void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) */
+static void
+android_glLightxv__II_3II
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jintArray params_ref, jint offset) {
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glLightxv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) */
+static void
+android_glLightxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glLightxv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glLineWidth ( GLfloat width ) */
+static void
+android_glLineWidth__F
+ (JNIEnv *_env, jobject _this, jfloat width) {
+ glLineWidth(
+ (GLfloat)width
+ );
+}
+
+/* void glLineWidthx ( GLfixed width ) */
+static void
+android_glLineWidthx__I
+ (JNIEnv *_env, jobject _this, jint width) {
+ glLineWidthx(
+ (GLfixed)width
+ );
+}
+
+/* void glLoadIdentity ( void ) */
+static void
+android_glLoadIdentity__
+ (JNIEnv *_env, jobject _this) {
+ glLoadIdentity();
+}
+
+/* void glLoadMatrixf ( const GLfloat *m ) */
+static void
+android_glLoadMatrixf___3FI
+ (JNIEnv *_env, jobject _this, jfloatArray m_ref, jint offset) {
+ GLfloat *m_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *m = (GLfloat *) 0;
+
+ if (!m_ref) {
+ _env->ThrowNew(IAEClass, "m == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(m_ref) - offset;
+ m_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0);
+ m = m_base + offset;
+
+ glLoadMatrixf(
+ (GLfloat *)m
+ );
+
+exit:
+ if (m_base) {
+ _env->ReleasePrimitiveArrayCritical(m_ref, m_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glLoadMatrixf ( const GLfloat *m ) */
+static void
+android_glLoadMatrixf__Ljava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jobject m_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *m = (GLfloat *) 0;
+
+ m = (GLfloat *)getPointer(_env, m_buf, &_array, &_remaining);
+ glLoadMatrixf(
+ (GLfloat *)m
+ );
+ if (_array) {
+ releasePointer(_env, _array, m, JNI_FALSE);
+ }
+}
+
+/* void glLoadMatrixx ( const GLfixed *m ) */
+static void
+android_glLoadMatrixx___3II
+ (JNIEnv *_env, jobject _this, jintArray m_ref, jint offset) {
+ GLfixed *m_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *m = (GLfixed *) 0;
+
+ if (!m_ref) {
+ _env->ThrowNew(IAEClass, "m == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(m_ref) - offset;
+ m_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0);
+ m = m_base + offset;
+
+ glLoadMatrixx(
+ (GLfixed *)m
+ );
+
+exit:
+ if (m_base) {
+ _env->ReleasePrimitiveArrayCritical(m_ref, m_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glLoadMatrixx ( const GLfixed *m ) */
+static void
+android_glLoadMatrixx__Ljava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jobject m_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *m = (GLfixed *) 0;
+
+ m = (GLfixed *)getPointer(_env, m_buf, &_array, &_remaining);
+ glLoadMatrixx(
+ (GLfixed *)m
+ );
+ if (_array) {
+ releasePointer(_env, _array, m, JNI_FALSE);
+ }
+}
+
+/* void glLogicOp ( GLenum opcode ) */
+static void
+android_glLogicOp__I
+ (JNIEnv *_env, jobject _this, jint opcode) {
+ glLogicOp(
+ (GLenum)opcode
+ );
+}
+
+/* void glMaterialf ( GLenum face, GLenum pname, GLfloat param ) */
+static void
+android_glMaterialf__IIF
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jfloat param) {
+ glMaterialf(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfloat)param
+ );
+}
+
+/* void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) */
+static void
+android_glMaterialfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jfloatArray params_ref, jint offset) {
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glMaterialfv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) */
+static void
+android_glMaterialfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glMaterialfv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glMaterialx ( GLenum face, GLenum pname, GLfixed param ) */
+static void
+android_glMaterialx__III
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jint param) {
+ glMaterialx(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfixed)param
+ );
+}
+
+/* void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) */
+static void
+android_glMaterialxv__II_3II
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jintArray params_ref, jint offset) {
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glMaterialxv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) */
+static void
+android_glMaterialxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glMaterialxv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glMatrixMode ( GLenum mode ) */
+static void
+android_glMatrixMode__I
+ (JNIEnv *_env, jobject _this, jint mode) {
+ glMatrixMode(
+ (GLenum)mode
+ );
+}
+
+/* void glMultMatrixf ( const GLfloat *m ) */
+static void
+android_glMultMatrixf___3FI
+ (JNIEnv *_env, jobject _this, jfloatArray m_ref, jint offset) {
+ GLfloat *m_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *m = (GLfloat *) 0;
+
+ if (!m_ref) {
+ _env->ThrowNew(IAEClass, "m == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(m_ref) - offset;
+ m_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0);
+ m = m_base + offset;
+
+ glMultMatrixf(
+ (GLfloat *)m
+ );
+
+exit:
+ if (m_base) {
+ _env->ReleasePrimitiveArrayCritical(m_ref, m_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glMultMatrixf ( const GLfloat *m ) */
+static void
+android_glMultMatrixf__Ljava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jobject m_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *m = (GLfloat *) 0;
+
+ m = (GLfloat *)getPointer(_env, m_buf, &_array, &_remaining);
+ glMultMatrixf(
+ (GLfloat *)m
+ );
+ if (_array) {
+ releasePointer(_env, _array, m, JNI_FALSE);
+ }
+}
+
+/* void glMultMatrixx ( const GLfixed *m ) */
+static void
+android_glMultMatrixx___3II
+ (JNIEnv *_env, jobject _this, jintArray m_ref, jint offset) {
+ GLfixed *m_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *m = (GLfixed *) 0;
+
+ if (!m_ref) {
+ _env->ThrowNew(IAEClass, "m == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(m_ref) - offset;
+ m_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(m_ref, (jboolean *)0);
+ m = m_base + offset;
+
+ glMultMatrixx(
+ (GLfixed *)m
+ );
+
+exit:
+ if (m_base) {
+ _env->ReleasePrimitiveArrayCritical(m_ref, m_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glMultMatrixx ( const GLfixed *m ) */
+static void
+android_glMultMatrixx__Ljava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jobject m_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *m = (GLfixed *) 0;
+
+ m = (GLfixed *)getPointer(_env, m_buf, &_array, &_remaining);
+ glMultMatrixx(
+ (GLfixed *)m
+ );
+ if (_array) {
+ releasePointer(_env, _array, m, JNI_FALSE);
+ }
+}
+
+/* void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) */
+static void
+android_glMultiTexCoord4f__IFFFF
+ (JNIEnv *_env, jobject _this, jint target, jfloat s, jfloat t, jfloat r, jfloat q) {
+ glMultiTexCoord4f(
+ (GLenum)target,
+ (GLfloat)s,
+ (GLfloat)t,
+ (GLfloat)r,
+ (GLfloat)q
+ );
+}
+
+/* void glMultiTexCoord4x ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) */
+static void
+android_glMultiTexCoord4x__IIIII
+ (JNIEnv *_env, jobject _this, jint target, jint s, jint t, jint r, jint q) {
+ glMultiTexCoord4x(
+ (GLenum)target,
+ (GLfixed)s,
+ (GLfixed)t,
+ (GLfixed)r,
+ (GLfixed)q
+ );
+}
+
+/* void glNormal3f ( GLfloat nx, GLfloat ny, GLfloat nz ) */
+static void
+android_glNormal3f__FFF
+ (JNIEnv *_env, jobject _this, jfloat nx, jfloat ny, jfloat nz) {
+ glNormal3f(
+ (GLfloat)nx,
+ (GLfloat)ny,
+ (GLfloat)nz
+ );
+}
+
+/* void glNormal3x ( GLfixed nx, GLfixed ny, GLfixed nz ) */
+static void
+android_glNormal3x__III
+ (JNIEnv *_env, jobject _this, jint nx, jint ny, jint nz) {
+ glNormal3x(
+ (GLfixed)nx,
+ (GLfixed)ny,
+ (GLfixed)nz
+ );
+}
+
+/* void glNormalPointer ( GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glNormalPointerBounds__IILjava_nio_Buffer_2I
+ (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf, jint remaining) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pointer = (GLvoid *) 0;
+
+ pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining);
+ glNormalPointerBounds(
+ (GLenum)type,
+ (GLsizei)stride,
+ (GLvoid *)pointer,
+ (GLsizei)remaining
+ );
+ if (_array) {
+ releasePointer(_env, _array, pointer, JNI_FALSE);
+ }
+}
+
+/* void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) */
+static void
+android_glOrthof__FFFFFF
+ (JNIEnv *_env, jobject _this, jfloat left, jfloat right, jfloat bottom, jfloat top, jfloat zNear, jfloat zFar) {
+ glOrthof(
+ (GLfloat)left,
+ (GLfloat)right,
+ (GLfloat)bottom,
+ (GLfloat)top,
+ (GLfloat)zNear,
+ (GLfloat)zFar
+ );
+}
+
+/* void glOrthox ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) */
+static void
+android_glOrthox__IIIIII
+ (JNIEnv *_env, jobject _this, jint left, jint right, jint bottom, jint top, jint zNear, jint zFar) {
+ glOrthox(
+ (GLfixed)left,
+ (GLfixed)right,
+ (GLfixed)bottom,
+ (GLfixed)top,
+ (GLfixed)zNear,
+ (GLfixed)zFar
+ );
+}
+
+/* void glPixelStorei ( GLenum pname, GLint param ) */
+static void
+android_glPixelStorei__II
+ (JNIEnv *_env, jobject _this, jint pname, jint param) {
+ glPixelStorei(
+ (GLenum)pname,
+ (GLint)param
+ );
+}
+
+/* void glPointSize ( GLfloat size ) */
+static void
+android_glPointSize__F
+ (JNIEnv *_env, jobject _this, jfloat size) {
+ glPointSize(
+ (GLfloat)size
+ );
+}
+
+/* void glPointSizex ( GLfixed size ) */
+static void
+android_glPointSizex__I
+ (JNIEnv *_env, jobject _this, jint size) {
+ glPointSizex(
+ (GLfixed)size
+ );
+}
+
+/* void glPolygonOffset ( GLfloat factor, GLfloat units ) */
+static void
+android_glPolygonOffset__FF
+ (JNIEnv *_env, jobject _this, jfloat factor, jfloat units) {
+ glPolygonOffset(
+ (GLfloat)factor,
+ (GLfloat)units
+ );
+}
+
+/* void glPolygonOffsetx ( GLfixed factor, GLfixed units ) */
+static void
+android_glPolygonOffsetx__II
+ (JNIEnv *_env, jobject _this, jint factor, jint units) {
+ glPolygonOffsetx(
+ (GLfixed)factor,
+ (GLfixed)units
+ );
+}
+
+/* void glPopMatrix ( void ) */
+static void
+android_glPopMatrix__
+ (JNIEnv *_env, jobject _this) {
+ glPopMatrix();
+}
+
+/* void glPushMatrix ( void ) */
+static void
+android_glPushMatrix__
+ (JNIEnv *_env, jobject _this) {
+ glPushMatrix();
+}
+
+/* void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) */
+static void
+android_glReadPixels__IIIIIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pixels = (GLvoid *) 0;
+
+ pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining);
+ glReadPixels(
+ (GLint)x,
+ (GLint)y,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLenum)format,
+ (GLenum)type,
+ (GLvoid *)pixels
+ );
+ if (_array) {
+ releasePointer(_env, _array, pixels, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) */
+static void
+android_glRotatef__FFFF
+ (JNIEnv *_env, jobject _this, jfloat angle, jfloat x, jfloat y, jfloat z) {
+ glRotatef(
+ (GLfloat)angle,
+ (GLfloat)x,
+ (GLfloat)y,
+ (GLfloat)z
+ );
+}
+
+/* void glRotatex ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) */
+static void
+android_glRotatex__IIII
+ (JNIEnv *_env, jobject _this, jint angle, jint x, jint y, jint z) {
+ glRotatex(
+ (GLfixed)angle,
+ (GLfixed)x,
+ (GLfixed)y,
+ (GLfixed)z
+ );
+}
+
+/* void glSampleCoverage ( GLclampf value, GLboolean invert ) */
+static void
+android_glSampleCoverage__FZ
+ (JNIEnv *_env, jobject _this, jfloat value, jboolean invert) {
+ glSampleCoverage(
+ (GLclampf)value,
+ (GLboolean)invert
+ );
+}
+
+/* void glSampleCoveragex ( GLclampx value, GLboolean invert ) */
+static void
+android_glSampleCoveragex__IZ
+ (JNIEnv *_env, jobject _this, jint value, jboolean invert) {
+ glSampleCoveragex(
+ (GLclampx)value,
+ (GLboolean)invert
+ );
+}
+
+/* void glScalef ( GLfloat x, GLfloat y, GLfloat z ) */
+static void
+android_glScalef__FFF
+ (JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z) {
+ glScalef(
+ (GLfloat)x,
+ (GLfloat)y,
+ (GLfloat)z
+ );
+}
+
+/* void glScalex ( GLfixed x, GLfixed y, GLfixed z ) */
+static void
+android_glScalex__III
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint z) {
+ glScalex(
+ (GLfixed)x,
+ (GLfixed)y,
+ (GLfixed)z
+ );
+}
+
+/* void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height ) */
+static void
+android_glScissor__IIII
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height) {
+ glScissor(
+ (GLint)x,
+ (GLint)y,
+ (GLsizei)width,
+ (GLsizei)height
+ );
+}
+
+/* void glShadeModel ( GLenum mode ) */
+static void
+android_glShadeModel__I
+ (JNIEnv *_env, jobject _this, jint mode) {
+ glShadeModel(
+ (GLenum)mode
+ );
+}
+
+/* void glStencilFunc ( GLenum func, GLint ref, GLuint mask ) */
+static void
+android_glStencilFunc__III
+ (JNIEnv *_env, jobject _this, jint func, jint ref, jint mask) {
+ glStencilFunc(
+ (GLenum)func,
+ (GLint)ref,
+ (GLuint)mask
+ );
+}
+
+/* void glStencilMask ( GLuint mask ) */
+static void
+android_glStencilMask__I
+ (JNIEnv *_env, jobject _this, jint mask) {
+ glStencilMask(
+ (GLuint)mask
+ );
+}
+
+/* void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass ) */
+static void
+android_glStencilOp__III
+ (JNIEnv *_env, jobject _this, jint fail, jint zfail, jint zpass) {
+ glStencilOp(
+ (GLenum)fail,
+ (GLenum)zfail,
+ (GLenum)zpass
+ );
+}
+
+/* void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pointer = (GLvoid *) 0;
+
+ pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining);
+ glTexCoordPointerBounds(
+ (GLint)size,
+ (GLenum)type,
+ (GLsizei)stride,
+ (GLvoid *)pointer,
+ (GLsizei)remaining
+ );
+ if (_array) {
+ releasePointer(_env, _array, pointer, JNI_FALSE);
+ }
+}
+
+/* void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) */
+static void
+android_glTexEnvf__IIF
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jfloat param) {
+ glTexEnvf(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat)param
+ );
+}
+
+/* void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) */
+static void
+android_glTexEnvfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jfloatArray params_ref, jint offset) {
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexEnvfv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) */
+static void
+android_glTexEnvfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glTexEnvfv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glTexEnvx ( GLenum target, GLenum pname, GLfixed param ) */
+static void
+android_glTexEnvx__III
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) {
+ glTexEnvx(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed)param
+ );
+}
+
+/* void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) */
+static void
+android_glTexEnvxv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexEnvxv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) */
+static void
+android_glTexEnvxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glTexEnvxv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) */
+static void
+android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint level, jint internalformat, jint width, jint height, jint border, jint format, jint type, jobject pixels_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pixels = (GLvoid *) 0;
+
+ if (pixels_buf) {
+ pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining);
+ }
+ glTexImage2D(
+ (GLenum)target,
+ (GLint)level,
+ (GLint)internalformat,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLint)border,
+ (GLenum)format,
+ (GLenum)type,
+ (GLvoid *)pixels
+ );
+ if (_array) {
+ releasePointer(_env, _array, pixels, JNI_FALSE);
+ }
+}
+
+/* void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) */
+static void
+android_glTexParameterf__IIF
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jfloat param) {
+ glTexParameterf(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat)param
+ );
+}
+
+/* void glTexParameterx ( GLenum target, GLenum pname, GLfixed param ) */
+static void
+android_glTexParameterx__III
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) {
+ glTexParameterx(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed)param
+ );
+}
+
+/* void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) */
+static void
+android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint level, jint xoffset, jint yoffset, jint width, jint height, jint format, jint type, jobject pixels_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pixels = (GLvoid *) 0;
+
+ if (pixels_buf) {
+ pixels = (GLvoid *)getPointer(_env, pixels_buf, &_array, &_remaining);
+ }
+ glTexSubImage2D(
+ (GLenum)target,
+ (GLint)level,
+ (GLint)xoffset,
+ (GLint)yoffset,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLenum)format,
+ (GLenum)type,
+ (GLvoid *)pixels
+ );
+ if (_array) {
+ releasePointer(_env, _array, pixels, JNI_FALSE);
+ }
+}
+
+/* void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) */
+static void
+android_glTranslatef__FFF
+ (JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z) {
+ glTranslatef(
+ (GLfloat)x,
+ (GLfloat)y,
+ (GLfloat)z
+ );
+}
+
+/* void glTranslatex ( GLfixed x, GLfixed y, GLfixed z ) */
+static void
+android_glTranslatex__III
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint z) {
+ glTranslatex(
+ (GLfixed)x,
+ (GLfixed)y,
+ (GLfixed)z
+ );
+}
+
+/* void glVertexPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glVertexPointerBounds__IIILjava_nio_Buffer_2I
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf, jint remaining) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pointer = (GLvoid *) 0;
+
+ pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining);
+ glVertexPointerBounds(
+ (GLint)size,
+ (GLenum)type,
+ (GLsizei)stride,
+ (GLvoid *)pointer,
+ (GLsizei)remaining
+ );
+ if (_array) {
+ releasePointer(_env, _array, pointer, JNI_FALSE);
+ }
+}
+
+/* void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) */
+static void
+android_glViewport__IIII
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height) {
+ glViewport(
+ (GLint)x,
+ (GLint)y,
+ (GLsizei)width,
+ (GLsizei)height
+ );
+}
+
+/* GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) */
+static jint
+android_glQueryMatrixxOES___3II_3II
+ (JNIEnv *_env, jobject _this, jintArray mantissa_ref, jint mantissaOffset, jintArray exponent_ref, jint exponentOffset) {
+ jint _exception = 0;
+ GLbitfield _returnValue = -1;
+ GLfixed *mantissa_base = (GLfixed *) 0;
+ jint _mantissaRemaining;
+ GLfixed *mantissa = (GLfixed *) 0;
+ GLint *exponent_base = (GLint *) 0;
+ jint _exponentRemaining;
+ GLint *exponent = (GLint *) 0;
+
+ if (!mantissa_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "mantissa == null");
+ goto exit;
+ }
+ if (mantissaOffset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "mantissaOffset < 0");
+ goto exit;
+ }
+ _mantissaRemaining = _env->GetArrayLength(mantissa_ref) - mantissaOffset;
+ if (_mantissaRemaining < 16) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - mantissaOffset < 16");
+ goto exit;
+ }
+ mantissa_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(mantissa_ref, (jboolean *)0);
+ mantissa = mantissa_base + mantissaOffset;
+
+ if (!exponent_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "exponent == null");
+ goto exit;
+ }
+ if (exponentOffset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "exponentOffset < 0");
+ goto exit;
+ }
+ _exponentRemaining = _env->GetArrayLength(exponent_ref) - exponentOffset;
+ if (_exponentRemaining < 16) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - exponentOffset < 16");
+ goto exit;
+ }
+ exponent_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(exponent_ref, (jboolean *)0);
+ exponent = exponent_base + exponentOffset;
+
+ _returnValue = glQueryMatrixxOES(
+ (GLfixed *)mantissa,
+ (GLint *)exponent
+ );
+
+exit:
+ if (exponent_base) {
+ _env->ReleasePrimitiveArrayCritical(exponent_ref, exponent_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (mantissa_base) {
+ _env->ReleasePrimitiveArrayCritical(mantissa_ref, mantissa_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ return _returnValue;
+}
+
+/* GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) */
+static jint
+android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jobject mantissa_buf, jobject exponent_buf) {
+ jint _exception = 0;
+ jarray _mantissaArray = (jarray) 0;
+ jarray _exponentArray = (jarray) 0;
+ GLbitfield _returnValue = -1;
+ jint _mantissaRemaining;
+ GLfixed *mantissa = (GLfixed *) 0;
+ jint _exponentRemaining;
+ GLint *exponent = (GLint *) 0;
+
+ mantissa = (GLfixed *)getPointer(_env, mantissa_buf, &_mantissaArray, &_mantissaRemaining);
+ if (_mantissaRemaining < 16) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 16");
+ goto exit;
+ }
+ exponent = (GLint *)getPointer(_env, exponent_buf, &_exponentArray, &_exponentRemaining);
+ if (_exponentRemaining < 16) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 16");
+ goto exit;
+ }
+ _returnValue = glQueryMatrixxOES(
+ (GLfixed *)mantissa,
+ (GLint *)exponent
+ );
+
+exit:
+ if (_mantissaArray) {
+ releasePointer(_env, _mantissaArray, exponent, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ if (_exponentArray) {
+ releasePointer(_env, _exponentArray, mantissa, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ return _returnValue;
+}
+
+/* void glBindBuffer ( GLenum target, GLuint buffer ) */
+static void
+android_glBindBuffer__II
+ (JNIEnv *_env, jobject _this, jint target, jint buffer) {
+ glBindBuffer(
+ (GLenum)target,
+ (GLuint)buffer
+ );
+}
+
+/* void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) */
+static void
+android_glBufferData__IILjava_nio_Buffer_2I
+ (JNIEnv *_env, jobject _this, jint target, jint size, jobject data_buf, jint usage) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *data = (GLvoid *) 0;
+
+ if (data_buf) {
+ data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ }
+ glBufferData(
+ (GLenum)target,
+ (GLsizeiptr)size,
+ (GLvoid *)data,
+ (GLenum)usage
+ );
+ if (_array) {
+ releasePointer(_env, _array, data, JNI_FALSE);
+ }
+}
+
+/* void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data ) */
+static void
+android_glBufferSubData__IIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint offset, jint size, jobject data_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *data = (GLvoid *) 0;
+
+ data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ glBufferSubData(
+ (GLenum)target,
+ (GLintptr)offset,
+ (GLsizeiptr)size,
+ (GLvoid *)data
+ );
+ if (_array) {
+ releasePointer(_env, _array, data, JNI_FALSE);
+ }
+}
+
+/* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
+static void
+android_glClipPlanef__I_3FI
+ (JNIEnv *_env, jobject _this, jint plane, jfloatArray equation_ref, jint offset) {
+ GLfloat *equation_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *equation = (GLfloat *) 0;
+
+ if (!equation_ref) {
+ _env->ThrowNew(IAEClass, "equation == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(equation_ref) - offset;
+ if (_remaining < 4) {
+ _env->ThrowNew(IAEClass, "length - offset < 4");
+ goto exit;
+ }
+ equation_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(equation_ref, (jboolean *)0);
+ equation = equation_base + offset;
+
+ glClipPlanef(
+ (GLenum)plane,
+ (GLfloat *)equation
+ );
+
+exit:
+ if (equation_base) {
+ _env->ReleasePrimitiveArrayCritical(equation_ref, equation_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
+static void
+android_glClipPlanef__ILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *equation = (GLfloat *) 0;
+
+ equation = (GLfloat *)getPointer(_env, equation_buf, &_array, &_remaining);
+ if (_remaining < 4) {
+ _env->ThrowNew(IAEClass, "remaining() < 4");
+ goto exit;
+ }
+ glClipPlanef(
+ (GLenum)plane,
+ (GLfloat *)equation
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, equation, JNI_FALSE);
+ }
+}
+
+/* void glClipPlanex ( GLenum plane, const GLfixed *equation ) */
+static void
+android_glClipPlanex__I_3II
+ (JNIEnv *_env, jobject _this, jint plane, jintArray equation_ref, jint offset) {
+ GLfixed *equation_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *equation = (GLfixed *) 0;
+
+ if (!equation_ref) {
+ _env->ThrowNew(IAEClass, "equation == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(equation_ref) - offset;
+ if (_remaining < 4) {
+ _env->ThrowNew(IAEClass, "length - offset < 4");
+ goto exit;
+ }
+ equation_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(equation_ref, (jboolean *)0);
+ equation = equation_base + offset;
+
+ glClipPlanex(
+ (GLenum)plane,
+ (GLfixed *)equation
+ );
+
+exit:
+ if (equation_base) {
+ _env->ReleasePrimitiveArrayCritical(equation_ref, equation_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glClipPlanex ( GLenum plane, const GLfixed *equation ) */
+static void
+android_glClipPlanex__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint plane, jobject equation_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *equation = (GLfixed *) 0;
+
+ equation = (GLfixed *)getPointer(_env, equation_buf, &_array, &_remaining);
+ if (_remaining < 4) {
+ _env->ThrowNew(IAEClass, "remaining() < 4");
+ goto exit;
+ }
+ glClipPlanex(
+ (GLenum)plane,
+ (GLfixed *)equation
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, equation, JNI_FALSE);
+ }
+}
+
+/* void glColor4ub ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) */
+static void
+android_glColor4ub__BBBB
+ (JNIEnv *_env, jobject _this, jbyte red, jbyte green, jbyte blue, jbyte alpha) {
+ glColor4ub(
+ (GLubyte)red,
+ (GLubyte)green,
+ (GLubyte)blue,
+ (GLubyte)alpha
+ );
+}
+
+/* void glColorPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
+static void
+android_glColorPointer__IIII
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) {
+ glColorPointer(
+ (GLint)size,
+ (GLenum)type,
+ (GLsizei)stride,
+ (const GLvoid *)offset
+ );
+}
+
+/* void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) */
+static void
+android_glDeleteBuffers__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray buffers_ref, jint offset) {
+ GLuint *buffers_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *buffers = (GLuint *) 0;
+
+ if (!buffers_ref) {
+ _env->ThrowNew(IAEClass, "buffers == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(buffers_ref) - offset;
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ buffers_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(buffers_ref, (jboolean *)0);
+ buffers = buffers_base + offset;
+
+ glDeleteBuffers(
+ (GLsizei)n,
+ (GLuint *)buffers
+ );
+
+exit:
+ if (buffers_base) {
+ _env->ReleasePrimitiveArrayCritical(buffers_ref, buffers_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) */
+static void
+android_glDeleteBuffers__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject buffers_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *buffers = (GLuint *) 0;
+
+ buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glDeleteBuffers(
+ (GLsizei)n,
+ (GLuint *)buffers
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, buffers, JNI_FALSE);
+ }
+}
+
+/* void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset ) */
+static void
+android_glDrawElements__IIII
+ (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jint offset) {
+ glDrawElements(
+ (GLenum)mode,
+ (GLsizei)count,
+ (GLenum)type,
+ (const GLvoid *)offset
+ );
+}
+
+/* void glGenBuffers ( GLsizei n, GLuint *buffers ) */
+static void
+android_glGenBuffers__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray buffers_ref, jint offset) {
+ jint _exception = 0;
+ GLuint *buffers_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *buffers = (GLuint *) 0;
+
+ if (!buffers_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "buffers == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(buffers_ref) - offset;
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < n");
+ goto exit;
+ }
+ buffers_base = (GLuint *)
+ _env->GetPrimitiveArrayCritical(buffers_ref, (jboolean *)0);
+ buffers = buffers_base + offset;
+
+ glGenBuffers(
+ (GLsizei)n,
+ (GLuint *)buffers
+ );
+
+exit:
+ if (buffers_base) {
+ _env->ReleasePrimitiveArrayCritical(buffers_ref, buffers_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGenBuffers ( GLsizei n, GLuint *buffers ) */
+static void
+android_glGenBuffers__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject buffers_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLuint *buffers = (GLuint *) 0;
+
+ buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
+ if (_remaining < n) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < n");
+ goto exit;
+ }
+ glGenBuffers(
+ (GLsizei)n,
+ (GLuint *)buffers
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, buffers, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetBooleanv ( GLenum pname, GLboolean *params ) */
+static void
+android_glGetBooleanv__I_3ZI
+ (JNIEnv *_env, jobject _this, jint pname, jbooleanArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLboolean *params_base = (GLboolean *) 0;
+ jint _remaining;
+ GLboolean *params = (GLboolean *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLboolean *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetBooleanv(
+ (GLenum)pname,
+ (GLboolean *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetBooleanv ( GLenum pname, GLboolean *params ) */
+static void
+android_glGetBooleanv__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLboolean *params = (GLboolean *) 0;
+
+ params = (GLboolean *)getPointer(_env, params_buf, &_array, &_remaining);
+ glGetBooleanv(
+ (GLenum)pname,
+ (GLboolean *)params
+ );
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetBufferParameteriv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGetBufferParameteriv");
+}
+
+/* void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGetBufferParameteriv");
+}
+
+/* void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) */
+static void
+android_glGetClipPlanef__I_3FI
+ (JNIEnv *_env, jobject _this, jint pname, jfloatArray eqn_ref, jint offset) {
+ jint _exception = 0;
+ GLfloat *eqn_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *eqn = (GLfloat *) 0;
+
+ if (!eqn_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "eqn == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(eqn_ref) - offset;
+ eqn_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(eqn_ref, (jboolean *)0);
+ eqn = eqn_base + offset;
+
+ glGetClipPlanef(
+ (GLenum)pname,
+ (GLfloat *)eqn
+ );
+
+exit:
+ if (eqn_base) {
+ _env->ReleasePrimitiveArrayCritical(eqn_ref, eqn_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) */
+static void
+android_glGetClipPlanef__ILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *eqn = (GLfloat *) 0;
+
+ eqn = (GLfloat *)getPointer(_env, eqn_buf, &_array, &_remaining);
+ glGetClipPlanef(
+ (GLenum)pname,
+ (GLfloat *)eqn
+ );
+ if (_array) {
+ releasePointer(_env, _array, eqn, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) */
+static void
+android_glGetClipPlanex__I_3II
+ (JNIEnv *_env, jobject _this, jint pname, jintArray eqn_ref, jint offset) {
+ jint _exception = 0;
+ GLfixed *eqn_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *eqn = (GLfixed *) 0;
+
+ if (!eqn_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "eqn == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(eqn_ref) - offset;
+ eqn_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(eqn_ref, (jboolean *)0);
+ eqn = eqn_base + offset;
+
+ glGetClipPlanex(
+ (GLenum)pname,
+ (GLfixed *)eqn
+ );
+
+exit:
+ if (eqn_base) {
+ _env->ReleasePrimitiveArrayCritical(eqn_ref, eqn_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) */
+static void
+android_glGetClipPlanex__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject eqn_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *eqn = (GLfixed *) 0;
+
+ eqn = (GLfixed *)getPointer(_env, eqn_buf, &_array, &_remaining);
+ glGetClipPlanex(
+ (GLenum)pname,
+ (GLfixed *)eqn
+ );
+ if (_array) {
+ releasePointer(_env, _array, eqn, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetFixedv ( GLenum pname, GLfixed *params ) */
+static void
+android_glGetFixedv__I_3II
+ (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetFixedv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetFixedv ( GLenum pname, GLfixed *params ) */
+static void
+android_glGetFixedv__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ glGetFixedv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetFloatv ( GLenum pname, GLfloat *params ) */
+static void
+android_glGetFloatv__I_3FI
+ (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetFloatv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetFloatv ( GLenum pname, GLfloat *params ) */
+static void
+android_glGetFloatv__ILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ glGetFloatv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) */
+static void
+android_glGetLightfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jfloatArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetLightfv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) */
+static void
+android_glGetLightfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glGetLightfv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) */
+static void
+android_glGetLightxv__II_3II
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetLightxv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) */
+static void
+android_glGetLightxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint light, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SPOT_EXPONENT)
+ case GL_SPOT_EXPONENT:
+#endif // defined(GL_SPOT_EXPONENT)
+#if defined(GL_SPOT_CUTOFF)
+ case GL_SPOT_CUTOFF:
+#endif // defined(GL_SPOT_CUTOFF)
+#if defined(GL_CONSTANT_ATTENUATION)
+ case GL_CONSTANT_ATTENUATION:
+#endif // defined(GL_CONSTANT_ATTENUATION)
+#if defined(GL_LINEAR_ATTENUATION)
+ case GL_LINEAR_ATTENUATION:
+#endif // defined(GL_LINEAR_ATTENUATION)
+#if defined(GL_QUADRATIC_ATTENUATION)
+ case GL_QUADRATIC_ATTENUATION:
+#endif // defined(GL_QUADRATIC_ATTENUATION)
+ _needed = 1;
+ break;
+#if defined(GL_SPOT_DIRECTION)
+ case GL_SPOT_DIRECTION:
+#endif // defined(GL_SPOT_DIRECTION)
+ _needed = 3;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glGetLightxv(
+ (GLenum)light,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) */
+static void
+android_glGetMaterialfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jfloatArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetMaterialfv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) */
+static void
+android_glGetMaterialfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glGetMaterialfv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) */
+static void
+android_glGetMaterialxv__II_3II
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetMaterialxv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) */
+static void
+android_glGetMaterialxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint face, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_SHININESS)
+ case GL_SHININESS:
+#endif // defined(GL_SHININESS)
+ _needed = 1;
+ break;
+#if defined(GL_AMBIENT)
+ case GL_AMBIENT:
+#endif // defined(GL_AMBIENT)
+#if defined(GL_DIFFUSE)
+ case GL_DIFFUSE:
+#endif // defined(GL_DIFFUSE)
+#if defined(GL_SPECULAR)
+ case GL_SPECULAR:
+#endif // defined(GL_SPECULAR)
+#if defined(GL_EMISSION)
+ case GL_EMISSION:
+#endif // defined(GL_EMISSION)
+#if defined(GL_AMBIENT_AND_DIFFUSE)
+ case GL_AMBIENT_AND_DIFFUSE:
+#endif // defined(GL_AMBIENT_AND_DIFFUSE)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glGetMaterialxv(
+ (GLenum)face,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) */
+static void
+android_glGetTexEnviv__II_3II
+ (JNIEnv *_env, jobject _this, jint env, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetTexEnviv(
+ (GLenum)env,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) */
+static void
+android_glGetTexEnviv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint env, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glGetTexEnviv(
+ (GLenum)env,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) */
+static void
+android_glGetTexEnvxv__II_3II
+ (JNIEnv *_env, jobject _this, jint env, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetTexEnvxv(
+ (GLenum)env,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) */
+static void
+android_glGetTexEnvxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint env, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glGetTexEnvxv(
+ (GLenum)env,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) */
+static void
+android_glGetTexParameterfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jfloatArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetTexParameterfv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) */
+static void
+android_glGetTexParameterfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glGetTexParameterfv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetTexParameteriv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetTexParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetTexParameteriv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glGetTexParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) */
+static void
+android_glGetTexParameterxv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetTexParameterxv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+/* void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) */
+static void
+android_glGetTexParameterxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _exception = 1;
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glGetTexParameterxv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+}
+
+/* GLboolean glIsBuffer ( GLuint buffer ) */
+static jboolean
+android_glIsBuffer__I
+ (JNIEnv *_env, jobject _this, jint buffer) {
+ GLboolean _returnValue;
+ _returnValue = glIsBuffer(
+ (GLuint)buffer
+ );
+ return _returnValue;
+}
+
+/* GLboolean glIsEnabled ( GLenum cap ) */
+static jboolean
+android_glIsEnabled__I
+ (JNIEnv *_env, jobject _this, jint cap) {
+ GLboolean _returnValue;
+ _returnValue = glIsEnabled(
+ (GLenum)cap
+ );
+ return _returnValue;
+}
+
+/* GLboolean glIsTexture ( GLuint texture ) */
+static jboolean
+android_glIsTexture__I
+ (JNIEnv *_env, jobject _this, jint texture) {
+ GLboolean _returnValue;
+ _returnValue = glIsTexture(
+ (GLuint)texture
+ );
+ return _returnValue;
+}
+
+/* void glNormalPointer ( GLenum type, GLsizei stride, GLint offset ) */
+static void
+android_glNormalPointer__III
+ (JNIEnv *_env, jobject _this, jint type, jint stride, jint offset) {
+ glNormalPointer(
+ (GLenum)type,
+ (GLsizei)stride,
+ (const GLvoid *)offset
+ );
+}
+
+/* void glPointParameterf ( GLenum pname, GLfloat param ) */
+static void
+android_glPointParameterf__IF
+ (JNIEnv *_env, jobject _this, jint pname, jfloat param) {
+ glPointParameterf(
+ (GLenum)pname,
+ (GLfloat)param
+ );
+}
+
+/* void glPointParameterfv ( GLenum pname, const GLfloat *params ) */
+static void
+android_glPointParameterfv__I_3FI
+ (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) {
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glPointParameterfv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glPointParameterfv ( GLenum pname, const GLfloat *params ) */
+static void
+android_glPointParameterfv__ILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glPointParameterfv(
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glPointParameterx ( GLenum pname, GLfixed param ) */
+static void
+android_glPointParameterx__II
+ (JNIEnv *_env, jobject _this, jint pname, jint param) {
+ glPointParameterx(
+ (GLenum)pname,
+ (GLfixed)param
+ );
+}
+
+/* void glPointParameterxv ( GLenum pname, const GLfixed *params ) */
+static void
+android_glPointParameterxv__I_3II
+ (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) {
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glPointParameterxv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glPointParameterxv ( GLenum pname, const GLfixed *params ) */
+static void
+android_glPointParameterxv__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glPointParameterxv(
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glPointSizePointerOES ( GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glPointSizePointerOES__IILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint type, jint stride, jobject pointer_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLvoid *pointer = (GLvoid *) 0;
+
+ pointer = (GLvoid *)getPointer(_env, pointer_buf, &_array, &_remaining);
+ glPointSizePointerOES(
+ (GLenum)type,
+ (GLsizei)stride,
+ (GLvoid *)pointer
+ );
+ if (_array) {
+ releasePointer(_env, _array, pointer, JNI_FALSE);
+ }
+}
+
+/* void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
+static void
+android_glTexCoordPointer__IIII
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) {
+ glTexCoordPointer(
+ (GLint)size,
+ (GLenum)type,
+ (GLsizei)stride,
+ (const GLvoid *)offset
+ );
+}
+
+/* void glTexEnvi ( GLenum target, GLenum pname, GLint param ) */
+static void
+android_glTexEnvi__III
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) {
+ glTexEnvi(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint)param
+ );
+}
+
+/* void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexEnviv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "length - offset < needed");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexEnviv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexEnviv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ int _needed;
+ switch (pname) {
+#if defined(GL_TEXTURE_ENV_MODE)
+ case GL_TEXTURE_ENV_MODE:
+#endif // defined(GL_TEXTURE_ENV_MODE)
+#if defined(GL_COMBINE_RGB)
+ case GL_COMBINE_RGB:
+#endif // defined(GL_COMBINE_RGB)
+#if defined(GL_COMBINE_ALPHA)
+ case GL_COMBINE_ALPHA:
+#endif // defined(GL_COMBINE_ALPHA)
+ _needed = 1;
+ break;
+#if defined(GL_TEXTURE_ENV_COLOR)
+ case GL_TEXTURE_ENV_COLOR:
+#endif // defined(GL_TEXTURE_ENV_COLOR)
+ _needed = 4;
+ break;
+ default:
+ _needed = 0;
+ break;
+ }
+ if (_remaining < _needed) {
+ _env->ThrowNew(IAEClass, "remaining() < needed");
+ goto exit;
+ }
+ glTexEnviv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) */
+static void
+android_glTexParameterfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jfloatArray params_ref, jint offset) {
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexParameterfv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) */
+static void
+android_glTexParameterfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glTexParameterfv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glTexParameteri ( GLenum target, GLenum pname, GLint param ) */
+static void
+android_glTexParameteri__III
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jint param) {
+ glTexParameteri(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint)param
+ );
+}
+
+/* void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexParameteriv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexParameteriv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glTexParameteriv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) */
+static void
+android_glTexParameterxv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ GLfixed *params_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ if (!params_ref) {
+ _env->ThrowNew(IAEClass, "params == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "length - offset < 1");
+ goto exit;
+ }
+ params_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexParameterxv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) */
+static void
+android_glTexParameterxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *params = (GLfixed *) 0;
+
+ params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
+ if (_remaining < 1) {
+ _env->ThrowNew(IAEClass, "remaining() < 1");
+ goto exit;
+ }
+ glTexParameterxv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLfixed *)params
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, params, JNI_FALSE);
+ }
+}
+
+/* void glVertexPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
+static void
+android_glVertexPointer__IIII
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) {
+ glVertexPointer(
+ (GLint)size,
+ (GLenum)type,
+ (GLsizei)stride,
+ (const GLvoid *)offset
+ );
+}
+
+/* void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) */
+static void
+android_glCurrentPaletteMatrixOES__I
+ (JNIEnv *_env, jobject _this, jint matrixpaletteindex) {
+ _env->ThrowNew(UOEClass,
+ "glCurrentPaletteMatrixOES");
+}
+
+/* void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height ) */
+static void
+android_glDrawTexfOES__FFFFF
+ (JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z, jfloat width, jfloat height) {
+ glDrawTexfOES(
+ (GLfloat)x,
+ (GLfloat)y,
+ (GLfloat)z,
+ (GLfloat)width,
+ (GLfloat)height
+ );
+}
+
+/* void glDrawTexfvOES ( const GLfloat *coords ) */
+static void
+android_glDrawTexfvOES___3FI
+ (JNIEnv *_env, jobject _this, jfloatArray coords_ref, jint offset) {
+ GLfloat *coords_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *coords = (GLfloat *) 0;
+
+ if (!coords_ref) {
+ _env->ThrowNew(IAEClass, "coords == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(coords_ref) - offset;
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "length - offset < 5");
+ goto exit;
+ }
+ coords_base = (GLfloat *)
+ _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0);
+ coords = coords_base + offset;
+
+ glDrawTexfvOES(
+ (GLfloat *)coords
+ );
+
+exit:
+ if (coords_base) {
+ _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glDrawTexfvOES ( const GLfloat *coords ) */
+static void
+android_glDrawTexfvOES__Ljava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jobject coords_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfloat *coords = (GLfloat *) 0;
+
+ coords = (GLfloat *)getPointer(_env, coords_buf, &_array, &_remaining);
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "remaining() < 5");
+ goto exit;
+ }
+ glDrawTexfvOES(
+ (GLfloat *)coords
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, coords, JNI_FALSE);
+ }
+}
+
+/* void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height ) */
+static void
+android_glDrawTexiOES__IIIII
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint z, jint width, jint height) {
+ glDrawTexiOES(
+ (GLint)x,
+ (GLint)y,
+ (GLint)z,
+ (GLint)width,
+ (GLint)height
+ );
+}
+
+/* void glDrawTexivOES ( const GLint *coords ) */
+static void
+android_glDrawTexivOES___3II
+ (JNIEnv *_env, jobject _this, jintArray coords_ref, jint offset) {
+ GLint *coords_base = (GLint *) 0;
+ jint _remaining;
+ GLint *coords = (GLint *) 0;
+
+ if (!coords_ref) {
+ _env->ThrowNew(IAEClass, "coords == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(coords_ref) - offset;
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "length - offset < 5");
+ goto exit;
+ }
+ coords_base = (GLint *)
+ _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0);
+ coords = coords_base + offset;
+
+ glDrawTexivOES(
+ (GLint *)coords
+ );
+
+exit:
+ if (coords_base) {
+ _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glDrawTexivOES ( const GLint *coords ) */
+static void
+android_glDrawTexivOES__Ljava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jobject coords_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLint *coords = (GLint *) 0;
+
+ coords = (GLint *)getPointer(_env, coords_buf, &_array, &_remaining);
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "remaining() < 5");
+ goto exit;
+ }
+ glDrawTexivOES(
+ (GLint *)coords
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, coords, JNI_FALSE);
+ }
+}
+
+/* void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height ) */
+static void
+android_glDrawTexsOES__SSSSS
+ (JNIEnv *_env, jobject _this, jshort x, jshort y, jshort z, jshort width, jshort height) {
+ glDrawTexsOES(
+ (GLshort)x,
+ (GLshort)y,
+ (GLshort)z,
+ (GLshort)width,
+ (GLshort)height
+ );
+}
+
+/* void glDrawTexsvOES ( const GLshort *coords ) */
+static void
+android_glDrawTexsvOES___3SI
+ (JNIEnv *_env, jobject _this, jshortArray coords_ref, jint offset) {
+ GLshort *coords_base = (GLshort *) 0;
+ jint _remaining;
+ GLshort *coords = (GLshort *) 0;
+
+ if (!coords_ref) {
+ _env->ThrowNew(IAEClass, "coords == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(coords_ref) - offset;
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "length - offset < 5");
+ goto exit;
+ }
+ coords_base = (GLshort *)
+ _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0);
+ coords = coords_base + offset;
+
+ glDrawTexsvOES(
+ (GLshort *)coords
+ );
+
+exit:
+ if (coords_base) {
+ _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glDrawTexsvOES ( const GLshort *coords ) */
+static void
+android_glDrawTexsvOES__Ljava_nio_ShortBuffer_2
+ (JNIEnv *_env, jobject _this, jobject coords_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLshort *coords = (GLshort *) 0;
+
+ coords = (GLshort *)getPointer(_env, coords_buf, &_array, &_remaining);
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "remaining() < 5");
+ goto exit;
+ }
+ glDrawTexsvOES(
+ (GLshort *)coords
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, coords, JNI_FALSE);
+ }
+}
+
+/* void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height ) */
+static void
+android_glDrawTexxOES__IIIII
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint z, jint width, jint height) {
+ glDrawTexxOES(
+ (GLfixed)x,
+ (GLfixed)y,
+ (GLfixed)z,
+ (GLfixed)width,
+ (GLfixed)height
+ );
+}
+
+/* void glDrawTexxvOES ( const GLfixed *coords ) */
+static void
+android_glDrawTexxvOES___3II
+ (JNIEnv *_env, jobject _this, jintArray coords_ref, jint offset) {
+ GLfixed *coords_base = (GLfixed *) 0;
+ jint _remaining;
+ GLfixed *coords = (GLfixed *) 0;
+
+ if (!coords_ref) {
+ _env->ThrowNew(IAEClass, "coords == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(coords_ref) - offset;
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "length - offset < 5");
+ goto exit;
+ }
+ coords_base = (GLfixed *)
+ _env->GetPrimitiveArrayCritical(coords_ref, (jboolean *)0);
+ coords = coords_base + offset;
+
+ glDrawTexxvOES(
+ (GLfixed *)coords
+ );
+
+exit:
+ if (coords_base) {
+ _env->ReleasePrimitiveArrayCritical(coords_ref, coords_base,
+ JNI_ABORT);
+ }
+}
+
+/* void glDrawTexxvOES ( const GLfixed *coords ) */
+static void
+android_glDrawTexxvOES__Ljava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jobject coords_buf) {
+ jarray _array = (jarray) 0;
+ jint _remaining;
+ GLfixed *coords = (GLfixed *) 0;
+
+ coords = (GLfixed *)getPointer(_env, coords_buf, &_array, &_remaining);
+ if (_remaining < 5) {
+ _env->ThrowNew(IAEClass, "remaining() < 5");
+ goto exit;
+ }
+ glDrawTexxvOES(
+ (GLfixed *)coords
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, coords, JNI_FALSE);
+ }
+}
+
+/* void glLoadPaletteFromModelViewMatrixOES ( void ) */
+static void
+android_glLoadPaletteFromModelViewMatrixOES__
+ (JNIEnv *_env, jobject _this) {
+ _env->ThrowNew(UOEClass,
+ "glLoadPaletteFromModelViewMatrixOES");
+}
+
+/* void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glMatrixIndexPointerOES__IIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf) {
+ _env->ThrowNew(UOEClass,
+ "glMatrixIndexPointerOES");
+}
+
+/* void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
+static void
+android_glMatrixIndexPointerOES__IIII
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glMatrixIndexPointerOES");
+}
+
+/* void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) */
+static void
+android_glWeightPointerOES__IIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jobject pointer_buf) {
+ _env->ThrowNew(UOEClass,
+ "glWeightPointerOES");
+}
+
+/* void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) */
+static void
+android_glWeightPointerOES__IIII
+ (JNIEnv *_env, jobject _this, jint size, jint type, jint stride, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glWeightPointerOES");
+}
+
+/* void glBindFramebufferOES ( GLint target, GLint framebuffer ) */
+static void
+android_glBindFramebufferOES__II
+ (JNIEnv *_env, jobject _this, jint target, jint framebuffer) {
+ _env->ThrowNew(UOEClass,
+ "glBindFramebufferOES");
+}
+
+/* void glBindRenderbufferOES ( GLint target, GLint renderbuffer ) */
+static void
+android_glBindRenderbufferOES__II
+ (JNIEnv *_env, jobject _this, jint target, jint renderbuffer) {
+ _env->ThrowNew(UOEClass,
+ "glBindRenderbufferOES");
+}
+
+/* void glBlendEquation ( GLint mode ) */
+static void
+android_glBlendEquation__I
+ (JNIEnv *_env, jobject _this, jint mode) {
+ _env->ThrowNew(UOEClass,
+ "glBlendEquation");
+}
+
+/* void glBlendEquationSeparate ( GLint modeRGB, GLint modeAlpha ) */
+static void
+android_glBlendEquationSeparate__II
+ (JNIEnv *_env, jobject _this, jint modeRGB, jint modeAlpha) {
+ _env->ThrowNew(UOEClass,
+ "glBlendEquationSeparate");
+}
+
+/* void glBlendFuncSeparate ( GLint srcRGB, GLint dstRGB, GLint srcAlpha, GLint dstAlpha ) */
+static void
+android_glBlendFuncSeparate__IIII
+ (JNIEnv *_env, jobject _this, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) {
+ _env->ThrowNew(UOEClass,
+ "glBlendFuncSeparate");
+}
+
+/* GLint glCheckFramebufferStatusOES ( GLint target ) */
+static jint
+android_glCheckFramebufferStatusOES__I
+ (JNIEnv *_env, jobject _this, jint target) {
+ _env->ThrowNew(UOEClass,
+ "glCheckFramebufferStatusOES");
+ return 0;
+}
+
+/* void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) */
+static void
+android_glDeleteFramebuffersOES__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glDeleteFramebuffersOES");
+}
+
+/* void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) */
+static void
+android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
+ _env->ThrowNew(UOEClass,
+ "glDeleteFramebuffersOES");
+}
+
+/* void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) */
+static void
+android_glDeleteRenderbuffersOES__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glDeleteRenderbuffersOES");
+}
+
+/* void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) */
+static void
+android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
+ _env->ThrowNew(UOEClass,
+ "glDeleteRenderbuffersOES");
+}
+
+/* void glFramebufferRenderbufferOES ( GLint target, GLint attachment, GLint renderbuffertarget, GLint renderbuffer ) */
+static void
+android_glFramebufferRenderbufferOES__IIII
+ (JNIEnv *_env, jobject _this, jint target, jint attachment, jint renderbuffertarget, jint renderbuffer) {
+ _env->ThrowNew(UOEClass,
+ "glFramebufferRenderbufferOES");
+}
+
+/* void glFramebufferTexture2DOES ( GLint target, GLint attachment, GLint textarget, GLint texture, GLint level ) */
+static void
+android_glFramebufferTexture2DOES__IIIII
+ (JNIEnv *_env, jobject _this, jint target, jint attachment, jint textarget, jint texture, jint level) {
+ _env->ThrowNew(UOEClass,
+ "glFramebufferTexture2DOES");
+}
+
+/* void glGenerateMipmapOES ( GLint target ) */
+static void
+android_glGenerateMipmapOES__I
+ (JNIEnv *_env, jobject _this, jint target) {
+ _env->ThrowNew(UOEClass,
+ "glGenerateMipmapOES");
+}
+
+/* void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) */
+static void
+android_glGenFramebuffersOES__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGenFramebuffersOES");
+}
+
+/* void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) */
+static void
+android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGenFramebuffersOES");
+}
+
+/* void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) */
+static void
+android_glGenRenderbuffersOES__I_3II
+ (JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGenRenderbuffersOES");
+}
+
+/* void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) */
+static void
+android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGenRenderbuffersOES");
+}
+
+/* void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params ) */
+static void
+android_glGetFramebufferAttachmentParameterivOES__III_3II
+ (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jintArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGetFramebufferAttachmentParameterivOES");
+}
+
+/* void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params ) */
+static void
+android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGetFramebufferAttachmentParameterivOES");
+}
+
+/* void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params ) */
+static void
+android_glGetRenderbufferParameterivOES__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGetRenderbufferParameterivOES");
+}
+
+/* void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params ) */
+static void
+android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGetRenderbufferParameterivOES");
+}
+
+/* void glGetTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */
+static void
+android_glGetTexGenfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGetTexGenfv");
+}
+
+/* void glGetTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */
+static void
+android_glGetTexGenfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGetTexGenfv");
+}
+
+/* void glGetTexGeniv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glGetTexGeniv__II_3II
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGetTexGeniv");
+}
+
+/* void glGetTexGeniv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glGetTexGeniv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGetTexGeniv");
+}
+
+/* void glGetTexGenxv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glGetTexGenxv__II_3II
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glGetTexGenxv");
+}
+
+/* void glGetTexGenxv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glGetTexGenxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glGetTexGenxv");
+}
+
+/* GLboolean glIsFramebufferOES ( GLint framebuffer ) */
+static jboolean
+android_glIsFramebufferOES__I
+ (JNIEnv *_env, jobject _this, jint framebuffer) {
+ _env->ThrowNew(UOEClass,
+ "glIsFramebufferOES");
+ return JNI_FALSE;
+}
+
+/* GLboolean glIsRenderbufferOES ( GLint renderbuffer ) */
+static jboolean
+android_glIsRenderbufferOES__I
+ (JNIEnv *_env, jobject _this, jint renderbuffer) {
+ _env->ThrowNew(UOEClass,
+ "glIsRenderbufferOES");
+ return JNI_FALSE;
+}
+
+/* void glRenderbufferStorageOES ( GLint target, GLint internalformat, GLint width, GLint height ) */
+static void
+android_glRenderbufferStorageOES__IIII
+ (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint width, jint height) {
+ _env->ThrowNew(UOEClass,
+ "glRenderbufferStorageOES");
+}
+
+/* void glTexGenf ( GLint coord, GLint pname, GLfloat param ) */
+static void
+android_glTexGenf__IIF
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloat param) {
+ _env->ThrowNew(UOEClass,
+ "glTexGenf");
+}
+
+/* void glTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */
+static void
+android_glTexGenfv__II_3FI
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glTexGenfv");
+}
+
+/* void glTexGenfv ( GLint coord, GLint pname, GLfloat *params ) */
+static void
+android_glTexGenfv__IILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glTexGenfv");
+}
+
+/* void glTexGeni ( GLint coord, GLint pname, GLint param ) */
+static void
+android_glTexGeni__III
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) {
+ _env->ThrowNew(UOEClass,
+ "glTexGeni");
+}
+
+/* void glTexGeniv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glTexGeniv__II_3II
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glTexGeniv");
+}
+
+/* void glTexGeniv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glTexGeniv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glTexGeniv");
+}
+
+/* void glTexGenx ( GLint coord, GLint pname, GLint param ) */
+static void
+android_glTexGenx__III
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) {
+ _env->ThrowNew(UOEClass,
+ "glTexGenx");
+}
+
+/* void glTexGenxv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glTexGenxv__II_3II
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
+ _env->ThrowNew(UOEClass,
+ "glTexGenxv");
+}
+
+/* void glTexGenxv ( GLint coord, GLint pname, GLint *params ) */
+static void
+android_glTexGenxv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
+ _env->ThrowNew(UOEClass,
+ "glTexGenxv");
+}
+
+static const char *classPathName = "com/google/android/gles_jni/GLImpl";
+
+static JNINativeMethod methods[] = {
+{"_nativeClassInit", "()V", (void*)nativeClassInit },
+{"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
+{"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF },
+{"glAlphaFuncx", "(II)V", (void *) android_glAlphaFuncx__II },
+{"glBindTexture", "(II)V", (void *) android_glBindTexture__II },
+{"glBlendFunc", "(II)V", (void *) android_glBlendFunc__II },
+{"glClear", "(I)V", (void *) android_glClear__I },
+{"glClearColor", "(FFFF)V", (void *) android_glClearColor__FFFF },
+{"glClearColorx", "(IIII)V", (void *) android_glClearColorx__IIII },
+{"glClearDepthf", "(F)V", (void *) android_glClearDepthf__F },
+{"glClearDepthx", "(I)V", (void *) android_glClearDepthx__I },
+{"glClearStencil", "(I)V", (void *) android_glClearStencil__I },
+{"glClientActiveTexture", "(I)V", (void *) android_glClientActiveTexture__I },
+{"glColor4f", "(FFFF)V", (void *) android_glColor4f__FFFF },
+{"glColor4x", "(IIII)V", (void *) android_glColor4x__IIII },
+{"glColorMask", "(ZZZZ)V", (void *) android_glColorMask__ZZZZ },
+{"glColorPointerBounds", "(IIILjava/nio/Buffer;I)V", (void *) android_glColorPointerBounds__IIILjava_nio_Buffer_2I },
+{"glCompressedTexImage2D", "(IIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexImage2D__IIIIIIILjava_nio_Buffer_2 },
+{"glCompressedTexSubImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glCompressedTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 },
+{"glCopyTexImage2D", "(IIIIIIII)V", (void *) android_glCopyTexImage2D__IIIIIIII },
+{"glCopyTexSubImage2D", "(IIIIIIII)V", (void *) android_glCopyTexSubImage2D__IIIIIIII },
+{"glCullFace", "(I)V", (void *) android_glCullFace__I },
+{"glDeleteTextures", "(I[II)V", (void *) android_glDeleteTextures__I_3II },
+{"glDeleteTextures", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteTextures__ILjava_nio_IntBuffer_2 },
+{"glDepthFunc", "(I)V", (void *) android_glDepthFunc__I },
+{"glDepthMask", "(Z)V", (void *) android_glDepthMask__Z },
+{"glDepthRangef", "(FF)V", (void *) android_glDepthRangef__FF },
+{"glDepthRangex", "(II)V", (void *) android_glDepthRangex__II },
+{"glDisable", "(I)V", (void *) android_glDisable__I },
+{"glDisableClientState", "(I)V", (void *) android_glDisableClientState__I },
+{"glDrawArrays", "(III)V", (void *) android_glDrawArrays__III },
+{"glDrawElements", "(IIILjava/nio/Buffer;)V", (void *) android_glDrawElements__IIILjava_nio_Buffer_2 },
+{"glEnable", "(I)V", (void *) android_glEnable__I },
+{"glEnableClientState", "(I)V", (void *) android_glEnableClientState__I },
+{"glFinish", "()V", (void *) android_glFinish__ },
+{"glFlush", "()V", (void *) android_glFlush__ },
+{"glFogf", "(IF)V", (void *) android_glFogf__IF },
+{"glFogfv", "(I[FI)V", (void *) android_glFogfv__I_3FI },
+{"glFogfv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glFogfv__ILjava_nio_FloatBuffer_2 },
+{"glFogx", "(II)V", (void *) android_glFogx__II },
+{"glFogxv", "(I[II)V", (void *) android_glFogxv__I_3II },
+{"glFogxv", "(ILjava/nio/IntBuffer;)V", (void *) android_glFogxv__ILjava_nio_IntBuffer_2 },
+{"glFrontFace", "(I)V", (void *) android_glFrontFace__I },
+{"glFrustumf", "(FFFFFF)V", (void *) android_glFrustumf__FFFFFF },
+{"glFrustumx", "(IIIIII)V", (void *) android_glFrustumx__IIIIII },
+{"glGenTextures", "(I[II)V", (void *) android_glGenTextures__I_3II },
+{"glGenTextures", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenTextures__ILjava_nio_IntBuffer_2 },
+{"glGetError", "()I", (void *) android_glGetError__ },
+{"glGetIntegerv", "(I[II)V", (void *) android_glGetIntegerv__I_3II },
+{"glGetIntegerv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetIntegerv__ILjava_nio_IntBuffer_2 },
+{"_glGetString", "(I)Ljava/lang/String;", (void *) android_glGetString },
+{"glHint", "(II)V", (void *) android_glHint__II },
+{"glLightModelf", "(IF)V", (void *) android_glLightModelf__IF },
+{"glLightModelfv", "(I[FI)V", (void *) android_glLightModelfv__I_3FI },
+{"glLightModelfv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glLightModelfv__ILjava_nio_FloatBuffer_2 },
+{"glLightModelx", "(II)V", (void *) android_glLightModelx__II },
+{"glLightModelxv", "(I[II)V", (void *) android_glLightModelxv__I_3II },
+{"glLightModelxv", "(ILjava/nio/IntBuffer;)V", (void *) android_glLightModelxv__ILjava_nio_IntBuffer_2 },
+{"glLightf", "(IIF)V", (void *) android_glLightf__IIF },
+{"glLightfv", "(II[FI)V", (void *) android_glLightfv__II_3FI },
+{"glLightfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glLightfv__IILjava_nio_FloatBuffer_2 },
+{"glLightx", "(III)V", (void *) android_glLightx__III },
+{"glLightxv", "(II[II)V", (void *) android_glLightxv__II_3II },
+{"glLightxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glLightxv__IILjava_nio_IntBuffer_2 },
+{"glLineWidth", "(F)V", (void *) android_glLineWidth__F },
+{"glLineWidthx", "(I)V", (void *) android_glLineWidthx__I },
+{"glLoadIdentity", "()V", (void *) android_glLoadIdentity__ },
+{"glLoadMatrixf", "([FI)V", (void *) android_glLoadMatrixf___3FI },
+{"glLoadMatrixf", "(Ljava/nio/FloatBuffer;)V", (void *) android_glLoadMatrixf__Ljava_nio_FloatBuffer_2 },
+{"glLoadMatrixx", "([II)V", (void *) android_glLoadMatrixx___3II },
+{"glLoadMatrixx", "(Ljava/nio/IntBuffer;)V", (void *) android_glLoadMatrixx__Ljava_nio_IntBuffer_2 },
+{"glLogicOp", "(I)V", (void *) android_glLogicOp__I },
+{"glMaterialf", "(IIF)V", (void *) android_glMaterialf__IIF },
+{"glMaterialfv", "(II[FI)V", (void *) android_glMaterialfv__II_3FI },
+{"glMaterialfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glMaterialfv__IILjava_nio_FloatBuffer_2 },
+{"glMaterialx", "(III)V", (void *) android_glMaterialx__III },
+{"glMaterialxv", "(II[II)V", (void *) android_glMaterialxv__II_3II },
+{"glMaterialxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glMaterialxv__IILjava_nio_IntBuffer_2 },
+{"glMatrixMode", "(I)V", (void *) android_glMatrixMode__I },
+{"glMultMatrixf", "([FI)V", (void *) android_glMultMatrixf___3FI },
+{"glMultMatrixf", "(Ljava/nio/FloatBuffer;)V", (void *) android_glMultMatrixf__Ljava_nio_FloatBuffer_2 },
+{"glMultMatrixx", "([II)V", (void *) android_glMultMatrixx___3II },
+{"glMultMatrixx", "(Ljava/nio/IntBuffer;)V", (void *) android_glMultMatrixx__Ljava_nio_IntBuffer_2 },
+{"glMultiTexCoord4f", "(IFFFF)V", (void *) android_glMultiTexCoord4f__IFFFF },
+{"glMultiTexCoord4x", "(IIIII)V", (void *) android_glMultiTexCoord4x__IIIII },
+{"glNormal3f", "(FFF)V", (void *) android_glNormal3f__FFF },
+{"glNormal3x", "(III)V", (void *) android_glNormal3x__III },
+{"glNormalPointerBounds", "(IILjava/nio/Buffer;I)V", (void *) android_glNormalPointerBounds__IILjava_nio_Buffer_2I },
+{"glOrthof", "(FFFFFF)V", (void *) android_glOrthof__FFFFFF },
+{"glOrthox", "(IIIIII)V", (void *) android_glOrthox__IIIIII },
+{"glPixelStorei", "(II)V", (void *) android_glPixelStorei__II },
+{"glPointSize", "(F)V", (void *) android_glPointSize__F },
+{"glPointSizex", "(I)V", (void *) android_glPointSizex__I },
+{"glPolygonOffset", "(FF)V", (void *) android_glPolygonOffset__FF },
+{"glPolygonOffsetx", "(II)V", (void *) android_glPolygonOffsetx__II },
+{"glPopMatrix", "()V", (void *) android_glPopMatrix__ },
+{"glPushMatrix", "()V", (void *) android_glPushMatrix__ },
+{"glReadPixels", "(IIIIIILjava/nio/Buffer;)V", (void *) android_glReadPixels__IIIIIILjava_nio_Buffer_2 },
+{"glRotatef", "(FFFF)V", (void *) android_glRotatef__FFFF },
+{"glRotatex", "(IIII)V", (void *) android_glRotatex__IIII },
+{"glSampleCoverage", "(FZ)V", (void *) android_glSampleCoverage__FZ },
+{"glSampleCoveragex", "(IZ)V", (void *) android_glSampleCoveragex__IZ },
+{"glScalef", "(FFF)V", (void *) android_glScalef__FFF },
+{"glScalex", "(III)V", (void *) android_glScalex__III },
+{"glScissor", "(IIII)V", (void *) android_glScissor__IIII },
+{"glShadeModel", "(I)V", (void *) android_glShadeModel__I },
+{"glStencilFunc", "(III)V", (void *) android_glStencilFunc__III },
+{"glStencilMask", "(I)V", (void *) android_glStencilMask__I },
+{"glStencilOp", "(III)V", (void *) android_glStencilOp__III },
+{"glTexCoordPointerBounds", "(IIILjava/nio/Buffer;I)V", (void *) android_glTexCoordPointerBounds__IIILjava_nio_Buffer_2I },
+{"glTexEnvf", "(IIF)V", (void *) android_glTexEnvf__IIF },
+{"glTexEnvfv", "(II[FI)V", (void *) android_glTexEnvfv__II_3FI },
+{"glTexEnvfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glTexEnvfv__IILjava_nio_FloatBuffer_2 },
+{"glTexEnvx", "(III)V", (void *) android_glTexEnvx__III },
+{"glTexEnvxv", "(II[II)V", (void *) android_glTexEnvxv__II_3II },
+{"glTexEnvxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexEnvxv__IILjava_nio_IntBuffer_2 },
+{"glTexImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexImage2D__IIIIIIIILjava_nio_Buffer_2 },
+{"glTexParameterf", "(IIF)V", (void *) android_glTexParameterf__IIF },
+{"glTexParameterx", "(III)V", (void *) android_glTexParameterx__III },
+{"glTexSubImage2D", "(IIIIIIIILjava/nio/Buffer;)V", (void *) android_glTexSubImage2D__IIIIIIIILjava_nio_Buffer_2 },
+{"glTranslatef", "(FFF)V", (void *) android_glTranslatef__FFF },
+{"glTranslatex", "(III)V", (void *) android_glTranslatex__III },
+{"glVertexPointerBounds", "(IIILjava/nio/Buffer;I)V", (void *) android_glVertexPointerBounds__IIILjava_nio_Buffer_2I },
+{"glViewport", "(IIII)V", (void *) android_glViewport__IIII },
+{"glQueryMatrixxOES", "([II[II)I", (void *) android_glQueryMatrixxOES___3II_3II },
+{"glQueryMatrixxOES", "(Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)I", (void *) android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 },
+{"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II },
+{"glBufferData", "(IILjava/nio/Buffer;I)V", (void *) android_glBufferData__IILjava_nio_Buffer_2I },
+{"glBufferSubData", "(IIILjava/nio/Buffer;)V", (void *) android_glBufferSubData__IIILjava_nio_Buffer_2 },
+{"glClipPlanef", "(I[FI)V", (void *) android_glClipPlanef__I_3FI },
+{"glClipPlanef", "(ILjava/nio/FloatBuffer;)V", (void *) android_glClipPlanef__ILjava_nio_FloatBuffer_2 },
+{"glClipPlanex", "(I[II)V", (void *) android_glClipPlanex__I_3II },
+{"glClipPlanex", "(ILjava/nio/IntBuffer;)V", (void *) android_glClipPlanex__ILjava_nio_IntBuffer_2 },
+{"glColor4ub", "(BBBB)V", (void *) android_glColor4ub__BBBB },
+{"glColorPointer", "(IIII)V", (void *) android_glColorPointer__IIII },
+{"glDeleteBuffers", "(I[II)V", (void *) android_glDeleteBuffers__I_3II },
+{"glDeleteBuffers", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteBuffers__ILjava_nio_IntBuffer_2 },
+{"glDrawElements", "(IIII)V", (void *) android_glDrawElements__IIII },
+{"glGenBuffers", "(I[II)V", (void *) android_glGenBuffers__I_3II },
+{"glGenBuffers", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenBuffers__ILjava_nio_IntBuffer_2 },
+{"glGetBooleanv", "(I[ZI)V", (void *) android_glGetBooleanv__I_3ZI },
+{"glGetBooleanv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetBooleanv__ILjava_nio_IntBuffer_2 },
+{"glGetBufferParameteriv", "(II[II)V", (void *) android_glGetBufferParameteriv__II_3II },
+{"glGetBufferParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2 },
+{"glGetClipPlanef", "(I[FI)V", (void *) android_glGetClipPlanef__I_3FI },
+{"glGetClipPlanef", "(ILjava/nio/FloatBuffer;)V", (void *) android_glGetClipPlanef__ILjava_nio_FloatBuffer_2 },
+{"glGetClipPlanex", "(I[II)V", (void *) android_glGetClipPlanex__I_3II },
+{"glGetClipPlanex", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetClipPlanex__ILjava_nio_IntBuffer_2 },
+{"glGetFixedv", "(I[II)V", (void *) android_glGetFixedv__I_3II },
+{"glGetFixedv", "(ILjava/nio/IntBuffer;)V", (void *) android_glGetFixedv__ILjava_nio_IntBuffer_2 },
+{"glGetFloatv", "(I[FI)V", (void *) android_glGetFloatv__I_3FI },
+{"glGetFloatv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glGetFloatv__ILjava_nio_FloatBuffer_2 },
+{"glGetLightfv", "(II[FI)V", (void *) android_glGetLightfv__II_3FI },
+{"glGetLightfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetLightfv__IILjava_nio_FloatBuffer_2 },
+{"glGetLightxv", "(II[II)V", (void *) android_glGetLightxv__II_3II },
+{"glGetLightxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetLightxv__IILjava_nio_IntBuffer_2 },
+{"glGetMaterialfv", "(II[FI)V", (void *) android_glGetMaterialfv__II_3FI },
+{"glGetMaterialfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetMaterialfv__IILjava_nio_FloatBuffer_2 },
+{"glGetMaterialxv", "(II[II)V", (void *) android_glGetMaterialxv__II_3II },
+{"glGetMaterialxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetMaterialxv__IILjava_nio_IntBuffer_2 },
+{"glGetTexEnviv", "(II[II)V", (void *) android_glGetTexEnviv__II_3II },
+{"glGetTexEnviv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexEnviv__IILjava_nio_IntBuffer_2 },
+{"glGetTexEnvxv", "(II[II)V", (void *) android_glGetTexEnvxv__II_3II },
+{"glGetTexEnvxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexEnvxv__IILjava_nio_IntBuffer_2 },
+{"glGetTexParameterfv", "(II[FI)V", (void *) android_glGetTexParameterfv__II_3FI },
+{"glGetTexParameterfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetTexParameterfv__IILjava_nio_FloatBuffer_2 },
+{"glGetTexParameteriv", "(II[II)V", (void *) android_glGetTexParameteriv__II_3II },
+{"glGetTexParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameteriv__IILjava_nio_IntBuffer_2 },
+{"glGetTexParameterxv", "(II[II)V", (void *) android_glGetTexParameterxv__II_3II },
+{"glGetTexParameterxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameterxv__IILjava_nio_IntBuffer_2 },
+{"glIsBuffer", "(I)Z", (void *) android_glIsBuffer__I },
+{"glIsEnabled", "(I)Z", (void *) android_glIsEnabled__I },
+{"glIsTexture", "(I)Z", (void *) android_glIsTexture__I },
+{"glNormalPointer", "(III)V", (void *) android_glNormalPointer__III },
+{"glPointParameterf", "(IF)V", (void *) android_glPointParameterf__IF },
+{"glPointParameterfv", "(I[FI)V", (void *) android_glPointParameterfv__I_3FI },
+{"glPointParameterfv", "(ILjava/nio/FloatBuffer;)V", (void *) android_glPointParameterfv__ILjava_nio_FloatBuffer_2 },
+{"glPointParameterx", "(II)V", (void *) android_glPointParameterx__II },
+{"glPointParameterxv", "(I[II)V", (void *) android_glPointParameterxv__I_3II },
+{"glPointParameterxv", "(ILjava/nio/IntBuffer;)V", (void *) android_glPointParameterxv__ILjava_nio_IntBuffer_2 },
+{"glPointSizePointerOES", "(IILjava/nio/Buffer;)V", (void *) android_glPointSizePointerOES__IILjava_nio_Buffer_2 },
+{"glTexCoordPointer", "(IIII)V", (void *) android_glTexCoordPointer__IIII },
+{"glTexEnvi", "(III)V", (void *) android_glTexEnvi__III },
+{"glTexEnviv", "(II[II)V", (void *) android_glTexEnviv__II_3II },
+{"glTexEnviv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexEnviv__IILjava_nio_IntBuffer_2 },
+{"glTexParameterfv", "(II[FI)V", (void *) android_glTexParameterfv__II_3FI },
+{"glTexParameterfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glTexParameterfv__IILjava_nio_FloatBuffer_2 },
+{"glTexParameteri", "(III)V", (void *) android_glTexParameteri__III },
+{"glTexParameteriv", "(II[II)V", (void *) android_glTexParameteriv__II_3II },
+{"glTexParameteriv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameteriv__IILjava_nio_IntBuffer_2 },
+{"glTexParameterxv", "(II[II)V", (void *) android_glTexParameterxv__II_3II },
+{"glTexParameterxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameterxv__IILjava_nio_IntBuffer_2 },
+{"glVertexPointer", "(IIII)V", (void *) android_glVertexPointer__IIII },
+{"glCurrentPaletteMatrixOES", "(I)V", (void *) android_glCurrentPaletteMatrixOES__I },
+{"glDrawTexfOES", "(FFFFF)V", (void *) android_glDrawTexfOES__FFFFF },
+{"glDrawTexfvOES", "([FI)V", (void *) android_glDrawTexfvOES___3FI },
+{"glDrawTexfvOES", "(Ljava/nio/FloatBuffer;)V", (void *) android_glDrawTexfvOES__Ljava_nio_FloatBuffer_2 },
+{"glDrawTexiOES", "(IIIII)V", (void *) android_glDrawTexiOES__IIIII },
+{"glDrawTexivOES", "([II)V", (void *) android_glDrawTexivOES___3II },
+{"glDrawTexivOES", "(Ljava/nio/IntBuffer;)V", (void *) android_glDrawTexivOES__Ljava_nio_IntBuffer_2 },
+{"glDrawTexsOES", "(SSSSS)V", (void *) android_glDrawTexsOES__SSSSS },
+{"glDrawTexsvOES", "([SI)V", (void *) android_glDrawTexsvOES___3SI },
+{"glDrawTexsvOES", "(Ljava/nio/ShortBuffer;)V", (void *) android_glDrawTexsvOES__Ljava_nio_ShortBuffer_2 },
+{"glDrawTexxOES", "(IIIII)V", (void *) android_glDrawTexxOES__IIIII },
+{"glDrawTexxvOES", "([II)V", (void *) android_glDrawTexxvOES___3II },
+{"glDrawTexxvOES", "(Ljava/nio/IntBuffer;)V", (void *) android_glDrawTexxvOES__Ljava_nio_IntBuffer_2 },
+{"glLoadPaletteFromModelViewMatrixOES", "()V", (void *) android_glLoadPaletteFromModelViewMatrixOES__ },
+{"glMatrixIndexPointerOES", "(IIILjava/nio/Buffer;)V", (void *) android_glMatrixIndexPointerOES__IIILjava_nio_Buffer_2 },
+{"glMatrixIndexPointerOES", "(IIII)V", (void *) android_glMatrixIndexPointerOES__IIII },
+{"glWeightPointerOES", "(IIILjava/nio/Buffer;)V", (void *) android_glWeightPointerOES__IIILjava_nio_Buffer_2 },
+{"glWeightPointerOES", "(IIII)V", (void *) android_glWeightPointerOES__IIII },
+{"glBindFramebufferOES", "(II)V", (void *) android_glBindFramebufferOES__II },
+{"glBindRenderbufferOES", "(II)V", (void *) android_glBindRenderbufferOES__II },
+{"glBlendEquation", "(I)V", (void *) android_glBlendEquation__I },
+{"glBlendEquationSeparate", "(II)V", (void *) android_glBlendEquationSeparate__II },
+{"glBlendFuncSeparate", "(IIII)V", (void *) android_glBlendFuncSeparate__IIII },
+{"glCheckFramebufferStatusOES", "(I)I", (void *) android_glCheckFramebufferStatusOES__I },
+{"glDeleteFramebuffersOES", "(I[II)V", (void *) android_glDeleteFramebuffersOES__I_3II },
+{"glDeleteFramebuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2 },
+{"glDeleteRenderbuffersOES", "(I[II)V", (void *) android_glDeleteRenderbuffersOES__I_3II },
+{"glDeleteRenderbuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2 },
+{"glFramebufferRenderbufferOES", "(IIII)V", (void *) android_glFramebufferRenderbufferOES__IIII },
+{"glFramebufferTexture2DOES", "(IIIII)V", (void *) android_glFramebufferTexture2DOES__IIIII },
+{"glGenerateMipmapOES", "(I)V", (void *) android_glGenerateMipmapOES__I },
+{"glGenFramebuffersOES", "(I[II)V", (void *) android_glGenFramebuffersOES__I_3II },
+{"glGenFramebuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2 },
+{"glGenRenderbuffersOES", "(I[II)V", (void *) android_glGenRenderbuffersOES__I_3II },
+{"glGenRenderbuffersOES", "(ILjava/nio/IntBuffer;)V", (void *) android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2 },
+{"glGetFramebufferAttachmentParameterivOES", "(III[II)V", (void *) android_glGetFramebufferAttachmentParameterivOES__III_3II },
+{"glGetFramebufferAttachmentParameterivOES", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2 },
+{"glGetRenderbufferParameterivOES", "(II[II)V", (void *) android_glGetRenderbufferParameterivOES__II_3II },
+{"glGetRenderbufferParameterivOES", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2 },
+{"glGetTexGenfv", "(II[FI)V", (void *) android_glGetTexGenfv__II_3FI },
+{"glGetTexGenfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glGetTexGenfv__IILjava_nio_FloatBuffer_2 },
+{"glGetTexGeniv", "(II[II)V", (void *) android_glGetTexGeniv__II_3II },
+{"glGetTexGeniv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexGeniv__IILjava_nio_IntBuffer_2 },
+{"glGetTexGenxv", "(II[II)V", (void *) android_glGetTexGenxv__II_3II },
+{"glGetTexGenxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexGenxv__IILjava_nio_IntBuffer_2 },
+{"glIsFramebufferOES", "(I)Z", (void *) android_glIsFramebufferOES__I },
+{"glIsRenderbufferOES", "(I)Z", (void *) android_glIsRenderbufferOES__I },
+{"glRenderbufferStorageOES", "(IIII)V", (void *) android_glRenderbufferStorageOES__IIII },
+{"glTexGenf", "(IIF)V", (void *) android_glTexGenf__IIF },
+{"glTexGenfv", "(II[FI)V", (void *) android_glTexGenfv__II_3FI },
+{"glTexGenfv", "(IILjava/nio/FloatBuffer;)V", (void *) android_glTexGenfv__IILjava_nio_FloatBuffer_2 },
+{"glTexGeni", "(III)V", (void *) android_glTexGeni__III },
+{"glTexGeniv", "(II[II)V", (void *) android_glTexGeniv__II_3II },
+{"glTexGeniv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexGeniv__IILjava_nio_IntBuffer_2 },
+{"glTexGenx", "(III)V", (void *) android_glTexGenx__III },
+{"glTexGenxv", "(II[II)V", (void *) android_glTexGenxv__II_3II },
+{"glTexGenxv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexGenxv__IILjava_nio_IntBuffer_2 },
+};
+
+int register_com_google_android_gles_jni_GLImpl(JNIEnv *_env)
+{
+ int err;
+ err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));
+ return err;
+}
diff --git a/core/jni/server/Android.mk b/core/jni/server/Android.mk
new file mode 100644
index 0000000..d108330
--- /dev/null
+++ b/core/jni/server/Android.mk
@@ -0,0 +1,37 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ com_android_server_AlarmManagerService.cpp \
+ com_android_server_BatteryService.cpp \
+ com_android_server_HardwareService.cpp \
+ com_android_server_KeyInputQueue.cpp \
+ com_android_server_SensorService.cpp \
+ com_android_server_SystemServer.cpp \
+ onload.cpp
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE)
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libhardware \
+ libnativehelper \
+ libsystem_server \
+ libutils \
+ libui
+
+ifeq ($(TARGET_OS),linux)
+ifeq ($(TARGET_ARCH),x86)
+LOCAL_LDLIBS += -lpthread -ldl -lrt
+endif
+endif
+
+ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
+ LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
+endif
+
+LOCAL_MODULE:= libandroid_servers
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/core/jni/server/com_android_server_AlarmManagerService.cpp b/core/jni/server/com_android_server_AlarmManagerService.cpp
new file mode 100644
index 0000000..a81a0ff
--- /dev/null
+++ b/core/jni/server/com_android_server_AlarmManagerService.cpp
@@ -0,0 +1,120 @@
+/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
+**
+** Copyright 2006, 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 "AlarmManagerService"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/ioctl.h>
+#include <linux/android_alarm.h>
+#endif
+
+#define ONE_NANOSECOND 1000000000LL
+#define NANOSECONDS_TO_SECONDS(x) (x / ONE_NANOSECOND)
+#define SECONDS_TO_NANOSECONDS(x) (x * ONE_NANOSECOND)
+
+namespace android {
+
+static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
+{
+#if HAVE_ANDROID_OS
+ return open("/dev/alarm", O_RDWR);
+#else
+ return -1;
+#endif
+}
+
+static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd)
+{
+#if HAVE_ANDROID_OS
+ close(fd);
+#endif
+}
+
+static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong nanoseconds)
+{
+#if HAVE_ANDROID_OS
+ struct timespec ts;
+ ts.tv_sec = NANOSECONDS_TO_SECONDS(nanoseconds);
+ ts.tv_nsec = nanoseconds - SECONDS_TO_NANOSECONDS(ts.tv_sec);
+
+ int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
+ if (result < 0)
+ {
+ LOGE("Unable to set alarm to %lld: %s\n", nanoseconds, strerror(errno));
+ }
+#endif
+}
+
+static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)
+{
+#if HAVE_ANDROID_OS
+ int result = 0;
+
+ do
+ {
+ result = ioctl(fd, ANDROID_ALARM_WAIT);
+ } while (result < 0 && errno == EINTR);
+
+ if (result < 0)
+ {
+ LOGE("Unable to wait on alarm: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return result;
+#endif
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"init", "()I", (void*)android_server_AlarmManagerService_init},
+ {"close", "(I)V", (void*)android_server_AlarmManagerService_close},
+ {"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set},
+ {"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
+};
+
+int register_android_server_AlarmManagerService(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("com/android/server/AlarmManagerService");
+
+ if (clazz == NULL)
+ {
+ LOGE("Can't find com/android/server/AlarmManagerService");
+ return -1;
+ }
+
+ return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
+ sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/server/com_android_server_BatteryService.cpp b/core/jni/server/com_android_server_BatteryService.cpp
new file mode 100644
index 0000000..6636a97
--- /dev/null
+++ b/core/jni/server/com_android_server_BatteryService.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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_TAG "BatteryService"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/ioctl.h>
+#endif
+
+namespace android {
+
+#define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"
+#define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"
+#define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"
+#define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"
+#define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"
+#define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"
+#define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"
+#define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"
+#define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology"
+
+struct FieldIds {
+ // members
+ jfieldID mAcOnline;
+ jfieldID mUsbOnline;
+ jfieldID mBatteryStatus;
+ jfieldID mBatteryHealth;
+ jfieldID mBatteryPresent;
+ jfieldID mBatteryLevel;
+ jfieldID mBatteryVoltage;
+ jfieldID mBatteryTemperature;
+ jfieldID mBatteryTechnology;
+};
+static FieldIds gFieldIds;
+
+struct BatteryManagerConstants {
+ jint statusUnknown;
+ jint statusCharging;
+ jint statusDischarging;
+ jint statusNotCharging;
+ jint statusFull;
+ jint healthUnknown;
+ jint healthGood;
+ jint healthOverheat;
+ jint healthDead;
+ jint healthOverVoltage;
+ jint healthUnspecifiedFailure;
+};
+static BatteryManagerConstants gConstants;
+
+static jint getBatteryStatus(const char* status)
+{
+ switch (status[0]) {
+ case 'C': return gConstants.statusCharging; // Charging
+ case 'D': return gConstants.statusDischarging; // Discharging
+ case 'F': return gConstants.statusFull; // Not charging
+ case 'N': return gConstants.statusNotCharging; // Full
+ case 'U': return gConstants.statusUnknown; // Unknown
+
+ default: {
+ LOGW("Unknown battery status '%s'", status);
+ return gConstants.statusUnknown;
+ }
+ }
+}
+
+static jint getBatteryHealth(const char* status)
+{
+ switch (status[0]) {
+ case 'D': return gConstants.healthDead; // Dead
+ case 'G': return gConstants.healthGood; // Good
+ case 'O': {
+ if (strcmp(status, "Overheat") == 0) {
+ return gConstants.healthOverheat;
+ } else if (strcmp(status, "Over voltage") == 0) {
+ return gConstants.healthOverVoltage;
+ }
+ LOGW("Unknown battery health[1] '%s'", status);
+ return gConstants.healthUnknown;
+ }
+
+ case 'U': {
+ if (strcmp(status, "Unspecified failure") == 0) {
+ return gConstants.healthUnspecifiedFailure;
+ } else if (strcmp(status, "Unknown") == 0) {
+ return gConstants.healthUnknown;
+ }
+ // fall through
+ }
+
+ default: {
+ LOGW("Unknown battery health[2] '%s'", status);
+ return gConstants.healthUnknown;
+ }
+ }
+}
+
+static int readFromFile(const char* path, char* buf, size_t size)
+{
+ int fd = open(path, O_RDONLY, 0);
+ if (fd == -1) {
+ LOGE("Could not open '%s'", path);
+ return -1;
+ }
+
+ size_t count = read(fd, buf, size);
+ if (count > 0) {
+ count = (count < size) ? count : size - 1;
+ while (count > 0 && buf[count-1] == '\n') count--;
+ buf[count] = '\0';
+ } else {
+ buf[0] = '\0';
+ }
+
+ close(fd);
+ return count;
+}
+
+static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
+{
+ const int SIZE = 16;
+ char buf[SIZE];
+
+ jboolean value = false;
+ if (readFromFile(path, buf, SIZE) > 0) {
+ if (buf[0] == '1') {
+ value = true;
+ }
+ }
+ env->SetBooleanField(obj, fieldID, value);
+}
+
+static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
+{
+ const int SIZE = 128;
+ char buf[SIZE];
+
+ jint value = 0;
+ if (readFromFile(path, buf, SIZE) > 0) {
+ value = atoi(buf);
+ }
+ env->SetIntField(obj, fieldID, value);
+}
+
+static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
+{
+ setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
+ setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
+ setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);
+
+ setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
+ setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
+ setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);
+
+ const int SIZE = 128;
+ char buf[SIZE];
+
+ if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
+ env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
+
+ if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
+ env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
+
+ if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
+ env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"native_update", "()V", (void*)android_server_BatteryService_update},
+};
+
+int register_android_server_BatteryService(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("com/android/server/BatteryService");
+
+ if (clazz == NULL) {
+ LOGE("Can't find com/android/server/BatteryService");
+ return -1;
+ }
+
+ gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
+ gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
+ gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
+ gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
+ gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
+ gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
+ gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;");
+ gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I");
+ gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I");
+
+ LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH");
+ LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH");
+ LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH");
+ LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH");
+ LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH");
+ LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH");
+ LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH");
+ LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH");
+ LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH");
+
+ clazz = env->FindClass("android/os/BatteryManager");
+
+ if (clazz == NULL) {
+ LOGE("Can't find android/os/BatteryManager");
+ return -1;
+ }
+
+ gConstants.statusUnknown = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I"));
+
+ gConstants.statusCharging = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I"));
+
+ gConstants.statusDischarging = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I"));
+
+ gConstants.statusNotCharging = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I"));
+
+ gConstants.statusFull = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I"));
+
+ gConstants.healthUnknown = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I"));
+
+ gConstants.healthGood = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I"));
+
+ gConstants.healthOverheat = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I"));
+
+ gConstants.healthDead = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I"));
+
+ gConstants.healthOverVoltage = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I"));
+
+ gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
+
+ return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/server/com_android_server_HardwareService.cpp b/core/jni/server/com_android_server_HardwareService.cpp
new file mode 100644
index 0000000..479e57d
--- /dev/null
+++ b/core/jni/server/com_android_server_HardwareService.cpp
@@ -0,0 +1,54 @@
+/* //device/libs/android_runtime/android_os_Vibrator.cpp
+**
+** Copyright 2006, 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 "Vibrator"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include <stdio.h>
+#include "android_runtime/AndroidRuntime.h"
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <hardware/vibrator.h>
+
+namespace android
+{
+
+static void on(JNIEnv *env, jobject clazz)
+{
+ // LOGI("on\n");
+ vibrator_on();
+}
+
+static void off(JNIEnv *env, jobject clazz)
+{
+ // LOGI("off\n");
+ vibrator_off();
+}
+
+static JNINativeMethod method_table[] = {
+ { "on", "()V", (void*)on },
+ { "off", "()V", (void*)off }
+};
+
+int register_android_os_Vibrator(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/HardwareService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/core/jni/server/com_android_server_KeyInputQueue.cpp b/core/jni/server/com_android_server_KeyInputQueue.cpp
new file mode 100644
index 0000000..4e9ffb1
--- /dev/null
+++ b/core/jni/server/com_android_server_KeyInputQueue.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2007 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 "Input"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include <utils/misc.h>
+#include <utils/Log.h>
+
+#include <ui/EventHub.h>
+#include <utils/threads.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct input_offsets_t
+{
+ jfieldID mMinValue;
+ jfieldID mMaxValue;
+ jfieldID mFlat;
+ jfieldID mFuzz;
+
+ jfieldID mDeviceId;
+ jfieldID mType;
+ jfieldID mScancode;
+ jfieldID mKeycode;
+ jfieldID mFlags;
+ jfieldID mValue;
+ jfieldID mWhen;
+} gInputOffsets;
+
+// ----------------------------------------------------------------------------
+
+static Mutex gLock;
+static sp<EventHub> gHub;
+
+static jboolean
+android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
+ jobject event)
+{
+ gLock.lock();
+ sp<EventHub> hub = gHub;
+ if (hub == NULL) {
+ hub = new EventHub;
+ gHub = hub;
+ }
+ gLock.unlock();
+
+ int32_t deviceId;
+ int32_t type;
+ int32_t scancode, keycode;
+ uint32_t flags;
+ int32_t value;
+ nsecs_t when;
+ bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
+ &flags, &value, &when);
+
+ env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
+ env->SetIntField(event, gInputOffsets.mType, (jint)type);
+ env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
+ env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
+ env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
+ env->SetIntField(event, gInputOffsets.mValue, value);
+ env->SetLongField(event, gInputOffsets.mWhen,
+ (jlong)(nanoseconds_to_milliseconds(when)));
+
+ return res;
+}
+
+static jint
+android_server_KeyInputQueue_getDeviceClasses(JNIEnv* env, jobject clazz,
+ jint deviceId)
+{
+ jint classes = 0;
+ gLock.lock();
+ if (gHub != NULL) classes = gHub->getDeviceClasses(deviceId);
+ gLock.unlock();
+ return classes;
+}
+
+static jstring
+android_server_KeyInputQueue_getDeviceName(JNIEnv* env, jobject clazz,
+ jint deviceId)
+{
+ String8 name;
+ gLock.lock();
+ if (gHub != NULL) name = gHub->getDeviceName(deviceId);
+ gLock.unlock();
+
+ if (name.size() > 0) {
+ return env->NewStringUTF(name.string());
+ }
+ return NULL;
+}
+
+static jboolean
+android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz,
+ jint deviceId, jint axis,
+ jobject info)
+{
+ int32_t minValue, maxValue, flat, fuzz;
+ int res = -1;
+ gLock.lock();
+ if (gHub != NULL) {
+ res = gHub->getAbsoluteInfo(deviceId, axis,
+ &minValue, &maxValue, &flat, &fuzz);
+ }
+ gLock.unlock();
+
+ if (res < 0) return JNI_FALSE;
+
+ env->SetIntField(info, gInputOffsets.mMinValue, (jint)minValue);
+ env->SetIntField(info, gInputOffsets.mMaxValue, (jint)maxValue);
+ env->SetIntField(info, gInputOffsets.mFlat, (jint)flat);
+ env->SetIntField(info, gInputOffsets.mFuzz, (jint)fuzz);
+ return JNI_TRUE;
+}
+
+static jint
+android_server_KeyInputQueue_getSwitchState(JNIEnv* env, jobject clazz,
+ jint sw)
+{
+ jint st = -1;
+ gLock.lock();
+ if (gHub != NULL) st = gHub->getSwitchState(sw);
+ gLock.unlock();
+
+ return st;
+}
+
+static jint
+android_server_KeyInputQueue_getSwitchStateDevice(JNIEnv* env, jobject clazz,
+ jint deviceId, jint sw)
+{
+ jint st = -1;
+ gLock.lock();
+ if (gHub != NULL) st = gHub->getSwitchState(deviceId, sw);
+ gLock.unlock();
+
+ return st;
+}
+
+static jint
+android_server_KeyInputQueue_getScancodeState(JNIEnv* env, jobject clazz,
+ jint sw)
+{
+ jint st = -1;
+ gLock.lock();
+ if (gHub != NULL) st = gHub->getScancodeState(sw);
+ gLock.unlock();
+
+ return st;
+}
+
+static jint
+android_server_KeyInputQueue_getScancodeStateDevice(JNIEnv* env, jobject clazz,
+ jint deviceId, jint sw)
+{
+ jint st = -1;
+ gLock.lock();
+ if (gHub != NULL) st = gHub->getScancodeState(deviceId, sw);
+ gLock.unlock();
+
+ return st;
+}
+
+static jint
+android_server_KeyInputQueue_getKeycodeState(JNIEnv* env, jobject clazz,
+ jint sw)
+{
+ jint st = -1;
+ gLock.lock();
+ if (gHub != NULL) st = gHub->getKeycodeState(sw);
+ gLock.unlock();
+
+ return st;
+}
+
+static jint
+android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
+ jint deviceId, jint sw)
+{
+ jint st = -1;
+ gLock.lock();
+ if (gHub != NULL) st = gHub->getKeycodeState(deviceId, sw);
+ gLock.unlock();
+
+ return st;
+}
+
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gInputMethods[] = {
+ /* name, signature, funcPtr */
+ { "readEvent", "(Landroid/view/RawInputEvent;)Z",
+ (void*) android_server_KeyInputQueue_readEvent },
+ { "getDeviceClasses", "(I)I",
+ (void*) android_server_KeyInputQueue_getDeviceClasses },
+ { "getDeviceName", "(I)Ljava/lang/String;",
+ (void*) android_server_KeyInputQueue_getDeviceName },
+ { "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z",
+ (void*) android_server_KeyInputQueue_getAbsoluteInfo },
+ { "getSwitchState", "(I)I",
+ (void*) android_server_KeyInputQueue_getSwitchState },
+ { "getSwitchState", "(II)I",
+ (void*) android_server_KeyInputQueue_getSwitchStateDevice },
+ { "getScancodeState", "(I)I",
+ (void*) android_server_KeyInputQueue_getScancodeState },
+ { "getScancodeState", "(II)I",
+ (void*) android_server_KeyInputQueue_getScancodeStateDevice },
+ { "getKeycodeState", "(I)I",
+ (void*) android_server_KeyInputQueue_getKeycodeState },
+ { "getKeycodeState", "(II)I",
+ (void*) android_server_KeyInputQueue_getKeycodeStateDevice },
+};
+
+int register_android_server_KeyInputQueue(JNIEnv* env)
+{
+ jclass input = env->FindClass("com/android/server/KeyInputQueue");
+ LOG_FATAL_IF(input == NULL, "Unable to find class com/android/server/KeyInputQueue");
+ int res = jniRegisterNativeMethods(env, "com/android/server/KeyInputQueue",
+ gInputMethods, NELEM(gInputMethods));
+
+ jclass absoluteInfo = env->FindClass("com/android/server/InputDevice$AbsoluteInfo");
+ LOG_FATAL_IF(absoluteInfo == NULL, "Unable to find class com/android/server/InputDevice$AbsoluteInfo");
+
+ gInputOffsets.mMinValue
+ = env->GetFieldID(absoluteInfo, "minValue", "I");
+ LOG_FATAL_IF(gInputOffsets.mMinValue == NULL, "Unable to find InputDevice.AbsoluteInfo.minValue");
+
+ gInputOffsets.mMaxValue
+ = env->GetFieldID(absoluteInfo, "maxValue", "I");
+ LOG_FATAL_IF(gInputOffsets.mMaxValue == NULL, "Unable to find InputDevice.AbsoluteInfo.maxValue");
+
+ gInputOffsets.mFlat
+ = env->GetFieldID(absoluteInfo, "flat", "I");
+ LOG_FATAL_IF(gInputOffsets.mFlat == NULL, "Unable to find InputDevice.AbsoluteInfo.flat");
+
+ gInputOffsets.mFuzz
+ = env->GetFieldID(absoluteInfo, "fuzz", "I");
+ LOG_FATAL_IF(gInputOffsets.mFuzz == NULL, "Unable to find InputDevice.AbsoluteInfo.fuzz");
+
+ jclass inputEvent = env->FindClass("android/view/RawInputEvent");
+ LOG_FATAL_IF(inputEvent == NULL, "Unable to find class android/view/RawInputEvent");
+
+ gInputOffsets.mDeviceId
+ = env->GetFieldID(inputEvent, "deviceId", "I");
+ LOG_FATAL_IF(gInputOffsets.mDeviceId == NULL, "Unable to find RawInputEvent.deviceId");
+
+ gInputOffsets.mType
+ = env->GetFieldID(inputEvent, "type", "I");
+ LOG_FATAL_IF(gInputOffsets.mType == NULL, "Unable to find RawInputEvent.type");
+
+ gInputOffsets.mScancode
+ = env->GetFieldID(inputEvent, "scancode", "I");
+ LOG_FATAL_IF(gInputOffsets.mScancode == NULL, "Unable to find RawInputEvent.scancode");
+
+ gInputOffsets.mKeycode
+ = env->GetFieldID(inputEvent, "keycode", "I");
+ LOG_FATAL_IF(gInputOffsets.mKeycode == NULL, "Unable to find RawInputEvent.keycode");
+
+ gInputOffsets.mFlags
+ = env->GetFieldID(inputEvent, "flags", "I");
+ LOG_FATAL_IF(gInputOffsets.mFlags == NULL, "Unable to find RawInputEvent.flags");
+
+ gInputOffsets.mValue
+ = env->GetFieldID(inputEvent, "value", "I");
+ LOG_FATAL_IF(gInputOffsets.mValue == NULL, "Unable to find RawInputEvent.value");
+
+ gInputOffsets.mWhen
+ = env->GetFieldID(inputEvent, "when", "J");
+ LOG_FATAL_IF(gInputOffsets.mWhen == NULL, "Unable to find RawInputEvent.when");
+
+ return res;
+}
+
+}; // namespace android
+
diff --git a/core/jni/server/com_android_server_SensorService.cpp b/core/jni/server/com_android_server_SensorService.cpp
new file mode 100644
index 0000000..37f6231
--- /dev/null
+++ b/core/jni/server/com_android_server_SensorService.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 "Sensors"
+
+#include <hardware/sensors.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+namespace android {
+
+
+static struct file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+ jfieldID mDescriptor;
+} gFileDescriptorOffsets;
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+/*
+ * The method below are not thread-safe and not intended to be
+ */
+
+static jint
+android_init(JNIEnv *env, jclass clazz)
+{
+ return sensors_control_init();
+}
+
+static jobject
+android_open(JNIEnv *env, jclass clazz)
+{
+ int fd = sensors_control_open();
+ // new FileDescriptor()
+ jobject filedescriptor = env->NewObject(
+ gFileDescriptorOffsets.mClass,
+ gFileDescriptorOffsets.mConstructor);
+
+ if (filedescriptor != NULL) {
+ env->SetIntField(filedescriptor, gFileDescriptorOffsets.mDescriptor, fd);
+ // new ParcelFileDescriptor()
+ return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor,
+ filedescriptor);
+ }
+ close(fd);
+ return NULL;
+}
+
+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;
+}
+
+static jint
+android_set_delay(JNIEnv *env, jclass clazz, jint ms)
+{
+ return sensors_control_delay(ms);
+}
+
+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_set_delay","(I)I", (void*) android_set_delay },
+};
+
+int register_android_server_SensorService(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("java/io/FileDescriptor");
+ gFileDescriptorOffsets.mClass = (jclass)env->NewGlobalRef(clazz);
+ gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
+ gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
+
+ clazz = env->FindClass("android/os/ParcelFileDescriptor");
+ gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+
+ return jniRegisterNativeMethods(env, "com/android/server/SensorService",
+ gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/server/com_android_server_SystemServer.cpp b/core/jni/server/com_android_server_SystemServer.cpp
new file mode 100644
index 0000000..ae29405
--- /dev/null
+++ b/core/jni/server/com_android_server_SystemServer.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+namespace android {
+
+extern "C" int system_init();
+
+static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
+{
+ system_init();
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
+};
+
+int register_android_server_SystemServer(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
+ gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
+
+
diff --git a/core/jni/server/onload.cpp b/core/jni/server/onload.cpp
new file mode 100644
index 0000000..3d68cfb
--- /dev/null
+++ b/core/jni/server/onload.cpp
@@ -0,0 +1,36 @@
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+namespace android {
+int register_android_server_AlarmManagerService(JNIEnv* env);
+int register_android_server_BatteryService(JNIEnv* env);
+int register_android_server_KeyInputQueue(JNIEnv* env);
+int register_android_os_Vibrator(JNIEnv* env);
+int register_android_server_SensorService(JNIEnv* env);
+int register_android_server_SystemServer(JNIEnv* env);
+};
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ LOGE("GetEnv failed!");
+ return result;
+ }
+ LOG_ASSERT(env, "Could not retrieve the env!");
+
+ register_android_server_KeyInputQueue(env);
+ register_android_os_Vibrator(env);
+ register_android_server_AlarmManagerService(env);
+ register_android_server_BatteryService(env);
+ register_android_server_SensorService(env);
+ register_android_server_SystemServer(env);
+
+ return JNI_VERSION_1_4;
+}
diff --git a/core/jni/sqlite3_exception.h b/core/jni/sqlite3_exception.h
new file mode 100644
index 0000000..13735a1
--- /dev/null
+++ b/core/jni/sqlite3_exception.h
@@ -0,0 +1,47 @@
+/* //device/libs/include/android_runtime/sqlite3_exception.h
+**
+** Copyright 2007, 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.
+*/
+
+#ifndef _SQLITE3_EXCEPTION_H
+#define _SQLITE3_EXCEPTION_H 1
+
+#include <jni.h>
+#include <JNIHelp.h>
+//#include <android_runtime/AndroidRuntime.h>
+
+#include <sqlite3.h>
+
+namespace android {
+
+/* throw a SQLiteException with a message appropriate for the error in handle */
+void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle);
+
+/* throw a SQLiteException with the given message */
+void throw_sqlite3_exception(JNIEnv* env, const char* message);
+
+/* throw a SQLiteException with a message appropriate for the error in handle
+ concatenated with the given message
+ */
+void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message);
+
+/* throw a SQLiteException for a given error code */
+void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message);
+
+void throw_sqlite3_exception(JNIEnv* env, int errcode,
+ const char* sqlite3Message, const char* message);
+}
+
+#endif // _SQLITE3_EXCEPTION_H