summaryrefslogtreecommitdiffstats
path: root/services/core/jni
diff options
context:
space:
mode:
Diffstat (limited to 'services/core/jni')
-rw-r--r--services/core/jni/Android.mk56
-rw-r--r--services/core/jni/com_android_server_AlarmManagerService.cpp321
-rw-r--r--services/core/jni/com_android_server_AssetAtlasService.cpp272
-rw-r--r--services/core/jni/com_android_server_ConsumerIrService.cpp114
-rw-r--r--services/core/jni/com_android_server_SerialService.cpp82
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp51
-rw-r--r--services/core/jni/com_android_server_UsbDeviceManager.cpp157
-rw-r--r--services/core/jni/com_android_server_UsbHostManager.cpp214
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp61
-rw-r--r--services/core/jni/com_android_server_connectivity_Vpn.cpp473
-rw-r--r--services/core/jni/com_android_server_input_InputApplicationHandle.cpp158
-rw-r--r--services/core/jni/com_android_server_input_InputApplicationHandle.h46
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp1472
-rw-r--r--services/core/jni/com_android_server_input_InputWindowHandle.cpp309
-rw-r--r--services/core/jni/com_android_server_input_InputWindowHandle.h47
-rw-r--r--services/core/jni/com_android_server_lights_LightsService.cpp141
-rw-r--r--services/core/jni/com_android_server_location_FlpHardwareProvider.cpp1002
-rw-r--r--services/core/jni/com_android_server_location_GpsLocationProvider.cpp800
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp252
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.h35
-rw-r--r--services/core/jni/onload.cpp73
21 files changed, 6136 insertions, 0 deletions
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
new file mode 100644
index 0000000..1a3ce63
--- /dev/null
+++ b/services/core/jni/Android.mk
@@ -0,0 +1,56 @@
+# This file is included by the top level services directory to collect source
+# files
+LOCAL_REL_DIR := core/jni
+
+LOCAL_SRC_FILES += \
+ $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_location_GpsLocationProvider.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
+ $(LOCAL_REL_DIR)/onload.cpp
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/services \
+ frameworks/base/libs \
+ frameworks/base/core/jni \
+ frameworks/native/services \
+ external/skia/include/core \
+ libcore/include \
+ libcore/include/libsuspend \
+ $(call include-path-for, libhardware)/hardware \
+ $(call include-path-for, libhardware_legacy)/hardware_legacy \
+
+LOCAL_SHARED_LIBRARIES += \
+ libandroid_runtime \
+ libandroidfw \
+ libbinder \
+ libcutils \
+ liblog \
+ libhardware \
+ libhardware_legacy \
+ libnativehelper \
+ libutils \
+ libui \
+ libinput \
+ libinputservice \
+ libsensorservice \
+ libskia \
+ libgui \
+ libusbhost \
+ libsuspend \
+ libEGL \
+ libGLESv2
+
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
new file mode 100644
index 0000000..342515b
--- /dev/null
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -0,0 +1,321 @@
+/* //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/epoll.h>
+#include <sys/timerfd.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>
+#include <linux/ioctl.h>
+#include <linux/android_alarm.h>
+
+namespace android {
+
+static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
+static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
+ CLOCK_REALTIME_ALARM,
+ CLOCK_REALTIME,
+ CLOCK_BOOTTIME_ALARM,
+ CLOCK_BOOTTIME,
+ CLOCK_MONOTONIC,
+ CLOCK_REALTIME,
+};
+/* to match the legacy alarm driver implementation, we need an extra
+ CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */
+
+class AlarmImpl
+{
+public:
+ AlarmImpl(int *fds, size_t n_fds);
+ virtual ~AlarmImpl();
+
+ virtual int set(int type, struct timespec *ts) = 0;
+ virtual int waitForAlarm() = 0;
+
+protected:
+ int *fds;
+ size_t n_fds;
+};
+
+class AlarmImplAlarmDriver : public AlarmImpl
+{
+public:
+ AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }
+
+ int set(int type, struct timespec *ts);
+ int waitForAlarm();
+};
+
+class AlarmImplTimerFd : public AlarmImpl
+{
+public:
+ AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd) :
+ AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd) { }
+ ~AlarmImplTimerFd();
+
+ int set(int type, struct timespec *ts);
+ int waitForAlarm();
+
+private:
+ int epollfd;
+};
+
+AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]),
+ n_fds(n_fds)
+{
+ memcpy(fds, fds_, n_fds * sizeof(fds[0]));
+}
+
+AlarmImpl::~AlarmImpl()
+{
+ for (size_t i = 0; i < n_fds; i++) {
+ close(fds[i]);
+ }
+ delete [] fds;
+}
+
+int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
+{
+ return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
+}
+
+int AlarmImplAlarmDriver::waitForAlarm()
+{
+ return ioctl(fds[0], ANDROID_ALARM_WAIT);
+}
+
+AlarmImplTimerFd::~AlarmImplTimerFd()
+{
+ for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
+ epoll_ctl(epollfd, EPOLL_CTL_DEL, fds[i], NULL);
+ }
+ close(epollfd);
+}
+
+int AlarmImplTimerFd::set(int type, struct timespec *ts)
+{
+ if (type > ANDROID_ALARM_TYPE_COUNT) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!ts->tv_nsec && !ts->tv_sec) {
+ ts->tv_nsec = 1;
+ }
+ /* timerfd interprets 0 = disarm, so replace with a practically
+ equivalent deadline of 1 ns */
+
+ struct itimerspec spec;
+ memset(&spec, 0, sizeof(spec));
+ memcpy(&spec.it_value, ts, sizeof(spec.it_value));
+
+ return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
+}
+
+int AlarmImplTimerFd::waitForAlarm()
+{
+ epoll_event events[N_ANDROID_TIMERFDS];
+
+ int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1);
+ if (nevents < 0) {
+ return nevents;
+ }
+
+ int result = 0;
+ for (int i = 0; i < nevents; i++) {
+ uint32_t alarm_idx = events[i].data.u32;
+ uint64_t unused;
+ ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
+ if (err < 0) {
+ if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
+ result |= ANDROID_ALARM_TIME_CHANGE_MASK;
+ } else {
+ return err;
+ }
+ } else {
+ result |= (1 << alarm_idx);
+ }
+ }
+
+ return result;
+}
+
+static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
+{
+ struct timezone tz;
+
+ tz.tz_minuteswest = minswest;
+ tz.tz_dsttime = 0;
+
+ int result = settimeofday(NULL, &tz);
+ if (result < 0) {
+ ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
+ return -1;
+ } else {
+ ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
+ }
+
+ return 0;
+}
+
+static jlong init_alarm_driver()
+{
+ int fd = open("/dev/alarm", O_RDWR);
+ if (fd < 0) {
+ ALOGV("opening alarm driver failed: %s", strerror(errno));
+ return 0;
+ }
+
+ AlarmImpl *ret = new AlarmImplAlarmDriver(fd);
+ return reinterpret_cast<jlong>(ret);
+}
+
+static jlong init_timerfd()
+{
+ int epollfd;
+ int fds[N_ANDROID_TIMERFDS];
+
+ epollfd = epoll_create(N_ANDROID_TIMERFDS);
+ if (epollfd < 0) {
+ ALOGV("epoll_create(%u) failed: %s", N_ANDROID_TIMERFDS,
+ strerror(errno));
+ return 0;
+ }
+
+ for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
+ fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
+ if (fds[i] < 0) {
+ ALOGV("timerfd_create(%u) failed: %s", android_alarm_to_clockid[i],
+ strerror(errno));
+ close(epollfd);
+ for (size_t j = 0; j < i; j++) {
+ close(fds[j]);
+ }
+ return 0;
+ }
+ }
+
+ AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd);
+
+ for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
+ epoll_event event;
+ event.events = EPOLLIN | EPOLLWAKEUP;
+ event.data.u32 = i;
+
+ int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
+ if (err < 0) {
+ ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
+ delete ret;
+ return 0;
+ }
+ }
+
+ struct itimerspec spec;
+ memset(&spec, 0, sizeof(spec));
+ /* 0 = disarmed; the timerfd doesn't need to be armed to get
+ RTC change notifications, just set up as cancelable */
+
+ int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
+ TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
+ if (err < 0) {
+ ALOGV("timerfd_settime() failed: %s", strerror(errno));
+ delete ret;
+ return 0;
+ }
+
+ return reinterpret_cast<jlong>(ret);
+}
+
+static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
+{
+ jlong ret = init_alarm_driver();
+ if (ret) {
+ return ret;
+ }
+
+ return init_timerfd();
+}
+
+static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
+{
+ AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
+ delete impl;
+}
+
+static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
+{
+ AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
+ struct timespec ts;
+ ts.tv_sec = seconds;
+ ts.tv_nsec = nanoseconds;
+
+ int result = impl->set(type, &ts);
+ if (result < 0)
+ {
+ ALOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
+ }
+}
+
+static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
+{
+ AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
+ int result = 0;
+
+ do
+ {
+ result = impl->waitForAlarm();
+ } while (result < 0 && errno == EINTR);
+
+ if (result < 0)
+ {
+ ALOGE("Unable to wait on alarm: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return result;
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"init", "()J", (void*)android_server_AlarmManagerService_init},
+ {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
+ {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
+ {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
+ {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
+};
+
+int register_android_server_AlarmManagerService(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
+ sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
new file mode 100644
index 0000000..4a1b55d
--- /dev/null
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2013 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 "AssetAtlasService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <android_view_GraphicBuffer.h>
+#include <cutils/log.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Defines
+// ----------------------------------------------------------------------------
+
+// Defines how long to wait for the GPU when uploading the atlas
+// This timeout is defined in nanoseconds (see EGL_KHR_fence_sync extension)
+#define FENCE_TIMEOUT 2000000000
+
+// ----------------------------------------------------------------------------
+// JNI Helpers
+// ----------------------------------------------------------------------------
+
+static struct {
+ jfieldID mFinalizer;
+ jfieldID mNativeCanvas;
+} gCanvasClassInfo;
+
+static struct {
+ jfieldID mNativeCanvas;
+} gCanvasFinalizerClassInfo;
+
+#define GET_LONG(object, field) \
+ env->GetLongField(object, field)
+
+#define SET_LONG(object, field, value) \
+ env->SetLongField(object, field, value)
+
+// ----------------------------------------------------------------------------
+// Canvas management
+// ----------------------------------------------------------------------------
+
+static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
+ jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
+ SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
+ GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
+ SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
+ SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
+ SkSafeUnref(previousCanvas);
+}
+
+static SkBitmap* com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
+ jobject canvas, jint width, jint height) {
+
+ SkBitmap* bitmap = new SkBitmap;
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap->allocPixels();
+ bitmap->eraseColor(0);
+
+ SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
+ swapCanvasPtr(env, canvas, nativeCanvas);
+
+ return bitmap;
+}
+
+static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject,
+ jobject canvas, SkBitmap* bitmap) {
+
+ SkCanvas* nativeCanvas = SkNEW(SkCanvas);
+ swapCanvasPtr(env, canvas, nativeCanvas);
+
+ delete bitmap;
+}
+
+#define CLEANUP_GL_AND_RETURN(result) \
+ if (fence != EGL_NO_SYNC_KHR) eglDestroySyncKHR(display, fence); \
+ if (image) eglDestroyImageKHR(display, image); \
+ if (texture) glDeleteTextures(1, &texture); \
+ if (surface != EGL_NO_SURFACE) eglDestroySurface(display, surface); \
+ if (context != EGL_NO_CONTEXT) eglDestroyContext(display, context); \
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); \
+ eglReleaseThread(); \
+ eglTerminate(display); \
+ return result;
+
+static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
+ jobject graphicBuffer, SkBitmap* bitmap) {
+
+ // The goal of this method is to copy the bitmap into the GraphicBuffer
+ // using the GPU to swizzle the texture content
+ sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
+
+ if (buffer != NULL) {
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (display == EGL_NO_DISPLAY) return false;
+
+ EGLint major;
+ EGLint minor;
+ if (!eglInitialize(display, &major, &minor)) {
+ ALOGW("Could not initialize EGL");
+ return false;
+ }
+
+ // We're going to use a 1x1 pbuffer surface later on
+ // The configuration doesn't really matter for what we're trying to do
+ EGLint configAttrs[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 0,
+ EGL_STENCIL_SIZE, 0,
+ EGL_NONE
+ };
+ EGLConfig configs[1];
+ EGLint configCount;
+ if (!eglChooseConfig(display, configAttrs, configs, 1, &configCount)) {
+ ALOGW("Could not select EGL configuration");
+ eglReleaseThread();
+ eglTerminate(display);
+ return false;
+ }
+ if (configCount <= 0) {
+ ALOGW("Could not find EGL configuration");
+ eglReleaseThread();
+ eglTerminate(display);
+ return false;
+ }
+
+ // These objects are initialized below but the default "null"
+ // values are used to cleanup properly at any point in the
+ // initialization sequence
+ GLuint texture = 0;
+ EGLImageKHR image = EGL_NO_IMAGE_KHR;
+ EGLSurface surface = EGL_NO_SURFACE;
+ EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
+ EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLContext context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, attrs);
+ if (context == EGL_NO_CONTEXT) {
+ ALOGW("Could not create EGL context");
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ // Create the 1x1 pbuffer
+ EGLint surfaceAttrs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+ surface = eglCreatePbufferSurface(display, configs[0], surfaceAttrs);
+ if (surface == EGL_NO_SURFACE) {
+ ALOGW("Could not create EGL surface");
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ if (!eglMakeCurrent(display, surface, surface, context)) {
+ ALOGW("Could not change current EGL context");
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ // We use an EGLImage to access the content of the GraphicBuffer
+ // The EGL image is later bound to a 2D texture
+ EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+ EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
+ if (image == EGL_NO_IMAGE_KHR) {
+ ALOGW("Could not create EGL image");
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+ if (glGetError() != GL_NO_ERROR) {
+ ALOGW("Could not create/bind texture");
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ // Upload the content of the bitmap in the GraphicBuffer
+ glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->width(), bitmap->height(),
+ GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
+ if (glGetError() != GL_NO_ERROR) {
+ ALOGW("Could not upload to texture");
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ // The fence is used to wait for the texture upload to finish
+ // properly. We cannot rely on glFlush() and glFinish() as
+ // some drivers completely ignore these API calls
+ fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
+ if (fence == EGL_NO_SYNC_KHR) {
+ ALOGW("Could not create sync fence %#x", eglGetError());
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
+ // pipeline flush (similar to what a glFlush() would do.)
+ EGLint waitStatus = eglClientWaitSyncKHR(display, fence,
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
+ if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
+ ALOGW("Failed to wait for the fence %#x", eglGetError());
+ CLEANUP_GL_AND_RETURN(false);
+ }
+
+ CLEANUP_GL_AND_RETURN(true);
+ }
+
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+const char* const kClassPathName = "com/android/server/AssetAtlasService";
+
+static JNINativeMethod gMethods[] = {
+ { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)I",
+ (void*) com_android_server_AssetAtlasService_acquireCanvas },
+ { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;I)V",
+ (void*) com_android_server_AssetAtlasService_releaseCanvas },
+ { "nUploadAtlas", "(Landroid/view/GraphicBuffer;I)Z",
+ (void*) com_android_server_AssetAtlasService_upload },
+};
+
+int register_android_server_AssetAtlasService(JNIEnv* env) {
+ jclass clazz;
+
+ FIND_CLASS(clazz, "android/graphics/Canvas");
+ GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
+ "Landroid/graphics/Canvas$CanvasFinalizer;");
+ GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+
+ FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
+ GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+
+ return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
new file mode 100644
index 0000000..004c0aa
--- /dev/null
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 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 "ConsumerIrService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <stdlib.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/consumerir.h>
+#include <ScopedPrimitiveArray.h>
+
+namespace android {
+
+static jint halOpen(JNIEnv *env, jobject obj) {
+ hw_module_t const* module;
+ consumerir_device_t *dev;
+ int err;
+
+ err = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &module);
+ if (err != 0) {
+ ALOGE("Can't open consumer IR HW Module, error: %d", err);
+ return 0;
+ }
+
+ err = module->methods->open(module, CONSUMERIR_TRANSMITTER,
+ (hw_device_t **) &dev);
+ if (err < 0) {
+ ALOGE("Can't open consumer IR transmitter, error: %d", err);
+ return 0;
+ }
+
+ return reinterpret_cast<jint>(dev);
+}
+
+static jint halTransmit(JNIEnv *env, jobject obj, jint halObject,
+ jint carrierFrequency, jintArray pattern) {
+ int ret;
+
+ consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject);
+ ScopedIntArrayRO cPattern(env, pattern);
+ if (cPattern.get() == NULL) {
+ return -EINVAL;
+ }
+ jsize patternLength = cPattern.size();
+
+ ret = dev->transmit(dev, carrierFrequency, cPattern.get(), patternLength);
+
+ return reinterpret_cast<jint>(ret);
+}
+
+static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject obj,
+ jint halObject) {
+ consumerir_device_t *dev = (consumerir_device_t *) halObject;
+ consumerir_freq_range_t *ranges;
+ int len;
+
+ len = dev->get_num_carrier_freqs(dev);
+ if (len <= 0)
+ return NULL;
+
+ ranges = new consumerir_freq_range_t[len];
+
+ len = dev->get_carrier_freqs(dev, len, ranges);
+ if (len <= 0) {
+ delete[] ranges;
+ return NULL;
+ }
+
+ int i;
+ ScopedIntArrayRW freqsOut(env, env->NewIntArray(len*2));
+ jint *arr = freqsOut.get();
+ if (arr == NULL) {
+ delete[] ranges;
+ return NULL;
+ }
+ for (i = 0; i < len; i++) {
+ arr[i*2] = ranges[i].min;
+ arr[i*2+1] = ranges[i].max;
+ }
+
+ delete[] ranges;
+ return freqsOut.getJavaArray();
+}
+
+static JNINativeMethod method_table[] = {
+ { "halOpen", "()I", (void *)halOpen },
+ { "halTransmit", "(II[I)I", (void *)halTransmit },
+ { "halGetCarrierFrequencies", "(I)[I", (void *)halGetCarrierFrequencies},
+};
+
+int register_android_server_ConsumerIrService(JNIEnv *env) {
+ return jniRegisterNativeMethods(env, "com/android/server/ConsumerIrService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
new file mode 100644
index 0000000..b889b78
--- /dev/null
+++ b/services/core/jni/com_android_server_SerialService.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 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 "SerialServiceJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android
+{
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+static jobject android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path)
+{
+ const char *pathStr = env->GetStringUTFChars(path, NULL);
+
+ int fd = open(pathStr, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ ALOGE("could not open %s", pathStr);
+ env->ReleaseStringUTFChars(path, pathStr);
+ return NULL;
+ }
+ env->ReleaseStringUTFChars(path, pathStr);
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ if (fileDescriptor == NULL) {
+ return NULL;
+ }
+ return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
+}
+
+
+static JNINativeMethod method_table[] = {
+ { "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
+ (void*)android_server_SerialService_open },
+};
+
+int register_android_server_SerialService(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/SerialService");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/SerialService");
+ return -1;
+ }
+
+ 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");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
+ "Unable to find constructor for android.os.ParcelFileDescriptor");
+
+ return jniRegisterNativeMethods(env, "com/android/server/SerialService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
new file mode 100644
index 0000000..0625544
--- /dev/null
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 <JNIHelp.h>
+
+#include <sensorservice/SensorService.h>
+
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+namespace android {
+
+static void android_server_SystemServer_nativeInit(JNIEnv* env, jobject clazz) {
+ char propBuf[PROPERTY_VALUE_MAX];
+ property_get("system_init.startsensorservice", propBuf, "1");
+ if (strcmp(propBuf, "1") == 0) {
+ // Start the sensor service
+ SensorService::instantiate();
+ }
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeInit", "()V", (void*) android_server_SystemServer_nativeInit },
+};
+
+int register_android_server_SystemServer(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
+ gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
new file mode 100644
index 0000000..3551733
--- /dev/null
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2010 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 "UsbDeviceManagerJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+
+#include <stdio.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/usb/f_accessory.h>
+
+#define DRIVER_NAME "/dev/usb_accessory"
+
+namespace android
+{
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+}
+
+static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strArray, int index)
+{
+ char buffer[256];
+
+ buffer[0] = 0;
+ int length = ioctl(fd, cmd, buffer);
+ if (buffer[0]) {
+ jstring obj = env->NewStringUTF(buffer);
+ env->SetObjectArrayElement(strArray, index, obj);
+ env->DeleteLocalRef(obj);
+ }
+}
+
+
+static jobjectArray android_server_UsbDeviceManager_getAccessoryStrings(JNIEnv *env, jobject thiz)
+{
+ int fd = open(DRIVER_NAME, O_RDWR);
+ if (fd < 0) {
+ ALOGE("could not open %s", DRIVER_NAME);
+ return NULL;
+ }
+ jclass stringClass = env->FindClass("java/lang/String");
+ jobjectArray strArray = env->NewObjectArray(6, stringClass, NULL);
+ if (!strArray) goto out;
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_SERIAL, strArray, 5);
+
+out:
+ close(fd);
+ return strArray;
+}
+
+static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobject thiz)
+{
+ int fd = open(DRIVER_NAME, O_RDWR);
+ if (fd < 0) {
+ ALOGE("could not open %s", DRIVER_NAME);
+ return NULL;
+ }
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ if (fileDescriptor == NULL) {
+ return NULL;
+ }
+ return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
+}
+
+static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv *env, jobject thiz)
+{
+ int fd = open(DRIVER_NAME, O_RDWR);
+ if (fd < 0) {
+ ALOGE("could not open %s", DRIVER_NAME);
+ return false;
+ }
+ int result = ioctl(fd, ACCESSORY_IS_START_REQUESTED);
+ close(fd);
+ return (result == 1);
+}
+
+static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv *env, jobject thiz)
+{
+ int fd = open(DRIVER_NAME, O_RDWR);
+ if (fd < 0) {
+ ALOGE("could not open %s", DRIVER_NAME);
+ return false;
+ }
+ int result = ioctl(fd, ACCESSORY_GET_AUDIO_MODE);
+ close(fd);
+ return result;
+}
+
+static JNINativeMethod method_table[] = {
+ { "nativeGetAccessoryStrings", "()[Ljava/lang/String;",
+ (void*)android_server_UsbDeviceManager_getAccessoryStrings },
+ { "nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;",
+ (void*)android_server_UsbDeviceManager_openAccessory },
+ { "nativeIsStartRequested", "()Z",
+ (void*)android_server_UsbDeviceManager_isStartRequested },
+ { "nativeGetAudioMode", "()I",
+ (void*)android_server_UsbDeviceManager_getAudioMode },
+};
+
+int register_android_server_UsbDeviceManager(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/usb/UsbDeviceManager");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/usb/UsbDeviceManager");
+ return -1;
+ }
+
+ 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");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
+ "Unable to find constructor for android.os.ParcelFileDescriptor");
+
+ return jniRegisterNativeMethods(env, "com/android/server/usb/UsbDeviceManager",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
new file mode 100644
index 0000000..f1fa6cf
--- /dev/null
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2010 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 "UsbHostManagerJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+#include "utils/Vector.h"
+
+#include <usbhost/usbhost.h>
+
+#include <stdio.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+namespace android
+{
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+static jmethodID method_usbDeviceAdded;
+static jmethodID method_usbDeviceRemoved;
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+}
+
+static int usb_device_added(const char *devname, void* client_data) {
+ struct usb_descriptor_header* desc;
+ struct usb_descriptor_iter iter;
+
+ struct usb_device *device = usb_device_open(devname);
+ if (!device) {
+ ALOGE("usb_device_open failed\n");
+ return 0;
+ }
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject thiz = (jobject)client_data;
+ Vector<int> interfaceValues;
+ Vector<int> endpointValues;
+ const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
+
+ uint16_t vendorId = usb_device_get_vendor_id(device);
+ uint16_t productId = usb_device_get_product_id(device);
+ uint8_t deviceClass = deviceDesc->bDeviceClass;
+ uint8_t deviceSubClass = deviceDesc->bDeviceSubClass;
+ uint8_t protocol = deviceDesc->bDeviceProtocol;
+ char *manufacturer = usb_device_get_manufacturer_name(device);
+ char *product = usb_device_get_product_name(device);
+ char *serial = usb_device_get_serial(device);
+
+ usb_descriptor_iter_init(device, &iter);
+
+ while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
+ if (desc->bDescriptorType == USB_DT_INTERFACE) {
+ struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
+
+ // push class, subclass, protocol and number of endpoints into interfaceValues vector
+ interfaceValues.add(interface->bInterfaceNumber);
+ interfaceValues.add(interface->bInterfaceClass);
+ interfaceValues.add(interface->bInterfaceSubClass);
+ interfaceValues.add(interface->bInterfaceProtocol);
+ interfaceValues.add(interface->bNumEndpoints);
+ } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
+ struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;
+
+ // push address, attributes, max packet size and interval into endpointValues vector
+ endpointValues.add(endpoint->bEndpointAddress);
+ endpointValues.add(endpoint->bmAttributes);
+ endpointValues.add(__le16_to_cpu(endpoint->wMaxPacketSize));
+ endpointValues.add(endpoint->bInterval);
+ }
+ }
+
+ usb_device_close(device);
+
+ // handle generic device notification
+ int length = interfaceValues.size();
+ jintArray interfaceArray = env->NewIntArray(length);
+ env->SetIntArrayRegion(interfaceArray, 0, length, interfaceValues.array());
+
+ length = endpointValues.size();
+ jintArray endpointArray = env->NewIntArray(length);
+ env->SetIntArrayRegion(endpointArray, 0, length, endpointValues.array());
+
+ jstring deviceName = env->NewStringUTF(devname);
+ jstring manufacturerName = env->NewStringUTF(manufacturer);
+ jstring productName = env->NewStringUTF(product);
+ jstring serialNumber = env->NewStringUTF(serial);
+ env->CallVoidMethod(thiz, method_usbDeviceAdded,
+ deviceName, vendorId, productId, deviceClass,
+ deviceSubClass, protocol, manufacturerName,
+ productName, serialNumber, interfaceArray, endpointArray);
+
+ env->DeleteLocalRef(interfaceArray);
+ env->DeleteLocalRef(endpointArray);
+ env->DeleteLocalRef(serialNumber);
+ env->DeleteLocalRef(productName);
+ env->DeleteLocalRef(manufacturerName);
+ env->DeleteLocalRef(deviceName);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+ return 0;
+}
+
+static int usb_device_removed(const char *devname, void* client_data) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject thiz = (jobject)client_data;
+
+ jstring deviceName = env->NewStringUTF(devname);
+ env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName);
+ env->DeleteLocalRef(deviceName);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return 0;
+}
+
+static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv *env, jobject thiz)
+{
+ struct usb_host_context* context = usb_host_init();
+ if (!context) {
+ ALOGE("usb_host_init failed");
+ return;
+ }
+ // this will never return so it is safe to pass thiz directly
+ usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);
+}
+
+static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject thiz, jstring deviceName)
+{
+ const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
+ struct usb_device* device = usb_device_open(deviceNameStr);
+ env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+
+ if (!device)
+ return NULL;
+
+ int fd = usb_device_get_fd(device);
+ if (fd < 0)
+ return NULL;
+ int newFD = dup(fd);
+ usb_device_close(device);
+
+ jobject fileDescriptor = jniCreateFileDescriptor(env, newFD);
+ if (fileDescriptor == NULL) {
+ return NULL;
+ }
+ return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
+}
+
+static JNINativeMethod method_table[] = {
+ { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus },
+ { "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
+ (void*)android_server_UsbHostManager_openDevice },
+};
+
+int register_android_server_UsbHostManager(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/usb/UsbHostManager");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/usb/UsbHostManager");
+ return -1;
+ }
+ method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I)V");
+ if (method_usbDeviceAdded == NULL) {
+ ALOGE("Can't find usbDeviceAdded");
+ return -1;
+ }
+ method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved", "(Ljava/lang/String;)V");
+ if (method_usbDeviceRemoved == NULL) {
+ ALOGE("Can't find usbDeviceRemoved");
+ return -1;
+ }
+
+ 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");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
+ "Unable to find constructor for android.os.ParcelFileDescriptor");
+
+ return jniRegisterNativeMethods(env, "com/android/server/usb/UsbHostManager",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
new file mode 100644
index 0000000..2b3f74a
--- /dev/null
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 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 "VibratorService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <hardware_legacy/vibrator.h>
+
+#include <stdio.h>
+
+namespace android
+{
+
+static jboolean vibratorExists(JNIEnv *env, jobject clazz)
+{
+ return vibrator_exists() > 0 ? JNI_TRUE : JNI_FALSE;
+}
+
+static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
+{
+ // ALOGI("vibratorOn\n");
+ vibrator_on(timeout_ms);
+}
+
+static void vibratorOff(JNIEnv *env, jobject clazz)
+{
+ // ALOGI("vibratorOff\n");
+ vibrator_off();
+}
+
+static JNINativeMethod method_table[] = {
+ { "vibratorExists", "()Z", (void*)vibratorExists },
+ { "vibratorOn", "(J)V", (void*)vibratorOn },
+ { "vibratorOff", "()V", (void*)vibratorOff }
+};
+
+int register_android_server_VibratorService(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
new file mode 100644
index 0000000..ab8c959
--- /dev/null
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "VpnJni"
+#include <cutils/log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/route.h>
+#include <linux/ipv6_route.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+namespace android
+{
+
+static int inet4 = -1;
+static int inet6 = -1;
+
+static inline in_addr_t *as_in_addr(sockaddr *sa) {
+ return &((sockaddr_in *)sa)->sin_addr.s_addr;
+}
+
+//------------------------------------------------------------------------------
+
+#define SYSTEM_ERROR -1
+#define BAD_ARGUMENT -2
+
+static int create_interface(int mtu)
+{
+ int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
+
+ ifreq ifr4;
+ memset(&ifr4, 0, sizeof(ifr4));
+
+ // Allocate interface.
+ ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
+ if (ioctl(tun, TUNSETIFF, &ifr4)) {
+ ALOGE("Cannot allocate TUN: %s", strerror(errno));
+ goto error;
+ }
+
+ // Activate interface.
+ ifr4.ifr_flags = IFF_UP;
+ if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) {
+ ALOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno));
+ goto error;
+ }
+
+ // Set MTU if it is specified.
+ ifr4.ifr_mtu = mtu;
+ if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
+ ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
+ goto error;
+ }
+
+ return tun;
+
+error:
+ close(tun);
+ return SYSTEM_ERROR;
+}
+
+static int get_interface_name(char *name, int tun)
+{
+ ifreq ifr4;
+ if (ioctl(tun, TUNGETIFF, &ifr4)) {
+ ALOGE("Cannot get interface name: %s", strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ strncpy(name, ifr4.ifr_name, IFNAMSIZ);
+ return 0;
+}
+
+static int get_interface_index(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
+ ALOGE("Cannot get index of %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return ifr4.ifr_ifindex;
+}
+
+static int set_addresses(const char *name, const char *addresses)
+{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
+
+ ifreq ifr4;
+ memset(&ifr4, 0, sizeof(ifr4));
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_addr.sa_family = AF_INET;
+ ifr4.ifr_netmask.sa_family = AF_INET;
+
+ in6_ifreq ifr6;
+ memset(&ifr6, 0, sizeof(ifr6));
+ ifr6.ifr6_ifindex = index;
+
+ char address[65];
+ int prefix;
+ int chars;
+ int count = 0;
+
+ while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
+ addresses += chars;
+
+ if (strchr(address, ':')) {
+ // Add an IPv6 address.
+ if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 ||
+ prefix < 0 || prefix > 128) {
+ count = BAD_ARGUMENT;
+ break;
+ }
+
+ ifr6.ifr6_prefixlen = prefix;
+ if (ioctl(inet6, SIOCSIFADDR, &ifr6)) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+ } else {
+ // Add an IPv4 address.
+ if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 ||
+ prefix < 0 || prefix > 32) {
+ count = BAD_ARGUMENT;
+ break;
+ }
+
+ if (count) {
+ sprintf(ifr4.ifr_name, "%s:%d", name, count);
+ }
+ if (ioctl(inet4, SIOCSIFADDR, &ifr4)) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+
+ in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
+ *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
+ if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+ }
+ ALOGD("Address added on %s: %s/%d", name, address, prefix);
+ ++count;
+ }
+
+ if (count == BAD_ARGUMENT) {
+ ALOGE("Invalid address: %s/%d", address, prefix);
+ } else if (count == SYSTEM_ERROR) {
+ ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno));
+ } else if (*addresses) {
+ ALOGE("Invalid address: %s", addresses);
+ count = BAD_ARGUMENT;
+ }
+
+ return count;
+}
+
+static int set_routes(const char *name, const char *routes)
+{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
+
+ rtentry rt4;
+ memset(&rt4, 0, sizeof(rt4));
+ rt4.rt_dev = (char *)name;
+ rt4.rt_flags = RTF_UP;
+ rt4.rt_dst.sa_family = AF_INET;
+ rt4.rt_genmask.sa_family = AF_INET;
+
+ in6_rtmsg rt6;
+ memset(&rt6, 0, sizeof(rt6));
+ rt6.rtmsg_ifindex = index;
+ rt6.rtmsg_flags = RTF_UP;
+
+ char address[65];
+ int prefix;
+ int chars;
+ int count = 0;
+
+ while (sscanf(routes, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
+ routes += chars;
+
+ if (strchr(address, ':')) {
+ // Add an IPv6 route.
+ if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 ||
+ prefix < 0 || prefix > 128) {
+ count = BAD_ARGUMENT;
+ break;
+ }
+
+ rt6.rtmsg_dst_len = prefix ? prefix : 1;
+ if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+
+ if (!prefix) {
+ // Split the route instead of replacing the default route.
+ rt6.rtmsg_dst.s6_addr[0] ^= 0x80;
+ if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
+ count = SYSTEM_ERROR;
+ break;
+ }
+ }
+ } else {
+ // Add an IPv4 route.
+ if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 ||
+ prefix < 0 || prefix > 32) {
+ count = BAD_ARGUMENT;
+ break;
+ }
+
+ in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000;
+ *as_in_addr(&rt4.rt_genmask) = htonl(mask);
+ if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+
+ if (!prefix) {
+ // Split the route instead of replacing the default route.
+ *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000);
+ if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
+ count = SYSTEM_ERROR;
+ break;
+ }
+ }
+ }
+ ALOGD("Route added on %s: %s/%d", name, address, prefix);
+ ++count;
+ }
+
+ if (count == BAD_ARGUMENT) {
+ ALOGE("Invalid route: %s/%d", address, prefix);
+ } else if (count == SYSTEM_ERROR) {
+ ALOGE("Cannot add route: %s/%d: %s",
+ address, prefix, strerror(errno));
+ } else if (*routes) {
+ ALOGE("Invalid route: %s", routes);
+ count = BAD_ARGUMENT;
+ }
+
+ return count;
+}
+
+static int reset_interface(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_flags = 0;
+
+ if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
+ ALOGE("Cannot reset %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+static int check_interface(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_flags = 0;
+
+ if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
+ ALOGE("Cannot check %s: %s", name, strerror(errno));
+ }
+ return ifr4.ifr_flags;
+}
+
+static int bind_to_interface(int socket, const char *name)
+{
+ if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
+ ALOGE("Cannot bind socket to %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+
+static void throwException(JNIEnv *env, int error, const char *message)
+{
+ if (error == SYSTEM_ERROR) {
+ jniThrowException(env, "java/lang/IllegalStateException", message);
+ } else {
+ jniThrowException(env, "java/lang/IllegalArgumentException", message);
+ }
+}
+
+static jint create(JNIEnv *env, jobject thiz, jint mtu)
+{
+ int tun = create_interface(mtu);
+ if (tun < 0) {
+ throwException(env, tun, "Cannot create interface");
+ return -1;
+ }
+ return tun;
+}
+
+static jstring getName(JNIEnv *env, jobject thiz, jint tun)
+{
+ char name[IFNAMSIZ];
+ if (get_interface_name(name, tun) < 0) {
+ throwException(env, SYSTEM_ERROR, "Cannot get interface name");
+ return NULL;
+ }
+ return env->NewStringUTF(name);
+}
+
+static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jAddresses)
+{
+ const char *name = NULL;
+ const char *addresses = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
+ if (!addresses) {
+ jniThrowNullPointerException(env, "addresses");
+ goto error;
+ }
+ count = set_addresses(name, addresses);
+ if (count < 0) {
+ throwException(env, count, "Cannot set address");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (addresses) {
+ env->ReleaseStringUTFChars(jAddresses, addresses);
+ }
+ return count;
+}
+
+static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jRoutes)
+{
+ const char *name = NULL;
+ const char *routes = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
+ if (!routes) {
+ jniThrowNullPointerException(env, "routes");
+ goto error;
+ }
+ count = set_routes(name, routes);
+ if (count < 0) {
+ throwException(env, count, "Cannot set route");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (routes) {
+ env->ReleaseStringUTFChars(jRoutes, routes);
+ }
+ return count;
+}
+
+static void reset(JNIEnv *env, jobject thiz, jstring jName)
+{
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ return;
+ }
+ if (reset_interface(name) < 0) {
+ throwException(env, SYSTEM_ERROR, "Cannot reset interface");
+ }
+ env->ReleaseStringUTFChars(jName, name);
+}
+
+static jint check(JNIEnv *env, jobject thiz, jstring jName)
+{
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ return 0;
+ }
+ int flags = check_interface(name);
+ env->ReleaseStringUTFChars(jName, name);
+ return flags;
+}
+
+static void protect(JNIEnv *env, jobject thiz, jint socket, jstring jName)
+{
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ return;
+ }
+ if (bind_to_interface(socket, name) < 0) {
+ throwException(env, SYSTEM_ERROR, "Cannot protect socket");
+ }
+ env->ReleaseStringUTFChars(jName, name);
+}
+
+//------------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"jniCreate", "(I)I", (void *)create},
+ {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
+ {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
+ {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
+ {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
+ {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
+ {"jniProtect", "(ILjava/lang/String;)V", (void *)protect},
+};
+
+int register_android_server_connectivity_Vpn(JNIEnv *env)
+{
+ if (inet4 == -1) {
+ inet4 = socket(AF_INET, SOCK_DGRAM, 0);
+ }
+ if (inet6 == -1) {
+ inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ }
+ return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
+ gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
new file mode 100644
index 0000000..f943d16
--- /dev/null
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 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 "InputApplicationHandle"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/threads.h>
+
+#include "com_android_server_input_InputApplicationHandle.h"
+
+namespace android {
+
+static struct {
+ jfieldID ptr;
+ jfieldID name;
+ jfieldID dispatchingTimeoutNanos;
+} gInputApplicationHandleClassInfo;
+
+static Mutex gHandleMutex;
+
+
+// --- NativeInputApplicationHandle ---
+
+NativeInputApplicationHandle::NativeInputApplicationHandle(jweak objWeak) :
+ mObjWeak(objWeak) {
+}
+
+NativeInputApplicationHandle::~NativeInputApplicationHandle() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteWeakGlobalRef(mObjWeak);
+}
+
+jobject NativeInputApplicationHandle::getInputApplicationHandleObjLocalRef(JNIEnv* env) {
+ return env->NewLocalRef(mObjWeak);
+}
+
+bool NativeInputApplicationHandle::updateInfo() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject obj = env->NewLocalRef(mObjWeak);
+ if (!obj) {
+ releaseInfo();
+ return false;
+ }
+
+ if (!mInfo) {
+ mInfo = new InputApplicationInfo();
+ }
+
+ jstring nameObj = jstring(env->GetObjectField(obj,
+ gInputApplicationHandleClassInfo.name));
+ if (nameObj) {
+ const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+ mInfo->name.setTo(nameStr);
+ env->ReleaseStringUTFChars(nameObj, nameStr);
+ env->DeleteLocalRef(nameObj);
+ } else {
+ mInfo->name.setTo("<null>");
+ }
+
+ mInfo->dispatchingTimeout = env->GetLongField(obj,
+ gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+
+ env->DeleteLocalRef(obj);
+ return true;
+}
+
+
+// --- Global functions ---
+
+sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle(
+ JNIEnv* env, jobject inputApplicationHandleObj) {
+ if (!inputApplicationHandleObj) {
+ return NULL;
+ }
+
+ AutoMutex _l(gHandleMutex);
+
+ jlong ptr = env->GetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr);
+ NativeInputApplicationHandle* handle;
+ if (ptr) {
+ handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
+ } else {
+ jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj);
+ handle = new NativeInputApplicationHandle(objWeak);
+ handle->incStrong((void*)android_server_InputApplicationHandle_getHandle);
+ env->SetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr,
+ reinterpret_cast<jlong>(handle));
+ }
+ return handle;
+}
+
+
+// --- JNI ---
+
+static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) {
+ AutoMutex _l(gHandleMutex);
+
+ jlong ptr = env->GetLongField(obj, gInputApplicationHandleClassInfo.ptr);
+ if (ptr) {
+ env->SetLongField(obj, gInputApplicationHandleClassInfo.ptr, 0);
+
+ NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
+ handle->decStrong((void*)android_server_InputApplicationHandle_getHandle);
+ }
+}
+
+
+static JNINativeMethod gInputApplicationHandleMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeDispose", "()V",
+ (void*) android_server_InputApplicationHandle_nativeDispose },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_InputApplicationHandle(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/input/InputApplicationHandle",
+ gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/input/InputApplicationHandle");
+
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz,
+ "ptr", "J");
+
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz,
+ "name", "Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos,
+ clazz,
+ "dispatchingTimeoutNanos", "J");
+
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.h b/services/core/jni/com_android_server_input_InputApplicationHandle.h
new file mode 100644
index 0000000..89d48c6
--- /dev/null
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 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_SERVER_INPUT_APPLICATION_HANDLE_H
+#define _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
+
+#include <input/InputApplication.h>
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+class NativeInputApplicationHandle : public InputApplicationHandle {
+public:
+ NativeInputApplicationHandle(jweak objWeak);
+ virtual ~NativeInputApplicationHandle();
+
+ jobject getInputApplicationHandleObjLocalRef(JNIEnv* env);
+
+ virtual bool updateInfo();
+
+private:
+ jweak mObjWeak;
+};
+
+
+extern sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle(
+ JNIEnv* env, jobject inputApplicationHandleObj);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
new file mode 100644
index 0000000..0542ce0
--- /dev/null
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -0,0 +1,1472 @@
+/*
+ * Copyright (C) 2010 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 "InputManager-JNI"
+
+//#define LOG_NDEBUG 0
+
+// Log debug messages about InputReaderPolicy
+#define DEBUG_INPUT_READER_POLICY 0
+
+// Log debug messages about InputDispatcherPolicy
+#define DEBUG_INPUT_DISPATCHER_POLICY 0
+
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <limits.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <utils/threads.h>
+
+#include <input/InputManager.h>
+#include <input/PointerController.h>
+#include <input/SpriteController.h>
+
+#include <android_os_MessageQueue.h>
+#include <android_view_InputDevice.h>
+#include <android_view_KeyEvent.h>
+#include <android_view_MotionEvent.h>
+#include <android_view_InputChannel.h>
+#include <android_view_PointerIcon.h>
+#include <android/graphics/GraphicsJNI.h>
+
+#include <ScopedLocalRef.h>
+#include <ScopedUtfChars.h>
+
+#include "com_android_server_power_PowerManagerService.h"
+#include "com_android_server_input_InputApplicationHandle.h"
+#include "com_android_server_input_InputWindowHandle.h"
+
+namespace android {
+
+// The exponent used to calculate the pointer speed scaling factor.
+// The scaling factor is calculated as 2 ^ (speed * exponent),
+// where the speed ranges from -7 to + 7 and is supplied by the user.
+static const float POINTER_SPEED_EXPONENT = 1.0f / 4;
+
+static struct {
+ jmethodID notifyConfigurationChanged;
+ jmethodID notifyInputDevicesChanged;
+ jmethodID notifySwitch;
+ jmethodID notifyInputChannelBroken;
+ jmethodID notifyANR;
+ jmethodID filterInputEvent;
+ jmethodID interceptKeyBeforeQueueing;
+ jmethodID interceptMotionBeforeQueueingWhenScreenOff;
+ jmethodID interceptKeyBeforeDispatching;
+ jmethodID dispatchUnhandledKey;
+ jmethodID checkInjectEventsPermission;
+ jmethodID getVirtualKeyQuietTimeMillis;
+ jmethodID getExcludedDeviceNames;
+ jmethodID getKeyRepeatTimeout;
+ jmethodID getKeyRepeatDelay;
+ jmethodID getHoverTapTimeout;
+ jmethodID getHoverTapSlop;
+ jmethodID getDoubleTapTimeout;
+ jmethodID getLongPressTimeout;
+ jmethodID getPointerLayer;
+ jmethodID getPointerIcon;
+ jmethodID getKeyboardLayoutOverlay;
+ jmethodID getDeviceAlias;
+} gServiceClassInfo;
+
+static struct {
+ jclass clazz;
+} gInputDeviceClassInfo;
+
+static struct {
+ jclass clazz;
+} gKeyEventClassInfo;
+
+static struct {
+ jclass clazz;
+} gMotionEventClassInfo;
+
+
+// --- Global functions ---
+
+template<typename T>
+inline static T min(const T& a, const T& b) {
+ return a < b ? a : b;
+}
+
+template<typename T>
+inline static T max(const T& a, const T& b) {
+ return a > b ? a : b;
+}
+
+static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
+ const sp<InputApplicationHandle>& inputApplicationHandle) {
+ if (inputApplicationHandle == NULL) {
+ return NULL;
+ }
+ return static_cast<NativeInputApplicationHandle*>(inputApplicationHandle.get())->
+ getInputApplicationHandleObjLocalRef(env);
+}
+
+static jobject getInputWindowHandleObjLocalRef(JNIEnv* env,
+ const sp<InputWindowHandle>& inputWindowHandle) {
+ if (inputWindowHandle == NULL) {
+ return NULL;
+ }
+ return static_cast<NativeInputWindowHandle*>(inputWindowHandle.get())->
+ getInputWindowHandleObjLocalRef(env);
+}
+
+static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t style,
+ SpriteIcon* outSpriteIcon) {
+ PointerIcon pointerIcon;
+ status_t status = android_view_PointerIcon_loadSystemIcon(env,
+ contextObj, style, &pointerIcon);
+ if (!status) {
+ pointerIcon.bitmap.copyTo(&outSpriteIcon->bitmap, SkBitmap::kARGB_8888_Config);
+ outSpriteIcon->hotSpotX = pointerIcon.hotSpotX;
+ outSpriteIcon->hotSpotY = pointerIcon.hotSpotY;
+ }
+}
+
+enum {
+ WM_ACTION_PASS_TO_USER = 1,
+ WM_ACTION_WAKE_UP = 2,
+ WM_ACTION_GO_TO_SLEEP = 4,
+};
+
+
+// --- NativeInputManager ---
+
+class NativeInputManager : public virtual RefBase,
+ public virtual InputReaderPolicyInterface,
+ public virtual InputDispatcherPolicyInterface,
+ public virtual PointerControllerPolicyInterface {
+protected:
+ virtual ~NativeInputManager();
+
+public:
+ NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper);
+
+ inline sp<InputManager> getInputManager() const { return mInputManager; }
+
+ void dump(String8& dump);
+
+ void setDisplayViewport(bool external, const DisplayViewport& viewport);
+
+ status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
+ const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
+ status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
+
+ void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray);
+ void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj);
+ void setInputDispatchMode(bool enabled, bool frozen);
+ void setSystemUiVisibility(int32_t visibility);
+ void setPointerSpeed(int32_t speed);
+ void setShowTouches(bool enabled);
+
+ /* --- InputReaderPolicyInterface implementation --- */
+
+ virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
+ virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
+ virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices);
+ virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor);
+ virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier);
+
+ /* --- InputDispatcherPolicyInterface implementation --- */
+
+ virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
+ uint32_t policyFlags);
+ virtual void notifyConfigurationChanged(nsecs_t when);
+ virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<InputWindowHandle>& inputWindowHandle,
+ const String8& reason);
+ virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
+ virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
+ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
+ virtual bool isKeyRepeatEnabled();
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
+ virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
+ virtual nsecs_t interceptKeyBeforeDispatching(
+ const sp<InputWindowHandle>& inputWindowHandle,
+ const KeyEvent* keyEvent, uint32_t policyFlags);
+ virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
+ const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent);
+ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
+ virtual bool checkInjectEventsPermissionNonReentrant(
+ int32_t injectorPid, int32_t injectorUid);
+
+ /* --- PointerControllerPolicyInterface implementation --- */
+
+ virtual void loadPointerResources(PointerResources* outResources);
+
+private:
+ sp<InputManager> mInputManager;
+
+ jobject mContextObj;
+ jobject mServiceObj;
+ sp<Looper> mLooper;
+
+ Mutex mLock;
+ struct Locked {
+ // Display size information.
+ DisplayViewport internalViewport;
+ DisplayViewport externalViewport;
+
+ // System UI visibility.
+ int32_t systemUiVisibility;
+
+ // Pointer speed.
+ int32_t pointerSpeed;
+
+ // True if pointer gestures are enabled.
+ bool pointerGesturesEnabled;
+
+ // Show touches feature enable/disable.
+ bool showTouches;
+
+ // Sprite controller singleton, created on first use.
+ sp<SpriteController> spriteController;
+
+ // Pointer controller singleton, created and destroyed as needed.
+ wp<PointerController> pointerController;
+ } mLocked;
+
+ void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
+ void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
+ void ensureSpriteControllerLocked();
+
+ // Power manager interactions.
+ bool isScreenOn();
+ bool isScreenBright();
+
+ static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
+
+ static inline JNIEnv* jniEnv() {
+ return AndroidRuntime::getJNIEnv();
+ }
+};
+
+
+
+NativeInputManager::NativeInputManager(jobject contextObj,
+ jobject serviceObj, const sp<Looper>& looper) :
+ mLooper(looper) {
+ JNIEnv* env = jniEnv();
+
+ mContextObj = env->NewGlobalRef(contextObj);
+ mServiceObj = env->NewGlobalRef(serviceObj);
+
+ {
+ AutoMutex _l(mLock);
+ mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
+ mLocked.pointerSpeed = 0;
+ mLocked.pointerGesturesEnabled = true;
+ mLocked.showTouches = false;
+ }
+
+ sp<EventHub> eventHub = new EventHub();
+ mInputManager = new InputManager(eventHub, this, this);
+}
+
+NativeInputManager::~NativeInputManager() {
+ JNIEnv* env = jniEnv();
+
+ env->DeleteGlobalRef(mContextObj);
+ env->DeleteGlobalRef(mServiceObj);
+}
+
+void NativeInputManager::dump(String8& dump) {
+ mInputManager->getReader()->dump(dump);
+ dump.append("\n");
+
+ mInputManager->getDispatcher()->dump(dump);
+ dump.append("\n");
+}
+
+bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ return true;
+ }
+ return false;
+}
+
+void NativeInputManager::setDisplayViewport(bool external, const DisplayViewport& viewport) {
+ bool changed = false;
+ {
+ AutoMutex _l(mLock);
+
+ DisplayViewport& v = external ? mLocked.externalViewport : mLocked.internalViewport;
+ if (v != viewport) {
+ changed = true;
+ v = viewport;
+
+ if (!external) {
+ sp<PointerController> controller = mLocked.pointerController.promote();
+ if (controller != NULL) {
+ controller->setDisplayViewport(
+ viewport.logicalRight - viewport.logicalLeft,
+ viewport.logicalBottom - viewport.logicalTop,
+ viewport.orientation);
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ }
+}
+
+status_t NativeInputManager::registerInputChannel(JNIEnv* env,
+ const sp<InputChannel>& inputChannel,
+ const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
+ return mInputManager->getDispatcher()->registerInputChannel(
+ inputChannel, inputWindowHandle, monitor);
+}
+
+status_t NativeInputManager::unregisterInputChannel(JNIEnv* env,
+ const sp<InputChannel>& inputChannel) {
+ return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
+}
+
+void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {
+ JNIEnv* env = jniEnv();
+
+ jint virtualKeyQuietTime = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.getVirtualKeyQuietTimeMillis);
+ if (!checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) {
+ outConfig->virtualKeyQuietTime = milliseconds_to_nanoseconds(virtualKeyQuietTime);
+ }
+
+ outConfig->excludedDeviceNames.clear();
+ jobjectArray excludedDeviceNames = jobjectArray(env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.getExcludedDeviceNames));
+ if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) {
+ jsize length = env->GetArrayLength(excludedDeviceNames);
+ for (jsize i = 0; i < length; i++) {
+ jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i));
+ const char* deviceNameChars = env->GetStringUTFChars(item, NULL);
+ outConfig->excludedDeviceNames.add(String8(deviceNameChars));
+ env->ReleaseStringUTFChars(item, deviceNameChars);
+ env->DeleteLocalRef(item);
+ }
+ env->DeleteLocalRef(excludedDeviceNames);
+ }
+
+ jint hoverTapTimeout = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.getHoverTapTimeout);
+ if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) {
+ jint doubleTapTimeout = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.getDoubleTapTimeout);
+ if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) {
+ jint longPressTimeout = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.getLongPressTimeout);
+ if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) {
+ outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(hoverTapTimeout);
+
+ // We must ensure that the tap-drag interval is significantly shorter than
+ // the long-press timeout because the tap is held down for the entire duration
+ // of the double-tap timeout.
+ jint tapDragInterval = max(min(longPressTimeout - 100,
+ doubleTapTimeout), hoverTapTimeout);
+ outConfig->pointerGestureTapDragInterval =
+ milliseconds_to_nanoseconds(tapDragInterval);
+ }
+ }
+ }
+
+ jint hoverTapSlop = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.getHoverTapSlop);
+ if (!checkAndClearExceptionFromCallback(env, "getHoverTapSlop")) {
+ outConfig->pointerGestureTapSlop = hoverTapSlop;
+ }
+
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed
+ * POINTER_SPEED_EXPONENT);
+ outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;
+
+ outConfig->showTouches = mLocked.showTouches;
+
+ outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
+ outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
+ } // release lock
+}
+
+sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t deviceId) {
+ AutoMutex _l(mLock);
+
+ sp<PointerController> controller = mLocked.pointerController.promote();
+ if (controller == NULL) {
+ ensureSpriteControllerLocked();
+
+ controller = new PointerController(this, mLooper, mLocked.spriteController);
+ mLocked.pointerController = controller;
+
+ DisplayViewport& v = mLocked.internalViewport;
+ controller->setDisplayViewport(
+ v.logicalRight - v.logicalLeft,
+ v.logicalBottom - v.logicalTop,
+ v.orientation);
+
+ JNIEnv* env = jniEnv();
+ jobject pointerIconObj = env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.getPointerIcon);
+ if (!checkAndClearExceptionFromCallback(env, "getPointerIcon")) {
+ PointerIcon pointerIcon;
+ status_t status = android_view_PointerIcon_load(env, pointerIconObj,
+ mContextObj, &pointerIcon);
+ if (!status && !pointerIcon.isNullIcon()) {
+ controller->setPointerIcon(SpriteIcon(pointerIcon.bitmap,
+ pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+ } else {
+ controller->setPointerIcon(SpriteIcon());
+ }
+ env->DeleteLocalRef(pointerIconObj);
+ }
+
+ updateInactivityTimeoutLocked(controller);
+ }
+ return controller;
+}
+
+void NativeInputManager::ensureSpriteControllerLocked() {
+ if (mLocked.spriteController == NULL) {
+ JNIEnv* env = jniEnv();
+ jint layer = env->CallIntMethod(mServiceObj, gServiceClassInfo.getPointerLayer);
+ if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) {
+ layer = -1;
+ }
+ mLocked.spriteController = new SpriteController(mLooper, layer);
+ }
+}
+
+void NativeInputManager::notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
+ JNIEnv* env = jniEnv();
+
+ size_t count = inputDevices.size();
+ jobjectArray inputDevicesObjArray = env->NewObjectArray(
+ count, gInputDeviceClassInfo.clazz, NULL);
+ if (inputDevicesObjArray) {
+ bool error = false;
+ for (size_t i = 0; i < count; i++) {
+ jobject inputDeviceObj = android_view_InputDevice_create(env, inputDevices.itemAt(i));
+ if (!inputDeviceObj) {
+ error = true;
+ break;
+ }
+
+ env->SetObjectArrayElement(inputDevicesObjArray, i, inputDeviceObj);
+ env->DeleteLocalRef(inputDeviceObj);
+ }
+
+ if (!error) {
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyInputDevicesChanged,
+ inputDevicesObjArray);
+ }
+
+ env->DeleteLocalRef(inputDevicesObjArray);
+ }
+
+ checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
+}
+
+sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
+ const String8& inputDeviceDescriptor) {
+ JNIEnv* env = jniEnv();
+
+ sp<KeyCharacterMap> result;
+ ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string()));
+ ScopedLocalRef<jobjectArray> arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.getKeyboardLayoutOverlay, descriptorObj.get())));
+ if (arrayObj.get()) {
+ ScopedLocalRef<jstring> filenameObj(env,
+ jstring(env->GetObjectArrayElement(arrayObj.get(), 0)));
+ ScopedLocalRef<jstring> contentsObj(env,
+ jstring(env->GetObjectArrayElement(arrayObj.get(), 1)));
+ ScopedUtfChars filenameChars(env, filenameObj.get());
+ ScopedUtfChars contentsChars(env, contentsObj.get());
+
+ KeyCharacterMap::loadContents(String8(filenameChars.c_str()),
+ String8(contentsChars.c_str()), KeyCharacterMap::FORMAT_OVERLAY, &result);
+ }
+ checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay");
+ return result;
+}
+
+String8 NativeInputManager::getDeviceAlias(const InputDeviceIdentifier& identifier) {
+ JNIEnv* env = jniEnv();
+
+ ScopedLocalRef<jstring> uniqueIdObj(env, env->NewStringUTF(identifier.uniqueId.string()));
+ ScopedLocalRef<jstring> aliasObj(env, jstring(env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.getDeviceAlias, uniqueIdObj.get())));
+ String8 result;
+ if (aliasObj.get()) {
+ ScopedUtfChars aliasChars(env, aliasObj.get());
+ result.setTo(aliasChars.c_str());
+ }
+ checkAndClearExceptionFromCallback(env, "getDeviceAlias");
+ return result;
+}
+
+void NativeInputManager::notifySwitch(nsecs_t when,
+ uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("notifySwitch - when=%lld, switchValues=0x%08x, switchMask=0x%08x, policyFlags=0x%x",
+ when, switchValues, switchMask, policyFlags);
+#endif
+
+ JNIEnv* env = jniEnv();
+
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySwitch,
+ when, switchValues, switchMask);
+ checkAndClearExceptionFromCallback(env, "notifySwitch");
+}
+
+void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("notifyConfigurationChanged - when=%lld", when);
+#endif
+
+ JNIEnv* env = jniEnv();
+
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyConfigurationChanged, when);
+ checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
+}
+
+nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<InputWindowHandle>& inputWindowHandle, const String8& reason) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("notifyANR");
+#endif
+
+ JNIEnv* env = jniEnv();
+
+ jobject inputApplicationHandleObj =
+ getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
+ jobject inputWindowHandleObj =
+ getInputWindowHandleObjLocalRef(env, inputWindowHandle);
+ jstring reasonObj = env->NewStringUTF(reason.string());
+
+ jlong newTimeout = env->CallLongMethod(mServiceObj,
+ gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj,
+ reasonObj);
+ if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
+ newTimeout = 0; // abort dispatch
+ } else {
+ assert(newTimeout >= 0);
+ }
+
+ env->DeleteLocalRef(reasonObj);
+ env->DeleteLocalRef(inputWindowHandleObj);
+ env->DeleteLocalRef(inputApplicationHandleObj);
+ return newTimeout;
+}
+
+void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("notifyInputChannelBroken");
+#endif
+
+ JNIEnv* env = jniEnv();
+
+ jobject inputWindowHandleObj =
+ getInputWindowHandleObjLocalRef(env, inputWindowHandle);
+ if (inputWindowHandleObj) {
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyInputChannelBroken,
+ inputWindowHandleObj);
+ checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken");
+
+ env->DeleteLocalRef(inputWindowHandleObj);
+ }
+}
+
+void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
+ JNIEnv* env = jniEnv();
+
+ jint keyRepeatTimeout = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.getKeyRepeatTimeout);
+ if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
+ outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
+ }
+
+ jint keyRepeatDelay = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.getKeyRepeatDelay);
+ if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
+ outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
+ }
+}
+
+bool NativeInputManager::isKeyRepeatEnabled() {
+ // Only enable automatic key repeating when the screen is on.
+ return isScreenOn();
+}
+
+void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
+ Vector<sp<InputWindowHandle> > windowHandles;
+
+ if (windowHandleObjArray) {
+ jsize length = env->GetArrayLength(windowHandleObjArray);
+ for (jsize i = 0; i < length; i++) {
+ jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
+ if (! windowHandleObj) {
+ break; // found null element indicating end of used portion of the array
+ }
+
+ sp<InputWindowHandle> windowHandle =
+ android_server_InputWindowHandle_getHandle(env, windowHandleObj);
+ if (windowHandle != NULL) {
+ windowHandles.push(windowHandle);
+ }
+ env->DeleteLocalRef(windowHandleObj);
+ }
+ }
+
+ mInputManager->getDispatcher()->setInputWindows(windowHandles);
+
+ // Do this after the dispatcher has updated the window handle state.
+ bool newPointerGesturesEnabled = true;
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ const InputWindowInfo* windowInfo = windowHandle->getInfo();
+ if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
+ & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
+ newPointerGesturesEnabled = false;
+ }
+ }
+
+ uint32_t changes = 0;
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mLocked.pointerGesturesEnabled != newPointerGesturesEnabled) {
+ mLocked.pointerGesturesEnabled = newPointerGesturesEnabled;
+ changes |= InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT;
+ }
+ } // release lock
+
+ if (changes) {
+ mInputManager->getReader()->requestRefreshConfiguration(changes);
+ }
+}
+
+void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationHandleObj) {
+ sp<InputApplicationHandle> applicationHandle =
+ android_server_InputApplicationHandle_getHandle(env, applicationHandleObj);
+ mInputManager->getDispatcher()->setFocusedApplication(applicationHandle);
+}
+
+void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
+ mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
+}
+
+void NativeInputManager::setSystemUiVisibility(int32_t visibility) {
+ AutoMutex _l(mLock);
+
+ if (mLocked.systemUiVisibility != visibility) {
+ mLocked.systemUiVisibility = visibility;
+
+ sp<PointerController> controller = mLocked.pointerController.promote();
+ if (controller != NULL) {
+ updateInactivityTimeoutLocked(controller);
+ }
+ }
+}
+
+void NativeInputManager::updateInactivityTimeoutLocked(const sp<PointerController>& controller) {
+ bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
+ controller->setInactivityTimeout(lightsOut
+ ? PointerController::INACTIVITY_TIMEOUT_SHORT
+ : PointerController::INACTIVITY_TIMEOUT_NORMAL);
+}
+
+void NativeInputManager::setPointerSpeed(int32_t speed) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mLocked.pointerSpeed == speed) {
+ return;
+ }
+
+ ALOGI("Setting pointer speed to %d.", speed);
+ mLocked.pointerSpeed = speed;
+ } // release lock
+
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_POINTER_SPEED);
+}
+
+void NativeInputManager::setShowTouches(bool enabled) {
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mLocked.showTouches == enabled) {
+ return;
+ }
+
+ ALOGI("Setting show touches feature to %s.", enabled ? "enabled" : "disabled");
+ mLocked.showTouches = enabled;
+ } // release lock
+
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+}
+
+bool NativeInputManager::isScreenOn() {
+ return android_server_PowerManagerService_isScreenOn();
+}
+
+bool NativeInputManager::isScreenBright() {
+ return android_server_PowerManagerService_isScreenBright();
+}
+
+bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
+ jobject inputEventObj;
+
+ JNIEnv* env = jniEnv();
+ switch (inputEvent->getType()) {
+ case AINPUT_EVENT_TYPE_KEY:
+ inputEventObj = android_view_KeyEvent_fromNative(env,
+ static_cast<const KeyEvent*>(inputEvent));
+ break;
+ case AINPUT_EVENT_TYPE_MOTION:
+ inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
+ static_cast<const MotionEvent*>(inputEvent));
+ break;
+ default:
+ return true; // dispatch the event normally
+ }
+
+ if (!inputEventObj) {
+ ALOGE("Failed to obtain input event object for filterInputEvent.");
+ return true; // dispatch the event normally
+ }
+
+ // The callee is responsible for recycling the event.
+ jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
+ inputEventObj, policyFlags);
+ if (checkAndClearExceptionFromCallback(env, "filterInputEvent")) {
+ pass = true;
+ }
+ env->DeleteLocalRef(inputEventObj);
+ return pass;
+}
+
+void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
+ uint32_t& policyFlags) {
+ // Policy:
+ // - Ignore untrusted events and pass them along.
+ // - Ask the window manager what to do with normal events and trusted injected events.
+ // - For normal events wake and brighten the screen if currently off or dim.
+ if ((policyFlags & POLICY_FLAG_TRUSTED)) {
+ nsecs_t when = keyEvent->getEventTime();
+ bool isScreenOn = this->isScreenOn();
+ bool isScreenBright = this->isScreenBright();
+
+ JNIEnv* env = jniEnv();
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ jint wmActions;
+ if (keyEventObj) {
+ wmActions = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.interceptKeyBeforeQueueing,
+ keyEventObj, policyFlags, isScreenOn);
+ if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+ wmActions = 0;
+ }
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ } else {
+ ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
+ wmActions = 0;
+ }
+
+ if (!(policyFlags & POLICY_FLAG_INJECTED)) {
+ if (!isScreenOn) {
+ policyFlags |= POLICY_FLAG_WOKE_HERE;
+ }
+
+ if (!isScreenBright) {
+ policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+ }
+ }
+
+ handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
+ } else {
+ policyFlags |= POLICY_FLAG_PASS_TO_USER;
+ }
+}
+
+void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
+ // Policy:
+ // - Ignore untrusted events and pass them along.
+ // - No special filtering for injected events required at this time.
+ // - Filter normal events based on screen state.
+ // - For normal events brighten (but do not wake) the screen if currently dim.
+ if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
+ if (isScreenOn()) {
+ policyFlags |= POLICY_FLAG_PASS_TO_USER;
+
+ if (!isScreenBright()) {
+ policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+ }
+ } else {
+ JNIEnv* env = jniEnv();
+ jint wmActions = env->CallIntMethod(mServiceObj,
+ gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
+ policyFlags);
+ if (checkAndClearExceptionFromCallback(env,
+ "interceptMotionBeforeQueueingWhenScreenOff")) {
+ wmActions = 0;
+ }
+
+ policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
+ handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
+ }
+ } else {
+ policyFlags |= POLICY_FLAG_PASS_TO_USER;
+ }
+}
+
+void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
+ uint32_t& policyFlags) {
+ if (wmActions & WM_ACTION_GO_TO_SLEEP) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("handleInterceptActions: Going to sleep.");
+#endif
+ android_server_PowerManagerService_goToSleep(when);
+ }
+
+ if (wmActions & WM_ACTION_WAKE_UP) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("handleInterceptActions: Waking up.");
+#endif
+ android_server_PowerManagerService_wakeUp(when);
+ }
+
+ if (wmActions & WM_ACTION_PASS_TO_USER) {
+ policyFlags |= POLICY_FLAG_PASS_TO_USER;
+ } else {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("handleInterceptActions: Not passing key to user.");
+#endif
+ }
+}
+
+nsecs_t NativeInputManager::interceptKeyBeforeDispatching(
+ const sp<InputWindowHandle>& inputWindowHandle,
+ const KeyEvent* keyEvent, uint32_t policyFlags) {
+ // Policy:
+ // - Ignore untrusted events and pass them along.
+ // - Filter normal events and trusted injected events through the window manager policy to
+ // handle the HOME key and the like.
+ nsecs_t result = 0;
+ if (policyFlags & POLICY_FLAG_TRUSTED) {
+ JNIEnv* env = jniEnv();
+
+ // Note: inputWindowHandle may be null.
+ jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle);
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ if (keyEventObj) {
+ jlong delayMillis = env->CallLongMethod(mServiceObj,
+ gServiceClassInfo.interceptKeyBeforeDispatching,
+ inputWindowHandleObj, keyEventObj, policyFlags);
+ bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ if (!error) {
+ if (delayMillis < 0) {
+ result = -1;
+ } else if (delayMillis > 0) {
+ result = milliseconds_to_nanoseconds(delayMillis);
+ }
+ }
+ } else {
+ ALOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
+ }
+ env->DeleteLocalRef(inputWindowHandleObj);
+ }
+ return result;
+}
+
+bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
+ const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
+ // Policy:
+ // - Ignore untrusted events and do not perform default handling.
+ bool result = false;
+ if (policyFlags & POLICY_FLAG_TRUSTED) {
+ JNIEnv* env = jniEnv();
+
+ // Note: inputWindowHandle may be null.
+ jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle);
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ if (keyEventObj) {
+ jobject fallbackKeyEventObj = env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.dispatchUnhandledKey,
+ inputWindowHandleObj, keyEventObj, policyFlags);
+ if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
+ fallbackKeyEventObj = NULL;
+ }
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+
+ if (fallbackKeyEventObj) {
+ // Note: outFallbackKeyEvent may be the same object as keyEvent.
+ if (!android_view_KeyEvent_toNative(env, fallbackKeyEventObj,
+ outFallbackKeyEvent)) {
+ result = true;
+ }
+ android_view_KeyEvent_recycle(env, fallbackKeyEventObj);
+ env->DeleteLocalRef(fallbackKeyEventObj);
+ }
+ } else {
+ ALOGE("Failed to obtain key event object for dispatchUnhandledKey.");
+ }
+ env->DeleteLocalRef(inputWindowHandleObj);
+ }
+ return result;
+}
+
+void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
+ android_server_PowerManagerService_userActivity(eventTime, eventType);
+}
+
+
+bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
+ int32_t injectorPid, int32_t injectorUid) {
+ JNIEnv* env = jniEnv();
+ jboolean result = env->CallBooleanMethod(mServiceObj,
+ gServiceClassInfo.checkInjectEventsPermission, injectorPid, injectorUid);
+ if (checkAndClearExceptionFromCallback(env, "checkInjectEventsPermission")) {
+ result = false;
+ }
+ return result;
+}
+
+void NativeInputManager::loadPointerResources(PointerResources* outResources) {
+ JNIEnv* env = jniEnv();
+
+ loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_HOVER,
+ &outResources->spotHover);
+ loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_TOUCH,
+ &outResources->spotTouch);
+ loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_ANCHOR,
+ &outResources->spotAnchor);
+}
+
+
+// ----------------------------------------------------------------------------
+
+static jlong nativeInit(JNIEnv* env, jclass clazz,
+ jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
+ sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
+ if (messageQueue == NULL) {
+ jniThrowRuntimeException(env, "MessageQueue is not initialized.");
+ return 0;
+ }
+
+ NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
+ messageQueue->getLooper());
+ im->incStrong(0);
+ return reinterpret_cast<jlong>(im);
+}
+
+static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ status_t result = im->getInputManager()->start();
+ if (result) {
+ jniThrowRuntimeException(env, "Input manager could not be started.");
+ }
+}
+
+static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jlong ptr, jboolean external,
+ jint displayId, jint orientation,
+ jint logicalLeft, jint logicalTop, jint logicalRight, jint logicalBottom,
+ jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom,
+ jint deviceWidth, jint deviceHeight) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ DisplayViewport v;
+ v.displayId = displayId;
+ v.orientation = orientation;
+ v.logicalLeft = logicalLeft;
+ v.logicalTop = logicalTop;
+ v.logicalRight = logicalRight;
+ v.logicalBottom = logicalBottom;
+ v.physicalLeft = physicalLeft;
+ v.physicalTop = physicalTop;
+ v.physicalRight = physicalRight;
+ v.physicalBottom = physicalBottom;
+ v.deviceWidth = deviceWidth;
+ v.deviceHeight = deviceHeight;
+ im->setDisplayViewport(external, v);
+}
+
+static jint nativeGetScanCodeState(JNIEnv* env, jclass clazz,
+ jlong ptr, jint deviceId, jint sourceMask, jint scanCode) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ return (jint) im->getInputManager()->getReader()->getScanCodeState(
+ deviceId, uint32_t(sourceMask), scanCode);
+}
+
+static jint nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
+ jlong ptr, jint deviceId, jint sourceMask, jint keyCode) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ return (jint) im->getInputManager()->getReader()->getKeyCodeState(
+ deviceId, uint32_t(sourceMask), keyCode);
+}
+
+static jint nativeGetSwitchState(JNIEnv* env, jclass clazz,
+ jlong ptr, jint deviceId, jint sourceMask, jint sw) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ return (jint) im->getInputManager()->getReader()->getSwitchState(
+ deviceId, uint32_t(sourceMask), sw);
+}
+
+static jboolean nativeHasKeys(JNIEnv* env, jclass clazz,
+ jlong ptr, jint deviceId, jint sourceMask, jintArray keyCodes, jbooleanArray outFlags) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
+ uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
+ jsize numCodes = env->GetArrayLength(keyCodes);
+ jboolean result;
+ if (numCodes == env->GetArrayLength(keyCodes)) {
+ if (im->getInputManager()->getReader()->hasKeys(
+ deviceId, uint32_t(sourceMask), numCodes, codes, flags)) {
+ result = JNI_TRUE;
+ } else {
+ result = JNI_FALSE;
+ }
+ } else {
+ result = JNI_FALSE;
+ }
+
+ env->ReleaseBooleanArrayElements(outFlags, flags, 0);
+ env->ReleaseIntArrayElements(keyCodes, codes, 0);
+ return result;
+}
+
+static void throwInputChannelNotInitialized(JNIEnv* env) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "inputChannel is not initialized");
+}
+
+static void handleInputChannelDisposed(JNIEnv* env,
+ jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) {
+ NativeInputManager* im = static_cast<NativeInputManager*>(data);
+
+ ALOGW("Input channel object '%s' was disposed without first being unregistered with "
+ "the input manager!", inputChannel->getName().string());
+ im->unregisterInputChannel(env, inputChannel);
+}
+
+static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
+ jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
+ inputChannelObj);
+ if (inputChannel == NULL) {
+ throwInputChannelNotInitialized(env);
+ return;
+ }
+
+ sp<InputWindowHandle> inputWindowHandle =
+ android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
+
+ status_t status = im->registerInputChannel(
+ env, inputChannel, inputWindowHandle, monitor);
+ if (status) {
+ String8 message;
+ message.appendFormat("Failed to register input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
+ return;
+ }
+
+ if (! monitor) {
+ android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
+ handleInputChannelDisposed, im);
+ }
+}
+
+static void nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
+ jlong ptr, jobject inputChannelObj) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
+ inputChannelObj);
+ if (inputChannel == NULL) {
+ throwInputChannelNotInitialized(env);
+ return;
+ }
+
+ android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
+
+ status_t status = im->unregisterInputChannel(env, inputChannel);
+ if (status && status != BAD_VALUE) { // ignore already unregistered channel
+ String8 message;
+ message.appendFormat("Failed to unregister input channel. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
+ }
+}
+
+static void nativeSetInputFilterEnabled(JNIEnv* env, jclass clazz,
+ jlong ptr, jboolean enabled) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getDispatcher()->setInputFilterEnabled(enabled);
+}
+
+static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz,
+ jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid,
+ jint syncMode, jint timeoutMillis, jint policyFlags) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
+ KeyEvent keyEvent;
+ status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
+ if (status) {
+ jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
+
+ return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
+ & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,
+ uint32_t(policyFlags));
+ } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
+ const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
+ if (!motionEvent) {
+ jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
+
+ return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
+ motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,
+ uint32_t(policyFlags));
+ } else {
+ jniThrowRuntimeException(env, "Invalid input event type.");
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
+}
+
+static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
+ jlong ptr, jobjectArray windowHandleObjArray) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setInputWindows(env, windowHandleObjArray);
+}
+
+static void nativeSetFocusedApplication(JNIEnv* env, jclass clazz,
+ jlong ptr, jobject applicationHandleObj) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setFocusedApplication(env, applicationHandleObj);
+}
+
+static void nativeSetInputDispatchMode(JNIEnv* env,
+ jclass clazz, jlong ptr, jboolean enabled, jboolean frozen) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setInputDispatchMode(enabled, frozen);
+}
+
+static void nativeSetSystemUiVisibility(JNIEnv* env,
+ jclass clazz, jlong ptr, jint visibility) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setSystemUiVisibility(visibility);
+}
+
+static jboolean nativeTransferTouchFocus(JNIEnv* env,
+ jclass clazz, jlong ptr, jobject fromChannelObj, jobject toChannelObj) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ sp<InputChannel> fromChannel =
+ android_view_InputChannel_getInputChannel(env, fromChannelObj);
+ sp<InputChannel> toChannel =
+ android_view_InputChannel_getInputChannel(env, toChannelObj);
+
+ if (fromChannel == NULL || toChannel == NULL) {
+ return JNI_FALSE;
+ }
+
+ if (im->getInputManager()->getDispatcher()->
+ transferTouchFocus(fromChannel, toChannel)) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static void nativeSetPointerSpeed(JNIEnv* env,
+ jclass clazz, jlong ptr, jint speed) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setPointerSpeed(speed);
+}
+
+static void nativeSetShowTouches(JNIEnv* env,
+ jclass clazz, jlong ptr, jboolean enabled) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setShowTouches(enabled);
+}
+
+static void nativeVibrate(JNIEnv* env,
+ jclass clazz, jlong ptr, jint deviceId, jlongArray patternObj,
+ jint repeat, jint token) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ size_t patternSize = env->GetArrayLength(patternObj);
+ if (patternSize > MAX_VIBRATE_PATTERN_SIZE) {
+ ALOGI("Skipped requested vibration because the pattern size is %d "
+ "which is more than the maximum supported size of %d.",
+ patternSize, MAX_VIBRATE_PATTERN_SIZE);
+ return; // limit to reasonable size
+ }
+
+ jlong* patternMillis = static_cast<jlong*>(env->GetPrimitiveArrayCritical(
+ patternObj, NULL));
+ nsecs_t pattern[patternSize];
+ for (size_t i = 0; i < patternSize; i++) {
+ pattern[i] = max(jlong(0), min(patternMillis[i],
+ (jlong)(MAX_VIBRATE_PATTERN_DELAY_NSECS / 1000000LL))) * 1000000LL;
+ }
+ env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT);
+
+ im->getInputManager()->getReader()->vibrate(deviceId, pattern, patternSize, repeat, token);
+}
+
+static void nativeCancelVibrate(JNIEnv* env,
+ jclass clazz, jlong ptr, jint deviceId, jint token) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->cancelVibrate(deviceId, token);
+}
+
+static void nativeReloadKeyboardLayouts(JNIEnv* env,
+ jclass clazz, jlong ptr) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS);
+}
+
+static void nativeReloadDeviceAliases(JNIEnv* env,
+ jclass clazz, jlong ptr) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_DEVICE_ALIAS);
+}
+
+static jstring nativeDump(JNIEnv* env, jclass clazz, jlong ptr) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ String8 dump;
+ im->dump(dump);
+ return env->NewStringUTF(dump.string());
+}
+
+static void nativeMonitor(JNIEnv* env, jclass clazz, jlong ptr) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getReader()->monitor();
+ im->getInputManager()->getDispatcher()->monitor();
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gInputManagerMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeInit",
+ "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J",
+ (void*) nativeInit },
+ { "nativeStart", "(J)V",
+ (void*) nativeStart },
+ { "nativeSetDisplayViewport", "(JZIIIIIIIIIIII)V",
+ (void*) nativeSetDisplayViewport },
+ { "nativeGetScanCodeState", "(JIII)I",
+ (void*) nativeGetScanCodeState },
+ { "nativeGetKeyCodeState", "(JIII)I",
+ (void*) nativeGetKeyCodeState },
+ { "nativeGetSwitchState", "(JIII)I",
+ (void*) nativeGetSwitchState },
+ { "nativeHasKeys", "(JII[I[Z)Z",
+ (void*) nativeHasKeys },
+ { "nativeRegisterInputChannel",
+ "(JLandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;Z)V",
+ (void*) nativeRegisterInputChannel },
+ { "nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V",
+ (void*) nativeUnregisterInputChannel },
+ { "nativeSetInputFilterEnabled", "(JZ)V",
+ (void*) nativeSetInputFilterEnabled },
+ { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIIII)I",
+ (void*) nativeInjectInputEvent },
+ { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;)V",
+ (void*) nativeSetInputWindows },
+ { "nativeSetFocusedApplication", "(JLcom/android/server/input/InputApplicationHandle;)V",
+ (void*) nativeSetFocusedApplication },
+ { "nativeSetInputDispatchMode", "(JZZ)V",
+ (void*) nativeSetInputDispatchMode },
+ { "nativeSetSystemUiVisibility", "(JI)V",
+ (void*) nativeSetSystemUiVisibility },
+ { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z",
+ (void*) nativeTransferTouchFocus },
+ { "nativeSetPointerSpeed", "(JI)V",
+ (void*) nativeSetPointerSpeed },
+ { "nativeSetShowTouches", "(JZ)V",
+ (void*) nativeSetShowTouches },
+ { "nativeVibrate", "(JI[JII)V",
+ (void*) nativeVibrate },
+ { "nativeCancelVibrate", "(JII)V",
+ (void*) nativeCancelVibrate },
+ { "nativeReloadKeyboardLayouts", "(J)V",
+ (void*) nativeReloadKeyboardLayouts },
+ { "nativeReloadDeviceAliases", "(J)V",
+ (void*) nativeReloadDeviceAliases },
+ { "nativeDump", "(J)Ljava/lang/String;",
+ (void*) nativeDump },
+ { "nativeMonitor", "(J)V",
+ (void*) nativeMonitor },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_InputManager(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/input/InputManagerService",
+ gInputManagerMethods, NELEM(gInputManagerMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ // Callbacks
+
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/input/InputManagerService");
+
+ GET_METHOD_ID(gServiceClassInfo.notifyConfigurationChanged, clazz,
+ "notifyConfigurationChanged", "(J)V");
+
+ GET_METHOD_ID(gServiceClassInfo.notifyInputDevicesChanged, clazz,
+ "notifyInputDevicesChanged", "([Landroid/view/InputDevice;)V");
+
+ GET_METHOD_ID(gServiceClassInfo.notifySwitch, clazz,
+ "notifySwitch", "(JII)V");
+
+ GET_METHOD_ID(gServiceClassInfo.notifyInputChannelBroken, clazz,
+ "notifyInputChannelBroken", "(Lcom/android/server/input/InputWindowHandle;)V");
+
+ GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
+ "notifyANR",
+ "(Lcom/android/server/input/InputApplicationHandle;Lcom/android/server/input/InputWindowHandle;Ljava/lang/String;)J");
+
+ GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
+ "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
+
+ GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
+ "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
+
+ GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
+ clazz,
+ "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
+
+ GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
+ "interceptKeyBeforeDispatching",
+ "(Lcom/android/server/input/InputWindowHandle;Landroid/view/KeyEvent;I)J");
+
+ GET_METHOD_ID(gServiceClassInfo.dispatchUnhandledKey, clazz,
+ "dispatchUnhandledKey",
+ "(Lcom/android/server/input/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
+
+ GET_METHOD_ID(gServiceClassInfo.checkInjectEventsPermission, clazz,
+ "checkInjectEventsPermission", "(II)Z");
+
+ GET_METHOD_ID(gServiceClassInfo.getVirtualKeyQuietTimeMillis, clazz,
+ "getVirtualKeyQuietTimeMillis", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getExcludedDeviceNames, clazz,
+ "getExcludedDeviceNames", "()[Ljava/lang/String;");
+
+ GET_METHOD_ID(gServiceClassInfo.getKeyRepeatTimeout, clazz,
+ "getKeyRepeatTimeout", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getKeyRepeatDelay, clazz,
+ "getKeyRepeatDelay", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getHoverTapTimeout, clazz,
+ "getHoverTapTimeout", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getHoverTapSlop, clazz,
+ "getHoverTapSlop", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getDoubleTapTimeout, clazz,
+ "getDoubleTapTimeout", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getLongPressTimeout, clazz,
+ "getLongPressTimeout", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getPointerLayer, clazz,
+ "getPointerLayer", "()I");
+
+ GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
+ "getPointerIcon", "()Landroid/view/PointerIcon;");
+
+ GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
+ "getKeyboardLayoutOverlay", "(Ljava/lang/String;)[Ljava/lang/String;");
+
+ GET_METHOD_ID(gServiceClassInfo.getDeviceAlias, clazz,
+ "getDeviceAlias", "(Ljava/lang/String;)Ljava/lang/String;");
+
+ // InputDevice
+
+ FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
+ gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
+
+ // KeyEvent
+
+ FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
+ gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
+
+ // MotionEvent
+
+ FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
+ gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
+
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
new file mode 100644
index 0000000..b80183c
--- /dev/null
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2011 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 "InputWindowHandle"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/threads.h>
+
+#include <android_view_InputChannel.h>
+#include <android/graphics/Region.h>
+
+#include "com_android_server_input_InputWindowHandle.h"
+#include "com_android_server_input_InputApplicationHandle.h"
+
+namespace android {
+
+static struct {
+ jfieldID ptr;
+ jfieldID inputApplicationHandle;
+ jfieldID inputChannel;
+ jfieldID name;
+ jfieldID layoutParamsFlags;
+ jfieldID layoutParamsPrivateFlags;
+ jfieldID layoutParamsType;
+ jfieldID dispatchingTimeoutNanos;
+ jfieldID frameLeft;
+ jfieldID frameTop;
+ jfieldID frameRight;
+ jfieldID frameBottom;
+ jfieldID scaleFactor;
+ jfieldID touchableRegion;
+ jfieldID visible;
+ jfieldID canReceiveKeys;
+ jfieldID hasFocus;
+ jfieldID hasWallpaper;
+ jfieldID paused;
+ jfieldID layer;
+ jfieldID ownerPid;
+ jfieldID ownerUid;
+ jfieldID inputFeatures;
+ jfieldID displayId;
+} gInputWindowHandleClassInfo;
+
+static Mutex gHandleMutex;
+
+
+// --- NativeInputWindowHandle ---
+
+NativeInputWindowHandle::NativeInputWindowHandle(
+ const sp<InputApplicationHandle>& inputApplicationHandle, jweak objWeak) :
+ InputWindowHandle(inputApplicationHandle),
+ mObjWeak(objWeak) {
+}
+
+NativeInputWindowHandle::~NativeInputWindowHandle() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteWeakGlobalRef(mObjWeak);
+}
+
+jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) {
+ return env->NewLocalRef(mObjWeak);
+}
+
+bool NativeInputWindowHandle::updateInfo() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject obj = env->NewLocalRef(mObjWeak);
+ if (!obj) {
+ releaseInfo();
+ return false;
+ }
+
+ if (!mInfo) {
+ mInfo = new InputWindowInfo();
+ }
+
+ jobject inputChannelObj = env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.inputChannel);
+ if (inputChannelObj) {
+ mInfo->inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
+ env->DeleteLocalRef(inputChannelObj);
+ } else {
+ mInfo->inputChannel.clear();
+ }
+
+ jstring nameObj = jstring(env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.name));
+ if (nameObj) {
+ const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+ mInfo->name.setTo(nameStr);
+ env->ReleaseStringUTFChars(nameObj, nameStr);
+ env->DeleteLocalRef(nameObj);
+ } else {
+ mInfo->name.setTo("<null>");
+ }
+
+ mInfo->layoutParamsFlags = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layoutParamsFlags);
+ mInfo->layoutParamsPrivateFlags = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layoutParamsPrivateFlags);
+ mInfo->layoutParamsType = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layoutParamsType);
+ mInfo->dispatchingTimeout = env->GetLongField(obj,
+ gInputWindowHandleClassInfo.dispatchingTimeoutNanos);
+ mInfo->frameLeft = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameLeft);
+ mInfo->frameTop = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameTop);
+ mInfo->frameRight = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameRight);
+ mInfo->frameBottom = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameBottom);
+ mInfo->scaleFactor = env->GetFloatField(obj,
+ gInputWindowHandleClassInfo.scaleFactor);
+
+ jobject regionObj = env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.touchableRegion);
+ if (regionObj) {
+ SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+ mInfo->touchableRegion.set(*region);
+ env->DeleteLocalRef(regionObj);
+ } else {
+ mInfo->touchableRegion.setEmpty();
+ }
+
+ mInfo->visible = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.visible);
+ mInfo->canReceiveKeys = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.canReceiveKeys);
+ mInfo->hasFocus = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.hasFocus);
+ mInfo->hasWallpaper = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.hasWallpaper);
+ mInfo->paused = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.paused);
+ mInfo->layer = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layer);
+ mInfo->ownerPid = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.ownerPid);
+ mInfo->ownerUid = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.ownerUid);
+ mInfo->inputFeatures = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.inputFeatures);
+ mInfo->displayId = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.displayId);
+
+ env->DeleteLocalRef(obj);
+ return true;
+}
+
+
+// --- Global functions ---
+
+sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle(
+ JNIEnv* env, jobject inputWindowHandleObj) {
+ if (!inputWindowHandleObj) {
+ return NULL;
+ }
+
+ AutoMutex _l(gHandleMutex);
+
+ jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
+ NativeInputWindowHandle* handle;
+ if (ptr) {
+ handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
+ } else {
+ jobject inputApplicationHandleObj = env->GetObjectField(inputWindowHandleObj,
+ gInputWindowHandleClassInfo.inputApplicationHandle);
+ sp<InputApplicationHandle> inputApplicationHandle =
+ android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
+ env->DeleteLocalRef(inputApplicationHandleObj);
+
+ jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
+ handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak);
+ handle->incStrong((void*)android_server_InputWindowHandle_getHandle);
+ env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
+ reinterpret_cast<jlong>(handle));
+ }
+ return handle;
+}
+
+
+// --- JNI ---
+
+static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) {
+ AutoMutex _l(gHandleMutex);
+
+ jlong ptr = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr);
+ if (ptr) {
+ env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0);
+
+ NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
+ handle->decStrong((void*)android_server_InputWindowHandle_getHandle);
+ }
+}
+
+
+static JNINativeMethod gInputWindowHandleMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeDispose", "()V",
+ (void*) android_server_InputWindowHandle_nativeDispose },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_InputWindowHandle(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/input/InputWindowHandle",
+ gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/input/InputWindowHandle");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
+ "ptr", "J");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle,
+ clazz,
+ "inputApplicationHandle", "Lcom/android/server/input/InputApplicationHandle;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz,
+ "inputChannel", "Landroid/view/InputChannel;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
+ "name", "Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
+ "layoutParamsFlags", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsPrivateFlags, clazz,
+ "layoutParamsPrivateFlags", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
+ "layoutParamsType", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
+ "dispatchingTimeoutNanos", "J");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
+ "frameLeft", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameTop, clazz,
+ "frameTop", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameRight, clazz,
+ "frameRight", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz,
+ "frameBottom", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz,
+ "scaleFactor", "F");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
+ "touchableRegion", "Landroid/graphics/Region;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
+ "visible", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.canReceiveKeys, clazz,
+ "canReceiveKeys", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.hasFocus, clazz,
+ "hasFocus", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
+ "hasWallpaper", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
+ "paused", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layer, clazz,
+ "layer", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
+ "ownerPid", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz,
+ "ownerUid", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz,
+ "inputFeatures", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
+ "displayId", "I");
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.h b/services/core/jni/com_android_server_input_InputWindowHandle.h
new file mode 100644
index 0000000..2cfa17d3
--- /dev/null
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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_SERVER_INPUT_WINDOW_HANDLE_H
+#define _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
+
+#include <input/InputWindow.h>
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+class NativeInputWindowHandle : public InputWindowHandle {
+public:
+ NativeInputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+ jweak objWeak);
+ virtual ~NativeInputWindowHandle();
+
+ jobject getInputWindowHandleObjLocalRef(JNIEnv* env);
+
+ virtual bool updateInfo();
+
+private:
+ jweak mObjWeak;
+};
+
+
+extern sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle(
+ JNIEnv* env, jobject inputWindowHandleObj);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
new file mode 100644
index 0000000..d51e044
--- /dev/null
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2009 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 "LightsService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/lights.h>
+
+#include <stdio.h>
+
+namespace android
+{
+
+// These values must correspond with the LIGHT_ID constants in
+// LightsService.java
+enum {
+ LIGHT_INDEX_BACKLIGHT = 0,
+ LIGHT_INDEX_KEYBOARD = 1,
+ LIGHT_INDEX_BUTTONS = 2,
+ LIGHT_INDEX_BATTERY = 3,
+ LIGHT_INDEX_NOTIFICATIONS = 4,
+ LIGHT_INDEX_ATTENTION = 5,
+ LIGHT_INDEX_BLUETOOTH = 6,
+ LIGHT_INDEX_WIFI = 7,
+ LIGHT_COUNT
+};
+
+struct Devices {
+ light_device_t* lights[LIGHT_COUNT];
+};
+
+static light_device_t* get_device(hw_module_t* module, char const* name)
+{
+ int err;
+ hw_device_t* device;
+ err = module->methods->open(module, name, &device);
+ if (err == 0) {
+ return (light_device_t*)device;
+ } else {
+ return NULL;
+ }
+}
+
+static jlong init_native(JNIEnv *env, jobject clazz)
+{
+ int err;
+ hw_module_t* module;
+ Devices* devices;
+
+ devices = (Devices*)malloc(sizeof(Devices));
+
+ err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+ if (err == 0) {
+ devices->lights[LIGHT_INDEX_BACKLIGHT]
+ = get_device(module, LIGHT_ID_BACKLIGHT);
+ devices->lights[LIGHT_INDEX_KEYBOARD]
+ = get_device(module, LIGHT_ID_KEYBOARD);
+ devices->lights[LIGHT_INDEX_BUTTONS]
+ = get_device(module, LIGHT_ID_BUTTONS);
+ devices->lights[LIGHT_INDEX_BATTERY]
+ = get_device(module, LIGHT_ID_BATTERY);
+ devices->lights[LIGHT_INDEX_NOTIFICATIONS]
+ = get_device(module, LIGHT_ID_NOTIFICATIONS);
+ devices->lights[LIGHT_INDEX_ATTENTION]
+ = get_device(module, LIGHT_ID_ATTENTION);
+ devices->lights[LIGHT_INDEX_BLUETOOTH]
+ = get_device(module, LIGHT_ID_BLUETOOTH);
+ devices->lights[LIGHT_INDEX_WIFI]
+ = get_device(module, LIGHT_ID_WIFI);
+ } else {
+ memset(devices, 0, sizeof(Devices));
+ }
+
+ return (jlong)devices;
+}
+
+static void finalize_native(JNIEnv *env, jobject clazz, jlong ptr)
+{
+ Devices* devices = (Devices*)ptr;
+ if (devices == NULL) {
+ return;
+ }
+
+ free(devices);
+}
+
+static void setLight_native(JNIEnv *env, jobject clazz, jlong ptr,
+ jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
+{
+ Devices* devices = (Devices*)ptr;
+ light_state_t state;
+
+ if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
+ return ;
+ }
+
+ memset(&state, 0, sizeof(light_state_t));
+ state.color = colorARGB;
+ state.flashMode = flashMode;
+ state.flashOnMS = onMS;
+ state.flashOffMS = offMS;
+ state.brightnessMode = brightnessMode;
+
+ {
+ ALOGD_IF_SLOW(50, "Excessive delay setting light");
+ devices->lights[light]->set_light(devices->lights[light], &state);
+ }
+}
+
+static JNINativeMethod method_table[] = {
+ { "init_native", "()J", (void*)init_native },
+ { "finalize_native", "(J)V", (void*)finalize_native },
+ { "setLight_native", "(JIIIIII)V", (void*)setLight_native },
+};
+
+int register_android_server_LightsService(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
new file mode 100644
index 0000000..6c14887
--- /dev/null
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -0,0 +1,1002 @@
+/*
+ * Copyright (C) 2013 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/license/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 "FlpHardwareProvider"
+#define LOG_NDEBUG 0
+
+#define WAKE_LOCK_NAME "FLP"
+#define LOCATION_CLASS_NAME "android/location/Location"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+#include "hardware/fused_location.h"
+#include "hardware_legacy/power.h"
+
+static jobject sCallbacksObj = NULL;
+static JNIEnv *sCallbackEnv = NULL;
+static hw_device_t* sHardwareDevice = NULL;
+
+static jmethodID sOnLocationReport = NULL;
+static jmethodID sOnDataReport = NULL;
+static jmethodID sOnGeofenceTransition = NULL;
+static jmethodID sOnGeofenceMonitorStatus = NULL;
+static jmethodID sOnGeofenceAdd = NULL;
+static jmethodID sOnGeofenceRemove = NULL;
+static jmethodID sOnGeofencePause = NULL;
+static jmethodID sOnGeofenceResume = NULL;
+
+static const FlpLocationInterface* sFlpInterface = NULL;
+static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
+static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL;
+static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL;
+
+namespace android {
+
+static inline void CheckExceptions(JNIEnv* env, const char* methodName) {
+ if(!env->ExceptionCheck()) {
+ return;
+ }
+
+ ALOGE("An exception was thrown by '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+}
+
+static inline void ThrowOnError(
+ JNIEnv* env,
+ int resultCode,
+ const char* methodName) {
+ if(resultCode == FLP_RESULT_SUCCESS) {
+ return;
+ }
+
+ ALOGE("Error %d in '%s'", resultCode, methodName);
+ env->FatalError(methodName);
+}
+
+static bool IsValidCallbackThread() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ if(sCallbackEnv == NULL || sCallbackEnv != env) {
+ ALOGE("CallbackThread check fail: env=%p, expected=%p", env, sCallbackEnv);
+ return false;
+ }
+
+ return true;
+}
+
+static int SetThreadEvent(ThreadEvent event) {
+ JavaVM* javaVm = AndroidRuntime::getJavaVM();
+
+ switch(event) {
+ case ASSOCIATE_JVM:
+ {
+ if(sCallbackEnv != NULL) {
+ ALOGE(
+ "Attempted to associate callback in '%s'. Callback already associated.",
+ __FUNCTION__
+ );
+ return FLP_RESULT_ERROR;
+ }
+
+ JavaVMAttachArgs args = {
+ JNI_VERSION_1_6,
+ "FLP Service Callback Thread",
+ /* group */ NULL
+ };
+
+ jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args);
+ if (attachResult != 0) {
+ ALOGE("Callback thread attachment error: %d", attachResult);
+ return FLP_RESULT_ERROR;
+ }
+
+ ALOGV("Callback thread attached: %p", sCallbackEnv);
+ break;
+ }
+ case DISASSOCIATE_JVM:
+ {
+ if (!IsValidCallbackThread()) {
+ ALOGE(
+ "Attempted to dissasociate an unnownk callback thread : '%s'.",
+ __FUNCTION__
+ );
+ return FLP_RESULT_ERROR;
+ }
+
+ if (javaVm->DetachCurrentThread() != 0) {
+ return FLP_RESULT_ERROR;
+ }
+
+ sCallbackEnv = NULL;
+ break;
+ }
+ default:
+ ALOGE("Invalid ThreadEvent request %d", event);
+ return FLP_RESULT_ERROR;
+ }
+
+ return FLP_RESULT_SUCCESS;
+}
+
+/*
+ * Initializes the FlpHardwareProvider class from the native side by opening
+ * the HW module and obtaining the proper interfaces.
+ */
+static void ClassInit(JNIEnv* env, jclass clazz) {
+ // get references to the Java provider methods
+ sOnLocationReport = env->GetMethodID(
+ clazz,
+ "onLocationReport",
+ "([Landroid/location/Location;)V");
+ sOnDataReport = env->GetMethodID(
+ clazz,
+ "onDataReport",
+ "(Ljava/lang/String;)V"
+ );
+ sOnGeofenceTransition = env->GetMethodID(
+ clazz,
+ "onGeofenceTransition",
+ "(ILandroid/location/Location;IJI)V"
+ );
+ sOnGeofenceMonitorStatus = env->GetMethodID(
+ clazz,
+ "onGeofenceMonitorStatus",
+ "(IILandroid/location/Location;)V"
+ );
+ sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V");
+ sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V");
+ sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V");
+ sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V");
+}
+
+/*
+ * Helper function to unwrap a java object back into a FlpLocation structure.
+ */
+static void TranslateFromObject(
+ JNIEnv* env,
+ jobject locationObject,
+ FlpLocation& location) {
+ location.size = sizeof(FlpLocation);
+ location.flags = 0;
+
+ jclass locationClass = env->GetObjectClass(locationObject);
+
+ jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D");
+ location.latitude = env->CallDoubleMethod(locationObject, getLatitude);
+ jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D");
+ location.longitude = env->CallDoubleMethod(locationObject, getLongitude);
+ jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J");
+ location.timestamp = env->CallLongMethod(locationObject, getTime);
+ location.flags |= FLP_LOCATION_HAS_LAT_LONG;
+
+ jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasAltitude)) {
+ jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D");
+ location.altitude = env->CallDoubleMethod(locationObject, getAltitude);
+ location.flags |= FLP_LOCATION_HAS_ALTITUDE;
+ }
+
+ jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasSpeed)) {
+ jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F");
+ location.speed = env->CallFloatMethod(locationObject, getSpeed);
+ location.flags |= FLP_LOCATION_HAS_SPEED;
+ }
+
+ jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasBearing)) {
+ jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F");
+ location.bearing = env->CallFloatMethod(locationObject, getBearing);
+ location.flags |= FLP_LOCATION_HAS_BEARING;
+ }
+
+ jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasAccuracy)) {
+ jmethodID getAccuracy = env->GetMethodID(
+ locationClass,
+ "getAccuracy",
+ "()F"
+ );
+ location.accuracy = env->CallFloatMethod(locationObject, getAccuracy);
+ location.flags |= FLP_LOCATION_HAS_ACCURACY;
+ }
+
+ // TODO: wire sources_used if Location class exposes them
+
+ env->DeleteLocalRef(locationClass);
+}
+
+/*
+ * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
+ */
+static void TranslateFromObject(
+ JNIEnv* env,
+ jobject batchOptionsObject,
+ FlpBatchOptions& batchOptions) {
+ jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
+
+ jmethodID getMaxPower = env->GetMethodID(
+ batchOptionsClass,
+ "getMaxPowerAllocationInMW",
+ "()D"
+ );
+ batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
+ batchOptionsObject,
+ getMaxPower
+ );
+
+ jmethodID getPeriod = env->GetMethodID(
+ batchOptionsClass,
+ "getPeriodInNS",
+ "()J"
+ );
+ batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
+
+ jmethodID getSourcesToUse = env->GetMethodID(
+ batchOptionsClass,
+ "getSourcesToUse",
+ "()I"
+ );
+ batchOptions.sources_to_use = env->CallIntMethod(
+ batchOptionsObject,
+ getSourcesToUse
+ );
+
+ jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
+ batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
+
+ env->DeleteLocalRef(batchOptionsClass);
+}
+
+/*
+ * Helper function to unwrap Geofence structures from the Java Runtime calls.
+ */
+static void TranslateGeofenceFromGeofenceHardwareRequestParcelable(
+ JNIEnv* env,
+ jobject geofenceRequestObject,
+ Geofence& geofence) {
+ jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject);
+
+ jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I");
+ geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId);
+
+ jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I");
+ // this works because GeofenceHardwareRequest.java and fused_location.h have
+ // the same notion of geofence types
+ GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType);
+ if(type != TYPE_CIRCLE) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+ geofence.data->type = type;
+ GeofenceCircle& circle = geofence.data->geofence.circle;
+
+ jmethodID getLatitude = env->GetMethodID(
+ geofenceRequestClass,
+ "getLatitude",
+ "()D");
+ circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude);
+
+ jmethodID getLongitude = env->GetMethodID(
+ geofenceRequestClass,
+ "getLongitude",
+ "()D");
+ circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude);
+
+ jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D");
+ circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius);
+
+ GeofenceOptions* options = geofence.options;
+ jmethodID getMonitorTransitions = env->GetMethodID(
+ geofenceRequestClass,
+ "getMonitorTransitions",
+ "()I");
+ options->monitor_transitions = env->CallIntMethod(
+ geofenceRequestObject,
+ getMonitorTransitions);
+
+ jmethodID getUnknownTimer = env->GetMethodID(
+ geofenceRequestClass,
+ "getUnknownTimer",
+ "()I");
+ options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer);
+
+ jmethodID getNotificationResponsiveness = env->GetMethodID(
+ geofenceRequestClass,
+ "getNotificationResponsiveness",
+ "()I");
+ options->notification_responsivenes_ms = env->CallIntMethod(
+ geofenceRequestObject,
+ getNotificationResponsiveness);
+
+ jmethodID getLastTransition = env->GetMethodID(
+ geofenceRequestClass,
+ "getLastTransition",
+ "()I");
+ options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition);
+
+ // TODO: set data.sources_to_use when available
+
+ env->DeleteLocalRef(geofenceRequestClass);
+}
+
+/*
+ * Helper function to transform FlpLocation into a java object.
+ */
+static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
+ jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+ jmethodID locationCtor = sCallbackEnv->GetMethodID(
+ locationClass,
+ "<init>",
+ "(Ljava/lang/String;)V"
+ );
+
+ // the provider is set in the upper JVM layer
+ locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
+ jint flags = location->flags;
+
+ // set the valid information in the object
+ if (flags & FLP_LOCATION_HAS_LAT_LONG) {
+ jmethodID setLatitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setLatitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
+
+ jmethodID setLongitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setLongitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(
+ locationObject,
+ setLongitude,
+ location->longitude
+ );
+
+ jmethodID setTime = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setTime",
+ "(J)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
+ }
+
+ if (flags & FLP_LOCATION_HAS_ALTITUDE) {
+ jmethodID setAltitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setAltitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
+ }
+
+ if (flags & FLP_LOCATION_HAS_SPEED) {
+ jmethodID setSpeed = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setSpeed",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
+ }
+
+ if (flags & FLP_LOCATION_HAS_BEARING) {
+ jmethodID setBearing = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setBearing",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
+ }
+
+ if (flags & FLP_LOCATION_HAS_ACCURACY) {
+ jmethodID setAccuracy = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setAccuracy",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
+ }
+
+ // TODO: wire FlpLocation::sources_used when needed
+
+ sCallbackEnv->DeleteLocalRef(locationClass);
+}
+
+/*
+ * Helper function to serialize FlpLocation structures.
+ */
+static void TranslateToObjectArray(
+ int32_t locationsCount,
+ FlpLocation** locations,
+ jobjectArray& locationsArray) {
+ jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+ locationsArray = sCallbackEnv->NewObjectArray(
+ locationsCount,
+ locationClass,
+ /* initialElement */ NULL
+ );
+
+ for (int i = 0; i < locationsCount; ++i) {
+ jobject locationObject = NULL;
+ TranslateToObject(locations[i], locationObject);
+ sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
+ sCallbackEnv->DeleteLocalRef(locationObject);
+ }
+
+ sCallbackEnv->DeleteLocalRef(locationClass);
+}
+
+static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ if(locationsCount == 0 || locations == NULL) {
+ ALOGE(
+ "Invalid LocationCallback. Count: %d, Locations: %p",
+ locationsCount,
+ locations
+ );
+ return;
+ }
+
+ jobjectArray locationsArray = NULL;
+ TranslateToObjectArray(locationsCount, locations, locationsArray);
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnLocationReport,
+ locationsArray
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+ if(locationsArray != NULL) {
+ sCallbackEnv->DeleteLocalRef(locationsArray);
+ }
+}
+
+static void AcquireWakelock() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+}
+
+static void ReleaseWakelock() {
+ release_wake_lock(WAKE_LOCK_NAME);
+}
+
+FlpCallbacks sFlpCallbacks = {
+ sizeof(FlpCallbacks),
+ LocationCallback,
+ AcquireWakelock,
+ ReleaseWakelock,
+ SetThreadEvent
+};
+
+static void ReportData(char* data, int length) {
+ jstring stringData = NULL;
+
+ if(length != 0 && data != NULL) {
+ stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
+ } else {
+ ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
+ sizeof(FlpDiagnosticCallbacks),
+ SetThreadEvent,
+ ReportData
+};
+
+static void GeofenceTransitionCallback(
+ int32_t geofenceId,
+ FlpLocation* location,
+ int32_t transition,
+ FlpUtcTime timestamp,
+ uint32_t sourcesUsed
+ ) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ if(location == NULL) {
+ ALOGE("GeofenceTransition received with invalid location: %p", location);
+ return;
+ }
+
+ jobject locationObject = NULL;
+ TranslateToObject(location, locationObject);
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceTransition,
+ geofenceId,
+ locationObject,
+ transition,
+ timestamp,
+ sourcesUsed
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+ if(locationObject != NULL) {
+ sCallbackEnv->DeleteLocalRef(locationObject);
+ }
+}
+
+static void GeofenceMonitorStatusCallback(
+ int32_t status,
+ uint32_t source,
+ FlpLocation* lastLocation) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ jobject locationObject = NULL;
+ if(lastLocation != NULL) {
+ TranslateToObject(lastLocation, locationObject);
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceMonitorStatus,
+ status,
+ source,
+ locationObject
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+
+ if(locationObject != NULL) {
+ sCallbackEnv->DeleteLocalRef(locationObject);
+ }
+}
+
+static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceRemove,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofencePause,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceResume,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
+ sizeof(FlpGeofenceCallbacks),
+ GeofenceTransitionCallback,
+ GeofenceMonitorStatusCallback,
+ GeofenceAddCallback,
+ GeofenceRemoveCallback,
+ GeofencePauseCallback,
+ GeofenceResumeCallback,
+ SetThreadEvent
+};
+
+/*
+ * Initializes the Fused Location Provider in the native side. It ensures that
+ * the Flp interfaces are initialized properly.
+ */
+static void Init(JNIEnv* env, jobject obj) {
+ if(sHardwareDevice != NULL) {
+ ALOGD("Hardware Device already opened.");
+ return;
+ }
+
+ const hw_module_t* module = NULL;
+ int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
+ if(err != 0) {
+ ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+ return;
+ }
+
+ err = module->methods->open(
+ module,
+ FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice);
+ if(err != 0) {
+ ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+ return;
+ }
+
+ sFlpInterface = NULL;
+ flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
+ sFlpInterface = flp_device->get_flp_interface(flp_device);
+
+ if(sFlpInterface != NULL) {
+ sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
+ sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)
+ );
+
+ sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
+ sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)
+ );
+
+ sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
+ sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)
+ );
+ }
+
+ if(sCallbacksObj == NULL) {
+ sCallbacksObj = env->NewGlobalRef(obj);
+ }
+
+ // initialize the Flp interfaces
+ if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpDiagnosticInterface != NULL) {
+ sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
+ }
+
+ if(sFlpGeofencingInterface != NULL) {
+ sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
+ }
+
+ // TODO: inject any device context if when needed
+}
+
+static jboolean IsSupported(JNIEnv* env, jclass clazz) {
+ return sFlpInterface != NULL;
+}
+
+static jint GetBatchSize(JNIEnv* env, jobject object) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ return sFlpInterface->get_batch_size();
+}
+
+static void StartBatching(
+ JNIEnv* env,
+ jobject object,
+ jint id,
+ jobject optionsObject) {
+ if(sFlpInterface == NULL || optionsObject == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ FlpBatchOptions options;
+ TranslateFromObject(env, optionsObject, options);
+ int result = sFlpInterface->start_batching(id, &options);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void UpdateBatchingOptions(
+ JNIEnv* env,
+ jobject object,
+ jint id,
+ jobject optionsObject) {
+ if(sFlpInterface == NULL || optionsObject == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ FlpBatchOptions options;
+ TranslateFromObject(env, optionsObject, options);
+ int result = sFlpInterface->update_batching_options(id, &options);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void StopBatching(JNIEnv* env, jobject object, jint id) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->stop_batching(id);
+}
+
+static void Cleanup(JNIEnv* env, jobject object) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->cleanup();
+
+ if(sCallbacksObj != NULL) {
+ env->DeleteGlobalRef(sCallbacksObj);
+ sCallbacksObj = NULL;
+ }
+
+ sFlpInterface = NULL;
+ sFlpDiagnosticInterface = NULL;
+ sFlpDeviceContextInterface = NULL;
+ sFlpGeofencingInterface = NULL;
+
+ if(sHardwareDevice != NULL) {
+ sHardwareDevice->close(sHardwareDevice);
+ sHardwareDevice = NULL;
+ }
+}
+
+static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->get_batched_location(lastNLocations);
+}
+
+static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
+ if(locationObject == NULL) {
+ ALOGE("Invalid location for injection: %p", locationObject);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpInterface == NULL) {
+ // there is no listener, bail
+ return;
+ }
+
+ FlpLocation location;
+ TranslateFromObject(env, locationObject, location);
+ int result = sFlpInterface->inject_location(&location);
+ if (result != FLP_RESULT_SUCCESS) {
+ // do not throw but log, this operation should be fire and forget
+ ALOGE("Error %d in '%s'", result, __FUNCTION__);
+ }
+}
+
+static jboolean IsDiagnosticSupported() {
+ return sFlpDiagnosticInterface != NULL;
+}
+
+static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
+ if(stringData == NULL) {
+ ALOGE("Invalid diagnostic data for injection: %p", stringData);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpDiagnosticInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int length = env->GetStringLength(stringData);
+ const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
+ if(data == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsDeviceContextSupported() {
+ return sFlpDeviceContextInterface != NULL;
+}
+
+static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
+ if(sFlpDeviceContextInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsGeofencingSupported() {
+ return sFlpGeofencingInterface != NULL;
+}
+
+static void AddGeofences(
+ JNIEnv* env,
+ jobject object,
+ jobjectArray geofenceRequestsArray) {
+ if(geofenceRequestsArray == NULL) {
+ ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if (sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray);
+ if(geofenceRequestsCount == 0) {
+ return;
+ }
+
+ Geofence* geofences = new Geofence[geofenceRequestsCount];
+ if (geofences == NULL) {
+ ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
+ }
+
+ for (int i = 0; i < geofenceRequestsCount; ++i) {
+ geofences[i].data = new GeofenceData();
+ geofences[i].options = new GeofenceOptions();
+ jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i);
+
+ TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]);
+ env->DeleteLocalRef(geofenceObject);
+ }
+
+ sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences);
+ if (geofences != NULL) {
+ for(int i = 0; i < geofenceRequestsCount; ++i) {
+ delete geofences[i].data;
+ delete geofences[i].options;
+ }
+ delete[] geofences;
+ }
+}
+
+static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->pause_geofence(geofenceId);
+}
+
+static void ResumeGeofence(
+ JNIEnv* env,
+ jobject object,
+ jint geofenceId,
+ jint monitorTransitions) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
+}
+
+static void ModifyGeofenceOption(
+ JNIEnv* env,
+ jobject object,
+ jint geofenceId,
+ jint lastTransition,
+ jint monitorTransitions,
+ jint notificationResponsiveness,
+ jint unknownTimer,
+ jint sourcesToUse) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ GeofenceOptions options = {
+ lastTransition,
+ monitorTransitions,
+ notificationResponsiveness,
+ unknownTimer,
+ (uint32_t)sourcesToUse
+ };
+
+ sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
+}
+
+static void RemoveGeofences(
+ JNIEnv* env,
+ jobject object,
+ jintArray geofenceIdsArray) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
+ jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
+ if(geofenceIds == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
+ env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/);
+}
+
+static JNINativeMethod sMethods[] = {
+ //{"name", "signature", functionPointer }
+ {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
+ {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
+ {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
+ {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
+ {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
+ {"nativeStartBatching",
+ "(ILandroid/location/FusedBatchOptions;)V",
+ reinterpret_cast<void*>(StartBatching)},
+ {"nativeUpdateBatchingOptions",
+ "(ILandroid/location/FusedBatchOptions;)V",
+ reinterpret_cast<void*>(UpdateBatchingOptions)},
+ {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
+ {"nativeRequestBatchedLocation",
+ "(I)V",
+ reinterpret_cast<void*>(GetBatchedLocation)},
+ {"nativeInjectLocation",
+ "(Landroid/location/Location;)V",
+ reinterpret_cast<void*>(InjectLocation)},
+ {"nativeIsDiagnosticSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsDiagnosticSupported)},
+ {"nativeInjectDiagnosticData",
+ "(Ljava/lang/String;)V",
+ reinterpret_cast<void*>(InjectDiagnosticData)},
+ {"nativeIsDeviceContextSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsDeviceContextSupported)},
+ {"nativeInjectDeviceContext",
+ "(I)V",
+ reinterpret_cast<void*>(InjectDeviceContext)},
+ {"nativeIsGeofencingSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsGeofencingSupported)},
+ {"nativeAddGeofences",
+ "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V",
+ reinterpret_cast<void*>(AddGeofences)},
+ {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
+ {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
+ {"nativeModifyGeofenceOption",
+ "(IIIIII)V",
+ reinterpret_cast<void*>(ModifyGeofenceOption)},
+ {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
+};
+
+/*
+ * Registration method invoked on JNI Load.
+ */
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
+ return jniRegisterNativeMethods(
+ env,
+ "com/android/server/location/FlpHardwareProvider",
+ sMethods,
+ NELEM(sMethods)
+ );
+}
+
+} /* name-space Android */
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
new file mode 100644
index 0000000..e9ba116
--- /dev/null
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -0,0 +1,800 @@
+/*
+ * 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"
+
+#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "hardware/hardware.h"
+#include "hardware/gps.h"
+#include "hardware_legacy/power.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+
+#include <string.h>
+#include <pthread.h>
+
+static jobject mCallbacksObj = NULL;
+
+static jmethodID method_reportLocation;
+static jmethodID method_reportStatus;
+static jmethodID method_reportSvStatus;
+static jmethodID method_reportAGpsStatus;
+static jmethodID method_reportNmea;
+static jmethodID method_setEngineCapabilities;
+static jmethodID method_xtraDownloadRequest;
+static jmethodID method_reportNiNotification;
+static jmethodID method_requestRefLocation;
+static jmethodID method_requestSetID;
+static jmethodID method_requestUtcTime;
+static jmethodID method_reportGeofenceTransition;
+static jmethodID method_reportGeofenceStatus;
+static jmethodID method_reportGeofenceAddStatus;
+static jmethodID method_reportGeofenceRemoveStatus;
+static jmethodID method_reportGeofencePauseStatus;
+static jmethodID method_reportGeofenceResumeStatus;
+
+static const GpsInterface* sGpsInterface = NULL;
+static const GpsXtraInterface* sGpsXtraInterface = NULL;
+static const AGpsInterface* sAGpsInterface = NULL;
+static const GpsNiInterface* sGpsNiInterface = NULL;
+static const GpsDebugInterface* sGpsDebugInterface = NULL;
+static const AGpsRilInterface* sAGpsRilInterface = NULL;
+static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
+
+// temporary storage for GPS callbacks
+static GpsSvStatus sGpsSvStatus;
+static const char* sNmeaString;
+static int sNmeaStringLength;
+
+#define WAKE_LOCK_NAME "GPS"
+
+namespace android {
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+}
+
+static void location_callback(GpsLocation* location)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
+ (jdouble)location->latitude, (jdouble)location->longitude,
+ (jdouble)location->altitude,
+ (jfloat)location->speed, (jfloat)location->bearing,
+ (jfloat)location->accuracy, (jlong)location->timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void status_callback(GpsStatus* status)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void sv_status_callback(GpsSvStatus* sv_status)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
+ env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ // The Java code will call back to read these values
+ // We do this to avoid creating unnecessary String objects
+ sNmeaString = nmea;
+ sNmeaStringLength = length;
+ env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void set_capabilities_callback(uint32_t capabilities)
+{
+ ALOGD("set_capabilities_callback: %du\n", capabilities);
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void acquire_wakelock_callback()
+{
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+}
+
+static void release_wakelock_callback()
+{
+ release_wake_lock(WAKE_LOCK_NAME);
+}
+
+static void request_utc_time_callback()
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
+{
+ return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
+}
+
+GpsCallbacks sGpsCallbacks = {
+ sizeof(GpsCallbacks),
+ location_callback,
+ status_callback,
+ sv_status_callback,
+ nmea_callback,
+ set_capabilities_callback,
+ acquire_wakelock_callback,
+ release_wakelock_callback,
+ create_thread_callback,
+ request_utc_time_callback,
+};
+
+static void xtra_download_request_callback()
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+GpsXtraCallbacks sGpsXtraCallbacks = {
+ xtra_download_request_callback,
+ create_thread_callback,
+};
+
+static void agps_status_callback(AGpsStatus* agps_status)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ uint32_t ipaddr;
+ // ipaddr field was not included in original AGpsStatus
+ if (agps_status->size >= sizeof(AGpsStatus))
+ ipaddr = agps_status->ipaddr;
+ else
+ ipaddr = 0xFFFFFFFF;
+ env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus,
+ agps_status->type, agps_status->status, ipaddr);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+AGpsCallbacks sAGpsCallbacks = {
+ agps_status_callback,
+ create_thread_callback,
+};
+
+static void gps_ni_notify_callback(GpsNiNotification *notification)
+{
+ ALOGD("gps_ni_notify_callback\n");
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jstring requestor_id = env->NewStringUTF(notification->requestor_id);
+ jstring text = env->NewStringUTF(notification->text);
+ jstring extras = env->NewStringUTF(notification->extras);
+
+ if (requestor_id && text && extras) {
+ env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
+ notification->notification_id, notification->ni_type,
+ notification->notify_flags, notification->timeout,
+ notification->default_response, requestor_id, text,
+ notification->requestor_id_encoding,
+ notification->text_encoding, extras);
+ } else {
+ ALOGE("out of memory in gps_ni_notify_callback\n");
+ }
+
+ if (requestor_id)
+ env->DeleteLocalRef(requestor_id);
+ if (text)
+ env->DeleteLocalRef(text);
+ if (extras)
+ env->DeleteLocalRef(extras);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+GpsNiCallbacks sGpsNiCallbacks = {
+ gps_ni_notify_callback,
+ create_thread_callback,
+};
+
+static void agps_request_set_id(uint32_t flags)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void agps_request_ref_location(uint32_t flags)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+AGpsRilCallbacks sAGpsRilCallbacks = {
+ agps_request_set_id,
+ agps_request_ref_location,
+ create_thread_callback,
+};
+
+static void gps_geofence_transition_callback(int32_t geofence_id, GpsLocation* location,
+ int32_t transition, GpsUtcTime timestamp)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
+ location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
+ (jdouble)location->altitude,
+ (jfloat)location->speed, (jfloat)location->bearing,
+ (jfloat)location->accuracy, (jlong)location->timestamp,
+ transition, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jint flags = 0;
+ jdouble latitude = 0;
+ jdouble longitude = 0;
+ jdouble altitude = 0;
+ jfloat speed = 0;
+ jfloat bearing = 0;
+ jfloat accuracy = 0;
+ jlong timestamp = 0;
+ if (location != NULL) {
+ flags = location->flags;
+ latitude = location->latitude;
+ longitude = location->longitude;
+ altitude = location->altitude;
+ speed = location->speed;
+ bearing = location->bearing;
+ accuracy = location->accuracy;
+ timestamp = location->timestamp;
+ }
+
+ env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
+ flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+ ALOGE("Error in geofence_add_callback: %d\n", status);
+ }
+ env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+ ALOGE("Error in geofence_remove_callback: %d\n", status);
+ }
+ env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+ ALOGE("Error in geofence_resume_callback: %d\n", status);
+ }
+ env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+ ALOGE("Error in geofence_pause_callback: %d\n", status);
+ }
+ env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
+ gps_geofence_transition_callback,
+ gps_geofence_status_callback,
+ gps_geofence_add_callback,
+ gps_geofence_remove_callback,
+ gps_geofence_pause_callback,
+ gps_geofence_resume_callback,
+ create_thread_callback,
+};
+
+static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+ int err;
+ hw_module_t* module;
+
+ method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
+ method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
+ method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
+ method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V");
+ method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
+ method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+ method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+ method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
+ "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
+ method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
+ method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
+ method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
+ method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
+ "(IIDDDFFFJIJ)V");
+ method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
+ "(IIDDDFFFJ)V");
+ method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
+ "(II)V");
+ method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
+ "(II)V");
+ method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
+ "(II)V");
+ method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
+ "(II)V");
+
+ err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+ if (err == 0) {
+ hw_device_t* device;
+ err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
+ if (err == 0) {
+ gps_device_t* gps_device = (gps_device_t *)device;
+ sGpsInterface = gps_device->get_gps_interface(gps_device);
+ }
+ }
+ if (sGpsInterface) {
+ sGpsXtraInterface =
+ (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
+ sAGpsInterface =
+ (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ sGpsNiInterface =
+ (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ sGpsDebugInterface =
+ (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
+ sAGpsRilInterface =
+ (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
+ sGpsGeofencingInterface =
+ (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
+ }
+}
+
+static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
+ if (sGpsInterface != NULL) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
+{
+ // this must be set before calling into the HAL library
+ if (!mCallbacksObj)
+ mCallbacksObj = env->NewGlobalRef(obj);
+
+ // fail if the main interface fails to initialize
+ if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ return JNI_FALSE;
+
+ // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
+ // but continue to allow the rest of the GPS interface to work.
+ if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
+ sGpsXtraInterface = NULL;
+ if (sAGpsInterface)
+ sAGpsInterface->init(&sAGpsCallbacks);
+ if (sGpsNiInterface)
+ sGpsNiInterface->init(&sGpsNiCallbacks);
+ if (sAGpsRilInterface)
+ sAGpsRilInterface->init(&sAGpsRilCallbacks);
+ if (sGpsGeofencingInterface)
+ sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
+
+ return JNI_TRUE;
+}
+
+static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
+{
+ if (sGpsInterface)
+ sGpsInterface->cleanup();
+}
+
+static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj,
+ jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time)
+{
+ if (sGpsInterface) {
+ if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
+ preferred_time) == 0) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+ }
+ else
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
+{
+ if (sGpsInterface) {
+ if (sGpsInterface->start() == 0) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+ }
+ else
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
+{
+ if (sGpsInterface) {
+ if (sGpsInterface->stop() == 0) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+ }
+ else
+ return JNI_FALSE;
+}
+
+static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
+{
+ if (sGpsInterface)
+ sGpsInterface->delete_aiding_data(flags);
+}
+
+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 reportSvStatus
+
+ 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 = sGpsSvStatus.num_svs;
+ for (int i = 0; i < num_svs; i++) {
+ prns[i] = sGpsSvStatus.sv_list[i].prn;
+ snrs[i] = sGpsSvStatus.sv_list[i].snr;
+ elev[i] = sGpsSvStatus.sv_list[i].elevation;
+ azim[i] = sGpsSvStatus.sv_list[i].azimuth;
+ }
+ mask[0] = sGpsSvStatus.ephemeris_mask;
+ mask[1] = sGpsSvStatus.almanac_mask;
+ mask[2] = sGpsSvStatus.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 (jint) num_svs;
+}
+
+static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env,
+ jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid)
+{
+ AGpsRefLocation location;
+
+ if (!sAGpsRilInterface) {
+ ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
+ return;
+ }
+
+ switch(type) {
+ case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
+ case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
+ location.type = type;
+ location.u.cellID.mcc = mcc;
+ location.u.cellID.mnc = mnc;
+ location.u.cellID.lac = lac;
+ location.u.cellID.cid = cid;
+ break;
+ default:
+ ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
+ return;
+ break;
+ }
+ sAGpsRilInterface->set_ref_location(&location, sizeof(location));
+}
+
+static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
+ jobject obj, jbyteArray ni_msg, jint size)
+{
+ size_t sz;
+
+ if (!sAGpsRilInterface) {
+ ALOGE("no AGPS RIL interface in send_ni_message");
+ return;
+ }
+ if (size < 0)
+ return;
+ sz = (size_t)size;
+ jbyte* b = env->GetByteArrayElements(ni_msg, 0);
+ sAGpsRilInterface->ni_message((uint8_t *)b,sz);
+ env->ReleaseByteArrayElements(ni_msg,b,0);
+}
+
+static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env,
+ jobject obj, jint type, jstring setid_string)
+{
+ if (!sAGpsRilInterface) {
+ ALOGE("no AGPS RIL interface in agps_set_id");
+ return;
+ }
+
+ const char *setid = env->GetStringUTFChars(setid_string, NULL);
+ sAGpsRilInterface->set_set_id(type, setid);
+ env->ReleaseStringUTFChars(setid_string, setid);
+}
+
+static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
+ jbyteArray nmeaArray, jint buffer_size)
+{
+ // this should only be called from within a call to reportNmea
+ jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
+ int length = sNmeaStringLength;
+ if (length > buffer_size)
+ length = buffer_size;
+ memcpy(nmea, sNmeaString, length);
+ env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
+ return (jint) length;
+}
+
+static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj,
+ jlong time, jlong timeReference, jint uncertainty)
+{
+ if (sGpsInterface)
+ sGpsInterface->inject_time(time, timeReference, uncertainty);
+}
+
+static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
+ jdouble latitude, jdouble longitude, jfloat accuracy)
+{
+ if (sGpsInterface)
+ sGpsInterface->inject_location(latitude, longitude, accuracy);
+}
+
+static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
+{
+ if (sGpsXtraInterface != NULL) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
+ jbyteArray data, jint length)
+{
+ if (!sGpsXtraInterface) {
+ ALOGE("no XTRA interface in inject_xtra_data");
+ return;
+ }
+
+ jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
+ sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
+ env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+}
+
+static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
+{
+ if (!sAGpsInterface) {
+ ALOGE("no AGPS interface in agps_data_conn_open");
+ return;
+ }
+ if (apn == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+ const char *apnStr = env->GetStringUTFChars(apn, NULL);
+ sAGpsInterface->data_conn_open(apnStr);
+ env->ReleaseStringUTFChars(apn, apnStr);
+}
+
+static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
+{
+ if (!sAGpsInterface) {
+ ALOGE("no AGPS interface in agps_data_conn_closed");
+ return;
+ }
+ sAGpsInterface->data_conn_closed();
+}
+
+static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
+{
+ if (!sAGpsInterface) {
+ ALOGE("no AGPS interface in agps_data_conn_failed");
+ return;
+ }
+ sAGpsInterface->data_conn_failed();
+}
+
+static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
+ jint type, jstring hostname, jint port)
+{
+ if (!sAGpsInterface) {
+ ALOGE("no AGPS interface in set_agps_server");
+ return;
+ }
+ const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
+ sAGpsInterface->set_server(type, c_hostname, port);
+ env->ReleaseStringUTFChars(hostname, c_hostname);
+}
+
+static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
+ jint notifId, jint response)
+{
+ if (!sGpsNiInterface) {
+ ALOGE("no NI interface in send_ni_response");
+ return;
+ }
+
+ sGpsNiInterface->respond(notifId, response);
+}
+
+static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
+{
+ jstring result = NULL;
+ if (sGpsDebugInterface) {
+ const size_t maxLength = 2047;
+ char buffer[maxLength+1];
+ size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
+ if (length > maxLength) length = maxLength;
+ buffer[length] = 0;
+ result = env->NewStringUTF(buffer);
+ }
+ return result;
+}
+
+static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
+ jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
+{
+
+ if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
+ if (extraInfo) {
+ const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
+ sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
+ env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
+ } else {
+ sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
+ }
+
+ // update_network_availability callback was not included in original AGpsRilInterface
+ if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
+ && sAGpsRilInterface->update_network_availability) {
+ const char *c_apn = env->GetStringUTFChars(apn, NULL);
+ sAGpsRilInterface->update_network_availability(available, c_apn);
+ env->ReleaseStringUTFChars(apn, c_apn);
+ }
+ }
+}
+
+static jboolean android_location_GpsLocationProvider_is_geofence_supported(JNIEnv* env,
+ jobject obj) {
+ if (sGpsGeofencingInterface != NULL) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* env, jobject obj,
+ jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
+ jint last_transition, jint monitor_transition, jint notification_responsiveness,
+ jint unknown_timer) {
+ if (sGpsGeofencingInterface != NULL) {
+ sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
+ radius, last_transition, monitor_transition, notification_responsiveness,
+ unknown_timer);
+ return JNI_TRUE;
+ } else {
+ ALOGE("Geofence interface not available");
+ }
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* env, jobject obj,
+ jint geofence_id) {
+ if (sGpsGeofencingInterface != NULL) {
+ sGpsGeofencingInterface->remove_geofence_area(geofence_id);
+ return JNI_TRUE;
+ } else {
+ ALOGE("Geofence interface not available");
+ }
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* env, jobject obj,
+ jint geofence_id) {
+ if (sGpsGeofencingInterface != NULL) {
+ sGpsGeofencingInterface->pause_geofence(geofence_id);
+ return JNI_TRUE;
+ } else {
+ ALOGE("Geofence interface not available");
+ }
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* env, jobject obj,
+ jint geofence_id, jint monitor_transition) {
+ if (sGpsGeofencingInterface != NULL) {
+ sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
+ return JNI_TRUE;
+ } else {
+ ALOGE("Geofence interface not available");
+ }
+ return JNI_FALSE;
+}
+
+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_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
+ {"native_set_position_mode", "(IIIII)Z", (void*)android_location_GpsLocationProvider_set_position_mode},
+ {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
+ {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
+ {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
+ {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+ {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
+ {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
+ {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
+ {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
+ {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
+ {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
+ {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
+ {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
+ {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id},
+ {"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
+ {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
+ {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
+ {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
+ {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
+ {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
+ {"native_is_geofence_supported", "()Z", (void*) android_location_GpsLocationProvider_is_geofence_supported},
+ {"native_add_geofence", "(IDDDIIII)Z", (void *)android_location_GpsLocationProvider_add_geofence},
+ {"native_remove_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_remove_geofence},
+ {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
+ {"native_resume_geofence", "(II)Z", (void *)android_location_GpsLocationProvider_resume_geofence}
+};
+
+int register_android_server_location_GpsLocationProvider(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
new file mode 100644
index 0000000..151e134
--- /dev/null
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2010 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 "PowerManagerService-JNI"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <ScopedUtfChars.h>
+
+#include <limits.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Timers.h>
+#include <utils/misc.h>
+#include <utils/String8.h>
+#include <utils/Log.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <suspend/autosuspend.h>
+
+#include "com_android_server_power_PowerManagerService.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct {
+ jmethodID wakeUpFromNative;
+ jmethodID goToSleepFromNative;
+ jmethodID userActivityFromNative;
+} gPowerManagerServiceClassInfo;
+
+// ----------------------------------------------------------------------------
+
+static jobject gPowerManagerServiceObj;
+static struct power_module* gPowerModule;
+
+static Mutex gPowerManagerLock;
+static bool gScreenOn;
+static bool gScreenBright;
+
+static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
+
+// Throttling interval for user activity calls.
+static const nsecs_t MIN_TIME_BETWEEN_USERACTIVITIES = 500 * 1000000L; // 500ms
+
+// ----------------------------------------------------------------------------
+
+static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ return true;
+ }
+ return false;
+}
+
+bool android_server_PowerManagerService_isScreenOn() {
+ AutoMutex _l(gPowerManagerLock);
+ return gScreenOn;
+}
+
+bool android_server_PowerManagerService_isScreenBright() {
+ AutoMutex _l(gPowerManagerLock);
+ return gScreenBright;
+}
+
+void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
+ // Tell the power HAL when user activity occurs.
+ if (gPowerModule && gPowerModule->powerHint) {
+ gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
+ }
+
+ if (gPowerManagerServiceObj) {
+ // Throttle calls into user activity by event type.
+ // We're a little conservative about argument checking here in case the caller
+ // passes in bad data which could corrupt system state.
+ if (eventType >= 0 && eventType <= USER_ACTIVITY_EVENT_LAST) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (eventTime > now) {
+ eventTime = now;
+ }
+
+ if (gLastEventTime[eventType] + MIN_TIME_BETWEEN_USERACTIVITIES > eventTime) {
+ return;
+ }
+ gLastEventTime[eventType] = eventTime;
+ }
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(gPowerManagerServiceObj,
+ gPowerManagerServiceClassInfo.userActivityFromNative,
+ nanoseconds_to_milliseconds(eventTime), eventType, 0);
+ checkAndClearExceptionFromCallback(env, "userActivityFromNative");
+ }
+}
+
+void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
+ if (gPowerManagerServiceObj) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(gPowerManagerServiceObj,
+ gPowerManagerServiceClassInfo.wakeUpFromNative,
+ nanoseconds_to_milliseconds(eventTime));
+ checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
+ }
+}
+
+void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
+ if (gPowerManagerServiceObj) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(gPowerManagerServiceObj,
+ gPowerManagerServiceClassInfo.goToSleepFromNative,
+ nanoseconds_to_milliseconds(eventTime), 0);
+ checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static void nativeInit(JNIEnv* env, jobject obj) {
+ gPowerManagerServiceObj = env->NewGlobalRef(obj);
+
+ status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&gPowerModule);
+ if (!err) {
+ gPowerModule->init(gPowerModule);
+ } else {
+ ALOGE("Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
+ }
+}
+
+static void nativeSetPowerState(JNIEnv* env,
+ jclass clazz, jboolean screenOn, jboolean screenBright) {
+ AutoMutex _l(gPowerManagerLock);
+ gScreenOn = screenOn;
+ gScreenBright = screenBright;
+}
+
+static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+ ScopedUtfChars name(env, nameStr);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
+}
+
+static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+ ScopedUtfChars name(env, nameStr);
+ release_wake_lock(name.c_str());
+}
+
+static void nativeSetInteractive(JNIEnv *env, jclass clazz, jboolean enable) {
+ if (gPowerModule) {
+ if (enable) {
+ ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
+ gPowerModule->setInteractive(gPowerModule, true);
+ } else {
+ ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
+ gPowerModule->setInteractive(gPowerModule, false);
+ }
+ }
+}
+
+static void nativeSetAutoSuspend(JNIEnv *env, jclass clazz, jboolean enable) {
+ if (enable) {
+ ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
+ autosuspend_enable();
+ } else {
+ ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on");
+ autosuspend_disable();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gPowerManagerServiceMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeInit", "()V",
+ (void*) nativeInit },
+ { "nativeSetPowerState", "(ZZ)V",
+ (void*) nativeSetPowerState },
+ { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
+ (void*) nativeAcquireSuspendBlocker },
+ { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
+ (void*) nativeReleaseSuspendBlocker },
+ { "nativeSetInteractive", "(Z)V",
+ (void*) nativeSetInteractive },
+ { "nativeSetAutoSuspend", "(Z)V",
+ (void*) nativeSetAutoSuspend },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_PowerManagerService(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService",
+ gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ // Callbacks
+
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
+
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
+ "wakeUpFromNative", "(J)V");
+
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
+ "goToSleepFromNative", "(JI)V");
+
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
+ "userActivityFromNative", "(JII)V");
+
+ // Initialize
+ for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
+ gLastEventTime[i] = LLONG_MIN;
+ }
+ gScreenOn = true;
+ gScreenBright = true;
+ gPowerManagerServiceObj = NULL;
+ gPowerModule = NULL;
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
new file mode 100644
index 0000000..0808b80
--- /dev/null
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 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_SERVER_POWER_MANAGER_SERVICE_H
+#define _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <androidfw/PowerManager.h>
+
+namespace android {
+
+extern bool android_server_PowerManagerService_isScreenOn();
+extern bool android_server_PowerManagerService_isScreenBright();
+extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
+extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
+extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
new file mode 100644
index 0000000..efc34a2
--- /dev/null
+++ b/services/core/jni/onload.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 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"
+
+namespace android {
+int register_android_server_AlarmManagerService(JNIEnv* env);
+int register_android_server_ConsumerIrService(JNIEnv *env);
+int register_android_server_InputApplicationHandle(JNIEnv* env);
+int register_android_server_InputWindowHandle(JNIEnv* env);
+int register_android_server_InputManager(JNIEnv* env);
+int register_android_server_LightsService(JNIEnv* env);
+int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_SerialService(JNIEnv* env);
+int register_android_server_UsbDeviceManager(JNIEnv* env);
+int register_android_server_UsbHostManager(JNIEnv* env);
+int register_android_server_VibratorService(JNIEnv* env);
+int register_android_server_SystemServer(JNIEnv* env);
+int register_android_server_location_GpsLocationProvider(JNIEnv* env);
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
+int register_android_server_connectivity_Vpn(JNIEnv* env);
+int register_android_server_AssetAtlasService(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) {
+ ALOGE("GetEnv failed!");
+ return result;
+ }
+ ALOG_ASSERT(env, "Could not retrieve the env!");
+
+ register_android_server_PowerManagerService(env);
+ register_android_server_SerialService(env);
+ register_android_server_InputApplicationHandle(env);
+ register_android_server_InputWindowHandle(env);
+ register_android_server_InputManager(env);
+ register_android_server_LightsService(env);
+ register_android_server_AlarmManagerService(env);
+ register_android_server_UsbDeviceManager(env);
+ register_android_server_UsbHostManager(env);
+ register_android_server_VibratorService(env);
+ register_android_server_SystemServer(env);
+ register_android_server_location_GpsLocationProvider(env);
+ register_android_server_location_FlpHardwareProvider(env);
+ register_android_server_connectivity_Vpn(env);
+ register_android_server_AssetAtlasService(env);
+ register_android_server_ConsumerIrService(env);
+
+
+ return JNI_VERSION_1_4;
+}