Merge "Local geomagnetic field update to sensor" into oc-dev
am: 33bbdda3d3
Change-Id: I3c450d9d16a998918bc3963ad624455d6e2bb361
This commit is contained in:
@@ -131,6 +131,64 @@ public class SensorAdditionalInfo {
|
||||
*/
|
||||
public static final int TYPE_SAMPLING = 0x10004;
|
||||
|
||||
/**
|
||||
* Local geo-magnetic Field.
|
||||
*
|
||||
* Additional into to sensor hardware. Local geomagnetic field information based on
|
||||
* device geo location. This type is primarily for for magnetic field calibration and rotation
|
||||
* vector sensor fusion.
|
||||
*
|
||||
* float[3]: strength (uT), declination and inclination angle (rad).
|
||||
* @hide
|
||||
*/
|
||||
public static final int TYPE_LOCAL_GEOMAGNETIC_FIELD = 0x30000;
|
||||
|
||||
/**
|
||||
* Local gravity acceleration strength.
|
||||
*
|
||||
* Additional info to sensor hardware for accelerometer calibration.
|
||||
*
|
||||
* float: gravitational acceleration norm in m/s^2.
|
||||
* @hide
|
||||
*/
|
||||
public static final int TYPE_LOCAL_GRAVITY = 0x30001;
|
||||
|
||||
/**
|
||||
* Device dock state.
|
||||
*
|
||||
* Additional info to sensor hardware indicating dock states of device.
|
||||
*
|
||||
* int32_t: dock state following definition of {@link android.content.Intent#EXTRA_DOCK_STATE}.
|
||||
* Undefined values are ignored.
|
||||
* @hide
|
||||
*/
|
||||
public static final int TYPE_DOCK_STATE = 0x30002;
|
||||
|
||||
/**
|
||||
* High performance mode.
|
||||
*
|
||||
* Additional info to sensor hardware. Device is able to use up more power and take more
|
||||
* resources to improve throughput and latency in high performance mode. One possible use case
|
||||
* is virtual reality, when sensor latency need to be carefully controlled.
|
||||
*
|
||||
* int32_t: 1 or 0, denoting device is in or out of high performance mode, respectively.
|
||||
* Other values are ignored.
|
||||
* @hide
|
||||
*/
|
||||
public static final int TYPE_HIGH_PERFORMANCE_MODE = 0x30003;
|
||||
|
||||
/**
|
||||
* Magnetic field calibration hint.
|
||||
*
|
||||
* Additional info to sensor hardware. Device is notified when manually triggered magnetic field
|
||||
* calibration procedure is started or stopped. The calibration procedure is assumed timed out
|
||||
* after 1 minute from start, even if an explicit stop is not received.
|
||||
*
|
||||
* int32_t: 1 for calibration start, 0 for stop, other values are ignored.
|
||||
* @hide
|
||||
*/
|
||||
public static final int TYPE_MAGNETIC_FIELD_CALIBRATION = 0x30004;
|
||||
|
||||
SensorAdditionalInfo(
|
||||
Sensor aSensor, int aType, int aSerial, int [] aIntValues, float [] aFloatValues) {
|
||||
sensor = aSensor;
|
||||
@@ -139,4 +197,18 @@ public class SensorAdditionalInfo {
|
||||
intValues = aIntValues;
|
||||
floatValues = aFloatValues;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static SensorAdditionalInfo createLocalGeomagneticField(
|
||||
float strength, float declination, float inclination) {
|
||||
if (strength < 10 || strength > 100 // much beyond extreme values on earth
|
||||
|| declination < 0 || declination > Math.PI
|
||||
|| inclination < -Math.PI / 2 || inclination > Math.PI / 2) {
|
||||
throw new IllegalArgumentException("Geomagnetic field info out of range");
|
||||
}
|
||||
|
||||
return new SensorAdditionalInfo(
|
||||
null, TYPE_LOCAL_GEOMAGNETIC_FIELD, 0,
|
||||
null, new float[] { strength, declination, inclination});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1927,4 +1927,12 @@ public abstract class SensorManager {
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public boolean setOperationParameter(SensorAdditionalInfo parameter) {
|
||||
return setOperationParameterImpl(parameter);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
protected abstract boolean setOperationParameterImpl(SensorAdditionalInfo parameter);
|
||||
}
|
||||
|
||||
@@ -67,6 +67,9 @@ public class SystemSensorManager extends SensorManager {
|
||||
private static native int nativeConfigDirectChannel(
|
||||
long nativeInstance, int channelHandle, int sensorHandle, int rate);
|
||||
|
||||
private static native int nativeSetOperationParameter(
|
||||
long nativeInstance, int type, float[] floatValues, int[] intValues);
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
@GuardedBy("sLock")
|
||||
private static boolean sNativeClassInited = false;
|
||||
@@ -928,4 +931,9 @@ public class SystemSensorManager extends SensorManager {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
|
||||
return nativeSetOperationParameter(
|
||||
mNativeInstance, parameter.type, parameter.floatValues, parameter.intValues) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,6 +282,25 @@ static jint nativeConfigDirectChannel(JNIEnv *_env, jclass _this, jlong sensorMa
|
||||
return mgr->configureDirectChannel(channelHandle, sensorHandle, rate);
|
||||
}
|
||||
|
||||
static jint nativeSetOperationParameter(JNIEnv *_env, jclass _this, jlong sensorManager,
|
||||
jint type, jfloatArray floats, jintArray ints) {
|
||||
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
||||
Vector<float> floatVector;
|
||||
Vector<int32_t> int32Vector;
|
||||
|
||||
if (floats != nullptr) {
|
||||
floatVector.resize(_env->GetArrayLength(floats));
|
||||
_env->GetFloatArrayRegion(floats, 0, _env->GetArrayLength(floats), floatVector.editArray());
|
||||
}
|
||||
|
||||
if (ints != nullptr) {
|
||||
int32Vector.resize(_env->GetArrayLength(ints));
|
||||
_env->GetIntArrayRegion(ints, 0, _env->GetArrayLength(ints), int32Vector.editArray());
|
||||
}
|
||||
|
||||
return mgr->setOperationParameter(type, floatVector, int32Vector);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class Receiver : public LooperCallback {
|
||||
@@ -499,6 +518,10 @@ static const JNINativeMethod gSystemSensorManagerMethods[] = {
|
||||
{"nativeConfigDirectChannel",
|
||||
"(JIII)I",
|
||||
(void*)nativeConfigDirectChannel },
|
||||
|
||||
{"nativeSetOperationParameter",
|
||||
"(JI[F[I)I",
|
||||
(void*)nativeSetOperationParameter },
|
||||
};
|
||||
|
||||
static const JNINativeMethod gBaseEventQueueMethods[] = {
|
||||
|
||||
@@ -20,25 +20,46 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.hardware.GeomagneticField;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorAdditionalInfo;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
|
||||
public class SensorNotificationService extends SystemService implements SensorEventListener {
|
||||
//TODO: set DBG to false or remove Slog before release
|
||||
private static final boolean DBG = true;
|
||||
public class SensorNotificationService extends SystemService
|
||||
implements SensorEventListener, LocationListener {
|
||||
private static final boolean DBG = false;
|
||||
private static final String TAG = "SensorNotificationService";
|
||||
private Context mContext;
|
||||
|
||||
private static final long MINUTE_IN_MS = 60 * 1000;
|
||||
private static final long KM_IN_M = 1000;
|
||||
|
||||
private static final long LOCATION_MIN_TIME = 30 * MINUTE_IN_MS;
|
||||
private static final long LOCATION_MIN_DISTANCE = 100 * KM_IN_M;
|
||||
|
||||
private static final String PROPERTY_USE_MOCKED_LOCATION =
|
||||
"sensor.notification.use_mocked"; // max key length is 32
|
||||
|
||||
private static final long MILLIS_2010_1_1 = 1262358000000l;
|
||||
|
||||
private Context mContext;
|
||||
private SensorManager mSensorManager;
|
||||
private LocationManager mLocationManager;
|
||||
private Sensor mMetaSensor;
|
||||
|
||||
// for rate limiting
|
||||
private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME;
|
||||
|
||||
public SensorNotificationService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
@@ -50,7 +71,6 @@ public class SensorNotificationService extends SystemService implements SensorEv
|
||||
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
|
||||
// start
|
||||
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
|
||||
mMetaSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DYNAMIC_SENSOR_META);
|
||||
if (mMetaSensor == null) {
|
||||
@@ -60,13 +80,28 @@ public class SensorNotificationService extends SystemService implements SensorEv
|
||||
SensorManager.SENSOR_DELAY_FASTEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (phase == PHASE_BOOT_COMPLETED) {
|
||||
// LocationManagerService is initialized after PHASE_THIRD_PARTY_APPS_CAN_START
|
||||
mLocationManager =
|
||||
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
|
||||
if (mLocationManager == null) {
|
||||
if (DBG) Slog.d(TAG, "Cannot obtain location service.");
|
||||
} else {
|
||||
mLocationManager.requestLocationUpdates(
|
||||
LocationManager.PASSIVE_PROVIDER,
|
||||
LOCATION_MIN_TIME,
|
||||
LOCATION_MIN_DISTANCE,
|
||||
this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastDynamicSensorChanged() {
|
||||
Intent i = new Intent(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
|
||||
i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); // avoid waking up manifest receivers
|
||||
mContext.sendBroadcastAsUser(i, UserHandle.ALL);
|
||||
if (DBG) Slog.d(TAG, "DYNS sent dynamic sensor broadcast");
|
||||
if (DBG) Slog.d(TAG, "dynamic sensor broadcast sent");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,8 +112,62 @@ public class SensorNotificationService extends SystemService implements SensorEv
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
public void onLocationChanged(Location location) {
|
||||
if (DBG) Slog.d(TAG, String.format(
|
||||
"Location is (%f, %f), h %f, acc %f, mocked %b",
|
||||
location.getLatitude(), location.getLongitude(),
|
||||
location.getAltitude(), location.getAccuracy(),
|
||||
location.isFromMockProvider()));
|
||||
|
||||
// lat long == 0 usually means invalid location
|
||||
if (location.getLatitude() == 0 && location.getLongitude() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update too often, ignore
|
||||
if (SystemClock.elapsedRealtime() - mLocalGeomagneticFieldUpdateTime < 10 * MINUTE_IN_MS) {
|
||||
return;
|
||||
}
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
// Mocked location should not be used. Except in test, only use mocked location
|
||||
// Wrong system clock also gives bad values so ignore as well.
|
||||
if (useMockedLocation() == location.isFromMockProvider() || time < MILLIS_2010_1_1) {
|
||||
return;
|
||||
}
|
||||
|
||||
GeomagneticField field = new GeomagneticField(
|
||||
(float) location.getLatitude(), (float) location.getLongitude(),
|
||||
(float) location.getAltitude(), time);
|
||||
if (DBG) Slog.d(TAG, String.format(
|
||||
"Nominal mag field, norm %fuT, decline %f deg, incline %f deg",
|
||||
field.getFieldStrength() / 1000, field.getDeclination(), field.getInclination()));
|
||||
|
||||
try {
|
||||
SensorAdditionalInfo info = SensorAdditionalInfo.createLocalGeomagneticField(
|
||||
field.getFieldStrength() / 1000, // convert from nT to uT
|
||||
(float)(field.getDeclination() * Math.PI / 180), // from degree to rad
|
||||
(float)(field.getInclination() * Math.PI / 180)); // from degree to rad
|
||||
if (info != null) {
|
||||
mSensorManager.setOperationParameter(info);
|
||||
mLocalGeomagneticFieldUpdateTime = SystemClock.elapsedRealtime();
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.e(TAG, "Invalid local geomagnetic field, ignore.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {}
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {}
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {}
|
||||
|
||||
private boolean useMockedLocation() {
|
||||
return "false".equals(System.getProperty(PROPERTY_USE_MOCKED_LOCATION, "false"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user