diff --git a/api/current.txt b/api/current.txt index 16cfff2d84b86..072d4bbf2cf7a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14208,6 +14208,7 @@ package android.hardware { public final class Sensor { method public int getFifoMaxEventCount(); method public int getFifoReservedEventCount(); + method public int getHighestDirectReportRateLevel(); method public int getId(); method public int getMaxDelay(); method public float getMaximumRange(); @@ -14221,6 +14222,7 @@ package android.hardware { method public java.lang.String getVendor(); method public int getVersion(); method public boolean isAdditionalInfoSupported(); + method public boolean isDirectChannelTypeSupported(int); method public boolean isDynamicSensor(); method public boolean isWakeUpSensor(); field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0 @@ -14298,6 +14300,17 @@ package android.hardware { field public final int type; } + public final class SensorDirectChannel implements java.lang.AutoCloseable { + method public void close(); + method public boolean isValid(); + field public static final int RATE_FAST = 2; // 0x2 + field public static final int RATE_NORMAL = 1; // 0x1 + field public static final int RATE_STOP = 0; // 0x0 + field public static final int RATE_VERY_FAST = 3; // 0x3 + field public static final int TYPE_ASHMEM = 1; // 0x1 + field public static final int TYPE_HARDWARE_BUFFER = 2; // 0x2 + } + public class SensorEvent { field public int accuracy; field public android.hardware.Sensor sensor; @@ -14329,6 +14342,9 @@ package android.hardware { public abstract class SensorManager { method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor); + method public int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int); + method public android.hardware.SensorDirectChannel createDirectChannel(android.os.MemoryFile); + method public android.hardware.SensorDirectChannel createDirectChannel(android.hardware.HardwareBuffer); method public boolean flush(android.hardware.SensorEventListener); method public static float getAltitude(float, float); method public static void getAngleChange(float[], float[], float[]); diff --git a/api/system-current.txt b/api/system-current.txt index 066f9ce6366ed..8a18190306c7d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -14766,6 +14766,7 @@ package android.hardware { public final class Sensor { method public int getFifoMaxEventCount(); method public int getFifoReservedEventCount(); + method public int getHighestDirectReportRateLevel(); method public int getId(); method public int getMaxDelay(); method public float getMaximumRange(); @@ -14781,6 +14782,7 @@ package android.hardware { method public int getVersion(); method public boolean isAdditionalInfoSupported(); method public boolean isDataInjectionSupported(); + method public boolean isDirectChannelTypeSupported(int); method public boolean isDynamicSensor(); method public boolean isWakeUpSensor(); field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0 @@ -14862,6 +14864,17 @@ package android.hardware { field public final int type; } + public final class SensorDirectChannel implements java.lang.AutoCloseable { + method public void close(); + method public boolean isValid(); + field public static final int RATE_FAST = 2; // 0x2 + field public static final int RATE_NORMAL = 1; // 0x1 + field public static final int RATE_STOP = 0; // 0x0 + field public static final int RATE_VERY_FAST = 3; // 0x3 + field public static final int TYPE_ASHMEM = 1; // 0x1 + field public static final int TYPE_HARDWARE_BUFFER = 2; // 0x2 + } + public class SensorEvent { field public int accuracy; field public android.hardware.Sensor sensor; @@ -14893,6 +14906,9 @@ package android.hardware { public abstract class SensorManager { method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor); + method public int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int); + method public android.hardware.SensorDirectChannel createDirectChannel(android.os.MemoryFile); + method public android.hardware.SensorDirectChannel createDirectChannel(android.hardware.HardwareBuffer); method public boolean flush(android.hardware.SensorEventListener); method public static float getAltitude(float, float); method public static void getAngleChange(float[], float[], float[]); diff --git a/api/test-current.txt b/api/test-current.txt index f0c628ceadac0..057d5a45f1aea 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -14240,6 +14240,7 @@ package android.hardware { public final class Sensor { method public int getFifoMaxEventCount(); method public int getFifoReservedEventCount(); + method public int getHighestDirectReportRateLevel(); method public int getId(); method public int getMaxDelay(); method public float getMaximumRange(); @@ -14253,6 +14254,7 @@ package android.hardware { method public java.lang.String getVendor(); method public int getVersion(); method public boolean isAdditionalInfoSupported(); + method public boolean isDirectChannelTypeSupported(int); method public boolean isDynamicSensor(); method public boolean isWakeUpSensor(); field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0 @@ -14330,6 +14332,17 @@ package android.hardware { field public final int type; } + public final class SensorDirectChannel implements java.lang.AutoCloseable { + method public void close(); + method public boolean isValid(); + field public static final int RATE_FAST = 2; // 0x2 + field public static final int RATE_NORMAL = 1; // 0x1 + field public static final int RATE_STOP = 0; // 0x0 + field public static final int RATE_VERY_FAST = 3; // 0x3 + field public static final int TYPE_ASHMEM = 1; // 0x1 + field public static final int TYPE_HARDWARE_BUFFER = 2; // 0x2 + } + public class SensorEvent { field public int accuracy; field public android.hardware.Sensor sensor; @@ -14361,6 +14374,9 @@ package android.hardware { public abstract class SensorManager { method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor); + method public int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int); + method public android.hardware.SensorDirectChannel createDirectChannel(android.os.MemoryFile); + method public android.hardware.SensorDirectChannel createDirectChannel(android.hardware.HardwareBuffer); method public boolean flush(android.hardware.SensorEventListener); method public static float getAltitude(float, float); method public static void getAngleChange(float[], float[], float[]); diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index 06ab13e9c0a5d..d87c55e1c7c79 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -729,14 +729,22 @@ public final class Sensor { private static final int DATA_INJECTION_MASK = 0x10; private static final int DATA_INJECTION_SHIFT = 4; - // MASK for dynamic sensor (sensor that added during runtime), bit 6. + // MASK for dynamic sensor (sensor that added during runtime), bit 5. private static final int DYNAMIC_SENSOR_MASK = 0x20; private static final int DYNAMIC_SENSOR_SHIFT = 5; - // MASK for indication bit of sensor additional information support (bit 7). + // MASK for indication bit of sensor additional information support, bit 6. private static final int ADDITIONAL_INFO_MASK = 0x40; private static final int ADDITIONAL_INFO_SHIFT = 6; + // Mask for direct mode highest rate level, bit 7, 8, 9. + private static final int DIRECT_REPORT_MASK = 0x380; + private static final int DIRECT_REPORT_SHIFT = 7; + + // Mask for supported direct channel, bit 10, 11 + private static final int DIRECT_CHANNEL_MASK = 0xC00; + private static final int DIRECT_CHANNEL_SHIFT = 10; + // TODO(): The following arrays are fragile and error-prone. This needs to be refactored. // Note: This needs to be updated, whenever a new sensor is added. @@ -796,6 +804,42 @@ public final class Sensor { return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT); } + /** + * Get the highest supported direct report mode rate level of the sensor. + * + * @return Highest direct report rate level of this sensor. If the sensor does not support + * direct report mode, this returns {@link SensorDirectChannel#RATE_STOP}. + * @see SensorDirectChannel#RATE_STOP + * @see SensorDirectChannel#RATE_NORMAL + * @see SensorDirectChannel#RATE_FAST + * @see SensorDirectChannel#RATE_VERY_FAST + */ + @SensorDirectChannel.RateLevel + public int getHighestDirectReportRateLevel() { + int rateLevel = ((mFlags & DIRECT_REPORT_MASK) >> DIRECT_REPORT_SHIFT); + return rateLevel <= SensorDirectChannel.RATE_VERY_FAST + ? rateLevel : SensorDirectChannel.RATE_VERY_FAST; + } + + /** + * Test if sensor support direct channel backed by a specific type of shared memory. + * + * @param sharedMemType type of shared memory used by direct channel. + * @return true if the shared memory type is supported. + * @see SensorDirectChannel#TYPE_ASHMEM + * @see SensorDirectChannel#TYPE_HARDWARE_BUFFER + */ + public boolean isDirectChannelTypeSupported(@SensorDirectChannel.MemoryType int sharedMemType) { + switch (sharedMemType) { + case SensorDirectChannel.TYPE_ASHMEM: + return (mFlags & (1 << DIRECT_CHANNEL_SHIFT)) > 0; + case SensorDirectChannel.TYPE_HARDWARE_BUFFER: + return (mFlags & (1 << DIRECT_CHANNEL_SHIFT + 1)) > 0; + default: + return false; + } + } + static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) { // RotationVector length has changed to 3 to 5 for API level 18 // Set it to 3 for backward compatibility. diff --git a/core/java/android/hardware/SensorDirectChannel.java b/core/java/android/hardware/SensorDirectChannel.java new file mode 100644 index 0000000000000..0efd62b463f8f --- /dev/null +++ b/core/java/android/hardware/SensorDirectChannel.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware; + +import android.annotation.IntDef; +import android.os.MemoryFile; + +import dalvik.system.CloseGuard; + +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Class representing a sensor direct channel. Use {@link + * SensorManager#createDirectChannel(android.os.MemoryFile)} to obtain object. + */ +public final class SensorDirectChannel implements AutoCloseable { + + // shared memory types + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = {TYPE_ASHMEM, TYPE_HARDWARE_BUFFER}) + public @interface MemoryType {}; + /** + * Shared memory type ashmem, wrapped in MemoryFile object. + * + * @see SensorManager#createDirectChannel(MemoryFile) + */ + public static final int TYPE_ASHMEM = 1; + + /** + * Shared memory type wrapped by HardwareBuffer object. + * + * @see SensorManager#createDirectChannel(HardwareBuffer) + */ + public static final int TYPE_HARDWARE_BUFFER = 2; + + // sensor rate levels + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = {RATE_STOP, RATE_NORMAL, RATE_FAST, RATE_VERY_FAST}) + public @interface RateLevel {}; + + /** + * Sensor stopped (no event output). + * + * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int) + */ + public static final int RATE_STOP = 0; + /** + * Sensor operates at nominal rate of 50Hz. + * + * The actual rate is expected to be between 55% to 220% of nominal rate, thus between 27.5Hz to + * 110Hz. + * + * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int) + */ + public static final int RATE_NORMAL = 1; //50Hz + /** + * Sensor operates at nominal rate of 200Hz. + * + * The actual rate is expected to be between 55% to 220% of nominal rate, thus between 110Hz to + * 440Hz. + * + * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int) + */ + public static final int RATE_FAST = 2; // ~200Hz + /** + * Sensor operates at nominal rate of 800Hz. + * + * The actual rate is expected to be between 55% to 220% of nominal rate, thus between 440Hz to + * 1760Hz. + * + * @see SensorManager#configureDirectChannel(SensorDirectChannel, Sensor, int) + */ + public static final int RATE_VERY_FAST = 3; // ~800Hz + + /** + * Determine if a channel is still valid. A channel is invalidated after {@link #close()} is + * called. + * + * @return true if channel is valid. + */ + public boolean isValid() { + return !mClosed.get(); + } + + /** + * Close sensor direct channel. + * + * Stop all active sensor in the channel and free sensor system resource related to channel. + * Shared memory used for creating the direct channel need to be closed or freed separately. + * + * @see SensorManager#createDirectChannel(MemoryFile) + * @see SensorManager#createDirectChannel(HardwareBuffer) + */ + @Override + public void close() { + mCloseGuard.close(); + if (mClosed.compareAndSet(false, true)) { + // actual close action + mManager.destroyDirectChannel(this); + } + } + + /** @hide */ + SensorDirectChannel(SensorManager manager, int id, int type, long size) { + mManager = manager; + mNativeHandle = id; + mType = type; + mSize = size; + mCloseGuard.open("SensorDirectChannel"); + } + + /** @hide */ + int getNativeHandle() { + return mNativeHandle; + } + + /** + * This function encode handle information in {@link android.os.Memory} into a long array to be + * passed down to native methods. + * + * @hide */ + static long[] encodeData(MemoryFile ashmem) { + int fd; + try { + fd = ashmem.getFileDescriptor().getInt$(); + } catch (IOException e) { + fd = -1; + } + return new long[] { 1 /*numFds*/, 0 /*numInts*/, fd }; + } + + @Override + protected void finalize() throws Throwable { + try { + mCloseGuard.warnIfOpen(); + close(); + } finally { + super.finalize(); + } + } + + private final AtomicBoolean mClosed = new AtomicBoolean(); + private final CloseGuard mCloseGuard = CloseGuard.get(); + private final SensorManager mManager; + private final int mNativeHandle; + private final long mSize; + private final int mType; +} diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 3ccac692be913..cfda2f4fa8b48 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -19,6 +19,7 @@ package android.hardware; import android.annotation.SystemApi; import android.os.Build; import android.os.Handler; +import android.os.MemoryFile; import android.util.Log; import android.util.SparseArray; @@ -880,6 +881,104 @@ public abstract class SensorManager { protected abstract boolean flushImpl(SensorEventListener listener); + /** + * Create a sensor direct channel backed by shared memory wrapped by MemoryFile object. + * + * Use the returned {@link android.hardware.SensorDirectChannel} object to configure direct + * report of sensor events. After use, call {@link android.hardware.SensorDirectChannel#close()} + * to free up resource in sensor system associated with the direct channel. + * + * @param mem A {@link android.os.MemoryFile} shared memory object. + * @return A {@link android.hardware.SensorDirectChannel} object if successful, null otherwise. + * @throws IllegalArgumentException when mem is null. + * @see SensorDirectChannel#close() + * @see #configureDirectChannel(SensorDirectChannel, Sensor, int) + */ + public SensorDirectChannel createDirectChannel(MemoryFile mem) { + return createDirectChannelImpl(mem.length(), mem, null); + } + + /** + * Create a sensor direct channel backed by shared memory wrapped by HardwareBuffer object. + * + * Use the returned {@link android.hardware.SensorDirectChannel} object to configure direct + * report of sensor events. After use, call {@link android.hardware.SensorDirectChannel#close()} + * to free up resource in sensor system associated with the direct channel. + * + * @param mem A {@link android.hardware.HardwareBuffer} shared memory object. + * @return A {@link android.hardware.SensorDirectChannel} object if successful, + * null otherwise. + * @throws IllegalArgumentException when mem is null. + * @see SensorDirectChannel#close() + * @see #configureDirectChannel(SensorDirectChannel, Sensor, int) + */ + public SensorDirectChannel createDirectChannel(HardwareBuffer mem) { + return null; + } + + /** @hide */ + protected abstract SensorDirectChannel createDirectChannelImpl(long size, + MemoryFile ashmemFile, HardwareBuffer hardwareBuffer); + + /** @hide */ + void destroyDirectChannel(SensorDirectChannel channel) { + destroyDirectChannelImpl(channel); + } + + /** @hide */ + protected abstract void destroyDirectChannelImpl(SensorDirectChannel channel); + + /** + * Configure sensor rate or stop sensor report on a direct report channel specified. + * + * To start event report of a sensor, or change rate of existing report, call this function with + * rateLevel other than {@link android.hardware.SensorDirectChannel#RATE_STOP}. Sensor events + * will be added into a queue formed by the shared memory used in creation of direction channel. + * Each element of the queue has size of 104 bytes and represents a sensor event. Data + * structure of an element (all fields in little-endian): + * + * offset type name + *- --------------------------------------------- + * 0x0000 int32_t size (always 104) + * 0x0004 int32_t sensor report token + * 0x0008 int32_t type (see SensorType) + * 0x000C uint32_t atomic counter + * 0x0010 int64_t timestamp (see Event) + * 0x0018 float[16]/int64_t[8] data (data type depends on sensor type) + * 0x0058 int32_t[4] reserved (set to zero) + * + * There is no head or tail pointers. The sequence and frontier of new sensor events is + * determined by the atomic counter, which counts from 1 after creation of direct channel and + * increments 1 for each new event. The writer in sensor system will wrap around from to + * start of shared memory region when it reaches the end. If size of memory region is not + * a multiple of size of element (104 bytes), the residual is not used at the end. + * Function returns a positive sensor report token on success. This token can be used for + * differentiate sensor events from multiple sensor of the same type. For example, if there are + * two accelerometer in the system A and B, it is guaranteed different report tokens will be + * returned when starting sensor A and B. + * + * To stop a sensor, call this function with rateLevel equal {@link + * android.hardware.SensorDirectChannel#RATE_STOP}. If the sensor parameter is left to be null, + * this will stop all active sensor report associated with the direct channel specified. + * Function return 1 on success or 0 on failure. + * + * @param channel A {@link android.hardware.SensorDirectChannel} object representing direct + * channel to be configured. + * @param sensor A {@link android.hardware.Sensor} object to denote sensor to be operated. + * @param rateLevel rate level defined in {@link android.hardware.SensorDirectChannel}. + * @return starting report or changing rate: positive sensor report token on success, 0 on failure; + * stopping report: 1 on success, 0 on failure. + * @throws IllegalArgumentException when SensorDirectChannel is null. + */ + public int configureDirectChannel(SensorDirectChannel channel, Sensor sensor, + @SensorDirectChannel.RateLevel int rateLevel) { + return configureDirectChannelImpl(channel, sensor, rateLevel); + } + + /** @hide */ + protected abstract int configureDirectChannelImpl( + SensorDirectChannel channel, Sensor s, int rate); + /** * Used for receiving notifications from the SensorManager when dynamic sensors are connected or * disconnected. diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 259ca032918b7..4992def7de152 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -24,6 +24,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; +import android.os.MemoryFile; import android.os.MessageQueue; import android.util.Log; import android.util.SparseArray; @@ -57,6 +58,13 @@ public class SystemSensorManager extends SensorManager { private static native void nativeGetDynamicSensors(long nativeInstance, List list); private static native boolean nativeIsDataInjectionEnabled(long nativeInstance); + private static native int nativeCreateDirectChannel( + long nativeInstance, long size, int channelType, long [] channelData); + private static native void nativeDestroyDirectChannel( + long nativeInstance, int channelHandle); + private static native int nativeConfigDirectChannel( + long nativeInstance, int channelHandle, int sensorHandle, int rate); + private static final Object sLock = new Object(); @GuardedBy("sLock") private static boolean sNativeClassInited = false; @@ -484,6 +492,71 @@ public class SystemSensorManager extends SensorManager { return changed; } + /** @hide */ + protected int configureDirectChannelImpl( + SensorDirectChannel channel, Sensor sensor, int rate) { + if (channel == null) throw new IllegalArgumentException("channel cannot be null"); + + if (!channel.isValid()) { + throw new IllegalStateException("channel is invalid"); + } + + if (rate < SensorDirectChannel.RATE_STOP + || rate > SensorDirectChannel.RATE_VERY_FAST) { + throw new IllegalArgumentException("rate parameter invalid"); + } + + if (sensor == null && rate != SensorDirectChannel.RATE_STOP) { + // the stop all sensors case + throw new IllegalArgumentException( + "when sensor is null, rate can only be DIRECT_RATE_STOP"); + } + + int sensorHandle = (sensor == null) ? -1 : sensor.getHandle(); + + int ret = nativeConfigDirectChannel( + mNativeInstance, channel.getNativeHandle(), sensorHandle, rate); + + if (rate == SensorDirectChannel.RATE_STOP) { + return (ret == 0) ? 1 : 0; + } else { + return (ret > 0) ? ret : 0; + } + } + + /** @hide */ + protected SensorDirectChannel createDirectChannelImpl(long size, + MemoryFile ashmemFile, HardwareBuffer grallocMemObject) { + SensorDirectChannel ch = null; + + if (size <= 0) throw new IllegalArgumentException("size has to be greater than 0"); + + if (ashmemFile != null) { + if (size != ashmemFile.length()) { + throw new IllegalArgumentException("size has to match MemoryFile.length()"); + } + int id = nativeCreateDirectChannel( + mNativeInstance, size, SensorDirectChannel.TYPE_ASHMEM, + SensorDirectChannel.encodeData(ashmemFile)); + if (id > 0) { + ch = new SensorDirectChannel(this, id, SensorDirectChannel.TYPE_ASHMEM, size); + } + } else if (grallocMemObject != null) { + Log.wtf(TAG, "Implement GRALLOC or remove GRALLOC support entirely"); + } else { + throw new IllegalArgumentException("Invalid parameter"); + } + + return ch; + } + + /** @hide */ + protected void destroyDirectChannelImpl(SensorDirectChannel channel) { + if (channel != null) { + nativeDestroyDirectChannel(mNativeInstance, channel.getNativeHandle()); + } + } + /* * BaseEventQueue is the communication channel with the sensor service, * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index 271f24b130524..bc2fc1c398906 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -243,6 +244,54 @@ static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong s return mgr->isDataInjectionEnabled(); } +static jint nativeCreateDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager, + jlong size, jint channelType, jlongArray channelData) { + jint ret = -1; + jsize len = _env->GetArrayLength(channelData); + if (len > 2) { + jlong *data = _env->GetLongArrayElements(channelData, NULL); + if (data != nullptr) { + // construct native handle from jlong* + jlong numFd = data[0]; + jlong numInt = data[1]; + if ((numFd + numInt + 2) == len) { + native_handle_t *nativeHandle = native_handle_create(numFd, numInt); + if (nativeHandle != nullptr) { + const jlong *readPointer = data + 2; + int *writePointer = nativeHandle->data; + size_t n = static_cast(numFd + numInt); + while (n--) { + // native type of data is int, jlong is just to ensure Java does not + // truncate data on 64-bit system. The cast here is safe. + *writePointer++ = static_cast(*readPointer++); + } + + SensorManager* mgr = reinterpret_cast(sensorManager); + ret = mgr->createDirectChannel(size, channelType, nativeHandle); + + // do not native_handle_close() here as handle is owned by java + native_handle_delete(nativeHandle); + } + } + // unidirectional parameter passing, thus JNI_ABORT + _env->ReleaseLongArrayElements(channelData, data, JNI_ABORT); + } + } + return ret; +} + +static void nativeDestroyDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager, + jint channelHandle) { + SensorManager* mgr = reinterpret_cast(sensorManager); + mgr->destroyDirectChannel(channelHandle); +} + +static jint nativeConfigDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager, + jint channelHandle, jint sensorHandle, jint rate) { + SensorManager* mgr = reinterpret_cast(sensorManager); + return mgr->configureDirectChannel(channelHandle, sensorHandle, rate); +} + //---------------------------------------------------------------------------- class Receiver : public LooperCallback { @@ -447,7 +496,19 @@ static const JNINativeMethod gSystemSensorManagerMethods[] = { {"nativeIsDataInjectionEnabled", "(J)Z", - (void*)nativeIsDataInjectionEnabled}, + (void*)nativeIsDataInjectionEnabled }, + + {"nativeCreateDirectChannel", + "(JJI[J)I", + (void*)nativeCreateDirectChannel }, + + {"nativeDestroyDirectChannel", + "(JI)V", + (void*)nativeDestroyDirectChannel }, + + {"nativeConfigDirectChannel", + "(JIII)I", + (void*)nativeConfigDirectChannel }, }; static const JNINativeMethod gBaseEventQueueMethods[] = {