This repository has been archived by the owner on Dec 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
695 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
325 changes: 325 additions & 0 deletions
325
src/main/java/org/chromium/device/sensors/PlatformSensor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,325 @@ | ||
// 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 androidx.annotation.GuardedBy; | ||
|
||
import org.chromium.base.Log; | ||
import org.chromium.base.annotations.CalledByNative; | ||
import org.chromium.base.annotations.JNINamespace; | ||
import org.chromium.base.annotations.NativeMethods; | ||
import org.chromium.device.mojom.ReportingMode; | ||
import org.chromium.device.mojom.SensorType; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* Implementation of PlatformSensor that uses Android Sensor Framework. Lifetime is controlled by | ||
* the device::PlatformSensorAndroid. | ||
*/ | ||
@JNINamespace("device") | ||
public class PlatformSensor implements SensorEventListener { | ||
private static final double MICROSECONDS_IN_SECOND = 1000000; | ||
private static final double SECONDS_IN_MICROSECOND = 0.000001d; | ||
private static final double SECONDS_IN_NANOSECOND = 0.000000001d; | ||
private static final String TAG = "PlatformSensor"; | ||
|
||
/** | ||
* The SENSOR_FREQUENCY_NORMAL is defined as 5Hz which corresponds to a polling delay | ||
* @see android.hardware.SensorManager.SENSOR_DELAY_NORMAL value that is defined as 200000 | ||
* microseconds. | ||
*/ | ||
private static final double SENSOR_FREQUENCY_NORMAL = 5.0d; | ||
|
||
/** | ||
* Lock protecting access to mNativePlatformSensorAndroid. | ||
*/ | ||
private final Object mLock = new Object(); | ||
|
||
/** | ||
* Identifier of device::PlatformSensorAndroid instance. | ||
*/ | ||
@GuardedBy("mLock") | ||
private long mNativePlatformSensorAndroid; | ||
|
||
/** | ||
* Used for fetching sensor reading values and obtaining information about the sensor. | ||
* @see android.hardware.Sensor | ||
*/ | ||
private final Sensor mSensor; | ||
|
||
/** | ||
* The minimum delay between two readings in microseconds that is supported by the sensor. | ||
*/ | ||
private final int mMinDelayUsec; | ||
|
||
/** | ||
* The number of sensor reading values required from the sensor. | ||
*/ | ||
private final int mReadingCount; | ||
|
||
/** | ||
* Frequncy that is currently used by the sensor for polling. | ||
*/ | ||
private double mCurrentPollingFrequency; | ||
|
||
/** | ||
* Provides shared SensorManager and event processing thread Handler to PlatformSensor objects. | ||
*/ | ||
private final PlatformSensorProvider mProvider; | ||
|
||
/** | ||
* Creates new PlatformSensor. | ||
* | ||
* @param provider object that shares SensorManager and polling thread Handler with sensors. | ||
* @param sensorType type of the sensor to be constructed. @see android.hardware.Sensor.TYPE_* | ||
* @param nativePlatformSensorAndroid identifier of device::PlatformSensorAndroid instance. | ||
*/ | ||
@CalledByNative | ||
public static PlatformSensor create( | ||
PlatformSensorProvider provider, int type, long nativePlatformSensorAndroid) { | ||
SensorManager sensorManager = provider.getSensorManager(); | ||
if (sensorManager == null) return null; | ||
|
||
List<Sensor> sensors; | ||
int readingCount; | ||
switch (type) { | ||
case SensorType.AMBIENT_LIGHT: | ||
sensors = provider.getSensorManager().getSensorList(Sensor.TYPE_LIGHT); | ||
readingCount = 1; | ||
break; | ||
case SensorType.ACCELEROMETER: | ||
sensors = provider.getSensorManager().getSensorList(Sensor.TYPE_ACCELEROMETER); | ||
readingCount = 3; | ||
break; | ||
case SensorType.LINEAR_ACCELERATION: | ||
sensors = | ||
provider.getSensorManager().getSensorList(Sensor.TYPE_LINEAR_ACCELERATION); | ||
readingCount = 3; | ||
break; | ||
case SensorType.GRAVITY: | ||
sensors = provider.getSensorManager().getSensorList(Sensor.TYPE_GRAVITY); | ||
readingCount = 3; | ||
break; | ||
case SensorType.GYROSCOPE: | ||
sensors = provider.getSensorManager().getSensorList(Sensor.TYPE_GYROSCOPE); | ||
readingCount = 3; | ||
break; | ||
case SensorType.MAGNETOMETER: | ||
sensors = provider.getSensorManager().getSensorList(Sensor.TYPE_MAGNETIC_FIELD); | ||
readingCount = 3; | ||
break; | ||
case SensorType.ABSOLUTE_ORIENTATION_QUATERNION: | ||
sensors = provider.getSensorManager().getSensorList(Sensor.TYPE_ROTATION_VECTOR); | ||
readingCount = 4; | ||
break; | ||
case SensorType.RELATIVE_ORIENTATION_QUATERNION: | ||
sensors = | ||
provider.getSensorManager().getSensorList(Sensor.TYPE_GAME_ROTATION_VECTOR); | ||
readingCount = 4; | ||
break; | ||
default: | ||
return null; | ||
} | ||
|
||
if (sensors.isEmpty()) return null; | ||
return new PlatformSensor( | ||
sensors.get(0), readingCount, provider, nativePlatformSensorAndroid); | ||
} | ||
|
||
/** | ||
* Constructor. | ||
*/ | ||
protected PlatformSensor(Sensor sensor, int readingCount, PlatformSensorProvider provider, | ||
long nativePlatformSensorAndroid) { | ||
mReadingCount = readingCount; | ||
mProvider = provider; | ||
mSensor = sensor; | ||
mNativePlatformSensorAndroid = nativePlatformSensorAndroid; | ||
mMinDelayUsec = mSensor.getMinDelay(); | ||
} | ||
|
||
/** | ||
* Returns reporting mode supported by the sensor. | ||
* | ||
* @return ReportingMode reporting mode. | ||
*/ | ||
@CalledByNative | ||
protected int getReportingMode() { | ||
return mSensor.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS | ||
? ReportingMode.CONTINUOUS | ||
: ReportingMode.ON_CHANGE; | ||
} | ||
|
||
/** | ||
* Returns default configuration supported by the sensor. Currently only frequency is supported. | ||
* | ||
* @return double frequency. | ||
*/ | ||
@CalledByNative | ||
protected double getDefaultConfiguration() { | ||
return SENSOR_FREQUENCY_NORMAL; | ||
} | ||
|
||
/** | ||
* Returns maximum sampling frequency supported by the sensor. | ||
* | ||
* @return double frequency in Hz. | ||
*/ | ||
@CalledByNative | ||
protected double getMaximumSupportedFrequency() { | ||
if (mMinDelayUsec == 0) return getDefaultConfiguration(); | ||
return 1 / (mMinDelayUsec * SECONDS_IN_MICROSECOND); | ||
} | ||
|
||
/** | ||
* Requests sensor to start polling for data. | ||
* | ||
* @return boolean true if successful, false otherwise. | ||
*/ | ||
@CalledByNative | ||
protected boolean startSensor(double frequency) { | ||
// If we already polling hw with same frequency, do not restart the sensor. | ||
if (mCurrentPollingFrequency == frequency) return true; | ||
|
||
// Unregister old listener if polling frequency has changed. | ||
unregisterListener(); | ||
|
||
mProvider.sensorStarted(this); | ||
boolean sensorStarted; | ||
try { | ||
sensorStarted = mProvider.getSensorManager().registerListener( | ||
this, mSensor, getSamplingPeriod(frequency), mProvider.getHandler()); | ||
} catch (RuntimeException e) { | ||
// This can fail due to internal framework errors. https://crbug.com/884190 | ||
Log.w(TAG, "Failed to register sensor listener.", e); | ||
sensorStarted = false; | ||
} | ||
|
||
if (!sensorStarted) { | ||
stopSensor(); | ||
return sensorStarted; | ||
} | ||
|
||
mCurrentPollingFrequency = frequency; | ||
return sensorStarted; | ||
} | ||
|
||
private void unregisterListener() { | ||
// Do not unregister if current polling frequency is 0, not polling for data. | ||
if (mCurrentPollingFrequency == 0) return; | ||
mProvider.getSensorManager().unregisterListener(this, mSensor); | ||
} | ||
|
||
/** | ||
* Requests sensor to stop polling for data. | ||
*/ | ||
@CalledByNative | ||
protected void stopSensor() { | ||
unregisterListener(); | ||
mProvider.sensorStopped(this); | ||
mCurrentPollingFrequency = 0; | ||
} | ||
|
||
/** | ||
* Checks whether configuration is supported by the sensor. Currently only frequency is | ||
* supported. | ||
* | ||
* @return boolean true if configuration is supported, false otherwise. | ||
*/ | ||
@CalledByNative | ||
protected boolean checkSensorConfiguration(double frequency) { | ||
return mMinDelayUsec <= getSamplingPeriod(frequency); | ||
} | ||
|
||
/** | ||
* Called from device::PlatformSensorAndroid destructor, so that this instance would be | ||
* notified not to deliver any updates about new sensor readings or errors. | ||
*/ | ||
@CalledByNative | ||
protected void sensorDestroyed() { | ||
stopSensor(); | ||
synchronized (mLock) { | ||
mNativePlatformSensorAndroid = 0; | ||
} | ||
} | ||
|
||
/** | ||
* Converts frequency to sampling period in microseconds. | ||
*/ | ||
private int getSamplingPeriod(double frequency) { | ||
return (int) ((1 / frequency) * MICROSECONDS_IN_SECOND); | ||
} | ||
|
||
/** | ||
* Notifies native device::PlatformSensorAndroid when there is an error. | ||
*/ | ||
@GuardedBy("mLock") | ||
protected void sensorError() { | ||
PlatformSensorJni.get().notifyPlatformSensorError( | ||
mNativePlatformSensorAndroid, PlatformSensor.this); | ||
} | ||
|
||
/** | ||
* Updates reading at native device::PlatformSensorAndroid. | ||
*/ | ||
@GuardedBy("mLock") | ||
protected void updateSensorReading( | ||
double timestamp, double value1, double value2, double value3, double value4) { | ||
PlatformSensorJni.get().updatePlatformSensorReading(mNativePlatformSensorAndroid, | ||
PlatformSensor.this, timestamp, value1, value2, value3, value4); | ||
} | ||
|
||
@Override | ||
public void onAccuracyChanged(Sensor sensor, int accuracy) {} | ||
|
||
@Override | ||
public void onSensorChanged(SensorEvent event) { | ||
// Acquire mLock to ensure that mNativePlatformSensorAndroid is not reset between this check | ||
// and when it is used. | ||
synchronized (mLock) { | ||
if (mNativePlatformSensorAndroid == 0) { | ||
Log.w(TAG, | ||
"Should not get sensor events after PlatformSensorAndroid is destroyed."); | ||
return; | ||
} | ||
|
||
if (event.values.length < mReadingCount) { | ||
sensorError(); | ||
stopSensor(); | ||
return; | ||
} | ||
|
||
double timestamp = event.timestamp * SECONDS_IN_NANOSECOND; | ||
switch (event.values.length) { | ||
case 1: | ||
updateSensorReading(timestamp, event.values[0], 0.0, 0.0, 0.0); | ||
break; | ||
case 2: | ||
updateSensorReading(timestamp, event.values[0], event.values[1], 0.0, 0.0); | ||
break; | ||
case 3: | ||
updateSensorReading( | ||
timestamp, event.values[0], event.values[1], event.values[2], 0.0); | ||
break; | ||
default: | ||
updateSensorReading(timestamp, event.values[0], event.values[1], | ||
event.values[2], event.values[3]); | ||
} | ||
} | ||
} | ||
|
||
@NativeMethods | ||
interface Natives { | ||
void notifyPlatformSensorError(long nativePlatformSensorAndroid, PlatformSensor caller); | ||
void updatePlatformSensorReading(long nativePlatformSensorAndroid, PlatformSensor caller, | ||
double timestamp, double value1, double value2, double value3, double value4); | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
src/main/java/org/chromium/device/sensors/PlatformSensorJni.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.chromium.device.sensors; | ||
|
||
import java.lang.Override; | ||
import javax.annotation.Generated; | ||
import org.chromium.base.JniStaticTestMocker; | ||
import org.chromium.base.NativeLibraryLoadedStatus; | ||
import org.chromium.base.annotations.CheckDiscard; | ||
import org.chromium.base.natives.GEN_JNI; | ||
|
||
@Generated("org.chromium.jni_generator.JniProcessor") | ||
@CheckDiscard("crbug.com/993421") | ||
class PlatformSensorJni implements PlatformSensor.Natives { | ||
private static PlatformSensor.Natives testInstance; | ||
|
||
public static final JniStaticTestMocker<PlatformSensor.Natives> TEST_HOOKS = new org.chromium.base.JniStaticTestMocker<org.chromium.device.sensors.PlatformSensor.Natives>() { | ||
@java.lang.Override | ||
public void setInstanceForTesting(org.chromium.device.sensors.PlatformSensor.Natives instance) { | ||
if (!org.chromium.base.natives.GEN_JNI.TESTING_ENABLED) { | ||
throw new RuntimeException("Tried to set a JNI mock when mocks aren't enabled!"); | ||
} | ||
testInstance = instance; | ||
} | ||
}; | ||
|
||
@Override | ||
public void notifyPlatformSensorError(long nativePlatformSensorAndroid, PlatformSensor caller) { | ||
GEN_JNI.org_chromium_device_sensors_PlatformSensor_notifyPlatformSensorError(nativePlatformSensorAndroid, caller); | ||
} | ||
|
||
@Override | ||
public void updatePlatformSensorReading(long nativePlatformSensorAndroid, PlatformSensor caller, | ||
double timestamp, double value1, double value2, double value3, double value4) { | ||
GEN_JNI.org_chromium_device_sensors_PlatformSensor_updatePlatformSensorReading(nativePlatformSensorAndroid, caller, timestamp, value1, value2, value3, value4); | ||
} | ||
|
||
public static PlatformSensor.Natives get() { | ||
if (GEN_JNI.TESTING_ENABLED) { | ||
if (testInstance != null) { | ||
return testInstance; | ||
} | ||
if (GEN_JNI.REQUIRE_MOCK) { | ||
throw new UnsupportedOperationException("No mock found for the native implementation for org.chromium.device.sensors.PlatformSensor.Natives. The current configuration requires all native implementations to have a mock instance."); | ||
} | ||
} | ||
NativeLibraryLoadedStatus.checkLoaded(false); | ||
return new PlatformSensorJni(); | ||
} | ||
} |
Oops, something went wrong.