1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.location.provider; 18 19 import static android.location.LocationRequest.QUALITY_BALANCED_POWER_ACCURACY; 20 import static android.location.LocationRequest.QUALITY_HIGH_ACCURACY; 21 import static android.location.LocationRequest.QUALITY_LOW_POWER; 22 23 import android.annotation.IntRange; 24 import android.annotation.NonNull; 25 import android.annotation.SystemApi; 26 import android.location.LocationRequest; 27 import android.location.LocationRequest.Quality; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 import android.os.WorkSource; 31 import android.util.TimeUtils; 32 33 import com.android.internal.util.Preconditions; 34 35 import java.util.Objects; 36 37 /** 38 * Location provider request. 39 * @hide 40 */ 41 @SystemApi 42 public final class ProviderRequest implements Parcelable { 43 44 public static final long INTERVAL_DISABLED = Long.MAX_VALUE; 45 46 public static final @NonNull ProviderRequest EMPTY_REQUEST = new ProviderRequest( 47 INTERVAL_DISABLED, 48 QUALITY_BALANCED_POWER_ACCURACY, 49 0, 50 false, 51 false, 52 false, 53 new WorkSource()); 54 55 private final long mIntervalMillis; 56 private final @Quality int mQuality; 57 private final long mMaxUpdateDelayMillis; 58 private final boolean mLowPower; 59 private final boolean mAdasGnssBypass; 60 private final boolean mLocationSettingsIgnored; 61 private final WorkSource mWorkSource; 62 63 /** 64 * Listener to be invoked when a new request is set to the provider. 65 */ 66 public interface ChangedListener { 67 68 /** 69 * Invoked when a new request is set. 70 * 71 * @param provider the location provider associated with the request 72 * @param request the new {@link ProviderRequest} 73 */ onProviderRequestChanged(@onNull String provider, @NonNull ProviderRequest request)74 void onProviderRequestChanged(@NonNull String provider, @NonNull ProviderRequest request); 75 } 76 ProviderRequest( long intervalMillis, @Quality int quality, long maxUpdateDelayMillis, boolean lowPower, boolean adasGnssBypass, boolean locationSettingsIgnored, @NonNull WorkSource workSource)77 private ProviderRequest( 78 long intervalMillis, 79 @Quality int quality, 80 long maxUpdateDelayMillis, 81 boolean lowPower, 82 boolean adasGnssBypass, 83 boolean locationSettingsIgnored, 84 @NonNull WorkSource workSource) { 85 mIntervalMillis = intervalMillis; 86 mQuality = quality; 87 mMaxUpdateDelayMillis = maxUpdateDelayMillis; 88 mLowPower = lowPower; 89 mAdasGnssBypass = adasGnssBypass; 90 mLocationSettingsIgnored = locationSettingsIgnored; 91 mWorkSource = Objects.requireNonNull(workSource); 92 } 93 94 /** 95 * True if this is an active request with a valid location reporting interval, false if this 96 * request is inactive and does not require any locations to be reported. 97 */ isActive()98 public boolean isActive() { 99 return mIntervalMillis != INTERVAL_DISABLED; 100 } 101 102 /** 103 * The interval at which a provider should report location. Will return 104 * {@link #INTERVAL_DISABLED} for an inactive request. 105 */ getIntervalMillis()106 public @IntRange(from = 0) long getIntervalMillis() { 107 return mIntervalMillis; 108 } 109 110 /** 111 * The quality hint for this location request. The quality hint informs the provider how it 112 * should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this 113 * provider request. 114 */ getQuality()115 public @Quality int getQuality() { 116 return mQuality; 117 } 118 119 /** 120 * The maximum time any location update may be delayed, and thus grouped with following updates 121 * to enable location batching. If the maximum update delay is equal to or greater than 122 * twice the interval, then the provider may provide batched results if possible. The maximum 123 * batch size a provider is allowed to return is the maximum update delay divided by the 124 * interval. 125 */ getMaxUpdateDelayMillis()126 public @IntRange(from = 0) long getMaxUpdateDelayMillis() { 127 return mMaxUpdateDelayMillis; 128 } 129 130 /** 131 * Whether any applicable hardware low power modes should be used to satisfy this request. 132 */ isLowPower()133 public boolean isLowPower() { 134 return mLowPower; 135 } 136 137 /** 138 * Returns true if this request may access GNSS even if location settings would normally deny 139 * this, in order to enable automotive safety features. This field is only respected on 140 * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced 141 * Driving Assistance Systems) application. 142 * 143 * @hide 144 */ isAdasGnssBypass()145 public boolean isAdasGnssBypass() { 146 return mAdasGnssBypass; 147 } 148 149 /** 150 * Whether the provider should ignore all location settings, user consents, power restrictions 151 * or any other restricting factors and always satisfy this request to the best of their 152 * ability. This should only be used in case of a user initiated emergency. 153 */ isLocationSettingsIgnored()154 public boolean isLocationSettingsIgnored() { 155 return mLocationSettingsIgnored; 156 } 157 158 /** 159 * Returns true if any bypass flag is set on this request. 160 * 161 * @hide 162 */ isBypass()163 public boolean isBypass() { 164 return mAdasGnssBypass || mLocationSettingsIgnored; 165 } 166 167 /** 168 * The power blame for this provider request. 169 */ getWorkSource()170 public @NonNull WorkSource getWorkSource() { 171 return mWorkSource; 172 } 173 174 public static final @NonNull Creator<ProviderRequest> CREATOR = new Creator<ProviderRequest>() { 175 @Override 176 public ProviderRequest createFromParcel(Parcel in) { 177 long intervalMillis = in.readLong(); 178 if (intervalMillis == INTERVAL_DISABLED) { 179 return EMPTY_REQUEST; 180 } else { 181 return new ProviderRequest( 182 intervalMillis, 183 /* quality= */ in.readInt(), 184 /* maxUpdateDelayMillis= */ in.readLong(), 185 /* lowPower= */ in.readBoolean(), 186 /* adasGnssBypass= */ in.readBoolean(), 187 /* locationSettingsIgnored= */ in.readBoolean(), 188 /* workSource= */ in.readTypedObject(WorkSource.CREATOR)); 189 } 190 } 191 192 @Override 193 public ProviderRequest[] newArray(int size) { 194 return new ProviderRequest[size]; 195 } 196 }; 197 198 @Override describeContents()199 public int describeContents() { 200 return 0; 201 } 202 203 @Override writeToParcel(@onNull Parcel parcel, int flags)204 public void writeToParcel(@NonNull Parcel parcel, int flags) { 205 parcel.writeLong(mIntervalMillis); 206 if (mIntervalMillis != INTERVAL_DISABLED) { 207 parcel.writeInt(mQuality); 208 parcel.writeLong(mMaxUpdateDelayMillis); 209 parcel.writeBoolean(mLowPower); 210 parcel.writeBoolean(mAdasGnssBypass); 211 parcel.writeBoolean(mLocationSettingsIgnored); 212 parcel.writeTypedObject(mWorkSource, flags); 213 } 214 } 215 216 @Override equals(Object o)217 public boolean equals(Object o) { 218 if (this == o) { 219 return true; 220 } 221 if (o == null || getClass() != o.getClass()) { 222 return false; 223 } 224 225 ProviderRequest that = (ProviderRequest) o; 226 if (mIntervalMillis == INTERVAL_DISABLED) { 227 return that.mIntervalMillis == INTERVAL_DISABLED; 228 } else { 229 return mIntervalMillis == that.mIntervalMillis 230 && mQuality == that.mQuality 231 && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis 232 && mLowPower == that.mLowPower 233 && mAdasGnssBypass == that.mAdasGnssBypass 234 && mLocationSettingsIgnored == that.mLocationSettingsIgnored 235 && mWorkSource.equals(that.mWorkSource); 236 } 237 } 238 239 @Override hashCode()240 public int hashCode() { 241 return Objects.hash(mIntervalMillis, mQuality, mWorkSource); 242 } 243 244 @Override toString()245 public String toString() { 246 StringBuilder s = new StringBuilder(); 247 s.append("ProviderRequest["); 248 if (mIntervalMillis != INTERVAL_DISABLED) { 249 s.append("@"); 250 TimeUtils.formatDuration(mIntervalMillis, s); 251 if (mQuality != QUALITY_BALANCED_POWER_ACCURACY) { 252 if (mQuality == QUALITY_HIGH_ACCURACY) { 253 s.append(", HIGH_ACCURACY"); 254 } else if (mQuality == QUALITY_LOW_POWER) { 255 s.append(", LOW_POWER"); 256 } 257 } 258 if (mMaxUpdateDelayMillis / 2 > mIntervalMillis) { 259 s.append(", maxUpdateDelay="); 260 TimeUtils.formatDuration(mMaxUpdateDelayMillis, s); 261 } 262 if (mLowPower) { 263 s.append(", lowPower"); 264 } 265 if (mAdasGnssBypass) { 266 s.append(", adasGnssBypass"); 267 } 268 if (mLocationSettingsIgnored) { 269 s.append(", settingsBypass"); 270 } 271 if (!mWorkSource.isEmpty()) { 272 s.append(", ").append(mWorkSource); 273 } 274 } else { 275 s.append("OFF"); 276 } 277 s.append(']'); 278 return s.toString(); 279 } 280 281 /** 282 * A Builder for {@link ProviderRequest}s. 283 */ 284 public static final class Builder { 285 286 private long mIntervalMillis = INTERVAL_DISABLED; 287 private int mQuality = QUALITY_BALANCED_POWER_ACCURACY; 288 private long mMaxUpdateDelayMillis = 0; 289 private boolean mLowPower; 290 private boolean mAdasGnssBypass; 291 private boolean mLocationSettingsIgnored; 292 private WorkSource mWorkSource = new WorkSource(); 293 294 /** 295 * Sets the request interval. Use {@link #INTERVAL_DISABLED} for an inactive request. 296 * Defaults to {@link #INTERVAL_DISABLED}. 297 */ setIntervalMillis(@ntRangefrom = 0) long intervalMillis)298 public @NonNull Builder setIntervalMillis(@IntRange(from = 0) long intervalMillis) { 299 mIntervalMillis = Preconditions.checkArgumentInRange(intervalMillis, 0, Long.MAX_VALUE, 300 "intervalMillis"); 301 return this; 302 } 303 304 /** 305 * Sets the request quality. The quality is a hint to providers on how they should weigh 306 * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and 307 * lower accuracy locations may cost less power to produce. Defaults to 308 * {@link LocationRequest#QUALITY_BALANCED_POWER_ACCURACY}. 309 */ setQuality(@uality int quality)310 public @NonNull Builder setQuality(@Quality int quality) { 311 Preconditions.checkArgument( 312 quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY 313 || quality == QUALITY_HIGH_ACCURACY); 314 mQuality = quality; 315 return this; 316 } 317 318 /** 319 * Sets the maximum time any location update may be delayed, and thus grouped with following 320 * updates to enable location batching. If the maximum update delay is equal to or greater 321 * than twice the interval, then location providers may provide batched results. Defaults to 322 * 0. 323 */ setMaxUpdateDelayMillis( @ntRangefrom = 0) long maxUpdateDelayMillis)324 public @NonNull Builder setMaxUpdateDelayMillis( 325 @IntRange(from = 0) long maxUpdateDelayMillis) { 326 mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0, 327 Long.MAX_VALUE, "maxUpdateDelayMillis"); 328 return this; 329 } 330 331 /** 332 * Sets whether hardware low power mode should be used. False by default. 333 */ setLowPower(boolean lowPower)334 public @NonNull Builder setLowPower(boolean lowPower) { 335 mLowPower = lowPower; 336 return this; 337 } 338 339 /** 340 * Sets whether this ADAS request should bypass GNSS settings. False by default. 341 * 342 * @hide 343 */ setAdasGnssBypass(boolean adasGnssBypass)344 public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) { 345 this.mAdasGnssBypass = adasGnssBypass; 346 return this; 347 } 348 349 /** 350 * Sets whether location settings should be ignored. False by default. 351 */ setLocationSettingsIgnored(boolean locationSettingsIgnored)352 public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) { 353 this.mLocationSettingsIgnored = locationSettingsIgnored; 354 return this; 355 } 356 357 /** 358 * Sets the work source for power blame. Empty by default. 359 */ setWorkSource(@onNull WorkSource workSource)360 public @NonNull Builder setWorkSource(@NonNull WorkSource workSource) { 361 mWorkSource = Objects.requireNonNull(workSource); 362 return this; 363 } 364 365 /** 366 * Builds a ProviderRequest. 367 */ build()368 public @NonNull ProviderRequest build() { 369 if (mIntervalMillis == INTERVAL_DISABLED) { 370 return EMPTY_REQUEST; 371 } else { 372 return new ProviderRequest( 373 mIntervalMillis, 374 mQuality, 375 mMaxUpdateDelayMillis, 376 mLowPower, 377 mAdasGnssBypass, 378 mLocationSettingsIgnored, 379 mWorkSource); 380 } 381 } 382 } 383 } 384