java.lang.Object
↳androidx.core.location.LocationCompat
Gradle dependencies
compile group: 'androidx.core', name: 'core', version: '1.15.0-alpha02'
- groupId: androidx.core
- artifactId: core
- version: 1.15.0-alpha02
Artifact androidx.core:core:1.15.0-alpha02 it located at Google repository (https://maven.google.com/)
Androidx artifact mapping:
androidx.core:core com.android.support:support-compat
Overview
Helper for accessing features in .
Summary
Fields |
---|
public static final java.lang.String | EXTRA_BEARING_ACCURACY Constant used as a key to store bearing accuracy in for
Android SDK levels below Oreo (26). |
public static final java.lang.String | EXTRA_IS_MOCK Constant used as a key to store mock location status in for
Android SDK levels below JBMR2 (18). |
public static final java.lang.String | EXTRA_MSL_ALTITUDE Constant used as a key to store Mean Sea Level altitude in . |
public static final java.lang.String | EXTRA_MSL_ALTITUDE_ACCURACY Constant used as a key to store Mean Sea Level altitude in . |
public static final java.lang.String | EXTRA_SPEED_ACCURACY Constant used as a key to store speed accuracy in for
Android SDK levels below Oreo (26). |
public static final java.lang.String | EXTRA_VERTICAL_ACCURACY Constant used as a key to store vertical accuracy in for
Android SDK levels below Oreo (26). |
Methods |
---|
public static float | getBearingAccuracyDegrees(Location location)
Get the estimated bearing accuracy of this location in degrees. |
public static long | getElapsedRealtimeMillis(Location location)
Return the time of this fix, in milliseconds of elapsed real-time since system boot. |
public static long | getElapsedRealtimeNanos(Location location)
Return the time of this fix, in nanoseconds of elapsed real-time since system boot. |
public static float | getMslAltitudeAccuracyMeters(Location location)
Returns the estimated Mean Sea Level altitude accuracy in meters of the location at the 68th
percentile confidence level. |
public static double | getMslAltitudeMeters(Location location)
Returns the Mean Sea Level altitude of the location in meters. |
public static float | getSpeedAccuracyMetersPerSecond(Location location)
Get the estimated speed accuracy of this location in meters per second. |
public static float | getVerticalAccuracyMeters(Location location)
Get the estimated vertical accuracy of this location in meters. |
public static boolean | hasBearingAccuracy(Location location)
Returns true if this location has a bearing accuracy. |
public static boolean | hasMslAltitude(Location location)
Returns true if the location has a Mean Sea Level altitude, false otherwise. |
public static boolean | hasMslAltitudeAccuracy(Location location)
Returns true if the location has a Mean Sea Level altitude accuracy, false otherwise. |
public static boolean | hasSpeedAccuracy(Location location)
Returns true if this location has a speed accuracy. |
public static boolean | hasVerticalAccuracy(Location location)
Returns true if this location has a vertical accuracy. |
public static boolean | isMock(Location location)
Returns true if this location is marked as a mock location. |
public static void | removeBearingAccuracy(Location location)
Removes the bearing accuracy from the location. |
public static void | removeMslAltitude(Location location)
Removes the Mean Sea Level altitude from the location. |
public static void | removeMslAltitudeAccuracy(Location location)
Removes the Mean Sea Level altitude accuracy from the location. |
public static void | removeSpeedAccuracy(Location location)
Removes the speed accuracy from the location. |
public static void | removeVerticalAccuracy(Location location)
Removes the vertical accuracy from the location. |
public static void | setBearingAccuracyDegrees(Location location, float bearingAccuracyD)
Set the estimated bearing accuracy of this location in degrees. |
public static void | setMock(Location location, boolean mock)
Sets whether this location is marked as a mock location. |
public static void | setMslAltitudeAccuracyMeters(Location location, float mslAltitudeAccuracyMeters)
Sets the Mean Sea Level altitude accuracy of the location in meters. |
public static void | setMslAltitudeMeters(Location location, double mslAltitudeMeters)
Sets the Mean Sea Level altitude of the location in meters. |
public static void | setSpeedAccuracyMetersPerSecond(Location location, float speedAccuracyMps)
Set the estimated speed accuracy of this location in meters per second. |
public static void | setVerticalAccuracyMeters(Location location, float verticalAccuracyM)
Set the estimated vertical accuracy of this location in meters. |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Fields
public static final java.lang.String
EXTRA_IS_MOCKConstant used as a key to store mock location status in for
Android SDK levels below JBMR2 (18).
public static final java.lang.String
EXTRA_VERTICAL_ACCURACYConstant used as a key to store vertical accuracy in for
Android SDK levels below Oreo (26).
public static final java.lang.String
EXTRA_SPEED_ACCURACYConstant used as a key to store speed accuracy in for
Android SDK levels below Oreo (26).
public static final java.lang.String
EXTRA_BEARING_ACCURACYConstant used as a key to store bearing accuracy in for
Android SDK levels below Oreo (26).
public static final java.lang.String
EXTRA_MSL_ALTITUDEConstant used as a key to store Mean Sea Level altitude in .
public static final java.lang.String
EXTRA_MSL_ALTITUDE_ACCURACYConstant used as a key to store Mean Sea Level altitude in .
Methods
public static long
getElapsedRealtimeNanos(Location location)
Deprecated: Call directly.
Return the time of this fix, in nanoseconds of elapsed real-time since system boot.
This value can be reliably compared to SystemClock.elapsedRealtimeNanos(), to calculate
the age of a fix and to compare location fixes. This is reliable because elapsed real-time
is guaranteed monotonic for each system boot and continues to increment even when the
system is in deep sleep (unlike getTime().
All locations generated by the LocationManager are guaranteed to have a valid elapsed
real-time.
NOTE: On API levels below 17, this method will attempt to provide an elapsed realtime
based on the difference between system time and the location time. This should be taken as a
best "guess" at what the elapsed realtime might have been, but if the clock used for
location derivation is different from the system clock, the results may be inaccurate.
public static long
getElapsedRealtimeMillis(Location location)
Return the time of this fix, in milliseconds of elapsed real-time since system boot.
See also: LocationCompat.getElapsedRealtimeNanos(Location)
public static boolean
hasVerticalAccuracy(Location location)
Returns true if this location has a vertical accuracy.
See also:
public static float
getVerticalAccuracyMeters(Location location)
Get the estimated vertical accuracy of this location in meters.
NOTE: On API levels below 26, the concept of vertical accuracy does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to read a
float extra with the key LocationCompat.EXTRA_VERTICAL_ACCURACY and return the result.
See also:
public static void
setVerticalAccuracyMeters(Location location, float verticalAccuracyM)
Set the estimated vertical accuracy of this location in meters.
NOTE: On API levels below 26, the concept of vertical accuracy does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to set a
float extra with the key LocationCompat.EXTRA_VERTICAL_ACCURACY to include vertical accuracy. Be
aware that this will overwrite any prior extra value under the same key.
See also:
public static void
removeVerticalAccuracy(Location location)
Removes the vertical accuracy from the location.
public static boolean
hasSpeedAccuracy(Location location)
Returns true if this location has a speed accuracy.
See also:
public static float
getSpeedAccuracyMetersPerSecond(Location location)
Get the estimated speed accuracy of this location in meters per second.
NOTE: On API levels below 26, the concept of speed accuracy does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to read a
float extra with the key LocationCompat.EXTRA_SPEED_ACCURACY and return the result.
See also:
public static void
setSpeedAccuracyMetersPerSecond(Location location, float speedAccuracyMps)
Set the estimated speed accuracy of this location in meters per second.
NOTE: On API levels below 26, the concept of speed accuracy does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to set a
float extra with the key LocationCompat.EXTRA_SPEED_ACCURACY to include speed accuracy. Be
aware that this will overwrite any prior extra value under the same key.
See also:
public static void
removeSpeedAccuracy(Location location)
Removes the speed accuracy from the location.
public static boolean
hasBearingAccuracy(Location location)
Returns true if this location has a bearing accuracy.
See also:
public static float
getBearingAccuracyDegrees(Location location)
Get the estimated bearing accuracy of this location in degrees.
NOTE: On API levels below 26, the concept of bearing accuracy does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to read a
float extra with the key LocationCompat.EXTRA_BEARING_ACCURACY and return the result.
See also:
public static void
setBearingAccuracyDegrees(Location location, float bearingAccuracyD)
Set the estimated bearing accuracy of this location in degrees.
NOTE: On API levels below 26, the concept of bearing accuracy does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to set a
float extra with the key LocationCompat.EXTRA_BEARING_ACCURACY to include bearing accuracy. Be
aware that this will overwrite any prior extra value under the same key.
See also:
public static void
removeBearingAccuracy(Location location)
Removes the bearing accuracy from the location.
public static double
getMslAltitudeMeters(Location location)
Returns the Mean Sea Level altitude of the location in meters.
This is only valid if LocationCompat.hasMslAltitude(Location) is true.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
order to allow for backwards compatibility and testing however, this method will attempt
to read a double extra with the key LocationCompat.EXTRA_MSL_ALTITUDE and return the result.
See also:
public static void
setMslAltitudeMeters(Location location, double mslAltitudeMeters)
Sets the Mean Sea Level altitude of the location in meters.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
order to allow for backwards compatibility and testing however, this method will attempt
to set a double extra with the key LocationCompat.EXTRA_MSL_ALTITUDE to include Mean Sea Level
altitude. Be aware that this will overwrite any prior extra value under the same key.
See also:
public static boolean
hasMslAltitude(Location location)
Returns true if the location has a Mean Sea Level altitude, false otherwise.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
order to allow for backwards compatibility and testing however, this method will return
true if an extra value is with the key LocationCompat.EXTRA_MSL_ALTITUDE.
See also:
public static void
removeMslAltitude(Location location)
Removes the Mean Sea Level altitude from the location.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
order to allow for backwards compatibility and testing however, this method will attempt
to remove any extra value with the key LocationCompat.EXTRA_MSL_ALTITUDE.
See also:
public static float
getMslAltitudeAccuracyMeters(Location location)
Returns the estimated Mean Sea Level altitude accuracy in meters of the location at the 68th
percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
altitude of the location falls within LocationCompat.getMslAltitudeMeters(Location) +/- this
uncertainty.
This is only valid if LocationCompat.hasMslAltitudeAccuracy(Location) is true.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
exist. In order to allow for backwards compatibility and testing however, this method will
attempt to read a float extra with the key LocationCompat.EXTRA_MSL_ALTITUDE_ACCURACY and return
the result.
See also:
public static void
setMslAltitudeAccuracyMeters(Location location, float mslAltitudeAccuracyMeters)
Sets the Mean Sea Level altitude accuracy of the location in meters.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
exist. In order to allow for backwards compatibility and testing however, this method will
attempt to set a float extra with the key LocationCompat.EXTRA_MSL_ALTITUDE_ACCURACY to include
Mean Sea Level altitude accuracy. Be aware that this will overwrite any prior extra value
under the same key.
See also:
public static boolean
hasMslAltitudeAccuracy(Location location)
Returns true if the location has a Mean Sea Level altitude accuracy, false otherwise.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
exist. In order to allow for backwards compatibility and testing however, this method will
return true if an extra value is with the key LocationCompat.EXTRA_MSL_ALTITUDE_ACCURACY.
See also:
public static void
removeMslAltitudeAccuracy(Location location)
Removes the Mean Sea Level altitude accuracy from the location.
NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
exist. In order to allow for backwards compatibility and testing however, this method will
attempt to remove any extra value with the key LocationCompat.EXTRA_MSL_ALTITUDE_ACCURACY.
See also:
public static boolean
isMock(Location location)
Returns true if this location is marked as a mock location. If this location comes from the
Android framework, this indicates that the location was provided by a test location provider,
and thus may not be related to the actual location of the device.
NOTE: On API levels below 18, the concept of a mock location does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to read a
boolean extra with the key LocationCompat.EXTRA_IS_MOCK and use the result to determine whether
this should be considered a mock location.
See also:
public static void
setMock(Location location, boolean mock)
Sets whether this location is marked as a mock location.
NOTE: On API levels below 18, the concept of a mock location does not exist. In order to
allow for backwards compatibility and testing however, this method will attempt to set a
boolean extra with the key LocationCompat.EXTRA_IS_MOCK to mark the location as mock. Be aware that
this will overwrite any prior extra value under the same key.
Source
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.core.location;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.annotation.SuppressLint;
import android.location.Location;
import android.os.Build.VERSION;
import android.os.Bundle;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Helper for accessing features in {@link android.location.Location}.
*/
public final class LocationCompat {
/**
* Constant used as a key to store mock location status in {@link Location#getExtras()} for
* Android SDK levels below JBMR2 (18).
*/
@SuppressWarnings("ActionValue") // legacy value
public static final String EXTRA_IS_MOCK = "mockLocation";
/**
* Constant used as a key to store vertical accuracy in {@link Location#getExtras()} for
* Android SDK levels below Oreo (26).
*/
@SuppressWarnings("ActionValue") // legacy value
public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
/**
* Constant used as a key to store speed accuracy in {@link Location#getExtras()} for
* Android SDK levels below Oreo (26).
*/
@SuppressWarnings("ActionValue") // legacy value
public static final String EXTRA_SPEED_ACCURACY = "speedAccuracy";
/**
* Constant used as a key to store bearing accuracy in {@link Location#getExtras()} for
* Android SDK levels below Oreo (26).
*/
@SuppressWarnings("ActionValue") // legacy value
public static final String EXTRA_BEARING_ACCURACY = "bearingAccuracy";
/**
* Constant used as a key to store Mean Sea Level altitude in {@link Location#getExtras()}.
*/
public static final String EXTRA_MSL_ALTITUDE = "androidx.core.location.extra.MSL_ALTITUDE";
/**
* Constant used as a key to store Mean Sea Level altitude in {@link Location#getExtras()}.
*/
public static final String EXTRA_MSL_ALTITUDE_ACCURACY =
"androidx.core.location.extra.MSL_ALTITUDE_ACCURACY";
@Nullable
private static Method sSetIsFromMockProviderMethod;
@Nullable
private static Field sFieldsMaskField;
@Nullable
private static Integer sHasSpeedAccuracyMask;
@Nullable
private static Integer sHasBearingAccuracyMask;
@Nullable
private static Integer sHasVerticalAccuracyMask;
private LocationCompat() {
}
/**
* Return the time of this fix, in nanoseconds of elapsed real-time since system boot.
*
* <p>This value can be reliably compared to SystemClock.elapsedRealtimeNanos(), to calculate
* the age of a fix and to compare location fixes. This is reliable because elapsed real-time
* is guaranteed monotonic for each system boot and continues to increment even when the
* system is in deep sleep (unlike getTime().
*
* <p>All locations generated by the LocationManager are guaranteed to have a valid elapsed
* real-time.
*
* <p>NOTE: On API levels below 17, this method will attempt to provide an elapsed realtime
* based on the difference between system time and the location time. This should be taken as a
* best "guess" at what the elapsed realtime might have been, but if the clock used for
* location derivation is different from the system clock, the results may be inaccurate.
* @deprecated Call {@link Location#getElapsedRealtimeNanos()} directly.
*/
@Deprecated
@androidx.annotation.ReplaceWith(expression = "location.getElapsedRealtimeNanos()")
public static long getElapsedRealtimeNanos(@NonNull Location location) {
return location.getElapsedRealtimeNanos();
}
/**
* Return the time of this fix, in milliseconds of elapsed real-time since system boot.
*
* @see #getElapsedRealtimeNanos(Location)
*/
public static long getElapsedRealtimeMillis(@NonNull Location location) {
return NANOSECONDS.toMillis(location.getElapsedRealtimeNanos());
}
/**
* Returns true if this location has a vertical accuracy.
*
* @see Location#hasVerticalAccuracy()
*/
public static boolean hasVerticalAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 26) {
return Api26Impl.hasVerticalAccuracy(location);
} else {
return containsExtra(location, EXTRA_VERTICAL_ACCURACY);
}
}
/**
* Get the estimated vertical accuracy of this location in meters.
*
* <p>NOTE: On API levels below 26, the concept of vertical accuracy does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to read a
* float extra with the key {@link #EXTRA_VERTICAL_ACCURACY} and return the result.
*
* @see Location#getVerticalAccuracyMeters()
*/
public static float getVerticalAccuracyMeters(@NonNull Location location) {
if (VERSION.SDK_INT >= 26) {
return Api26Impl.getVerticalAccuracyMeters(location);
} else {
Bundle extras = location.getExtras();
if (extras == null) {
return 0.0f;
}
return extras.getFloat(EXTRA_VERTICAL_ACCURACY, 0.0f);
}
}
/**
* Set the estimated vertical accuracy of this location in meters.
*
* <p>NOTE: On API levels below 26, the concept of vertical accuracy does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to set a
* float extra with the key {@link #EXTRA_VERTICAL_ACCURACY} to include vertical accuracy. Be
* aware that this will overwrite any prior extra value under the same key.
*
* @see Location#setVerticalAccuracyMeters(float)
*/
public static void setVerticalAccuracyMeters(@NonNull Location location,
float verticalAccuracyM) {
if (VERSION.SDK_INT >= 26) {
Api26Impl.setVerticalAccuracyMeters(location, verticalAccuracyM);
} else {
getOrCreateExtras(location).putFloat(EXTRA_VERTICAL_ACCURACY, verticalAccuracyM);
}
}
/**
* Removes the vertical accuracy from the location.
*/
public static void removeVerticalAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 33) {
Api33Impl.removeVerticalAccuracy(location);
} else if (VERSION.SDK_INT >= 29) {
Api29Impl.removeVerticalAccuracy(location);
} else if (VERSION.SDK_INT >= 28) {
Api28Impl.removeVerticalAccuracy(location);
} else if (VERSION.SDK_INT >= 26) {
Api26Impl.removeVerticalAccuracy(location);
} else {
removeExtra(location, EXTRA_VERTICAL_ACCURACY);
}
}
/**
* Returns true if this location has a speed accuracy.
*
* @see Location#hasSpeedAccuracy()
*/
public static boolean hasSpeedAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 26) {
return Api26Impl.hasSpeedAccuracy(location);
} else {
return containsExtra(location, EXTRA_SPEED_ACCURACY);
}
}
/**
* Get the estimated speed accuracy of this location in meters per second.
*
* <p>NOTE: On API levels below 26, the concept of speed accuracy does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to read a
* float extra with the key {@link #EXTRA_SPEED_ACCURACY} and return the result.
*
* @see Location#getSpeedAccuracyMetersPerSecond()
*/
public static float getSpeedAccuracyMetersPerSecond(@NonNull Location location) {
if (VERSION.SDK_INT >= 26) {
return Api26Impl.getSpeedAccuracyMetersPerSecond(location);
} else {
Bundle extras = location.getExtras();
if (extras == null) {
return 0.0f;
}
return extras.getFloat(EXTRA_SPEED_ACCURACY, 0.0f);
}
}
/**
* Set the estimated speed accuracy of this location in meters per second.
*
* <p>NOTE: On API levels below 26, the concept of speed accuracy does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to set a
* float extra with the key {@link #EXTRA_SPEED_ACCURACY} to include speed accuracy. Be
* aware that this will overwrite any prior extra value under the same key.
*
* @see Location#setSpeedAccuracyMetersPerSecond(float)
*/
public static void setSpeedAccuracyMetersPerSecond(@NonNull Location location,
float speedAccuracyMps) {
if (VERSION.SDK_INT >= 26) {
Api26Impl.setSpeedAccuracyMetersPerSecond(location, speedAccuracyMps);
} else {
getOrCreateExtras(location).putFloat(EXTRA_SPEED_ACCURACY, speedAccuracyMps);
}
}
/**
* Removes the speed accuracy from the location.
*/
public static void removeSpeedAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 33) {
Api33Impl.removeSpeedAccuracy(location);
} else if (VERSION.SDK_INT >= 29) {
Api29Impl.removeSpeedAccuracy(location);
} else if (VERSION.SDK_INT >= 28) {
Api28Impl.removeSpeedAccuracy(location);
} else if (VERSION.SDK_INT >= 26) {
Api26Impl.removeSpeedAccuracy(location);
} else {
removeExtra(location, EXTRA_SPEED_ACCURACY);
}
}
/**
* Returns true if this location has a bearing accuracy.
*
* @see Location#hasBearingAccuracy()
*/
public static boolean hasBearingAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 26) {
return Api26Impl.hasBearingAccuracy(location);
} else {
return containsExtra(location, EXTRA_BEARING_ACCURACY);
}
}
/**
* Get the estimated bearing accuracy of this location in degrees.
*
* <p>NOTE: On API levels below 26, the concept of bearing accuracy does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to read a
* float extra with the key {@link #EXTRA_BEARING_ACCURACY} and return the result.
*
* @see Location#getBearingAccuracyDegrees()
*/
public static float getBearingAccuracyDegrees(@NonNull Location location) {
if (VERSION.SDK_INT >= 26) {
return Api26Impl.getBearingAccuracyDegrees(location);
} else {
Bundle extras = location.getExtras();
if (extras == null) {
return 0.0f;
}
return extras.getFloat(EXTRA_BEARING_ACCURACY, 0.0f);
}
}
/**
* Set the estimated bearing accuracy of this location in degrees.
*
* <p>NOTE: On API levels below 26, the concept of bearing accuracy does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to set a
* float extra with the key {@link #EXTRA_BEARING_ACCURACY} to include bearing accuracy. Be
* aware that this will overwrite any prior extra value under the same key.
*
* @see Location#setBearingAccuracyDegrees(float)
*/
public static void setBearingAccuracyDegrees(@NonNull Location location,
float bearingAccuracyD) {
if (VERSION.SDK_INT >= 26) {
Api26Impl.setBearingAccuracyDegrees(location, bearingAccuracyD);
} else {
getOrCreateExtras(location).putFloat(EXTRA_BEARING_ACCURACY, bearingAccuracyD);
}
}
/**
* Removes the bearing accuracy from the location.
*/
public static void removeBearingAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 33) {
Api33Impl.removeBearingAccuracy(location);
} else if (VERSION.SDK_INT >= 29) {
Api29Impl.removeBearingAccuracy(location);
} else if (VERSION.SDK_INT >= 28) {
Api28Impl.removeBearingAccuracy(location);
} else if (VERSION.SDK_INT >= 26) {
Api26Impl.removeBearingAccuracy(location);
} else {
removeExtra(location, EXTRA_BEARING_ACCURACY);
}
}
/**
* Returns the Mean Sea Level altitude of the location in meters.
*
* <p>This is only valid if {@link #hasMslAltitude(Location)} is true.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
* order to allow for backwards compatibility and testing however, this method will attempt
* to read a double extra with the key {@link #EXTRA_MSL_ALTITUDE} and return the result.
*
* @see Location#getMslAltitudeMeters()
*/
public static double getMslAltitudeMeters(@NonNull Location location) {
if (VERSION.SDK_INT >= 34) {
return Api34Impl.getMslAltitudeMeters(location);
}
return getOrCreateExtras(location).getDouble(EXTRA_MSL_ALTITUDE);
}
/**
* Sets the Mean Sea Level altitude of the location in meters.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
* order to allow for backwards compatibility and testing however, this method will attempt
* to set a double extra with the key {@link #EXTRA_MSL_ALTITUDE} to include Mean Sea Level
* altitude. Be aware that this will overwrite any prior extra value under the same key.
*
* @see Location#setMslAltitudeMeters(double)
*/
public static void setMslAltitudeMeters(@NonNull Location location,
double mslAltitudeMeters) {
if (VERSION.SDK_INT >= 34) {
Api34Impl.setMslAltitudeMeters(location, mslAltitudeMeters);
} else {
getOrCreateExtras(location).putDouble(EXTRA_MSL_ALTITUDE, mslAltitudeMeters);
}
}
/**
* Returns true if the location has a Mean Sea Level altitude, false otherwise.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
* order to allow for backwards compatibility and testing however, this method will return
* true if an extra value is with the key {@link #EXTRA_MSL_ALTITUDE}.
*
* @see Location#hasMslAltitude()
*/
public static boolean hasMslAltitude(@NonNull Location location) {
if (VERSION.SDK_INT >= 34) {
return Api34Impl.hasMslAltitude(location);
}
return containsExtra(location, EXTRA_MSL_ALTITUDE);
}
/**
* Removes the Mean Sea Level altitude from the location.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
* order to allow for backwards compatibility and testing however, this method will attempt
* to remove any extra value with the key {@link #EXTRA_MSL_ALTITUDE}.
*
* @see Location#removeMslAltitude()
*/
public static void removeMslAltitude(@NonNull Location location) {
if (VERSION.SDK_INT >= 34) {
Api34Impl.removeMslAltitude(location);
} else {
removeExtra(location, EXTRA_MSL_ALTITUDE);
}
}
/**
* Returns the estimated Mean Sea Level altitude accuracy in meters of the location at the 68th
* percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
* altitude of the location falls within {@link #getMslAltitudeMeters(Location)} +/- this
* uncertainty.
*
* <p>This is only valid if {@link #hasMslAltitudeAccuracy(Location)} is true.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
* exist. In order to allow for backwards compatibility and testing however, this method will
* attempt to read a float extra with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY} and return
* the result.
*
* @see Location#getMslAltitudeAccuracyMeters()
*/
public static @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters(
@NonNull Location location) {
if (VERSION.SDK_INT >= 34) {
return Api34Impl.getMslAltitudeAccuracyMeters(location);
}
return getOrCreateExtras(location).getFloat(EXTRA_MSL_ALTITUDE_ACCURACY);
}
/**
* Sets the Mean Sea Level altitude accuracy of the location in meters.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
* exist. In order to allow for backwards compatibility and testing however, this method will
* attempt to set a float extra with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY} to include
* Mean Sea Level altitude accuracy. Be aware that this will overwrite any prior extra value
* under the same key.
*
* @see Location#setMslAltitudeAccuracyMeters(float)
*/
public static void setMslAltitudeAccuracyMeters(@NonNull Location location,
@FloatRange(from = 0.0) float mslAltitudeAccuracyMeters) {
if (VERSION.SDK_INT >= 34) {
Api34Impl.setMslAltitudeAccuracyMeters(location, mslAltitudeAccuracyMeters);
} else {
getOrCreateExtras(location).putFloat(EXTRA_MSL_ALTITUDE_ACCURACY,
mslAltitudeAccuracyMeters);
}
}
/**
* Returns true if the location has a Mean Sea Level altitude accuracy, false otherwise.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
* exist. In order to allow for backwards compatibility and testing however, this method will
* return true if an extra value is with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY}.
*
* @see Location#hasMslAltitudeAccuracy()
*/
public static boolean hasMslAltitudeAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 34) {
return Api34Impl.hasMslAltitudeAccuracy(location);
}
return containsExtra(location, EXTRA_MSL_ALTITUDE_ACCURACY);
}
/**
* Removes the Mean Sea Level altitude accuracy from the location.
*
* <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
* exist. In order to allow for backwards compatibility and testing however, this method will
* attempt to remove any extra value with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY}.
*
* @see Location#removeMslAltitudeAccuracy()
*/
public static void removeMslAltitudeAccuracy(@NonNull Location location) {
if (VERSION.SDK_INT >= 34) {
Api34Impl.removeMslAltitudeAccuracy(location);
} else {
removeExtra(location, EXTRA_MSL_ALTITUDE_ACCURACY);
}
}
/**
* Returns true if this location is marked as a mock location. If this location comes from the
* Android framework, this indicates that the location was provided by a test location provider,
* and thus may not be related to the actual location of the device.
*
* <p>NOTE: On API levels below 18, the concept of a mock location does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to read a
* boolean extra with the key {@link #EXTRA_IS_MOCK} and use the result to determine whether
* this should be considered a mock location.
*
* @see android.location.LocationManager#addTestProvider
*/
@SuppressWarnings("deprecation")
public static boolean isMock(@NonNull Location location) {
if (VERSION.SDK_INT >= 31) {
return Api31Impl.isMock(location);
} else {
return location.isFromMockProvider();
}
}
/**
* Sets whether this location is marked as a mock location.
*
* <p>NOTE: On API levels below 18, the concept of a mock location does not exist. In order to
* allow for backwards compatibility and testing however, this method will attempt to set a
* boolean extra with the key {@link #EXTRA_IS_MOCK} to mark the location as mock. Be aware that
* this will overwrite any prior extra value under the same key.
*/
@SuppressLint("BanUncheckedReflection")
public static void setMock(@NonNull Location location, boolean mock) {
try {
getSetIsFromMockProviderMethod().invoke(location, mock);
} catch (NoSuchMethodException e) {
Error error = new NoSuchMethodError();
error.initCause(e);
throw error;
} catch (IllegalAccessException e) {
Error error = new IllegalAccessError();
error.initCause(e);
throw error;
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@RequiresApi(34)
private static class Api34Impl {
private Api34Impl() {
}
static double getMslAltitudeMeters(Location location) {
return location.getMslAltitudeMeters();
}
static void setMslAltitudeMeters(Location location, double mslAltitudeMeters) {
location.setMslAltitudeMeters(mslAltitudeMeters);
}
static boolean hasMslAltitude(Location location) {
return location.hasMslAltitude();
}
static void removeMslAltitude(Location location) {
location.removeMslAltitude();
}
static float getMslAltitudeAccuracyMeters(Location location) {
return location.getMslAltitudeAccuracyMeters();
}
static void setMslAltitudeAccuracyMeters(Location location,
float mslAltitudeAccuracyMeters) {
location.setMslAltitudeAccuracyMeters(mslAltitudeAccuracyMeters);
}
static boolean hasMslAltitudeAccuracy(Location location) {
return location.hasMslAltitudeAccuracy();
}
static void removeMslAltitudeAccuracy(Location location) {
location.removeMslAltitudeAccuracy();
}
}
@RequiresApi(33)
private static class Api33Impl {
private Api33Impl() {}
static void removeVerticalAccuracy(Location location) {
location.removeVerticalAccuracy();
}
static void removeSpeedAccuracy(Location location) {
location.removeSpeedAccuracy();
}
static void removeBearingAccuracy(Location location) {
location.removeBearingAccuracy();
}
}
@RequiresApi(29)
private static class Api29Impl {
private Api29Impl() {}
static void removeVerticalAccuracy(Location location) {
if (!location.hasVerticalAccuracy()) {
return;
}
// reflection of non-SDK APIs doesn't work on P+, fallback to resetting the location
double elapsedRealtimeUncertaintyNs = location.getElapsedRealtimeUncertaintyNanos();
Api28Impl.removeVerticalAccuracy(location);
location.setElapsedRealtimeUncertaintyNanos(elapsedRealtimeUncertaintyNs);
}
static void removeSpeedAccuracy(Location location) {
if (!location.hasSpeedAccuracy()) {
return;
}
// reflection of non-SDK APIs doesn't work on P+, fallback to resetting the location
double elapsedRealtimeUncertaintyNs = location.getElapsedRealtimeUncertaintyNanos();
Api28Impl.removeSpeedAccuracy(location);
location.setElapsedRealtimeUncertaintyNanos(elapsedRealtimeUncertaintyNs);
}
static void removeBearingAccuracy(Location location) {
if (!location.hasBearingAccuracy()) {
return;
}
// reflection of non-SDK APIs doesn't work on P+, fallback to resetting the location
double elapsedRealtimeUncertaintyNs = location.getElapsedRealtimeUncertaintyNanos();
Api28Impl.removeBearingAccuracy(location);
location.setElapsedRealtimeUncertaintyNanos(elapsedRealtimeUncertaintyNs);
}
}
@RequiresApi(28)
private static class Api28Impl {
private Api28Impl() {}
static void removeVerticalAccuracy(Location location) {
if (!location.hasVerticalAccuracy()) {
return;
}
// reflection of non-SDK APIs doesn't work on P+, fallback to resetting the location
// (which unfortunately means a new Bundle will be created)
String provider = location.getProvider();
long time = location.getTime();
long elapsedRealtimeNs = location.getElapsedRealtimeNanos();
double latitude = location.getLatitude();
double longitude = location.getLongitude();
boolean hasAltitude = location.hasAltitude();
double altitude = location.getAltitude();
boolean hasSpeed = location.hasSpeed();
float speed = location.getSpeed();
boolean hasBearing = location.hasBearing();
float bearing = location.getBearing();
boolean hasAccuracy = location.hasAccuracy();
float accuracy = location.getAccuracy();
boolean hasSpeedAccuracy = location.hasSpeedAccuracy();
float speedAccuracy = location.getSpeedAccuracyMetersPerSecond();
boolean hasBearingAccuracy = location.hasBearingAccuracy();
float bearingAccuracy = location.getBearingAccuracyDegrees();
Bundle extras = location.getExtras();
location.reset();
location.setProvider(provider);
location.setTime(time);
location.setElapsedRealtimeNanos(elapsedRealtimeNs);
location.setLatitude(latitude);
location.setLongitude(longitude);
if (hasAltitude) {
location.setAltitude(altitude);
}
if (hasSpeed) {
location.setSpeed(speed);
}
if (hasBearing) {
location.setBearing(bearing);
}
if (hasAccuracy) {
location.setAccuracy(accuracy);
}
if (hasSpeedAccuracy) {
location.setSpeedAccuracyMetersPerSecond(speedAccuracy);
}
if (hasBearingAccuracy) {
location.setBearingAccuracyDegrees(bearingAccuracy);
}
if (extras != null) {
location.setExtras(extras);
}
}
static void removeSpeedAccuracy(Location location) {
if (!location.hasSpeedAccuracy()) {
return;
}
// reflection of non-SDK APIs doesn't work on P+, fallback to resetting the location
// (which unfortunately means a new Bundle will be created)
String provider = location.getProvider();
long time = location.getTime();
long elapsedRealtimeNs = location.getElapsedRealtimeNanos();
double latitude = location.getLatitude();
double longitude = location.getLongitude();
boolean hasAltitude = location.hasAltitude();
double altitude = location.getAltitude();
boolean hasSpeed = location.hasSpeed();
float speed = location.getSpeed();
boolean hasBearing = location.hasBearing();
float bearing = location.getBearing();
boolean hasAccuracy = location.hasAccuracy();
float accuracy = location.getAccuracy();
boolean hasVerticalAccuracy = location.hasVerticalAccuracy();
float verticalAccuracy = location.getVerticalAccuracyMeters();
boolean hasBearingAccuracy = location.hasBearingAccuracy();
float bearingAccuracy = location.getBearingAccuracyDegrees();
Bundle extras = location.getExtras();
location.reset();
location.setProvider(provider);
location.setTime(time);
location.setElapsedRealtimeNanos(elapsedRealtimeNs);
location.setLatitude(latitude);
location.setLongitude(longitude);
if (hasAltitude) {
location.setAltitude(altitude);
}
if (hasSpeed) {
location.setSpeed(speed);
}
if (hasBearing) {
location.setBearing(bearing);
}
if (hasAccuracy) {
location.setAccuracy(accuracy);
}
if (hasVerticalAccuracy) {
location.setVerticalAccuracyMeters(verticalAccuracy);
}
if (hasBearingAccuracy) {
location.setBearingAccuracyDegrees(bearingAccuracy);
}
if (extras != null) {
location.setExtras(extras);
}
}
static void removeBearingAccuracy(Location location) {
if (!location.hasBearingAccuracy()) {
return;
}
// reflection of non-SDK APIs doesn't work on P+, fallback to resetting the location
// (which unfortunately means a new Bundle will be created)
String provider = location.getProvider();
long time = location.getTime();
long elapsedRealtimeNs = location.getElapsedRealtimeNanos();
double latitude = location.getLatitude();
double longitude = location.getLongitude();
boolean hasAltitude = location.hasAltitude();
double altitude = location.getAltitude();
boolean hasSpeed = location.hasSpeed();
float speed = location.getSpeed();
boolean hasBearing = location.hasBearing();
float bearing = location.getBearing();
boolean hasAccuracy = location.hasAccuracy();
float accuracy = location.getAccuracy();
boolean hasVerticalAccuracy = location.hasVerticalAccuracy();
float verticalAccuracy = location.getVerticalAccuracyMeters();
boolean hasSpeedAccuracy = location.hasSpeedAccuracy();
float speedAccuracy = location.getSpeedAccuracyMetersPerSecond();
Bundle extras = location.getExtras();
location.reset();
location.setProvider(provider);
location.setTime(time);
location.setElapsedRealtimeNanos(elapsedRealtimeNs);
location.setLatitude(latitude);
location.setLongitude(longitude);
if (hasAltitude) {
location.setAltitude(altitude);
}
if (hasSpeed) {
location.setSpeed(speed);
}
if (hasBearing) {
location.setBearing(bearing);
}
if (hasAccuracy) {
location.setAccuracy(accuracy);
}
if (hasVerticalAccuracy) {
location.setVerticalAccuracyMeters(verticalAccuracy);
}
if (hasSpeedAccuracy) {
location.setBearingAccuracyDegrees(speedAccuracy);
}
if (extras != null) {
location.setExtras(extras);
}
}
}
@RequiresApi(26)
private static class Api26Impl {
private Api26Impl() {
}
static boolean hasVerticalAccuracy(Location location) {
return location.hasVerticalAccuracy();
}
static float getVerticalAccuracyMeters(Location location) {
return location.getVerticalAccuracyMeters();
}
static void setVerticalAccuracyMeters(Location location, float verticalAccuracyM) {
location.setVerticalAccuracyMeters(verticalAccuracyM);
}
static void removeVerticalAccuracy(Location location) {
try {
byte fieldsMask = getFieldsMaskField().getByte(location);
fieldsMask = (byte) (fieldsMask & ~getHasVerticalAccuracyMask());
getFieldsMaskField().setByte(location, fieldsMask);
} catch (NoSuchFieldException | IllegalAccessException e) {
Error error = new IllegalAccessError();
error.initCause(e);
throw error;
}
}
static boolean hasSpeedAccuracy(Location location) {
return location.hasSpeedAccuracy();
}
static float getSpeedAccuracyMetersPerSecond(Location location) {
return location.getSpeedAccuracyMetersPerSecond();
}
static void setSpeedAccuracyMetersPerSecond(Location location, float speedAccuracyMps) {
location.setSpeedAccuracyMetersPerSecond(speedAccuracyMps);
}
static void removeSpeedAccuracy(Location location) {
try {
byte fieldsMask = getFieldsMaskField().getByte(location);
fieldsMask = (byte) (fieldsMask & ~getHasSpeedAccuracyMask());
getFieldsMaskField().setByte(location, fieldsMask);
} catch (NoSuchFieldException e) {
Error error = new NoSuchFieldError();
error.initCause(e);
throw error;
} catch (IllegalAccessException e) {
Error error = new IllegalAccessError();
error.initCause(e);
throw error;
}
}
static boolean hasBearingAccuracy(Location location) {
return location.hasBearingAccuracy();
}
static float getBearingAccuracyDegrees(Location location) {
return location.getBearingAccuracyDegrees();
}
static void setBearingAccuracyDegrees(Location location, float bearingAccuracyD) {
location.setBearingAccuracyDegrees(bearingAccuracyD);
}
static void removeBearingAccuracy(Location location) {
try {
byte fieldsMask = getFieldsMaskField().getByte(location);
fieldsMask = (byte) (fieldsMask & ~getHasBearingAccuracyMask());
getFieldsMaskField().setByte(location, fieldsMask);
} catch (NoSuchFieldException e) {
Error error = new NoSuchFieldError();
error.initCause(e);
throw error;
} catch (IllegalAccessException e) {
Error error = new IllegalAccessError();
error.initCause(e);
throw error;
}
}
}
private static Method getSetIsFromMockProviderMethod() throws NoSuchMethodException {
if (sSetIsFromMockProviderMethod == null) {
sSetIsFromMockProviderMethod = Location.class.getDeclaredMethod("setIsFromMockProvider",
boolean.class);
sSetIsFromMockProviderMethod.setAccessible(true);
}
return sSetIsFromMockProviderMethod;
}
@SuppressLint("BlockedPrivateApi")
static Field getFieldsMaskField() throws NoSuchFieldException {
if (sFieldsMaskField == null) {
sFieldsMaskField = Location.class.getDeclaredField("mFieldsMask");
sFieldsMaskField.setAccessible(true);
}
return sFieldsMaskField;
}
@SuppressLint("SoonBlockedPrivateApi")
static int getHasSpeedAccuracyMask() throws NoSuchFieldException,
IllegalAccessException {
if (sHasSpeedAccuracyMask == null) {
Field hasSpeedAccuracyMaskField = Location.class.getDeclaredField(
"HAS_SPEED_ACCURACY_MASK");
hasSpeedAccuracyMaskField.setAccessible(true);
sHasSpeedAccuracyMask = hasSpeedAccuracyMaskField.getInt(null);
}
return sHasSpeedAccuracyMask;
}
@SuppressLint("SoonBlockedPrivateApi")
static int getHasBearingAccuracyMask()
throws NoSuchFieldException, IllegalAccessException {
if (sHasBearingAccuracyMask == null) {
Field hasBearingAccuracyMaskField = Location.class.getDeclaredField(
"HAS_BEARING_ACCURACY_MASK");
hasBearingAccuracyMaskField.setAccessible(true);
sHasBearingAccuracyMask = hasBearingAccuracyMaskField.getInt(null);
}
return sHasBearingAccuracyMask;
}
@SuppressLint("SoonBlockedPrivateApi")
static int getHasVerticalAccuracyMask()
throws NoSuchFieldException, IllegalAccessException {
if (sHasVerticalAccuracyMask == null) {
Field hasVerticalAccuracyMaskField = Location.class.getDeclaredField(
"HAS_VERTICAL_ACCURACY_MASK");
hasVerticalAccuracyMaskField.setAccessible(true);
sHasVerticalAccuracyMask = hasVerticalAccuracyMaskField.getInt(null);
}
return sHasVerticalAccuracyMask;
}
private static Bundle getOrCreateExtras(@NonNull Location location) {
Bundle extras = location.getExtras();
if (extras == null) {
location.setExtras(new Bundle());
extras = location.getExtras();
}
return extras;
}
private static boolean containsExtra(@NonNull Location location, String key) {
Bundle extras = location.getExtras();
return extras != null && extras.containsKey(key);
}
private static void removeExtra(@NonNull Location location, String key) {
Bundle extras = location.getExtras();
if (extras != null) {
extras.remove(key);
if (extras.isEmpty()) {
location.setExtras(null);
}
}
}
@RequiresApi(31)
static class Api31Impl {
private Api31Impl() {
// This class is not instantiable.
}
static boolean isMock(Location location) {
return location.isMock();
}
}
}