1 /* 2 * Copyright (C) 2010 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 com.android.location.provider; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Context; 22 import android.location.ILocationManager; 23 import android.location.Location; 24 import android.location.LocationManager; 25 import android.location.LocationProvider; 26 import android.location.provider.ILocationProvider; 27 import android.location.provider.ILocationProviderManager; 28 import android.location.provider.ProviderProperties; 29 import android.location.provider.ProviderRequest; 30 import android.os.Build.VERSION_CODES; 31 import android.os.Bundle; 32 import android.os.IBinder; 33 import android.os.RemoteException; 34 import android.os.ServiceManager; 35 import android.os.WorkSource; 36 import android.util.Log; 37 38 import androidx.annotation.RequiresApi; 39 40 import java.io.FileDescriptor; 41 import java.io.PrintWriter; 42 import java.util.ArrayList; 43 import java.util.List; 44 45 /** 46 * Base class for location providers implemented as unbundled services. 47 * 48 * <p>The network location provider must export a service with action 49 * "com.android.location.service.v2.NetworkLocationProvider" 50 * and a valid minor version in a meta-data field on the service, and 51 * then return the result of {@link #getBinder()} on service binding. 52 * 53 * <p>The fused location provider must export a service with action 54 * "com.android.location.service.FusedLocationProvider" 55 * and a valid minor version in a meta-data field on the service, and 56 * then return the result of {@link #getBinder()} on service binding. 57 * 58 * <p>IMPORTANT: This class is effectively a public API for unbundled 59 * applications, and must remain API stable. See README.txt in the root 60 * of this package for more information. 61 * 62 * @deprecated This class is not part of the standard API surface - use 63 * {@link android.location.provider.LocationProviderBase} instead. 64 */ 65 @Deprecated 66 public abstract class LocationProviderBase { 67 68 /** 69 * Callback to be invoked when a flush operation is complete and all flushed locations have been 70 * reported. 71 */ 72 protected interface OnFlushCompleteCallback { 73 74 /** 75 * Should be invoked once the flush is complete. 76 */ onFlushComplete()77 void onFlushComplete(); 78 } 79 80 /** 81 * Bundle key for a version of the location containing no GPS data. 82 * Allows location providers to flag locations as being safe to 83 * feed to LocationFudger. 84 * 85 * @deprecated Do not use from Android R onwards. 86 */ 87 @Deprecated 88 public static final String EXTRA_NO_GPS_LOCATION = Location.EXTRA_NO_GPS_LOCATION; 89 90 /** 91 * Name of the Fused location provider. 92 * 93 * <p>This provider combines inputs for all possible location sources 94 * to provide the best possible Location fix. 95 */ 96 public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER; 97 98 final String mTag; 99 @Nullable final String mAttributionTag; 100 final IBinder mBinder; 101 102 /** 103 * This field may be removed in the future, do not rely on it. 104 * 105 * @deprecated Do not use this field! Use LocationManager APIs instead. If you use this field 106 * you may be broken in the future. 107 * @hide 108 */ 109 @Deprecated 110 protected final ILocationManager mLocationManager; 111 112 // write locked on mBinder, read lock is optional depending on atomicity requirements 113 @Nullable volatile ILocationProviderManager mManager; 114 volatile ProviderProperties mProperties; 115 volatile boolean mAllowed; 116 117 /** 118 * @deprecated Prefer 119 * {@link #LocationProviderBase(Context, String, ProviderPropertiesUnbundled)}. 120 */ 121 @Deprecated LocationProviderBase(String tag, ProviderPropertiesUnbundled properties)122 public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) { 123 this(null, tag, properties); 124 } 125 126 /** 127 * This constructor associates the feature id of the given context with this location provider. 128 * The location service may afford special privileges to incoming calls identified as belonging 129 * to this location provider. 130 */ 131 @RequiresApi(VERSION_CODES.R) LocationProviderBase(Context context, String tag, ProviderPropertiesUnbundled properties)132 public LocationProviderBase(Context context, String tag, 133 ProviderPropertiesUnbundled properties) { 134 mTag = tag; 135 mAttributionTag = context != null ? context.getAttributionTag() : null; 136 mBinder = new Service(); 137 138 mLocationManager = ILocationManager.Stub.asInterface( 139 ServiceManager.getService(Context.LOCATION_SERVICE)); 140 141 mManager = null; 142 mProperties = properties.getProviderProperties(); 143 mAllowed = true; 144 } 145 getBinder()146 public IBinder getBinder() { 147 return mBinder; 148 } 149 150 /** 151 * @deprecated Use {@link #setAllowed(boolean)} instead. 152 */ 153 @Deprecated 154 @RequiresApi(VERSION_CODES.Q) setEnabled(boolean enabled)155 public void setEnabled(boolean enabled) { 156 setAllowed(enabled); 157 } 158 159 /** 160 * Sets whether this provider is currently allowed or not. Note that this is specific to the 161 * provider only, and is not related to global location settings. This is a hint to the Location 162 * Manager that this provider will generally be unable to fulfill incoming requests. This 163 * provider may still receive callbacks to onSetRequest while not allowed, and must decide 164 * whether to attempt to satisfy those requests or not. 165 * 166 * <p>Some guidelines: providers should set their own allowed/disallowed status based only on 167 * state "owned" by that provider. For instance, providers should not take into account the 168 * state of the location master setting when setting themselves allowed or disallowed, as this 169 * state is not owned by a particular provider. If a provider requires some additional user 170 * consent that is particular to the provider, this should be use to set the allowed/disallowed 171 * state. If the provider proxies to another provider, the child provider's allowed/disallowed 172 * state should be taken into account in the parent's allowed state. For most providers, it is 173 * expected that they will be always allowed. 174 */ 175 @RequiresApi(VERSION_CODES.R) setAllowed(boolean allowed)176 public void setAllowed(boolean allowed) { 177 synchronized (mBinder) { 178 if (mAllowed == allowed) { 179 return; 180 } 181 182 mAllowed = allowed; 183 } 184 185 ILocationProviderManager manager = mManager; 186 if (manager != null) { 187 try { 188 manager.onSetAllowed(mAllowed); 189 } catch (RemoteException e) { 190 throw e.rethrowFromSystemServer(); 191 } catch (RuntimeException e) { 192 Log.w(mTag, e); 193 } 194 } 195 } 196 197 /** 198 * Sets the provider properties that may be queried by clients. Generally speaking, providers 199 * should try to avoid changing their properties after construction. 200 */ 201 @RequiresApi(VERSION_CODES.Q) setProperties(ProviderPropertiesUnbundled properties)202 public void setProperties(ProviderPropertiesUnbundled properties) { 203 synchronized (mBinder) { 204 mProperties = properties.getProviderProperties(); 205 } 206 207 ILocationProviderManager manager = mManager; 208 if (manager != null) { 209 try { 210 manager.onSetProperties(mProperties); 211 } catch (RemoteException e) { 212 throw e.rethrowFromSystemServer(); 213 } catch (RuntimeException e) { 214 Log.w(mTag, e); 215 } 216 } 217 } 218 219 /** 220 * Sets a list of additional packages that should be considered as part of this location 221 * provider for the purposes of generating locations. This should generally only be used when 222 * another package may issue location requests on behalf of this package in the course of 223 * providing location. This will inform location services to treat the other packages as 224 * location providers as well. 225 * 226 * @deprecated On Android R and above this has no effect. 227 */ 228 @Deprecated 229 @RequiresApi(VERSION_CODES.Q) setAdditionalProviderPackages(List<String> packageNames)230 public void setAdditionalProviderPackages(List<String> packageNames) {} 231 232 /** 233 * @deprecated Use {@link #isAllowed()} instead. 234 */ 235 @Deprecated 236 @RequiresApi(VERSION_CODES.Q) isEnabled()237 public boolean isEnabled() { 238 return isAllowed(); 239 } 240 241 /** 242 * Returns true if this provider is allowed. Providers start as allowed on construction. 243 */ 244 @RequiresApi(VERSION_CODES.R) isAllowed()245 public boolean isAllowed() { 246 return mAllowed; 247 } 248 249 /** 250 * Reports a new location from this provider. 251 */ reportLocation(@onNull Location location)252 public void reportLocation(@NonNull Location location) { 253 ILocationProviderManager manager = mManager; 254 if (manager != null) { 255 try { 256 manager.onReportLocation(stripExtras(location)); 257 } catch (RemoteException e) { 258 throw e.rethrowFromSystemServer(); 259 } catch (RuntimeException e) { 260 Log.w(mTag, e); 261 } 262 } 263 } 264 265 /** 266 * Reports a new batch of locations from this provider. Locations must be ordered in the list 267 * from earliest first to latest last. 268 */ reportLocations(@onNull List<Location> locations)269 public void reportLocations(@NonNull List<Location> locations) { 270 ILocationProviderManager manager = mManager; 271 if (manager != null) { 272 try { 273 manager.onReportLocations(stripExtras(locations)); 274 } catch (RemoteException e) { 275 throw e.rethrowFromSystemServer(); 276 } catch (RuntimeException e) { 277 Log.w(mTag, e); 278 } 279 } 280 } 281 onInit()282 protected void onInit() { 283 // call once so that providers designed for APIs pre-Q are not broken 284 onEnable(); 285 } 286 287 /** 288 * @deprecated This callback will be invoked once when the provider is created to maintain 289 * backwards compatibility with providers not designed for Android Q and above. This method 290 * should only be implemented in location providers that need to support SDKs below Android Q. 291 * Even in this case, it is usually unnecessary to implement this callback with the correct 292 * design. This method may be removed in the future. 293 */ 294 @Deprecated onEnable()295 protected void onEnable() {} 296 297 /** 298 * @deprecated This callback will be never be invoked on Android Q and above. This method should 299 * only be implemented in location providers that need to support SDKs below Android Q. Even in 300 * this case, it is usually unnecessary to implement this callback with the correct design. This 301 * method may be removed in the future. 302 */ 303 @Deprecated onDisable()304 protected void onDisable() {} 305 306 /** 307 * Set the {@link ProviderRequest} requirements for this provider. Each call to this method 308 * overrides all previous requests. This method might trigger the provider to start returning 309 * locations, or to stop returning locations, depending on the parameters in the request. 310 */ onSetRequest(ProviderRequestUnbundled request, WorkSource source)311 protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source); 312 313 /** 314 * Requests a flush of any pending batched locations. The callback must always be invoked once 315 * per invocation, and should be invoked after {@link #reportLocation(Location)} or 316 * {@link #reportLocations(List)} has been invoked with any flushed locations. The callback may 317 * be invoked immediately if no locations are flushed. 318 */ onFlush(OnFlushCompleteCallback callback)319 protected void onFlush(OnFlushCompleteCallback callback) { 320 callback.onFlushComplete(); 321 } 322 323 /** 324 * @deprecated This callback will never be invoked on Android Q and above. This method may be 325 * removed in the future. Prefer to dump provider state via the containing service instead. 326 */ 327 @Deprecated onDump(FileDescriptor fd, PrintWriter pw, String[] args)328 protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {} 329 330 /** 331 * This method will no longer be invoked. 332 * 333 * @deprecated This callback will be never be invoked on Android Q and above. This method should 334 * only be implemented in location providers that need to support SDKs below Android Q. This 335 * method may be removed in the future. 336 */ 337 @Deprecated onGetStatus(Bundle extras)338 protected int onGetStatus(Bundle extras) { 339 return LocationProvider.AVAILABLE; 340 } 341 342 /** 343 * This method will no longer be invoked. 344 * 345 * @deprecated This callback will be never be invoked on Android Q and above. This method should 346 * only be implemented in location providers that need to support SDKs below Android Q. This 347 * method may be removed in the future. 348 */ 349 @Deprecated onGetStatusUpdateTime()350 protected long onGetStatusUpdateTime() { 351 return 0; 352 } 353 354 /** 355 * Implements location provider specific custom commands. The return value will be ignored on 356 * Android Q and above. 357 */ onSendExtraCommand(@ullable String command, @Nullable Bundle extras)358 protected boolean onSendExtraCommand(@Nullable String command, @Nullable Bundle extras) { 359 return false; 360 } 361 362 private final class Service extends ILocationProvider.Stub { 363 Service()364 Service() { 365 } 366 367 @Override setLocationProviderManager(ILocationProviderManager manager)368 public void setLocationProviderManager(ILocationProviderManager manager) { 369 synchronized (mBinder) { 370 try { 371 manager.onInitialize(mAllowed, mProperties, mAttributionTag); 372 } catch (RemoteException e) { 373 throw e.rethrowFromSystemServer(); 374 } catch (RuntimeException e) { 375 Log.w(mTag, e); 376 } 377 378 mManager = manager; 379 } 380 381 onInit(); 382 } 383 384 @Override setRequest(ProviderRequest request)385 public void setRequest(ProviderRequest request) { 386 onSetRequest(new ProviderRequestUnbundled(request), request.getWorkSource()); 387 } 388 389 @Override flush()390 public void flush() { 391 onFlush(this::onFlushComplete); 392 } 393 onFlushComplete()394 private void onFlushComplete() { 395 ILocationProviderManager manager = mManager; 396 if (manager != null) { 397 try { 398 manager.onFlushComplete(); 399 } catch (RemoteException e) { 400 throw e.rethrowFromSystemServer(); 401 } catch (RuntimeException e) { 402 Log.w(mTag, e); 403 } 404 } 405 } 406 407 @Override sendExtraCommand(String command, Bundle extras)408 public void sendExtraCommand(String command, Bundle extras) { 409 onSendExtraCommand(command, extras); 410 } 411 } 412 stripExtras(Location location)413 private static Location stripExtras(Location location) { 414 Bundle extras = location.getExtras(); 415 if (extras != null && (extras.containsKey(EXTRA_NO_GPS_LOCATION) 416 || extras.containsKey("indoorProbability") 417 || extras.containsKey("coarseLocation"))) { 418 location = new Location(location); 419 extras = location.getExtras(); 420 extras.remove(EXTRA_NO_GPS_LOCATION); 421 extras.remove("indoorProbability"); 422 extras.remove("coarseLocation"); 423 if (extras.isEmpty()) { 424 location.setExtras(null); 425 } 426 } 427 return location; 428 } 429 stripExtras(List<Location> locations)430 private static List<Location> stripExtras(List<Location> locations) { 431 List<Location> mapped = locations; 432 final int size = locations.size(); 433 int i = 0; 434 for (Location location : locations) { 435 Location newLocation = stripExtras(location); 436 if (mapped != locations) { 437 mapped.add(newLocation); 438 } else if (newLocation != location) { 439 mapped = new ArrayList<>(size); 440 int j = 0; 441 for (Location copiedLocation : locations) { 442 if (j >= i) { 443 break; 444 } 445 mapped.add(copiedLocation); 446 j++; 447 } 448 mapped.add(newLocation); 449 } 450 i++; 451 } 452 453 return mapped; 454 } 455 } 456