Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58e1a90b authored by Peng Xu's avatar Peng Xu Committed by android-build-merger
Browse files

Merge "Local geomagnetic field update to sensor" into oc-dev

am: 33bbdda3

Change-Id: I3c450d9d16a998918bc3963ad624455d6e2bb361
parents 484c0186 33bbdda3
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -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});
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -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);
}
+8 −0
Original line number Diff line number Diff line
@@ -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;
    }
}
+23 −0
Original line number Diff line number Diff line
@@ -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[] = {
+96 −7
Original line number Diff line number Diff line
@@ -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"));
    }
}