• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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