|
2 | 2 |
|
3 | 3 | import android.Manifest; |
4 | 4 | import android.location.Location; |
| 5 | +import android.support.annotation.IntRange; |
5 | 6 | import android.support.annotation.RequiresPermission; |
| 7 | +import android.support.annotation.Size; |
6 | 8 |
|
7 | 9 | import java.util.concurrent.CopyOnWriteArrayList; |
8 | 10 |
|
9 | 11 | /** |
10 | | - * In part inspired by the LocationSource interface |
11 | | - * https://developers.google.com/android/reference/com/google/android/gms/maps/LocationSource |
| 12 | + * Abstract implementation of a location engine. A location engine makes it simple to switch between providers without |
| 13 | + * the hassle of including boilerplate inside your code. This allows developers to use Google Play Services location |
| 14 | + * provider or the default LOST location provider, among others. For a good example setting up a location engine from |
| 15 | + * this abstract class, have a look at the {@code LostLocationEngine} found inside the {@code libandroid-services} |
| 16 | + * module. |
| 17 | + * |
| 18 | + * @since 2.0.0 |
12 | 19 | */ |
13 | | - |
14 | 20 | public abstract class LocationEngine { |
15 | 21 |
|
16 | 22 | private static final int TWO_MINUTES = 1000 * 60 * 2; |
17 | 23 |
|
18 | 24 | protected int priority; |
| 25 | + protected Integer interval = 1000; |
| 26 | + protected Integer fastestInterval = 1000; |
| 27 | + protected Float smallestDisplacement = 3.0f; |
19 | 28 | protected CopyOnWriteArrayList<LocationEngineListener> locationListeners; |
20 | 29 |
|
| 30 | + /** |
| 31 | + * Construct a location engine. |
| 32 | + * |
| 33 | + * @since 2.0.0 |
| 34 | + */ |
21 | 35 | public LocationEngine() { |
22 | 36 | locationListeners = new CopyOnWriteArrayList<>(); |
23 | 37 | } |
24 | 38 |
|
| 39 | + /** |
| 40 | + * Activate the location engine which will connect whichever location provider you are using. You'll need to call |
| 41 | + * this before requesting user location updates using {@link LocationEngine#requestLocationUpdates()}. |
| 42 | + * |
| 43 | + * @since 2.0.0 |
| 44 | + */ |
25 | 45 | public abstract void activate(); |
26 | 46 |
|
| 47 | + /** |
| 48 | + * Disconnect the location engine, useful when you no longer need location updates or requesting the users |
| 49 | + * {@link LocationEngine#getLastLocation()}. Before deactivating you'll need to stop request user location updates |
| 50 | + * using {@link LocationEngine#removeLocationUpdates()}. |
| 51 | + * |
| 52 | + * @since 2.0.0 |
| 53 | + */ |
27 | 54 | public abstract void deactivate(); |
28 | 55 |
|
| 56 | + /** |
| 57 | + * Check if your location provider has been activated/connected. This is mainly used internally but is also useful in |
| 58 | + * the rare cases when you'd like to know if your location engine is connected or not. |
| 59 | + * |
| 60 | + * @return boolean true if the location engine has been activated/connected, else false. |
| 61 | + * @since 2.0.0 |
| 62 | + */ |
29 | 63 | public abstract boolean isConnected(); |
30 | 64 |
|
| 65 | + /** |
| 66 | + * When first initializing the location engine the location updates oftentimes aren't immediate and your user |
| 67 | + * experience might diminish since they are forced to wait till a more accurate update arrives. A solution to this is |
| 68 | + * to request the last known user location. There are no guarantees this won't return null since the {@link Location} |
| 69 | + * object is simply stored in cache. |
| 70 | + * |
| 71 | + * @return The last known user location as a {@link Location} object. |
| 72 | + * @since 2.0.0 |
| 73 | + */ |
31 | 74 | @RequiresPermission(anyOf = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}) |
32 | 75 | public abstract Location getLastLocation(); |
33 | 76 |
|
| 77 | + /** |
| 78 | + * if a {@link LocationEngineListener} is setup, registering for location updates will tell the provider to begin |
| 79 | + * sending updates. |
| 80 | + * |
| 81 | + * @since 2.0.0 |
| 82 | + */ |
34 | 83 | @RequiresPermission(anyOf = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}) |
35 | 84 | public abstract void requestLocationUpdates(); |
36 | 85 |
|
| 86 | + |
| 87 | + /** |
| 88 | + * When you no longer wish to receive location updates, you should call this method to prevent the devices battery |
| 89 | + * from draining. It's important to note that your location listeners will remain intake until you call |
| 90 | + * {@link LocationEngine#removeLocationEngineListener(LocationEngineListener)}. |
| 91 | + * |
| 92 | + * @since 2.0.0 |
| 93 | + */ |
37 | 94 | public abstract void removeLocationUpdates(); |
38 | 95 |
|
| 96 | + /** |
| 97 | + * Get the current priority being used. |
| 98 | + * |
| 99 | + * @return Integer representing one of the priorities listed inside the {@link LocationEnginePriority} file. |
| 100 | + * @since 2.0.0 |
| 101 | + */ |
39 | 102 | public int getPriority() { |
40 | 103 | return priority; |
41 | 104 | } |
42 | 105 |
|
43 | | - public void setPriority(int priority) { |
| 106 | + /** |
| 107 | + * This method sets the priority of the request, providing this will help the location provide know which location |
| 108 | + * sources to use. You'll find more information on the different priority values inside the |
| 109 | + * {@link LocationEnginePriority} file. |
| 110 | + * |
| 111 | + * @param priority One of the {@link LocationEnginePriority}s listed. |
| 112 | + * @since 2.0.0 |
| 113 | + */ |
| 114 | + public void setPriority(@IntRange(from = 0, to = 3) int priority) { |
44 | 115 | this.priority = priority; |
45 | 116 | } |
46 | 117 |
|
| 118 | + /** |
| 119 | + * Get the current interval being used to receive location updates. Default is 1 second. |
| 120 | + * |
| 121 | + * @return the current interval value being used in milliseconds. |
| 122 | + * @since 2.1.0 |
| 123 | + */ |
| 124 | + public int getInterval() { |
| 125 | + return interval; |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Set the rate in milliseconds at which your app prefers to receive location updates. Note that the location updates |
| 130 | + * may be faster than this rate if another app is receiving updates at a faster rate, or slower than this rate, or |
| 131 | + * there may be no updates at all (if the device has no connectivity, for example). |
| 132 | + * |
| 133 | + * @param interval integer in milliseconds defining the rate in which you'd like to receive location updates. |
| 134 | + * @since 2.1.0 |
| 135 | + */ |
| 136 | + public void setInterval(@Size(min = 0) int interval) { |
| 137 | + this.interval = interval; |
| 138 | + } |
| 139 | + |
| 140 | + /** |
| 141 | + * Get the current fastest interval being used to receive location updates. Default is 1 second. |
| 142 | + * |
| 143 | + * @return the current fastest interval value being used in milliseconds. |
| 144 | + * @since 2.1.0 |
| 145 | + */ |
| 146 | + public int getFastestInterval() { |
| 147 | + return fastestInterval; |
| 148 | + } |
| 149 | + |
| 150 | + /** |
| 151 | + * Set the fastest rate in milliseconds at which your application can handle location updates. You need to set |
| 152 | + * this rate because other apps also affect the rate at which updates are sent. If this rate is faster than your app |
| 153 | + * can handle, you may encounter problems with UI flicker or data overflow. To prevent this, use this method to set |
| 154 | + * an upper limit to the update rate. |
| 155 | + * |
| 156 | + * @param fastestInterval in milliseconds at which your app can handle location updates. |
| 157 | + * @since 2.1.0 |
| 158 | + */ |
| 159 | + public void setFastestInterval(@Size(min = 0) int fastestInterval) { |
| 160 | + this.fastestInterval = fastestInterval; |
| 161 | + } |
| 162 | + |
| 163 | + /** |
| 164 | + * Get the current smallest displacement being used to receive location updates. Default is 3 meters. |
| 165 | + * |
| 166 | + * @return the current smallest displacement value being used in meters. |
| 167 | + * @since 2.1.0 |
| 168 | + */ |
| 169 | + public float getSmallestDisplacement() { |
| 170 | + return smallestDisplacement; |
| 171 | + } |
| 172 | + |
| 173 | + /** |
| 174 | + * Set the smallest distance value in meters at which the user must move before a new location update comes in. |
| 175 | + * |
| 176 | + * @param smallestDisplacement in meters which the user must move before a new location update's supplied. |
| 177 | + * @since 2.1.0 |
| 178 | + */ |
| 179 | + public void setSmallestDisplacement(@Size(min = 0) float smallestDisplacement) { |
| 180 | + this.smallestDisplacement = smallestDisplacement; |
| 181 | + } |
| 182 | + |
| 183 | + /** |
| 184 | + * Useful when you'd like to add a location listener to handle location connections and update events. It is important |
| 185 | + * to note, that the callback will continue getting called even when your application isn't in the foreground. |
| 186 | + * Therefore, it is a good idea to use {@link LocationEngine#removeLocationEngineListener(LocationEngineListener)} |
| 187 | + * inside your activities {@code onStop()} method. |
| 188 | + * |
| 189 | + * @param listener A {@link LocationEngineListener} which you'd like to add to your location engine. |
| 190 | + * @since 2.0.0 |
| 191 | + */ |
47 | 192 | public void addLocationEngineListener(LocationEngineListener listener) { |
48 | 193 | if (!this.locationListeners.contains(listener)) { |
49 | 194 | this.locationListeners.add(listener); |
50 | 195 | } |
51 | 196 | } |
52 | 197 |
|
| 198 | + /** |
| 199 | + * If you no longer need your {@link LocationEngineListener} to be invoked with every location update, use this |
| 200 | + * method to remove it. It's also important to remove your listeners before the activity is destroyed to prevent any |
| 201 | + * potential memory leaks. |
| 202 | + * |
| 203 | + * @param listener the {@link LocationEngineListener} you'd like to remove from this {@link LocationEngine}. |
| 204 | + * @return true if the listener has been removed, else false. |
| 205 | + * @since 2.0.0 |
| 206 | + */ |
53 | 207 | public boolean removeLocationEngineListener(LocationEngineListener listener) { |
54 | 208 | return this.locationListeners.remove(listener); |
55 | 209 | } |
56 | 210 |
|
57 | 211 | /** |
58 | | - * Determines whether one Location reading is better than the current Location fix |
59 | | - * https://developer.android.com/guide/topics/location/strategies.html#BestEstimate |
| 212 | + * Determines whether one Location reading is better than the current Location fix. This is great to check whether |
| 213 | + * the most recent location fix is more accurate then a previous. The result of this criteria also varies depending |
| 214 | + * on the use-cases of the application and field testing. More specifically, this method checks if the location |
| 215 | + * retrieved is significantly newer than the previous estimate, checks if the accuracy claimed by the location is |
| 216 | + * better or worse than the previous estimate, and check which provider the new location is from and determine if |
| 217 | + * you trust it more. |
60 | 218 | * |
61 | | - * @param location The new Location that you want to evaluate |
62 | | - * @param currentBestLocation The current Location fix, to which you want to compare the new one |
| 219 | + * @param location The new Location that you want to evaluate. |
| 220 | + * @param currentBestLocation The current Location fix, to which you want to compare the new one. |
| 221 | + * @since 2.0.0 |
63 | 222 | */ |
64 | 223 | protected static boolean isBetterLocation(Location location, Location currentBestLocation) { |
65 | 224 | if (currentBestLocation == null) { |
@@ -104,11 +263,7 @@ protected static boolean isBetterLocation(Location location, Location currentBes |
104 | 263 | return false; |
105 | 264 | } |
106 | 265 |
|
107 | | - /** |
108 | | - * Checks whether two providers are the same |
109 | | - * https://developer.android.com/guide/topics/location/strategies.html#BestEstimate |
110 | | - * */ |
111 | | - public static boolean isSameProvider(String provider1, String provider2) { |
| 266 | + private static boolean isSameProvider(String provider1, String provider2) { |
112 | 267 | if (provider1 == null) { |
113 | 268 | return provider2 == null; |
114 | 269 | } |
|
0 commit comments