Index: device/sensors/android/java/src/org/chromium/device/sensors/SensorBase.java |
diff --git a/device/sensors/android/java/src/org/chromium/device/sensors/SensorBase.java b/device/sensors/android/java/src/org/chromium/device/sensors/SensorBase.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f72a1e89db64b5370d3fd6624cc0dddce51a147a |
--- /dev/null |
+++ b/device/sensors/android/java/src/org/chromium/device/sensors/SensorBase.java |
@@ -0,0 +1,233 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.device.sensors; |
+ |
+import android.hardware.Sensor; |
+import android.hardware.SensorEvent; |
+import android.hardware.SensorEventListener; |
+import android.hardware.SensorManager; |
+import android.os.Build; |
+import android.os.Handler; |
+ |
+import org.chromium.mojo.system.SharedBufferHandle; |
+import org.chromium.mojom.device.sensors.SensorConfiguration; |
+import org.chromium.mojom.device.sensors.ReportingMode; |
+ |
+import java.util.HashMap; |
+import java.util.List; |
+import java.util.Map; |
+ |
+import java.nio.ByteBuffer; |
+import java.nio.ByteOrder; |
+import java.nio.BufferOverflowException; |
+ |
+/** |
+ * Base interface for Sensors |
+ */ |
+public abstract class SensorBase implements SensorEventListener { |
+ private static final double MICROSECONDS_PER_SECOND = 1000000; |
+ private final Sensor mSensor; |
+ private final SensorManager mSensorManager; |
+ private final SensorStateObserver mSensorStateObserver; |
+ private final Map<SensorProxy, Boolean> mSensorProxies = new HashMap<SensorProxy, Boolean>(); |
+ private final SharedBufferHandle mSharedBufferHandle; |
+ private final Handler mHandler; |
+ private final long mSize; |
+ private final long mOffset; |
+ private final int mMinDelay; |
+ private SensorConfiguration mCurrentConfiguration; |
+ private ByteBuffer mSharedBuffer; |
+ private ByteBuffer mSensorReadingData; |
+ |
+ protected SensorBase(int sensorType, SensorManager manager, Handler handler, |
+ SharedBufferHandle handle, long offset, long size, SensorStateObserver observer) |
+ throws SensorException { |
+ if (handle == null || !handle.isValid()) throw new SensorException(); |
+ mSensorManager = manager; |
+ mHandler = handler; |
+ mSensorStateObserver = observer; |
+ mSharedBufferHandle = handle; |
+ mSize = size; |
+ mOffset = offset; |
+ List<Sensor> sensors = mSensorManager.getSensorList(sensorType); |
+ if (sensors.isEmpty()) throw new SensorException(); |
+ mSensor = sensors.get(0); |
+ mMinDelay = mSensor.getMinDelay(); |
+ } |
+ |
+ public int reportingMode() { |
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
+ return mSensor.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS ? |
+ ReportingMode.CONTINUOUS : ReportingMode.ON_CHANGE; |
+ } |
+ return ReportingMode.CONTINUOUS; |
+ } |
+ |
+ public abstract int getType(); |
+ protected abstract void fillSensorReadingData(SensorEvent event, ByteBuffer buffer) |
+ throws SensorException; |
+ |
+ public boolean startListening(SensorProxy proxy) { |
+ if (proxy == null) return false; |
+ |
+ if (!mapSharedBuffer()) { |
+ return false; |
+ } |
+ |
+ setSensorListening(proxy); |
+ SensorConfiguration configuration = optimalConfiguration(); |
+ return restartIfNeeded(configuration); |
+ } |
+ |
+ private SensorConfiguration optimalConfiguration() { |
+ SensorConfigurations configurations = new SensorConfigurations(); |
+ for (Map.Entry<SensorProxy, Boolean> entry : mSensorProxies.entrySet()) { |
+ if (entry.getValue() == true) { |
+ configurations.add(entry.getKey().getCurrentConfiguration()); |
+ } |
+ } |
+ if (!configurations.isEmpty()) |
+ return configurations.get(0); |
+ return null; |
+ } |
+ |
+ public boolean stopListening(SensorProxy proxy) { |
+ if (proxy == null) return false; |
+ |
+ SensorConfiguration configuration = optimalConfiguration(); |
+ setSensorNotListening(proxy); |
+ |
+ if (hasListeners()) { |
+ return restartIfNeeded(configuration); |
+ } else { |
+ stopListening(); |
+ } |
+ |
+ return true; |
+ } |
+ |
+ public boolean configuratoinUpdated() { |
+ return restartIfNeeded(optimalConfiguration()); |
+ } |
+ |
+ public boolean restartIfNeeded(SensorConfiguration configuration) { |
+ boolean restarted = true; |
+ if (configuration != null && configuration != mCurrentConfiguration) { |
+ SensorConfiguration oldConfiguration = mCurrentConfiguration; |
+ mCurrentConfiguration = configuration; |
+ stopListening(); |
+ restarted = startListening(); |
+ if (!restarted) { |
+ mCurrentConfiguration = oldConfiguration; |
+ startListening(); |
+ } |
+ } |
+ return restarted; |
+ } |
+ |
+ private boolean startListening() { |
+ int samplingFrequency = getSamplingFrequency(); |
+ if (samplingFrequency < mMinDelay) return false; |
+ return mSensorManager.registerListener(this, mSensor, samplingFrequency, mHandler); |
+ } |
+ |
+ private void stopListening() { |
+ mSensorManager.unregisterListener(this); |
+ } |
+ |
+ public void addSensorProxy(SensorProxy proxy) { |
+ mSensorProxies.put(proxy, false); |
+ } |
+ |
+ public void removeSensorProxy(SensorProxy proxy) { |
+ mSensorProxies.remove(proxy); |
+ if (mSensorProxies.isEmpty()) { |
+ stopListening(); |
+ mSensorStateObserver.onSensorNotInUse(this); |
+ } |
+ } |
+ |
+ private int getSamplingFrequency() { |
+ if (mCurrentConfiguration == null) |
+ return getDefaultSamplingFrequency(); |
+ |
+ if (mCurrentConfiguration.frequency > 0) { |
+ return (int)((1 / mCurrentConfiguration.frequency) * MICROSECONDS_PER_SECOND); |
+ } else { |
+ return getDefaultSamplingFrequency(); |
+ } |
+ } |
+ |
+ private int getDefaultSamplingFrequency() { |
+ return SensorManager.SENSOR_DELAY_NORMAL; |
+ } |
+ |
+ private void setSensorListening(SensorProxy proxy) { |
+ setSensorFlag(proxy, true); |
+ } |
+ |
+ private void setSensorNotListening(SensorProxy proxy) { |
+ setSensorFlag(proxy, false); |
+ } |
+ |
+ private void setSensorFlag(SensorProxy proxy, boolean listening) { |
+ if (mSensorProxies.containsKey(proxy)) { |
+ mSensorProxies.put(proxy, listening); |
+ } |
+ } |
+ |
+ protected boolean hasListeners() { |
+ for (Map.Entry<SensorProxy, Boolean> entry : mSensorProxies.entrySet()) { |
+ if (entry.getValue() == true) return true; |
+ } |
+ return false; |
+ } |
+ |
+ private boolean isValidConfiguration(SensorConfiguration configuration) { |
+ return true; |
+ } |
+ |
+ private boolean mapSharedBuffer() { |
+ if (mSharedBuffer == null) { |
+ mSharedBuffer = mSharedBufferHandle.map(mOffset, mSize, SharedBufferHandle.MapFlags.none()); |
+ mSensorReadingData = ByteBuffer.allocate(mSharedBuffer.capacity()); |
+ mSensorReadingData.order(ByteOrder.nativeOrder()); |
+ } |
+ |
+ return mSharedBuffer != null; |
+ } |
+ |
+ @Override |
+ public void onAccuracyChanged(Sensor sensor, int accuracy) { } |
+ |
+ @Override |
+ public void onSensorChanged(SensorEvent event) { |
+ try { |
+ mSensorReadingData.mark(); |
+ // Timestamp in milliseconds |
+ mSensorReadingData.putDouble(event.timestamp * 0.000001d); |
+ fillSensorReadingData(event, mSensorReadingData); |
+ |
+ mSensorReadingData.reset(); |
+ |
+ mSharedBuffer.mark(); |
+ mSharedBuffer.put(mSensorReadingData); |
+ mSensorReadingData.reset(); |
+ mSharedBuffer.reset(); |
+ |
+ if (reportingMode() == ReportingMode.ON_CHANGE) { |
+ for (Map.Entry<SensorProxy, Boolean> entry : mSensorProxies.entrySet()) { |
+ if (entry.getValue() == true) { |
+ entry.getKey().reportSensorReadingChaned(); |
+ } |
+ } |
+ } |
+ } catch (BufferOverflowException | SensorException e) { |
+ for (SensorProxy proxy : mSensorProxies.keySet()) { |
+ proxy.reportError(); |
+ } |
+ } |
+ } |
+}; |