public final class

LocationCompat

extends java.lang.Object

 java.lang.Object

↳androidx.core.location.LocationCompat

Gradle dependencies

compile group: 'androidx.core', name: 'core', version: '1.9.0-alpha04'

  • groupId: androidx.core
  • artifactId: core
  • version: 1.9.0-alpha04

Artifact androidx.core:core:1.9.0-alpha04 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.StringEXTRA_BEARING_ACCURACY

Constant used as a key to store bearing accuracy in for Android SDK levels below Oreo (26).

public static final java.lang.StringEXTRA_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.StringEXTRA_SPEED_ACCURACY

Constant used as a key to store speed accuracy in for Android SDK levels below Oreo (26).

public static final java.lang.StringEXTRA_VERTICAL_ACCURACY

Constant used as a key to store vertical accuracy in for Android SDK levels below Oreo (26).

Methods
public static floatgetBearingAccuracyDegrees(Location location)

Get the estimated bearing accuracy of this location in degrees.

public static longgetElapsedRealtimeMillis(Location location)

Return the time of this fix, in milliseconds of elapsed real-time since system boot.

public static longgetElapsedRealtimeNanos(Location location)

Return the time of this fix, in nanoseconds of elapsed real-time since system boot.

public static floatgetSpeedAccuracyMetersPerSecond(Location location)

Get the estimated speed accuracy of this location in meters per second.

public static floatgetVerticalAccuracyMeters(Location location)

Get the estimated vertical accuracy of this location in meters.

public static booleanhasBearingAccuracy(Location location)

Returns true if this location has a bearing accuracy.

public static booleanhasSpeedAccuracy(Location location)

Returns true if this location has a speed accuracy.

public static booleanhasVerticalAccuracy(Location location)

Returns true if this location has a vertical accuracy.

public static booleanisMock(Location location)

Returns true if this location is marked as a mock location.

public static voidsetBearingAccuracyDegrees(Location location, float bearingAccuracyD)

Set the estimated bearing accuracy of this location in degrees.

public static voidsetMock(Location location, boolean mock)

Sets whether this location is marked as a mock location.

public static voidsetSpeedAccuracyMetersPerSecond(Location location, float speedAccuracyMps)

Set the estimated speed accuracy of this location in meters per second.

public static voidsetVerticalAccuracyMeters(Location location, float verticalAccuracyM)

Set the estimated vertical accuracy of this location in meters.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

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_VERTICAL_ACCURACY

Constant used as a key to store vertical accuracy in for Android SDK levels below Oreo (26).

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_BEARING_ACCURACY

Constant used as a key to store bearing accuracy in for Android SDK levels below Oreo (26).

Methods

public static long getElapsedRealtimeNanos(Location location)

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 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 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 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.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

import android.location.Location;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.SystemClock;

import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

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";

    @Nullable
    private static Method sSetIsFromMockProviderMethod;

    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.
     */
    public static long getElapsedRealtimeNanos(@NonNull Location location) {
        if (VERSION.SDK_INT >= 17) {
            return Api17Impl.getElapsedRealtimeNanos(location);
        } else {
            return MILLISECONDS.toNanos(getElapsedRealtimeMillis(location));
        }
    }

    /**
     * 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) {
        if (VERSION.SDK_INT >= 17) {
            return NANOSECONDS.toMillis(Api17Impl.getElapsedRealtimeNanos(location));
        } else {
            long timeDeltaMs = System.currentTimeMillis() - location.getTime();
            long elapsedRealtimeMs = SystemClock.elapsedRealtime();
            if (timeDeltaMs < 0) {
                // don't return an elapsed realtime from the future
                return elapsedRealtimeMs;
            } else if (timeDeltaMs > elapsedRealtimeMs) {
                // don't return an elapsed realtime from before boot
                return 0;
            } else {
                return elapsedRealtimeMs - timeDeltaMs;
            }
        }
    }

    /**
     * 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 {
            Bundle extras = location.getExtras();
            if (extras == null) {
                return false;
            }

            return extras.containsKey(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 {
            Bundle extras = location.getExtras();
            if (extras == null) {
                location.setExtras(new Bundle());
                extras = location.getExtras();
            }

            extras.putFloat(EXTRA_VERTICAL_ACCURACY, verticalAccuracyM);
        }
    }

    /**
     * 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 {
            Bundle extras = location.getExtras();
            if (extras == null) {
                return false;
            }

            return extras.containsKey(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 {
            Bundle extras = location.getExtras();
            if (extras == null) {
                location.setExtras(new Bundle());
                extras = location.getExtras();
            }

            extras.putFloat(EXTRA_SPEED_ACCURACY, speedAccuracyMps);
        }
    }

    /**
     * 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 {
            Bundle extras = location.getExtras();
            if (extras == null) {
                return false;
            }

            return extras.containsKey(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 {
            Bundle extras = location.getExtras();
            if (extras == null) {
                location.setExtras(new Bundle());
                extras = location.getExtras();
            }

            extras.putFloat(EXTRA_BEARING_ACCURACY, bearingAccuracyD);
        }
    }

    /**
     * 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
     */
    public static boolean isMock(@NonNull Location location) {
        if (VERSION.SDK_INT >= 18) {
            return Api18Impl.isMock(location);
        } else {
            Bundle extras = location.getExtras();
            if (extras == null) {
                return false;
            }

            return extras.getBoolean(EXTRA_IS_MOCK, false);
        }
    }

    /**
     * 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.
     */
    public static void setMock(@NonNull Location location, boolean mock) {
        if (VERSION.SDK_INT >= 18) {
            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);
            }
        } else {
            Bundle extras = location.getExtras();
            if (extras == null) {
                if (mock) {
                    extras = new Bundle();
                    extras.putBoolean(EXTRA_IS_MOCK, true);
                    location.setExtras(extras);
                }
            } else {
                if (mock) {
                    extras.putBoolean(EXTRA_IS_MOCK, true);
                } else {
                    extras.remove(EXTRA_IS_MOCK);
                    if (extras.isEmpty()) {
                        location.setExtras(null);
                    }
                }
            }
        }
    }

    @RequiresApi(26)
    private static class Api26Impl {

        private Api26Impl() {}

        @DoNotInline
        static boolean hasVerticalAccuracy(Location location) {
            return location.hasVerticalAccuracy();
        }

        @DoNotInline
        static float getVerticalAccuracyMeters(Location location) {
            return location.getVerticalAccuracyMeters();
        }

        @DoNotInline
        static void setVerticalAccuracyMeters(Location location, float verticalAccuracyM) {
            location.setVerticalAccuracyMeters(verticalAccuracyM);
        }

        @DoNotInline
        static boolean hasSpeedAccuracy(Location location) {
            return location.hasSpeedAccuracy();
        }

        @DoNotInline
        static float getSpeedAccuracyMetersPerSecond(Location location) {
            return location.getSpeedAccuracyMetersPerSecond();
        }

        @DoNotInline
        static void setSpeedAccuracyMetersPerSecond(Location location, float speedAccuracyMps) {
            location.setSpeedAccuracyMetersPerSecond(speedAccuracyMps);
        }

        @DoNotInline
        static boolean hasBearingAccuracy(Location location) {
            return location.hasBearingAccuracy();
        }

        @DoNotInline
        static float getBearingAccuracyDegrees(Location location) {
            return location.getBearingAccuracyDegrees();
        }

        @DoNotInline
        static void setBearingAccuracyDegrees(Location location, float bearingAccuracyD) {
            location.setBearingAccuracyDegrees(bearingAccuracyD);
        }
    }

    @RequiresApi(18)
    private static class Api18Impl {

        private Api18Impl() {}

        @DoNotInline
        static boolean isMock(Location location) {
            return location.isFromMockProvider();
        }
    }

    @RequiresApi(17)
    private static class Api17Impl {

        private Api17Impl() {}

        @DoNotInline
        static long getElapsedRealtimeNanos(Location location) {
            return location.getElapsedRealtimeNanos();
        }
    }

    private static Method getSetIsFromMockProviderMethod() throws NoSuchMethodException {
        if (sSetIsFromMockProviderMethod == null) {
            sSetIsFromMockProviderMethod = Location.class.getDeclaredMethod("setIsFromMockProvider",
                    boolean.class);
            sSetIsFromMockProviderMethod.setAccessible(true);
        }

        return sSetIsFromMockProviderMethod;
    }
}