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;
18 
19 import static android.Manifest.permission.LOCATION_BYPASS;
20 
21 import android.Manifest;
22 import android.annotation.NonNull;
23 import android.annotation.RequiresFeature;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.content.pm.PackageManager;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 
30 import java.util.Objects;
31 
32 /**
33  * An encapsulation of various parameters for requesting last location via {@link LocationManager}.
34  *
35  * @hide
36  */
37 @SystemApi
38 public final class LastLocationRequest implements Parcelable {
39 
40     private final boolean mHiddenFromAppOps;
41     private final boolean mAdasGnssBypass;
42     private final boolean mLocationSettingsIgnored;
43 
LastLocationRequest( boolean hiddenFromAppOps, boolean adasGnssBypass, boolean locationSettingsIgnored)44     private LastLocationRequest(
45             boolean hiddenFromAppOps,
46             boolean adasGnssBypass,
47             boolean locationSettingsIgnored) {
48         mHiddenFromAppOps = hiddenFromAppOps;
49         mAdasGnssBypass = adasGnssBypass;
50         mLocationSettingsIgnored = locationSettingsIgnored;
51     }
52 
53     /**
54      * Returns true if this last location request should be ignored while updating app ops with
55      * location usage. This implies that someone else (usually the creator of the last location
56      * request) is responsible for updating app ops.
57      *
58      * @return true if this request should be ignored while updating app ops with location usage
59      *
60      * @hide
61      */
62     @SystemApi
isHiddenFromAppOps()63     public boolean isHiddenFromAppOps() {
64         return mHiddenFromAppOps;
65     }
66 
67     /**
68      * Returns true if this request may access GNSS even if location settings would normally deny
69      * this, in order to enable automotive safety features. This field is only respected on
70      * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
71      * Driving Assistance Systems) application.
72      *
73      * @return true if all limiting factors will be ignored to satisfy GNSS request
74      *
75      * @hide
76      */
77     @SystemApi
isAdasGnssBypass()78     public boolean isAdasGnssBypass() {
79         return mAdasGnssBypass;
80     }
81 
82 
83     /**
84      * Returns true if location settings, throttling, background location limits, and any other
85      * possible limiting factors will be ignored in order to satisfy this last location request.
86      *
87      * @return true if all limiting factors will be ignored to satisfy this request
88      *
89      * @hide
90      */
91     @SystemApi
isLocationSettingsIgnored()92     public boolean isLocationSettingsIgnored() {
93         return mLocationSettingsIgnored;
94     }
95 
96     /**
97      * Returns true if any bypass flag is set on this request. For internal use only.
98      *
99      * @hide
100      */
isBypass()101     public boolean isBypass() {
102         return mAdasGnssBypass || mLocationSettingsIgnored;
103     }
104 
105     public static final @NonNull Parcelable.Creator<LastLocationRequest> CREATOR =
106             new Parcelable.Creator<LastLocationRequest>() {
107                 @Override
108                 public LastLocationRequest createFromParcel(Parcel in) {
109                     return new LastLocationRequest(
110                             /* hiddenFromAppOps= */ in.readBoolean(),
111                             /* adasGnssBypass= */ in.readBoolean(),
112                             /* locationSettingsIgnored= */ in.readBoolean());
113                 }
114                 @Override
115                 public LastLocationRequest[] newArray(int size) {
116                     return new LastLocationRequest[size];
117                 }
118             };
119     @Override
describeContents()120     public int describeContents() {
121         return 0;
122     }
123 
124     @Override
writeToParcel(@onNull Parcel parcel, int flags)125     public void writeToParcel(@NonNull Parcel parcel, int flags) {
126         parcel.writeBoolean(mHiddenFromAppOps);
127         parcel.writeBoolean(mAdasGnssBypass);
128         parcel.writeBoolean(mLocationSettingsIgnored);
129     }
130 
131     @Override
equals(Object o)132     public boolean equals(Object o) {
133         if (this == o) {
134             return true;
135         }
136         if (o == null || getClass() != o.getClass()) {
137             return false;
138         }
139         LastLocationRequest that = (LastLocationRequest) o;
140         return mHiddenFromAppOps == that.mHiddenFromAppOps
141                 && mAdasGnssBypass == that.mAdasGnssBypass
142                 && mLocationSettingsIgnored == that.mLocationSettingsIgnored;
143     }
144 
145     @Override
hashCode()146     public int hashCode() {
147         return Objects.hash(mHiddenFromAppOps, mAdasGnssBypass, mLocationSettingsIgnored);
148     }
149 
150     @NonNull
151     @Override
toString()152     public String toString() {
153         StringBuilder s = new StringBuilder();
154         s.append("LastLocationRequest[");
155         if (mHiddenFromAppOps) {
156             s.append("hiddenFromAppOps, ");
157         }
158         if (mAdasGnssBypass) {
159             s.append("adasGnssBypass, ");
160         }
161         if (mLocationSettingsIgnored) {
162             s.append("settingsBypass, ");
163         }
164         if (s.length() > "LastLocationRequest[".length()) {
165             s.setLength(s.length() - 2);
166         }
167         s.append(']');
168         return s.toString();
169     }
170 
171     /**
172      * A builder class for {@link LastLocationRequest}.
173      */
174     public static final class Builder {
175 
176         private boolean mHiddenFromAppOps;
177         private boolean mAdasGnssBypass;
178         private boolean mLocationSettingsIgnored;
179 
180         /**
181          * Creates a new Builder.
182          */
Builder()183         public Builder() {
184             mHiddenFromAppOps = false;
185             mAdasGnssBypass = false;
186             mLocationSettingsIgnored = false;
187         }
188 
189         /**
190          * Creates a new Builder with all parameters copied from the given last location request.
191          */
Builder(@onNull LastLocationRequest lastLocationRequest)192         public Builder(@NonNull LastLocationRequest lastLocationRequest) {
193             mHiddenFromAppOps = lastLocationRequest.mHiddenFromAppOps;
194             mAdasGnssBypass = lastLocationRequest.mAdasGnssBypass;
195             mLocationSettingsIgnored = lastLocationRequest.mLocationSettingsIgnored;
196         }
197 
198         /**
199          * If set to true, indicates that app ops should not be updated with location usage due to
200          * this request. This implies that someone else (usually the creator of the last location
201          * request) is responsible for updating app ops as appropriate. Defaults to false.
202          *
203          * <p>Permissions enforcement occurs when resulting last location request is actually used,
204          * not when this method is invoked.
205          *
206          * @hide
207          */
208         @SystemApi
209         @RequiresPermission(Manifest.permission.UPDATE_APP_OPS_STATS)
setHiddenFromAppOps(boolean hiddenFromAppOps)210         public @NonNull Builder setHiddenFromAppOps(boolean hiddenFromAppOps) {
211             mHiddenFromAppOps = hiddenFromAppOps;
212             return this;
213         }
214 
215         /**
216          * If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
217          * Systems) client, which requires access to GNSS even if location settings would normally
218          * deny this, in order to enable auto safety features. This field is only respected on
219          * automotive devices, and only if the client is recognized as a legitimate ADAS
220          * application. Defaults to false.
221          *
222          * <p>Permissions enforcement occurs when resulting location request is actually used, not
223          * when this method is invoked.
224          *
225          * @hide
226          */
227         @SystemApi
228         @RequiresPermission(LOCATION_BYPASS)
229         @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
setAdasGnssBypass(boolean adasGnssBypass)230         public @NonNull LastLocationRequest.Builder setAdasGnssBypass(boolean adasGnssBypass) {
231             mAdasGnssBypass = adasGnssBypass;
232             return this;
233         }
234 
235         /**
236          * If set to true, indicates that location settings, throttling, background location limits,
237          * and any other possible limiting factors should be ignored in order to satisfy this
238          * last location request. This is only intended for use in user initiated emergency
239          * situations, and should be used extremely cautiously. Defaults to false.
240          *
241          * <p>Permissions enforcement occurs when resulting last location request is actually used,
242          * not when this method is invoked.
243          *
244          * @hide
245          */
246         @SystemApi
247         @RequiresPermission(LOCATION_BYPASS)
setLocationSettingsIgnored(boolean locationSettingsIgnored)248         public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
249             mLocationSettingsIgnored = locationSettingsIgnored;
250             return this;
251         }
252 
253         /**
254          * Builds a last location request from this builder.
255          *
256          * @return a new last location request
257          */
build()258         public @NonNull LastLocationRequest build() {
259             return new LastLocationRequest(
260                     mHiddenFromAppOps,
261                     mAdasGnssBypass,
262                     mLocationSettingsIgnored);
263         }
264     }
265 }
266