133873d2b41a5cd2597b20a4e88eb8942944c0f23Tyler Schultzpackage com.xtremelabs.robolectric.shadows;
21d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
31d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richardimport android.location.Location;
42f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchilleimport android.os.Bundle;
522c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.Implementation;
622c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.Implements;
71d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
8093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richardimport static com.xtremelabs.robolectric.Robolectric.shadowOf_;
9093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard
1059d9df0f147b94712b36ad44939ebd2afa4cf1b7Phil Goodwin/**
1159d9df0f147b94712b36ad44939ebd2afa4cf1b7Phil Goodwin * Shadow of {@code Location} that treats it primarily as a data-holder
1259d9df0f147b94712b36ad44939ebd2afa4cf1b7Phil Goodwin * todo: support Location's static utility methods
1359d9df0f147b94712b36ad44939ebd2afa4cf1b7Phil Goodwin */
1459d9df0f147b94712b36ad44939ebd2afa4cf1b7Phil Goodwin
151d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard@SuppressWarnings({"UnusedDeclaration"})
161d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard@Implements(Location.class)
17afe0a89d904a7fe2f5980b9deb26cc3240192459Christian Williamspublic class ShadowLocation {
181d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    private long time;
191d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    private String provider;
201d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    private double latitude;
211d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    private double longitude;
22c2d957dabd415221fc6d8b698045e2bed6caa5c7Adam Cohen-Rose    private float accuracy;
2362ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    private float bearing;
2462ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    private double altitude;
2562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    private float speed;
2662ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    private boolean hasAccuracy;
2762ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    private boolean hasAltitude;
2862ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    private boolean hasBearing;
2962ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    private boolean hasSpeed;
30b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
31e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    // Cache the inputs and outputs of computeDistanceAndBearing
32e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    // so calls to distanceTo() and bearingTo() can share work
33e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    private double mLat1 = 0.0;
34e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    private double mLon1 = 0.0;
35e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    private double mLat2 = 0.0;
36e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    private double mLon2 = 0.0;
37e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    private float mDistance = 0.0f;
38e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    private float mInitialBearing = 0.0f;
39e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    // Scratchpad
40b3438371b252df848ae681fadc4b33d67de63721Jan Berkel    private final float[] mResults = new float[2];
41b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
422f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille    private Bundle extras = new Bundle();
432f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille
44093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard    public void __constructor__(Location l) {
45093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard        set(l);
46093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard    }
47093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard
4817969d4f202bc5c4f60a6598b85fea1d378b4a66Adam Cohen-Rose    public void __constructor__(String provider) {
49323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.provider = provider;
50323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        time = System.currentTimeMillis();
5117969d4f202bc5c4f60a6598b85fea1d378b4a66Adam Cohen-Rose    }
521d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
53de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
54093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard    public void set(Location l) {
55093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard        time = l.getTime();
56093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard        provider = l.getProvider();
57093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard        latitude = l.getLatitude();
58093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard        longitude = l.getLongitude();
59093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard        accuracy = l.getAccuracy();
6062ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        bearing = l.getBearing();
6162ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        altitude = l.getAltitude();
6262ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        speed = l.getSpeed();
63b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
6462ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        hasAccuracy = l.hasAccuracy();
6562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        hasAltitude = l.hasAltitude();
6662ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        hasBearing = l.hasBearing();
6762ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        hasSpeed = l.hasSpeed();
68093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard    }
69093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard
70093f83e427cab119e9f35d80e5dd9d165387c62aRyan Richard    @Implementation
711d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public String getProvider() {
721d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        return provider;
731d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
741d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
75de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
761d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public void setProvider(String provider) {
771d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        this.provider = provider;
781d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
791d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
80de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
811d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public long getTime() {
821d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        return time;
831d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
841d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
85de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
861d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public void setTime(long time) {
871d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        this.time = time;
881d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
891d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
90de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
9162ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public float getAccuracy() {
92323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        return accuracy;
93323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
94b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
9562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
9662ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public void setAccuracy(float accuracy) {
97323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.accuracy = accuracy;
98323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasAccuracy = true;
99323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
100b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
10162ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
102b3438371b252df848ae681fadc4b33d67de63721Jan Berkel    public void removeAccuracy() {
103323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.accuracy = 0.0f;
104323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasAccuracy = false;
10562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
10662ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer
10762ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
10862ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public boolean hasAccuracy() {
10962ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        return hasAccuracy;
11062ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
11162ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer
11262ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
11362ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public double getAltitude() {
114323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        return altitude;
115323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
116b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
11762ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
11862ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public void setAltitude(double altitude) {
119323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.altitude = altitude;
120323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasAltitude = true;
121323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
12262ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer
12362ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
124b3438371b252df848ae681fadc4b33d67de63721Jan Berkel    public void removeAltitude() {
125323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.altitude = 0.0d;
126323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasAltitude = false;
12762ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
12862ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer
12962ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
13062ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public boolean hasAltitude() {
13162ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        return hasAltitude;
13262ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
133b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
13462ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
13562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public float getBearing() {
136323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        return bearing;
137323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
138b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
13962ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
14062ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public void setBearing(float bearing) {
141323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.bearing = bearing;
142323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasBearing = true;
143323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
144b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
14562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
146b3438371b252df848ae681fadc4b33d67de63721Jan Berkel    public void removeBearing() {
147323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.bearing = 0.0f;
148323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasBearing = false;
14962ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
150b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
15162ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
15262ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public boolean hasBearing() {
15362ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        return hasBearing;
15462ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
15562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer
156b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
15762ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
1581d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public double getLatitude() {
1591d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        return latitude;
1601d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
1611d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
162de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1631d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public void setLatitude(double latitude) {
1641d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        this.latitude = latitude;
1651d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
1661d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
167de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1681d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public double getLongitude() {
1691d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        return longitude;
1701d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
1711d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
172de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1731d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public void setLongitude(double longitude) {
1741d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        this.longitude = longitude;
1751d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
176b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
177c2d957dabd415221fc6d8b698045e2bed6caa5c7Adam Cohen-Rose    @Implementation
17862ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public float getSpeed() {
179323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        return speed;
180323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
181b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
182c2d957dabd415221fc6d8b698045e2bed6caa5c7Adam Cohen-Rose    @Implementation
18362ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public void setSpeed(float speed) {
184323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.speed = speed;
185323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasSpeed = true;
186323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer    }
187b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
18862ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
189b3438371b252df848ae681fadc4b33d67de63721Jan Berkel    public void removeSpeed() {
190323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.hasSpeed = false;
191323389e10bc2073083f03b4f928a3f4c9f793d4cMatthias Kiefer        this.speed = 0.0f;
19262ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
19362ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer
19462ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    @Implementation
19562ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    public boolean hasSpeed() {
19662ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer        return hasSpeed;
19762ee66897fa153fdedb030ee6319d6cf18b343feMatthias Kiefer    }
198b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
199bbf6ae3d37d2303d8463094096ef0bb9906fd658Christian Williams    @Override @Implementation
2001d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public boolean equals(Object o) {
201537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin        if (o == null) return false;
202537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin        o = shadowOf_(o);
203537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin        if (o == null) return false;
204537f38b99433fee0ee08d7c634763e7381942f58Phil Goodwin        if (getClass() != o.getClass()) return false;
2051d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        if (this == o) return true;
2061d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
207afe0a89d904a7fe2f5980b9deb26cc3240192459Christian Williams        ShadowLocation that = (ShadowLocation) o;
2081d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
2091d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        if (Double.compare(that.latitude, latitude) != 0) return false;
2101d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        if (Double.compare(that.longitude, longitude) != 0) return false;
2111d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        if (time != that.time) return false;
2121d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        if (provider != null ? !provider.equals(that.provider) : that.provider != null) return false;
213c2d957dabd415221fc6d8b698045e2bed6caa5c7Adam Cohen-Rose        if (accuracy != that.accuracy) return false;
2141d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        return true;
2151d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
2161d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
217bbf6ae3d37d2303d8463094096ef0bb9906fd658Christian Williams    @Override @Implementation
2181d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    public int hashCode() {
2191d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        int result;
2201d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        long temp;
2211d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        result = (int) (time ^ (time >>> 32));
2221d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        result = 31 * result + (provider != null ? provider.hashCode() : 0);
2231d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        temp = latitude != +0.0d ? Double.doubleToLongBits(latitude) : 0L;
2241d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        result = 31 * result + (int) (temp ^ (temp >>> 32));
2251d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        temp = longitude != +0.0d ? Double.doubleToLongBits(longitude) : 0L;
2261d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        result = 31 * result + (int) (temp ^ (temp >>> 32));
227c2d957dabd415221fc6d8b698045e2bed6caa5c7Adam Cohen-Rose        temp = accuracy != 0f ? Float.floatToIntBits(accuracy) : 0;
228c2d957dabd415221fc6d8b698045e2bed6caa5c7Adam Cohen-Rose        result = 31 * result + (int) (temp ^ (temp >>> 32));
2291d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        return result;
2301d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
2311d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard
232bbf6ae3d37d2303d8463094096ef0bb9906fd658Christian Williams    @Override @Implementation
233bbf6ae3d37d2303d8463094096ef0bb9906fd658Christian Williams    public String toString() {
2341d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard        return "Location{" +
2351d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard                "time=" + time +
2361d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard                ", provider='" + provider + '\'' +
2371d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard                ", latitude=" + latitude +
2381d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard                ", longitude=" + longitude +
239c2d957dabd415221fc6d8b698045e2bed6caa5c7Adam Cohen-Rose                ", accuracy=" + accuracy +
2401d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard                '}';
2411d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard    }
242b3438371b252df848ae681fadc4b33d67de63721Jan Berkel
243e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    private static void computeDistanceAndBearing(double lat1, double lon1,
244e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double lat2, double lon2, float[] results) {
245e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
246e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        // using the "Inverse Formula" (section 4)
247e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
248e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        int MAXITERS = 20;
249e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        // Convert lat/long to radians
250e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        lat1 *= Math.PI / 180.0;
251e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        lat2 *= Math.PI / 180.0;
252e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        lon1 *= Math.PI / 180.0;
253e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        lon2 *= Math.PI / 180.0;
254e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
255e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double a = 6378137.0; // WGS84 major axis
256e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double b = 6356752.3142; // WGS84 semi-major axis
257e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double f = (a - b) / a;
258e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
259e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
260e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double L = lon2 - lon1;
261e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double A = 0.0;
262e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
263e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
264e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
265e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double cosU1 = Math.cos(U1);
266e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double cosU2 = Math.cos(U2);
267e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double sinU1 = Math.sin(U1);
268e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double sinU2 = Math.sin(U2);
269e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double cosU1cosU2 = cosU1 * cosU2;
270e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double sinU1sinU2 = sinU1 * sinU2;
271e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
272e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double sigma = 0.0;
273e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double deltaSigma = 0.0;
274e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double cosSqAlpha = 0.0;
275e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double cos2SM = 0.0;
276e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double cosSigma = 0.0;
277e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double sinSigma = 0.0;
278e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double cosLambda = 0.0;
279e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double sinLambda = 0.0;
280e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
281e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double lambda = L; // initial guess
282e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        for (int iter = 0; iter < MAXITERS; iter++) {
283e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double lambdaOrig = lambda;
284e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            cosLambda = Math.cos(lambda);
285e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            sinLambda = Math.sin(lambda);
286e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double t1 = cosU2 * sinLambda;
287e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
288e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double sinSqSigma = t1 * t1 + t2 * t2; // (14)
289e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            sinSigma = Math.sqrt(sinSqSigma);
290e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
291e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            sigma = Math.atan2(sinSigma, cosSigma); // (16)
292e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double sinAlpha = (sinSigma == 0) ? 0.0 :
293e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                cosU1cosU2 * sinLambda / sinSigma; // (17)
294e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
295e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            cos2SM = (cosSqAlpha == 0) ? 0.0 :
296e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
297e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
298e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
299e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            A = 1 + (uSquared / 16384.0) * // (3)
300e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                (4096.0 + uSquared *
301e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                 (-768 + uSquared * (320.0 - 175.0 * uSquared)));
302e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double B = (uSquared / 1024.0) * // (4)
303e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                (256.0 + uSquared *
304e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                 (-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
305e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double C = (f / 16.0) *
306e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                cosSqAlpha *
307e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
308e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double cos2SMSq = cos2SM * cos2SM;
309e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            deltaSigma = B * sinSigma * // (6)
310e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                (cos2SM + (B / 4.0) *
311e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                 (cosSigma * (-1.0 + 2.0 * cos2SMSq) -
312e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                  (B / 6.0) * cos2SM *
313e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                  (-3.0 + 4.0 * sinSigma * sinSigma) *
314e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                  (-3.0 + 4.0 * cos2SMSq)));
315e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
316e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            lambda = L +
317e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                (1.0 - C) * f * sinAlpha *
318e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                (sigma + C * sinSigma *
319e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                 (cos2SM + C * cosSigma *
320e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                  (-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
321e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
322e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            double delta = (lambda - lambdaOrig) / lambda;
323e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            if (Math.abs(delta) < 1.0e-12) {
324e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                break;
325e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            }
326e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        }
327e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
328e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        float distance = (float) (b * A * (sigma - deltaSigma));
329e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        results[0] = distance;
330e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        if (results.length > 1) {
331e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
332e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
333e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            initialBearing *= 180.0 / Math.PI;
334e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            results[1] = initialBearing;
335e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            if (results.length > 2) {
336e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
337e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                    -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
338e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                finalBearing *= 180.0 / Math.PI;
339e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                results[2] = finalBearing;
340e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            }
341e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        }
342e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    }
343e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
344e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    /**
345e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * Computes the approximate distance in meters between two
346e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * locations, and optionally the initial and final bearings of the
347e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * shortest path between them.  Distance and bearing are defined using the
348e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * WGS84 ellipsoid.
349e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     *
350e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * <p> The computed distance is stored in results[0].  If results has length
351e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * 2 or greater, the initial bearing is stored in results[1]. If results has
352e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * length 3 or greater, the final bearing is stored in results[2].
353e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     *
354e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @param startLatitude the starting latitude
355e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @param startLongitude the starting longitude
356e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @param endLatitude the ending latitude
357e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @param endLongitude the ending longitude
358e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @param results an array of floats to hold the results
359e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     *
360e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @throws IllegalArgumentException if results is null or has length < 1
361e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     */
362e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    @Implementation
363e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    public static void distanceBetween(double startLatitude, double startLongitude,
364e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        double endLatitude, double endLongitude, float[] results) {
365e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        if (results == null || results.length < 1) {
366e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            throw new IllegalArgumentException("results is null or has length < 1");
367e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        }
368e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        computeDistanceAndBearing(startLatitude, startLongitude,
369e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            endLatitude, endLongitude, results);
370e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    }
371e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
372e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    /**
373e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * Returns the approximate distance in meters between this
374e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * location and the given location.  Distance is defined using
375e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * the WGS84 ellipsoid.
376e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     *
377e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @param dest the destination location
378e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @return the approximate distance in meters
379e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     */
380e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    @Implementation
381e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    public float distanceTo(Location dest) {
382e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        // See if we already have the result
383e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        synchronized (mResults) {
384e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            if (latitude != mLat1 || longitude != mLon1 ||
385e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                dest.getLatitude() != mLat2 || dest.getLongitude() != mLon2) {
386e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                computeDistanceAndBearing(latitude, longitude,
387e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                    dest.getLatitude(), dest.getLongitude(), mResults);
388e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLat1 = latitude;
389e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLon1 = longitude;
390e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLat2 = dest.getLatitude();
391e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLon2 = dest.getLongitude();
392e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mDistance = mResults[0];
393e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mInitialBearing = mResults[1];
394e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            }
395e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            return mDistance;
396e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        }
397e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    }
398e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose
399e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    /**
400e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * Returns the approximate initial bearing in degrees East of true
401e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * North when traveling along the shortest path between this
402e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * location and the given location.  The shortest path is defined
403e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * using the WGS84 ellipsoid.  Locations that are (nearly)
404e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * antipodal may produce meaningless results.
405e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     *
406e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @param dest the destination location
407e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     * @return the initial bearing in degrees
408e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose     */
409e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    @Implementation
410e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    public float bearingTo(Location dest) {
411e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        synchronized (mResults) {
412e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            // See if we already have the result
413e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            if (latitude != mLat1 || longitude != mLon1 ||
414e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                            dest.getLatitude() != mLat2 || dest.getLongitude() != mLon2) {
415e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                computeDistanceAndBearing(latitude, longitude,
416e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                    dest.getLatitude(), dest.getLongitude(), mResults);
417e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLat1 = latitude;
418e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLon1 = longitude;
419e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLat2 = dest.getLatitude();
420e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mLon2 = dest.getLongitude();
421e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mDistance = mResults[0];
422e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose                mInitialBearing = mResults[1];
423e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            }
424e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose            return mInitialBearing;
425e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose        }
426e82ab86b5f0e7d7d01386e17820a0fefa5dd53c4Adam Cohen-Rose    }
4272f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille
4282f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille    @Implementation
4292f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille    public Bundle getExtras() {
4302f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille        return extras;
4312f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille    }
4322f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille
4332f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille    @Implementation
4342f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille    public void setExtras(Bundle extras) {
4352f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille        this.extras = extras;
4362f801b3a28ca4b90be2f8ab46041f93d0ce9aedcStefano Dacchille    }
4371d9f4919935ddc729e248df65ba6365f337eec42Christian Williams & Ryan Richard}
438