| /* | |
| * Copyright (C) 2012 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 android.location; | |
| import static android.Manifest.permission.LOCATION_BYPASS; | |
| import static java.lang.Math.max; | |
| import static java.lang.Math.min; | |
| import android.Manifest; | |
| import android.annotation.FloatRange; | |
| import android.annotation.IntDef; | |
| import android.annotation.IntRange; | |
| import android.annotation.NonNull; | |
| import android.annotation.Nullable; | |
| import android.annotation.RequiresFeature; | |
| import android.annotation.RequiresPermission; | |
| import android.annotation.SystemApi; | |
| import android.compat.annotation.ChangeId; | |
| import android.compat.annotation.EnabledAfter; | |
| import android.content.pm.PackageManager; | |
| import android.os.Build; | |
| import android.os.Parcel; | |
| import android.os.Parcelable; | |
| import android.os.WorkSource; | |
| import android.util.TimeUtils; | |
| import com.android.internal.util.Preconditions; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| import java.util.Objects; | |
| /** | |
| * An encapsulation of various parameters for requesting location via {@link LocationManager}. | |
| */ | |
| public final class LocationRequest implements Parcelable { | |
| /** | |
| * For apps targeting Android S and above, all LocationRequest objects marked as low power will | |
| * throw exceptions if the caller does not have the LOCATION_HARDWARE permission, instead of | |
| * silently dropping the low power part of the request. | |
| * | |
| * @hide | |
| */ | |
| @ChangeId | |
| @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) | |
| public static final long LOW_POWER_EXCEPTIONS = 168936375L; | |
| /** | |
| * Represents a passive only request. Such a request will not trigger any active locations or | |
| * power usage itself, but may receive locations generated in response to other requests. | |
| * | |
| * @see LocationRequest#getIntervalMillis() | |
| */ | |
| public static final long PASSIVE_INTERVAL = Long.MAX_VALUE; | |
| /** @hide */ | |
| @Retention(RetentionPolicy.SOURCE) | |
| @IntDef({QUALITY_LOW_POWER, QUALITY_BALANCED_POWER_ACCURACY, QUALITY_HIGH_ACCURACY}) | |
| public @interface Quality {} | |
| /** | |
| * A quality constant indicating a location provider may choose to satisfy this request by | |
| * providing very accurate locations at the expense of potentially increased power usage. Each | |
| * location provider may interpret this field differently, but as an example, the network | |
| * provider may choose to return only wifi based locations rather than cell based locations in | |
| * order to have greater accuracy when this flag is present. | |
| */ | |
| public static final int QUALITY_HIGH_ACCURACY = 100; | |
| /** | |
| * A quality constant indicating a location provider may choose to satisfy this request by | |
| * equally balancing power and accuracy constraints. Each location provider may interpret this | |
| * field differently, but location providers will generally use their default behavior when this | |
| * flag is present. | |
| */ | |
| public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; | |
| /** | |
| * A quality constant indicating a location provider may choose to satisfy this request by | |
| * providing less accurate locations in order to save power. Each location provider may | |
| * interpret this field differently, but as an example, the network provider may choose to | |
| * return cell based locations rather than wifi based locations in order to save power when this | |
| * flag is present. | |
| */ | |
| public static final int QUALITY_LOW_POWER = 104; | |
| /** | |
| * Used with {@link #setQuality} to request the most accurate locations available. | |
| * | |
| * <p>This may be up to 1 meter accuracy, although this is implementation dependent. | |
| * | |
| * @hide | |
| * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead. | |
| */ | |
| @Deprecated | |
| @SystemApi | |
| public static final int ACCURACY_FINE = QUALITY_HIGH_ACCURACY; | |
| /** | |
| * Used with {@link #setQuality} to request "block" level accuracy. | |
| * | |
| * <p>Block level accuracy is considered to be about 100 meter accuracy, | |
| * although this is implementation dependent. Using a coarse accuracy | |
| * such as this often consumes less power. | |
| * | |
| * @hide | |
| * @deprecated Use {@link #QUALITY_BALANCED_POWER_ACCURACY} instead. | |
| */ | |
| @Deprecated | |
| @SystemApi | |
| public static final int ACCURACY_BLOCK = QUALITY_BALANCED_POWER_ACCURACY; | |
| /** | |
| * Used with {@link #setQuality} to request "city" level accuracy. | |
| * | |
| * <p>City level accuracy is considered to be about 10km accuracy, | |
| * although this is implementation dependent. Using a coarse accuracy | |
| * such as this often consumes less power. | |
| * | |
| * @hide | |
| * @deprecated Use {@link #QUALITY_LOW_POWER} instead. | |
| */ | |
| @Deprecated | |
| @SystemApi | |
| public static final int ACCURACY_CITY = QUALITY_LOW_POWER; | |
| /** | |
| * Used with {@link #setQuality} to require no direct power impact (passive locations). | |
| * | |
| * <p>This location request will not trigger any active location requests, | |
| * but will receive locations triggered by other applications. Your application | |
| * will not receive any direct power blame for location work. | |
| * | |
| * @hide | |
| * @deprecated Use {@link #PASSIVE_INTERVAL} instead. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public static final int POWER_NONE = 200; | |
| /** | |
| * Used with {@link #setQuality} to request low power impact. | |
| * | |
| * <p>This location request will avoid high power location work where | |
| * possible. | |
| * | |
| * @hide | |
| * @deprecated Use {@link #QUALITY_LOW_POWER} instead. | |
| */ | |
| @Deprecated | |
| @SystemApi | |
| public static final int POWER_LOW = 201; | |
| /** | |
| * Used with {@link #setQuality} to allow high power consumption for location. | |
| * | |
| * <p>This location request will allow high power location work. | |
| * | |
| * @hide | |
| * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead. | |
| */ | |
| @Deprecated | |
| @SystemApi | |
| public static final int POWER_HIGH = 203; | |
| private static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1; | |
| private static final double IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR = 1D / 6D; | |
| private @Nullable String mProvider; | |
| private @Quality int mQuality; | |
| private long mIntervalMillis; | |
| private long mMinUpdateIntervalMillis; | |
| private long mExpireAtRealtimeMillis; | |
| private long mDurationMillis; | |
| private int mMaxUpdates; | |
| private float mMinUpdateDistanceMeters; | |
| private final long mMaxUpdateDelayMillis; | |
| private boolean mHideFromAppOps; | |
| private final boolean mAdasGnssBypass; | |
| private boolean mBypass; | |
| private boolean mLowPower; | |
| private @Nullable WorkSource mWorkSource; | |
| /** | |
| * @hide | |
| * @deprecated Use the Builder to construct new LocationRequests. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| @NonNull | |
| public static LocationRequest create() { | |
| // 60 minutes is the default legacy interval | |
| return new LocationRequest.Builder(60 * 60 * 1000).build(); | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use the Builder to construct new LocationRequests. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| @NonNull | |
| public static LocationRequest createFromDeprecatedProvider(@NonNull String provider, | |
| long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) { | |
| Preconditions.checkArgument(provider != null, "invalid null provider"); | |
| if (intervalMillis < 0) { | |
| intervalMillis = 0; | |
| } else if (intervalMillis == PASSIVE_INTERVAL) { | |
| intervalMillis = Long.MAX_VALUE - 1; | |
| } | |
| if (minUpdateDistanceMeters < 0) { | |
| minUpdateDistanceMeters = 0; | |
| } | |
| int quality; | |
| if (LocationManager.PASSIVE_PROVIDER.equals(provider)) { | |
| quality = POWER_NONE; | |
| } else if (LocationManager.GPS_PROVIDER.equals(provider)) { | |
| quality = QUALITY_HIGH_ACCURACY; | |
| } else { | |
| quality = QUALITY_BALANCED_POWER_ACCURACY; | |
| } | |
| return new LocationRequest.Builder(intervalMillis) | |
| .setMinUpdateIntervalMillis(intervalMillis) | |
| .setMinUpdateDistanceMeters(minUpdateDistanceMeters) | |
| .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE) | |
| .build() | |
| .setProvider(provider) | |
| .setQuality(quality); | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use the Builder to construct new LocationRequests. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| @NonNull | |
| public static LocationRequest createFromDeprecatedCriteria(@NonNull Criteria criteria, | |
| long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) { | |
| Preconditions.checkArgument(criteria != null, "invalid null criteria"); | |
| if (intervalMillis < 0) { | |
| intervalMillis = 0; | |
| } else if (intervalMillis == PASSIVE_INTERVAL) { | |
| intervalMillis = Long.MAX_VALUE - 1; | |
| } | |
| if (minUpdateDistanceMeters < 0) { | |
| minUpdateDistanceMeters = 0; | |
| } | |
| return new LocationRequest.Builder(intervalMillis) | |
| .setQuality(criteria) | |
| .setMinUpdateIntervalMillis(intervalMillis) | |
| .setMinUpdateDistanceMeters(minUpdateDistanceMeters) | |
| .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE) | |
| .build(); | |
| } | |
| private LocationRequest( | |
| @Nullable String provider, | |
| long intervalMillis, | |
| @Quality int quality, | |
| long expireAtRealtimeMillis, | |
| long durationMillis, | |
| int maxUpdates, | |
| long minUpdateIntervalMillis, | |
| float minUpdateDistanceMeters, | |
| long maxUpdateDelayMillis, | |
| boolean hiddenFromAppOps, | |
| boolean adasGnssBypass, | |
| boolean bypass, | |
| boolean lowPower, | |
| WorkSource workSource) { | |
| mProvider = provider; | |
| mIntervalMillis = intervalMillis; | |
| mQuality = quality; | |
| mMinUpdateIntervalMillis = minUpdateIntervalMillis; | |
| mExpireAtRealtimeMillis = expireAtRealtimeMillis; | |
| mDurationMillis = durationMillis; | |
| mMaxUpdates = maxUpdates; | |
| mMinUpdateDistanceMeters = minUpdateDistanceMeters; | |
| mMaxUpdateDelayMillis = maxUpdateDelayMillis; | |
| mHideFromAppOps = hiddenFromAppOps; | |
| mAdasGnssBypass = adasGnssBypass; | |
| mBypass = bypass; | |
| mLowPower = lowPower; | |
| mWorkSource = Objects.requireNonNull(workSource); | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setProvider(@NonNull String provider) { | |
| Preconditions.checkArgument(provider != null); | |
| mProvider = provider; | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Providers are no longer an explicit part of a location request. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull String getProvider() { | |
| return mProvider != null ? mProvider : LocationManager.FUSED_PROVIDER; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setQuality(int quality) { | |
| switch (quality) { | |
| case POWER_HIGH: | |
| // fall through | |
| case QUALITY_HIGH_ACCURACY: | |
| mQuality = QUALITY_HIGH_ACCURACY; | |
| break; | |
| case QUALITY_BALANCED_POWER_ACCURACY: | |
| mQuality = QUALITY_BALANCED_POWER_ACCURACY; | |
| break; | |
| case POWER_LOW: | |
| // fall through | |
| case QUALITY_LOW_POWER: | |
| mQuality = QUALITY_LOW_POWER; | |
| break; | |
| case POWER_NONE: | |
| mIntervalMillis = PASSIVE_INTERVAL; | |
| break; | |
| default: | |
| throw new IllegalArgumentException("invalid quality: " + quality); | |
| } | |
| return this; | |
| } | |
| /** | |
| * Returns the quality hint for this location request. The quality hint informs the provider how | |
| * it should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this | |
| * location request. | |
| * | |
| * @return the desired quality tradeoffs between accuracy and power | |
| */ | |
| public @Quality int getQuality() { | |
| return mQuality; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setInterval(long millis) { | |
| Preconditions.checkArgument(millis >= 0); | |
| // legacy clients don't know about the passive interval | |
| if (millis == PASSIVE_INTERVAL) { | |
| millis = Long.MAX_VALUE - 1; | |
| } | |
| mIntervalMillis = millis; | |
| if (mMinUpdateIntervalMillis > mIntervalMillis) { | |
| mMinUpdateIntervalMillis = mIntervalMillis; | |
| } | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use {@link #getIntervalMillis()} instead. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public long getInterval() { | |
| return getIntervalMillis(); | |
| } | |
| /** | |
| * Returns the desired interval of location updates, or {@link #PASSIVE_INTERVAL} if this is a | |
| * passive, no power request. A passive request will not actively generate location updates | |
| * (and thus will not be power blamed for location), but may receive location updates generated | |
| * as a result of other location requests. A passive request must always have an explicit | |
| * minimum update interval set. | |
| * | |
| * <p>Locations may be available at a faster interval than specified here, see | |
| * {@link #getMinUpdateIntervalMillis()} for the behavior in that case. | |
| * | |
| * @return the desired interval of location updates | |
| */ | |
| public @IntRange(from = 0) long getIntervalMillis() { | |
| return mIntervalMillis; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setFastestInterval(long millis) { | |
| Preconditions.checkArgument(millis >= 0); | |
| mMinUpdateIntervalMillis = millis; | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use {@link #getMinUpdateIntervalMillis()} instead. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public long getFastestInterval() { | |
| return getMinUpdateIntervalMillis(); | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setExpireAt(long millis) { | |
| mExpireAtRealtimeMillis = max(millis, 0); | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Prefer {@link #getDurationMillis()} where possible. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public long getExpireAt() { | |
| return mExpireAtRealtimeMillis; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setExpireIn(long millis) { | |
| mDurationMillis = millis; | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use {@link #getDurationMillis()} instead. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public long getExpireIn() { | |
| return getDurationMillis(); | |
| } | |
| /** | |
| * Returns the duration for which location will be provided before the request is automatically | |
| * removed. A duration of <code>Long.MAX_VALUE</code> represents an unlimited duration. | |
| * | |
| * @return the duration for which location will be provided | |
| */ | |
| public @IntRange(from = 1) long getDurationMillis() { | |
| return mDurationMillis; | |
| } | |
| /** | |
| * @hide | |
| */ | |
| public long getExpirationRealtimeMs(long startRealtimeMs) { | |
| long expirationRealtimeMs; | |
| // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0): | |
| if (mDurationMillis > Long.MAX_VALUE - startRealtimeMs) { | |
| expirationRealtimeMs = Long.MAX_VALUE; | |
| } else { | |
| expirationRealtimeMs = startRealtimeMs + mDurationMillis; | |
| } | |
| return min(expirationRealtimeMs, mExpireAtRealtimeMillis); | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setNumUpdates(int numUpdates) { | |
| if (numUpdates <= 0) { | |
| throw new IllegalArgumentException( | |
| "invalid numUpdates: " + numUpdates); | |
| } | |
| mMaxUpdates = numUpdates; | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use {@link #getMaxUpdates()} instead. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public int getNumUpdates() { | |
| return getMaxUpdates(); | |
| } | |
| /** | |
| * Returns the maximum number of location updates for this request before the request is | |
| * automatically removed. A max updates value of <code>Integer.MAX_VALUE</code> represents an | |
| * unlimited number of updates. | |
| */ | |
| public @IntRange(from = 1, to = Integer.MAX_VALUE) int getMaxUpdates() { | |
| return mMaxUpdates; | |
| } | |
| /** | |
| * Returns the minimum update interval. If location updates are available faster than the | |
| * request interval then locations will only be updated if the minimum update interval has | |
| * expired since the last location update. | |
| * | |
| * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the | |
| * minimum update interval, so you need not worry about updates blocked simply because they | |
| * arrived a fraction of a second earlier than expected. | |
| * | |
| * @return the minimum update interval | |
| */ | |
| public @IntRange(from = 0) long getMinUpdateIntervalMillis() { | |
| if (mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) { | |
| return (long) (mIntervalMillis * IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR); | |
| } else { | |
| // the min is only necessary in case someone use a deprecated function to mess with the | |
| // interval or min update interval | |
| return min(mMinUpdateIntervalMillis, mIntervalMillis); | |
| } | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setSmallestDisplacement(float minDisplacementMeters) { | |
| mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minDisplacementMeters, 0, | |
| Float.MAX_VALUE, "minDisplacementMeters"); | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use {@link #getMinUpdateDistanceMeters()} instead. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public float getSmallestDisplacement() { | |
| return getMinUpdateDistanceMeters(); | |
| } | |
| /** | |
| * Returns the minimum distance between location updates. If a potential location update is | |
| * closer to the last location update than the minimum update distance, then the potential | |
| * location update will not occur. A value of 0 meters implies that no location update will ever | |
| * be rejected due to failing this constraint. | |
| * | |
| * @return the minimum distance between location updates | |
| */ | |
| public @FloatRange(from = 0, to = Float.MAX_VALUE) float getMinUpdateDistanceMeters() { | |
| return mMinUpdateDistanceMeters; | |
| } | |
| /** | |
| * Returns the maximum time any location update may be delayed, and thus grouped with following | |
| * updates to enable location batching. If the maximum update delay is equal to or greater than | |
| * twice the interval, then location providers may provide batched results. The maximum batch | |
| * size is the maximum update delay divided by the interval. Not all devices or location | |
| * providers support batching, and use of this parameter does not guarantee that the client will | |
| * see batched results, or that batched results will always be of the maximum size. | |
| * | |
| * When available, batching can provide substantial power savings to the device, and clients are | |
| * encouraged to take advantage where appropriate for the use case. | |
| * | |
| * @see LocationListener#onLocationChanged(java.util.List) | |
| * @return the maximum time by which a location update may be delayed | |
| */ | |
| public @IntRange(from = 0) long getMaxUpdateDelayMillis() { | |
| return mMaxUpdateDelayMillis; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public void setHideFromAppOps(boolean hiddenFromAppOps) { | |
| mHideFromAppOps = hiddenFromAppOps; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use {@link #isHiddenFromAppOps()} instead. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public boolean getHideFromAppOps() { | |
| return isHiddenFromAppOps(); | |
| } | |
| /** | |
| * Returns true if this request should be ignored while updating app ops with location usage. | |
| * This implies that someone else (usually the creator of the location request) is responsible | |
| * for updating app ops. | |
| * | |
| * @return true if this request should be ignored while updating app ops with location usage | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| public boolean isHiddenFromAppOps() { | |
| return mHideFromAppOps; | |
| } | |
| /** | |
| * Returns true if this request may access GNSS even if location settings would normally deny | |
| * this, in order to enable automotive safety features. This field is only respected on | |
| * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced | |
| * Driving Assistance Systems) application. | |
| * | |
| * @return true if all limiting factors will be ignored to satisfy GNSS request | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| public boolean isAdasGnssBypass() { | |
| return mAdasGnssBypass; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| @RequiresPermission(LOCATION_BYPASS) | |
| public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) { | |
| mBypass = locationSettingsIgnored; | |
| return this; | |
| } | |
| /** | |
| * Returns true if location settings, throttling, background location limits, and any other | |
| * possible limiting factors will be ignored in order to satisfy this request. | |
| * | |
| * @return true if all limiting factors will be ignored to satisfy this request | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| public boolean isLocationSettingsIgnored() { | |
| return mBypass; | |
| } | |
| /** | |
| * Returns true if any bypass flag is set on this request. For internal use only. | |
| * | |
| * @hide | |
| */ | |
| public boolean isBypass() { | |
| return mAdasGnssBypass || mBypass; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public @NonNull LocationRequest setLowPowerMode(boolean enabled) { | |
| mLowPower = enabled; | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated Use {@link #isLowPower()} instead. | |
| */ | |
| @Deprecated | |
| @SystemApi | |
| public boolean isLowPowerMode() { | |
| return isLowPower(); | |
| } | |
| /** | |
| * Returns true if extreme trade-offs should be made to save power for this request. This | |
| * usually involves specialized hardware modes which can greatly affect the quality of | |
| * locations. | |
| * | |
| * @return true if extreme trade-offs should be made to save power for this request | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| public boolean isLowPower() { | |
| return mLowPower; | |
| } | |
| /** | |
| * @hide | |
| * @deprecated LocationRequests should be treated as immutable. | |
| */ | |
| @SystemApi | |
| @Deprecated | |
| public void setWorkSource(@Nullable WorkSource workSource) { | |
| if (workSource == null) { | |
| workSource = new WorkSource(); | |
| } | |
| mWorkSource = workSource; | |
| } | |
| /** | |
| * Returns the work source used for power blame for this request. If empty, the system is free | |
| * to assign power blame as it deems most appropriate. | |
| * | |
| * @return the work source used for power blame for this request | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| public @NonNull WorkSource getWorkSource() { | |
| return mWorkSource; | |
| } | |
| public static final @NonNull Parcelable.Creator<LocationRequest> CREATOR = | |
| new Parcelable.Creator<LocationRequest>() { | |
| @Override | |
| public LocationRequest createFromParcel(Parcel in) { | |
| return new LocationRequest( | |
| /* provider= */ in.readString(), | |
| /* intervalMillis= */ in.readLong(), | |
| /* quality= */ in.readInt(), | |
| /* expireAtRealtimeMillis= */ in.readLong(), | |
| /* durationMillis= */ in.readLong(), | |
| /* maxUpdates= */ in.readInt(), | |
| /* minUpdateIntervalMillis= */ in.readLong(), | |
| /* minUpdateDistanceMeters= */ in.readFloat(), | |
| /* maxUpdateDelayMillis= */ in.readLong(), | |
| /* hiddenFromAppOps= */ in.readBoolean(), | |
| /* adasGnssBypass= */ in.readBoolean(), | |
| /* locationSettingsIgnored= */ in.readBoolean(), | |
| /* lowPower= */ in.readBoolean(), | |
| /* workSource= */ in.readTypedObject(WorkSource.CREATOR)); | |
| } | |
| @Override | |
| public LocationRequest[] newArray(int size) { | |
| return new LocationRequest[size]; | |
| } | |
| }; | |
| @Override | |
| public int describeContents() { | |
| return 0; | |
| } | |
| @Override | |
| public void writeToParcel(@NonNull Parcel parcel, int flags) { | |
| parcel.writeString(mProvider); | |
| parcel.writeLong(mIntervalMillis); | |
| parcel.writeInt(mQuality); | |
| parcel.writeLong(mExpireAtRealtimeMillis); | |
| parcel.writeLong(mDurationMillis); | |
| parcel.writeInt(mMaxUpdates); | |
| parcel.writeLong(mMinUpdateIntervalMillis); | |
| parcel.writeFloat(mMinUpdateDistanceMeters); | |
| parcel.writeLong(mMaxUpdateDelayMillis); | |
| parcel.writeBoolean(mHideFromAppOps); | |
| parcel.writeBoolean(mAdasGnssBypass); | |
| parcel.writeBoolean(mBypass); | |
| parcel.writeBoolean(mLowPower); | |
| parcel.writeTypedObject(mWorkSource, 0); | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| if (o == null || getClass() != o.getClass()) { | |
| return false; | |
| } | |
| LocationRequest that = (LocationRequest) o; | |
| return mIntervalMillis == that.mIntervalMillis | |
| && mQuality == that.mQuality | |
| && mExpireAtRealtimeMillis == that.mExpireAtRealtimeMillis | |
| && mDurationMillis == that.mDurationMillis | |
| && mMaxUpdates == that.mMaxUpdates | |
| && mMinUpdateIntervalMillis == that.mMinUpdateIntervalMillis | |
| && Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0 | |
| && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis | |
| && mHideFromAppOps == that.mHideFromAppOps | |
| && mAdasGnssBypass == that.mAdasGnssBypass | |
| && mBypass == that.mBypass | |
| && mLowPower == that.mLowPower | |
| && Objects.equals(mProvider, that.mProvider) | |
| && Objects.equals(mWorkSource, that.mWorkSource); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return Objects.hash(mProvider, mIntervalMillis, mWorkSource); | |
| } | |
| @NonNull | |
| @Override | |
| public String toString() { | |
| StringBuilder s = new StringBuilder(); | |
| s.append("Request["); | |
| if (mProvider != null) { | |
| s.append(mProvider).append(" "); | |
| } | |
| if (mIntervalMillis != PASSIVE_INTERVAL) { | |
| s.append("@"); | |
| TimeUtils.formatDuration(mIntervalMillis, s); | |
| switch (mQuality) { | |
| case QUALITY_HIGH_ACCURACY: | |
| s.append(" HIGH_ACCURACY"); | |
| break; | |
| case QUALITY_BALANCED_POWER_ACCURACY: | |
| s.append(" BALANCED"); | |
| break; | |
| case QUALITY_LOW_POWER: | |
| s.append(" LOW_POWER"); | |
| break; | |
| } | |
| } else { | |
| s.append("PASSIVE"); | |
| } | |
| if (mExpireAtRealtimeMillis != Long.MAX_VALUE) { | |
| s.append(", expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis)); | |
| } | |
| if (mDurationMillis != Long.MAX_VALUE) { | |
| s.append(", duration="); | |
| TimeUtils.formatDuration(mDurationMillis, s); | |
| } | |
| if (mMaxUpdates != Integer.MAX_VALUE) { | |
| s.append(", maxUpdates=").append(mMaxUpdates); | |
| } | |
| if (mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL | |
| && mMinUpdateIntervalMillis < mIntervalMillis) { | |
| s.append(", minUpdateInterval="); | |
| TimeUtils.formatDuration(mMinUpdateIntervalMillis, s); | |
| } | |
| if (mMinUpdateDistanceMeters > 0.0) { | |
| s.append(", minUpdateDistance=").append(mMinUpdateDistanceMeters); | |
| } | |
| if (mMaxUpdateDelayMillis / 2 > mIntervalMillis) { | |
| s.append(", maxUpdateDelay="); | |
| TimeUtils.formatDuration(mMaxUpdateDelayMillis, s); | |
| } | |
| if (mLowPower) { | |
| s.append(", lowPower"); | |
| } | |
| if (mHideFromAppOps) { | |
| s.append(", hiddenFromAppOps"); | |
| } | |
| if (mAdasGnssBypass) { | |
| s.append(", adasGnssBypass"); | |
| } | |
| if (mBypass) { | |
| s.append(", bypass"); | |
| } | |
| if (mWorkSource != null && !mWorkSource.isEmpty()) { | |
| s.append(", ").append(mWorkSource); | |
| } | |
| s.append(']'); | |
| return s.toString(); | |
| } | |
| /** | |
| * A builder class for {@link LocationRequest}. | |
| */ | |
| public static final class Builder { | |
| private long mIntervalMillis; | |
| private @Quality int mQuality; | |
| private long mDurationMillis; | |
| private int mMaxUpdates; | |
| private long mMinUpdateIntervalMillis; | |
| private float mMinUpdateDistanceMeters; | |
| private long mMaxUpdateDelayMillis; | |
| private boolean mHiddenFromAppOps; | |
| private boolean mAdasGnssBypass; | |
| private boolean mBypass; | |
| private boolean mLowPower; | |
| @Nullable private WorkSource mWorkSource; | |
| /** | |
| * Creates a new Builder with the given interval. See {@link #setIntervalMillis(long)} for | |
| * more information on the interval. | |
| */ | |
| public Builder(long intervalMillis) { | |
| // gives us a range check | |
| setIntervalMillis(intervalMillis); | |
| mQuality = QUALITY_BALANCED_POWER_ACCURACY; | |
| mDurationMillis = Long.MAX_VALUE; | |
| mMaxUpdates = Integer.MAX_VALUE; | |
| mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL; | |
| mMinUpdateDistanceMeters = 0; | |
| mMaxUpdateDelayMillis = 0; | |
| mHiddenFromAppOps = false; | |
| mAdasGnssBypass = false; | |
| mBypass = false; | |
| mLowPower = false; | |
| mWorkSource = null; | |
| } | |
| /** | |
| * Creates a new Builder with all parameters copied from the given location request. | |
| */ | |
| public Builder(@NonNull LocationRequest locationRequest) { | |
| mIntervalMillis = locationRequest.mIntervalMillis; | |
| mQuality = locationRequest.mQuality; | |
| mDurationMillis = locationRequest.mDurationMillis; | |
| mMaxUpdates = locationRequest.mMaxUpdates; | |
| mMinUpdateIntervalMillis = locationRequest.mMinUpdateIntervalMillis; | |
| mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters; | |
| mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis; | |
| mHiddenFromAppOps = locationRequest.mHideFromAppOps; | |
| mAdasGnssBypass = locationRequest.mAdasGnssBypass; | |
| mBypass = locationRequest.mBypass; | |
| mLowPower = locationRequest.mLowPower; | |
| mWorkSource = locationRequest.mWorkSource; | |
| // handle edge cases that can only happen with location request that has been modified | |
| // by deprecated SystemApi methods | |
| if (mIntervalMillis == PASSIVE_INTERVAL | |
| && mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) { | |
| // this is the legacy default minimum update interval, so if we're forced to | |
| // change the value, at least this should be unsuprising to legacy clients (which | |
| // should be the only clients capable of getting in this weird state). | |
| mMinUpdateIntervalMillis = 10 * 60 * 1000; | |
| } | |
| } | |
| /** | |
| * Sets the request interval. The request interval may be set to {@link #PASSIVE_INTERVAL} | |
| * which indicates this request will not actively generate location updates (and thus will | |
| * not be power blamed for location), but may receive location updates generated as a result | |
| * of other location requests. A passive request must always have an explicit minimum | |
| * update interval set. | |
| * | |
| * <p>Locations may be available at a faster interval than specified here, see | |
| * {@link #setMinUpdateIntervalMillis(long)} for the behavior in that case. | |
| */ | |
| public @NonNull Builder setIntervalMillis(@IntRange(from = 0) long intervalMillis) { | |
| mIntervalMillis = Preconditions.checkArgumentInRange(intervalMillis, 0, Long.MAX_VALUE, | |
| "intervalMillis"); | |
| return this; | |
| } | |
| /** | |
| * Sets the request quality. The quality is a hint to providers on how they should weigh | |
| * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and | |
| * lower accuracy locations may cost less power to produce. Defaults to | |
| * {@link #QUALITY_BALANCED_POWER_ACCURACY}. | |
| */ | |
| public @NonNull Builder setQuality(@Quality int quality) { | |
| Preconditions.checkArgument( | |
| quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY | |
| || quality == QUALITY_HIGH_ACCURACY, | |
| "quality must be a defined QUALITY constant, not %d", quality); | |
| mQuality = quality; | |
| return this; | |
| } | |
| /** | |
| * @hide | |
| */ | |
| public @NonNull Builder setQuality(@NonNull Criteria criteria) { | |
| switch (criteria.getAccuracy()) { | |
| case Criteria.ACCURACY_COARSE: | |
| mQuality = QUALITY_BALANCED_POWER_ACCURACY; | |
| break; | |
| case Criteria.ACCURACY_FINE: | |
| mQuality = QUALITY_HIGH_ACCURACY; | |
| break; | |
| default: { | |
| if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) { | |
| mQuality = POWER_HIGH; | |
| } else { | |
| mQuality = POWER_LOW; | |
| } | |
| } | |
| } | |
| return this; | |
| } | |
| /** | |
| * Sets the duration this request will continue before being automatically removed. Defaults | |
| * to <code>Long.MAX_VALUE</code>, which represents an unlimited duration. | |
| */ | |
| public @NonNull Builder setDurationMillis(@IntRange(from = 1) long durationMillis) { | |
| mDurationMillis = Preconditions.checkArgumentInRange(durationMillis, 1, Long.MAX_VALUE, | |
| "durationMillis"); | |
| return this; | |
| } | |
| /** | |
| * Sets the maximum number of location updates for this request before this request is | |
| * automatically removed. Defaults to <code>Integer.MAX_VALUE</code>, which represents an | |
| * unlimited number of updates. | |
| */ | |
| public @NonNull Builder setMaxUpdates( | |
| @IntRange(from = 1, to = Integer.MAX_VALUE) int maxUpdates) { | |
| mMaxUpdates = Preconditions.checkArgumentInRange(maxUpdates, 1, Integer.MAX_VALUE, | |
| "maxUpdates"); | |
| return this; | |
| } | |
| /** | |
| * Sets an explicit minimum update interval. If location updates are available faster than | |
| * the request interval then an update will only occur if the minimum update interval has | |
| * expired since the last location update. Defaults to no explicit minimum update interval | |
| * set, which means some sensible default between 0 and the interval will be chosen. The | |
| * exact value is not specified at the moment. If an exact known value is required, clients | |
| * should set an explicit value themselves. | |
| * | |
| * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the | |
| * minimum update interval, so you need not worry about updates blocked simply because they | |
| * arrived a fraction of a second earlier than expected. | |
| * | |
| * <p class="note"><strong>Note:</strong> When {@link #build()} is invoked, the minimum of | |
| * the interval and the minimum update interval will be used as the minimum update interval | |
| * of the built request. | |
| */ | |
| public @NonNull Builder setMinUpdateIntervalMillis( | |
| @IntRange(from = 0) long minUpdateIntervalMillis) { | |
| mMinUpdateIntervalMillis = Preconditions.checkArgumentInRange(minUpdateIntervalMillis, | |
| 0, Long.MAX_VALUE, "minUpdateIntervalMillis"); | |
| return this; | |
| } | |
| /** | |
| * Clears an explicitly set minimum update interval and reverts to an implicit minimum | |
| * update interval (ie, the minimum update interval is some sensible default between 0 and | |
| * the interval). | |
| */ | |
| public @NonNull Builder clearMinUpdateIntervalMillis() { | |
| mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL; | |
| return this; | |
| } | |
| /** | |
| * Sets the minimum update distance between location updates. If a potential location | |
| * update is closer to the last location update than the minimum update distance, then | |
| * the potential location update will not occur. Defaults to 0, which represents no minimum | |
| * update distance. | |
| */ | |
| public @NonNull Builder setMinUpdateDistanceMeters( | |
| @FloatRange(from = 0, to = Float.MAX_VALUE) float minUpdateDistanceMeters) { | |
| mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minUpdateDistanceMeters, | |
| 0, Float.MAX_VALUE, "minUpdateDistanceMeters"); | |
| return this; | |
| } | |
| /** | |
| * Sets the maximum time any location update may be delayed, and thus grouped with following | |
| * updates to enable location batching. If the maximum update delay is equal to or greater | |
| * than twice the interval, then location providers may provide batched results. Defaults to | |
| * 0, which represents no batching allowed. | |
| */ | |
| public @NonNull Builder setMaxUpdateDelayMillis( | |
| @IntRange(from = 0) long maxUpdateDelayMillis) { | |
| mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0, | |
| Long.MAX_VALUE, "maxUpdateDelayMillis"); | |
| return this; | |
| } | |
| /** | |
| * If set to true, indicates that app ops should not be updated with location usage due to | |
| * this request. This implies that someone else (usually the creator of the location | |
| * request) is responsible for updating app ops as appropriate. Defaults to false. | |
| * | |
| * <p>Permissions enforcement occurs when resulting location request is actually used, not | |
| * when this method is invoked. | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| @RequiresPermission(Manifest.permission.UPDATE_APP_OPS_STATS) | |
| public @NonNull Builder setHiddenFromAppOps(boolean hiddenFromAppOps) { | |
| mHiddenFromAppOps = hiddenFromAppOps; | |
| return this; | |
| } | |
| /** | |
| * If set to true, indicates that the client is an ADAS (Advanced Driving Assistance | |
| * Systems) client, which requires access to GNSS even if location settings would normally | |
| * deny this, in order to enable auto safety features. This field is only respected on | |
| * automotive devices, and only if the client is recognized as a legitimate ADAS | |
| * application. Defaults to false. | |
| * | |
| * <p>Permissions enforcement occurs when resulting location request is actually used, not | |
| * when this method is invoked. | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| @RequiresPermission(LOCATION_BYPASS) | |
| @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) | |
| public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) { | |
| mAdasGnssBypass = adasGnssBypass; | |
| return this; | |
| } | |
| /** | |
| * If set to true, indicates that location settings, throttling, background location limits, | |
| * and any other possible limiting factors should be ignored in order to satisfy this | |
| * request. This is only intended for use in user initiated emergency situations, and | |
| * should be used extremely cautiously. Defaults to false. | |
| * | |
| * <p>Permissions enforcement occurs when resulting location request is actually used, not | |
| * when this method is invoked. | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| @RequiresPermission(LOCATION_BYPASS) | |
| public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) { | |
| mBypass = locationSettingsIgnored; | |
| return this; | |
| } | |
| /** | |
| * It set to true, indicates that extreme trade-offs should be made if possible to save | |
| * power for this request. This usually involves specialized hardware modes which can | |
| * greatly affect the quality of locations. Not all devices may support this. Defaults to | |
| * false. | |
| * | |
| * <p>Permissions enforcement occurs when resulting location request is actually used, not | |
| * when this method is invoked. | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) | |
| public @NonNull Builder setLowPower(boolean lowPower) { | |
| mLowPower = lowPower; | |
| return this; | |
| } | |
| /** | |
| * Sets the work source to use for power blame for this location request. Defaults to an | |
| * empty WorkSource, which implies the system is free to assign power blame as it determines | |
| * best for this request (which usually means blaming the owner of the location listener). | |
| * | |
| * <p>Permissions enforcement occurs when resulting location request is actually used, not | |
| * when this method is invoked. | |
| * | |
| * @hide | |
| */ | |
| @SystemApi | |
| @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS) | |
| public @NonNull Builder setWorkSource(@Nullable WorkSource workSource) { | |
| mWorkSource = workSource; | |
| return this; | |
| } | |
| /** | |
| * Builds a location request from this builder. If an explicit minimum update interval is | |
| * set, the minimum update interval of the location request will be the minimum of the | |
| * interval and minimum update interval. | |
| * | |
| * <p>If building a passive request then you must have set an explicit minimum update | |
| * interval. | |
| * | |
| * @throws IllegalStateException if building a passive request with no explicit minimum | |
| * update interval set | |
| * @return a new location request | |
| */ | |
| public @NonNull LocationRequest build() { | |
| Preconditions.checkState(mIntervalMillis != PASSIVE_INTERVAL | |
| || mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL, | |
| "passive location requests must have an explicit minimum update interval"); | |
| return new LocationRequest( | |
| null, | |
| mIntervalMillis, | |
| mQuality, | |
| Long.MAX_VALUE, | |
| mDurationMillis, | |
| mMaxUpdates, | |
| min(mMinUpdateIntervalMillis, mIntervalMillis), | |
| mMinUpdateDistanceMeters, | |
| mMaxUpdateDelayMillis, | |
| mHiddenFromAppOps, | |
| mAdasGnssBypass, | |
| mBypass, | |
| mLowPower, | |
| new WorkSource(mWorkSource)); | |
| } | |
| } | |
| } |