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

Commit e978607a authored by David Christie's avatar David Christie Committed by Android (Google) Code Review
Browse files

Merge "Make Location objects take less memory."

parents 38c96cb8 923b2602
Loading
Loading
Loading
Loading
+115 −100
Original line number Diff line number Diff line
@@ -78,32 +78,51 @@ public class Location implements Parcelable {
     */
    public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";

    /**
     * Bit mask for mFieldsMask indicating the presence of mAltitude.
     */
    private static final byte HAS_ALTITUDE_MASK = 1;
    /**
     * Bit mask for mFieldsMask indicating the presence of mSpeed.
     */
    private static final byte HAS_SPEED_MASK = 2;
    /**
     * Bit mask for mFieldsMask indicating the presence of mBearing.
     */
    private static final byte HAS_BEARING_MASK = 4;
    /**
     * Bit mask for mFieldsMask indicating the presence of mAccuracy.
     */
    private static final byte HAS_ACCURACY_MASK = 8;
    /**
     * Bit mask for mFieldsMask indicating location is from a mock provider.
     */
    private static final byte HAS_MOCK_PROVIDER_MASK = 16;

    // Cached data to make bearing/distance computations more efficient for the case
    // where distanceTo and bearingTo are called in sequence.  Assume this typically happens
    // on the same thread for caching purposes.
    private static ThreadLocal<BearingDistanceCache> sBearingDistanceCache
            = new ThreadLocal<BearingDistanceCache>() {
        @Override
        protected BearingDistanceCache initialValue() {
            return new BearingDistanceCache();
        }
    };

    private String mProvider;
    private long mTime = 0;
    private long mElapsedRealtimeNanos = 0;
    private double mLatitude = 0.0;
    private double mLongitude = 0.0;
    private boolean mHasAltitude = false;
    private double mAltitude = 0.0f;
    private boolean mHasSpeed = false;
    private float mSpeed = 0.0f;
    private boolean mHasBearing = false;
    private float mBearing = 0.0f;
    private boolean mHasAccuracy = false;
    private float mAccuracy = 0.0f;
    private Bundle mExtras = null;
    private boolean mIsFromMockProvider = false;

    // Cache the inputs and outputs of computeDistanceAndBearing
    // so calls to distanceTo() and bearingTo() can share work
    private double mLat1 = 0.0;
    private double mLon1 = 0.0;
    private double mLat2 = 0.0;
    private double mLon2 = 0.0;
    private float mDistance = 0.0f;
    private float mInitialBearing = 0.0f;
    // Scratchpad
    private final float[] mResults = new float[2];
    // A bitmask of fields present in this object (see HAS_* constants defined above).
    private byte mFieldsMask = 0;

    /**
     * Construct a new Location with a named provider.
@@ -131,18 +150,14 @@ public class Location implements Parcelable {
        mProvider = l.mProvider;
        mTime = l.mTime;
        mElapsedRealtimeNanos = l.mElapsedRealtimeNanos;
        mFieldsMask = l.mFieldsMask;
        mLatitude = l.mLatitude;
        mLongitude = l.mLongitude;
        mHasAltitude = l.mHasAltitude;
        mAltitude = l.mAltitude;
        mHasSpeed = l.mHasSpeed;
        mSpeed = l.mSpeed;
        mHasBearing = l.mHasBearing;
        mBearing = l.mBearing;
        mHasAccuracy = l.mHasAccuracy;
        mAccuracy = l.mAccuracy;
        mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
        mIsFromMockProvider = l.mIsFromMockProvider;
    }

    /**
@@ -152,18 +167,14 @@ public class Location implements Parcelable {
        mProvider = null;
        mTime = 0;
        mElapsedRealtimeNanos = 0;
        mFieldsMask = 0;
        mLatitude = 0;
        mLongitude = 0;
        mHasAltitude = false;
        mAltitude = 0;
        mHasSpeed = false;
        mSpeed = 0;
        mHasBearing = false;
        mBearing = 0;
        mHasAccuracy = false;
        mAccuracy = 0;
        mExtras = null;
        mIsFromMockProvider = false;
    }

    /**
@@ -297,7 +308,7 @@ public class Location implements Parcelable {
    }

    private static void computeDistanceAndBearing(double lat1, double lon1,
        double lat2, double lon2, float[] results) {
        double lat2, double lon2, BearingDistanceCache results) {
        // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
        // using the "Inverse Formula" (section 4)

@@ -382,19 +393,19 @@ public class Location implements Parcelable {
        }

        float distance = (float) (b * A * (sigma - deltaSigma));
        results[0] = distance;
        if (results.length > 1) {
        results.mDistance = distance;
        float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
            cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
        initialBearing *= 180.0 / Math.PI;
            results[1] = initialBearing;
            if (results.length > 2) {
        results.mInitialBearing = initialBearing;
        float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
                -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
        finalBearing *= 180.0 / Math.PI;
                results[2] = finalBearing;
            }
        }
        results.mFinalBearing = finalBearing;
        results.mLat1 = lat1;
        results.mLat2 = lat2;
        results.mLon1 = lon1;
        results.mLon2 = lon2;
    }

    /**
@@ -420,8 +431,16 @@ public class Location implements Parcelable {
        if (results == null || results.length < 1) {
            throw new IllegalArgumentException("results is null or has length < 1");
        }
        BearingDistanceCache cache = sBearingDistanceCache.get();
        computeDistanceAndBearing(startLatitude, startLongitude,
            endLatitude, endLongitude, results);
                endLatitude, endLongitude, cache);
        results[0] = cache.mDistance;
        if (results.length > 1) {
            results[1] = cache.mInitialBearing;
            if (results.length > 2) {
                results[2] = cache.mFinalBearing;
            }
        }
    }

    /**
@@ -433,21 +452,14 @@ public class Location implements Parcelable {
     * @return the approximate distance in meters
     */
    public float distanceTo(Location dest) {
        BearingDistanceCache cache = sBearingDistanceCache.get();
        // See if we already have the result
        synchronized (mResults) {
            if (mLatitude != mLat1 || mLongitude != mLon1 ||
                dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
        if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 ||
            dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) {
            computeDistanceAndBearing(mLatitude, mLongitude,
                    dest.mLatitude, dest.mLongitude, mResults);
                mLat1 = mLatitude;
                mLon1 = mLongitude;
                mLat2 = dest.mLatitude;
                mLon2 = dest.mLongitude;
                mDistance = mResults[0];
                mInitialBearing = mResults[1];
            }
            return mDistance;
                dest.mLatitude, dest.mLongitude, cache);
        }
        return cache.mDistance;
    }

    /**
@@ -461,21 +473,14 @@ public class Location implements Parcelable {
     * @return the initial bearing in degrees
     */
    public float bearingTo(Location dest) {
        synchronized (mResults) {
        BearingDistanceCache cache = sBearingDistanceCache.get();
        // See if we already have the result
            if (mLatitude != mLat1 || mLongitude != mLon1 ||
                            dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
        if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 ||
                        dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) {
            computeDistanceAndBearing(mLatitude, mLongitude,
                    dest.mLatitude, dest.mLongitude, mResults);
                mLat1 = mLatitude;
                mLon1 = mLongitude;
                mLat2 = dest.mLatitude;
                mLon2 = dest.mLongitude;
                mDistance = mResults[0];
                mInitialBearing = mResults[1];
            }
            return mInitialBearing;
                dest.mLatitude, dest.mLongitude, cache);
        }
        return cache.mInitialBearing;
    }

    /**
@@ -591,7 +596,7 @@ public class Location implements Parcelable {
     * True if this location has an altitude.
     */
    public boolean hasAltitude() {
        return mHasAltitude;
        return (mFieldsMask & HAS_ALTITUDE_MASK) != 0;
    }

    /**
@@ -611,7 +616,7 @@ public class Location implements Parcelable {
     */
    public void setAltitude(double altitude) {
        mAltitude = altitude;
        mHasAltitude = true;
        mFieldsMask |= HAS_ALTITUDE_MASK;
    }

    /**
@@ -622,14 +627,14 @@ public class Location implements Parcelable {
     */
    public void removeAltitude() {
        mAltitude = 0.0f;
        mHasAltitude = false;
        mFieldsMask &= ~HAS_ALTITUDE_MASK;
    }

    /**
     * True if this location has a speed.
     */
    public boolean hasSpeed() {
        return mHasSpeed;
        return (mFieldsMask & HAS_SPEED_MASK) != 0;
    }

    /**
@@ -648,7 +653,7 @@ public class Location implements Parcelable {
     */
    public void setSpeed(float speed) {
        mSpeed = speed;
        mHasSpeed = true;
        mFieldsMask |= HAS_SPEED_MASK;
    }

    /**
@@ -659,14 +664,14 @@ public class Location implements Parcelable {
     */
    public void removeSpeed() {
        mSpeed = 0.0f;
        mHasSpeed = false;
        mFieldsMask &= ~HAS_SPEED_MASK;
    }

    /**
     * True if this location has a bearing.
     */
    public boolean hasBearing() {
        return mHasBearing;
        return (mFieldsMask & HAS_BEARING_MASK) != 0;
    }

    /**
@@ -698,7 +703,7 @@ public class Location implements Parcelable {
            bearing -= 360.0f;
        }
        mBearing = bearing;
        mHasBearing = true;
        mFieldsMask |= HAS_BEARING_MASK;
    }

    /**
@@ -709,7 +714,7 @@ public class Location implements Parcelable {
     */
    public void removeBearing() {
        mBearing = 0.0f;
        mHasBearing = false;
        mFieldsMask &= ~HAS_BEARING_MASK;
    }

    /**
@@ -719,7 +724,7 @@ public class Location implements Parcelable {
     * accuracy.
     */
    public boolean hasAccuracy() {
        return mHasAccuracy;
        return (mFieldsMask & HAS_ACCURACY_MASK) != 0;
    }

    /**
@@ -757,7 +762,7 @@ public class Location implements Parcelable {
     */
    public void setAccuracy(float accuracy) {
        mAccuracy = accuracy;
        mHasAccuracy = true;
        mFieldsMask |= HAS_ACCURACY_MASK;
    }

    /**
@@ -768,7 +773,7 @@ public class Location implements Parcelable {
     */
    public void removeAccuracy() {
        mAccuracy = 0.0f;
        mHasAccuracy = false;
        mFieldsMask &= ~HAS_ACCURACY_MASK;
    }

    /**
@@ -786,7 +791,7 @@ public class Location implements Parcelable {
    @SystemApi
    public boolean isComplete() {
        if (mProvider == null) return false;
        if (!mHasAccuracy) return false;
        if (!hasAccuracy()) return false;
        if (mTime == 0) return false;
        if (mElapsedRealtimeNanos == 0) return false;
        return true;
@@ -804,8 +809,8 @@ public class Location implements Parcelable {
    @SystemApi
    public void makeComplete() {
        if (mProvider == null) mProvider = "?";
        if (!mHasAccuracy) {
            mHasAccuracy = true;
        if (!hasAccuracy()) {
            mFieldsMask |= HAS_ACCURACY_MASK;
            mAccuracy = 100.0f;
        }
        if (mTime == 0) mTime = System.currentTimeMillis();
@@ -844,7 +849,7 @@ public class Location implements Parcelable {
        s.append("Location[");
        s.append(mProvider);
        s.append(String.format(" %.6f,%.6f", mLatitude, mLongitude));
        if (mHasAccuracy) s.append(String.format(" acc=%.0f", mAccuracy));
        if (hasAccuracy()) s.append(String.format(" acc=%.0f", mAccuracy));
        else s.append(" acc=???");
        if (mTime == 0) {
            s.append(" t=?!?");
@@ -855,10 +860,10 @@ public class Location implements Parcelable {
            s.append(" et=");
            TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s);
        }
        if (mHasAltitude) s.append(" alt=").append(mAltitude);
        if (mHasSpeed) s.append(" vel=").append(mSpeed);
        if (mHasBearing) s.append(" bear=").append(mBearing);
        if (mIsFromMockProvider) s.append(" mock");
        if (hasAltitude()) s.append(" alt=").append(mAltitude);
        if (hasSpeed()) s.append(" vel=").append(mSpeed);
        if (hasBearing()) s.append(" bear=").append(mBearing);
        if (isFromMockProvider()) s.append(" mock");

        if (mExtras != null) {
            s.append(" {").append(mExtras).append('}');
@@ -879,18 +884,14 @@ public class Location implements Parcelable {
            Location l = new Location(provider);
            l.mTime = in.readLong();
            l.mElapsedRealtimeNanos = in.readLong();
            l.mFieldsMask = in.readByte();
            l.mLatitude = in.readDouble();
            l.mLongitude = in.readDouble();
            l.mHasAltitude = in.readInt() != 0;
            l.mAltitude = in.readDouble();
            l.mHasSpeed = in.readInt() != 0;
            l.mSpeed = in.readFloat();
            l.mHasBearing = in.readInt() != 0;
            l.mBearing = in.readFloat();
            l.mHasAccuracy = in.readInt() != 0;
            l.mAccuracy = in.readFloat();
            l.mExtras = in.readBundle();
            l.mIsFromMockProvider = in.readInt() != 0;
            return l;
        }

@@ -910,18 +911,14 @@ public class Location implements Parcelable {
        parcel.writeString(mProvider);
        parcel.writeLong(mTime);
        parcel.writeLong(mElapsedRealtimeNanos);
        parcel.writeByte(mFieldsMask);
        parcel.writeDouble(mLatitude);
        parcel.writeDouble(mLongitude);
        parcel.writeInt(mHasAltitude ? 1 : 0);
        parcel.writeDouble(mAltitude);
        parcel.writeInt(mHasSpeed ? 1 : 0);
        parcel.writeFloat(mSpeed);
        parcel.writeInt(mHasBearing ? 1 : 0);
        parcel.writeFloat(mBearing);
        parcel.writeInt(mHasAccuracy ? 1 : 0);
        parcel.writeFloat(mAccuracy);
        parcel.writeBundle(mExtras);
        parcel.writeInt(mIsFromMockProvider? 1 : 0);
    }

    /**
@@ -946,7 +943,7 @@ public class Location implements Parcelable {
     * Attaches an extra {@link Location} to this Location.
     *
     * @param key the key associated with the Location extra
     * @param location the Location to attach
     * @param value the Location to attach
     * @hide
     */
    public void setExtraLocation(String key, Location value) {
@@ -962,7 +959,7 @@ public class Location implements Parcelable {
     * @return true if this Location came from a mock provider, false otherwise
     */
    public boolean isFromMockProvider() {
        return mIsFromMockProvider;
        return (mFieldsMask & HAS_MOCK_PROVIDER_MASK) != 0;
    }

    /**
@@ -973,6 +970,24 @@ public class Location implements Parcelable {
     */
    @SystemApi
    public void setIsFromMockProvider(boolean isFromMockProvider) {
        mIsFromMockProvider = isFromMockProvider;
        if (isFromMockProvider) {
            mFieldsMask |= HAS_MOCK_PROVIDER_MASK;
        } else {
            mFieldsMask &= ~HAS_MOCK_PROVIDER_MASK;
        }
    }

    /**
     * Caches data used to compute distance and bearing (so successive calls to {@link #distanceTo}
     * and {@link #bearingTo} don't duplicate work.
     */
    private static class BearingDistanceCache {
        private double mLat1 = 0.0;
        private double mLon1 = 0.0;
        private double mLat2 = 0.0;
        private double mLon2 = 0.0;
        private float mDistance = 0.0f;
        private float mInitialBearing = 0.0f;
        private float mFinalBearing = 0.0f;
    }
}
+35 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.location;

import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;

import junit.framework.TestCase;
@@ -225,6 +226,40 @@ public class LocationTest extends TestCase {
        assertEquals(message, loc.getBearing(), 0, 0);
    }

    public void testParcel() {
        final double expectedLat = 33;
        final double expectedLon = -122;
        final float expectedAccuracy = 15;
        final float expectedSpeed = 5;
        Location loc = new Location("test");
        loc.setLatitude(expectedLat);
        loc.setLongitude(expectedLon);
        loc.setAccuracy(expectedAccuracy);
        loc.setSpeed(expectedSpeed);

        // Serialize location object into bytes via parcelable capability
        Parcel parcel = Parcel.obtain();
        loc.writeToParcel(parcel, 0);
        byte[] rawBytes = parcel.marshall();
        parcel.recycle();

        // Turn the bytes back into a location object
        parcel = Parcel.obtain();
        parcel.unmarshall(rawBytes, 0, rawBytes.length);
        parcel.setDataPosition(0);
        Location deserialized = Location.CREATOR.createFromParcel(parcel);
        parcel.recycle();

        assertEquals(expectedLat, deserialized.getLatitude());
        assertEquals(expectedLon, deserialized.getLongitude());
        assertEquals(expectedAccuracy, deserialized.getAccuracy());
        assertTrue(deserialized.hasAccuracy());
        assertEquals(expectedSpeed, deserialized.getSpeed());
        assertTrue(deserialized.hasSpeed());
        assertFalse(deserialized.hasBearing());
        assertFalse(deserialized.hasAltitude());
        assertFalse(deserialized.isFromMockProvider());
    }
}