Loading location/java/android/location/ILocationManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ interface ILocationManager boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName); void flushGnssBatch(String packageName); boolean stopGnssBatch(); boolean injectLocation(in Location location); // --- deprecated --- List<String> getAllProviders(); Loading location/java/android/location/LocationManager.java +29 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import java.util.List; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.LOCATION_HARDWARE; /** * This class provides access to the system location services. These Loading Loading @@ -882,6 +883,34 @@ public class LocationManager { requestLocationUpdates(request, null, null, intent); } /** * Set the last known location with a new location. * * <p>A privileged client can inject a {@link Location} if it has a better estimate of what * the recent location is. This is especially useful when the device boots up and the GPS * chipset is in the process of getting the first fix. If the client has cached the location, * it can inject the {@link Location}, so if an app requests for a {@link Location} from {@link * #getLastKnownLocation(String)}, the location information is still useful before getting * the first fix.</p> * * <p> Useful in products like Auto. * * @param newLocation newly available {@link Location} object * @return true if update was successful, false if not * * @throws SecurityException if no suitable permission is present * * @hide */ @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION}) public boolean injectLocation(Location newLocation) { try { return mService.injectLocation(newLocation); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private ListenerTransport wrapListener(LocationListener listener, Looper looper) { if (listener == null) return null; synchronized (mListeners) { Loading services/core/java/com/android/server/LocationManagerService.java +87 −17 Original line number Diff line number Diff line Loading @@ -2254,6 +2254,64 @@ public class LocationManagerService extends ILocationManager.Stub { } } /** * Provides an interface to inject and set the last location if location is not available * currently. * * This helps in cases where the product (Cars for example) has saved the last known location * before powering off. This interface lets the client inject the saved location while the GPS * chipset is getting its first fix, there by improving user experience. * * @param location - Location object to inject * @return true if update was successful, false if not */ @Override public boolean injectLocation(Location location) { mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to inject location"); mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, "Access Fine Location permission not granted to inject Location"); if (location == null) { if (D) { Log.d(TAG, "injectLocation(): called with null location"); } return false; } LocationProviderInterface p = null; String provider = location.getProvider(); if (provider != null) { p = mProvidersByName.get(provider); } if (p == null) { if (D) { Log.d(TAG, "injectLocation(): unknown provider"); } return false; } synchronized (mLock) { if (!isAllowedByCurrentUserSettingsLocked(provider)) { if (D) { Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId); } return false; } else { // NOTE: If last location is already available, location is not injected. If // provider's normal source (like a GPS chipset) have already provided an output, // there is no need to inject this location. if (mLastLocation.get(provider) == null) { updateLastLocationLocked(location, provider); } else { if (D) { Log.d(TAG, "injectLocation(): Location exists. Not updating"); } return false; } } } return true; } @Override public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, String packageName) { Loading Loading @@ -2614,30 +2672,18 @@ public class LocationManagerService extends ILocationManager.Stub { private void handleLocationChangedLocked(Location location, boolean passive) { if (D) Log.d(TAG, "incoming location: " + location); long now = SystemClock.elapsedRealtime(); String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); // Skip if the provider is unknown. LocationProviderInterface p = mProvidersByName.get(provider); if (p == null) return; // Update last known locations Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); Location lastNoGPSLocation; updateLastLocationLocked(location, provider); // mLastLocation should have been updated from the updateLastLocationLocked call above. Location lastLocation = mLastLocation.get(provider); if (lastLocation == null) { lastLocation = new Location(provider); mLastLocation.put(provider, lastLocation); } else { lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); if (noGPSLocation == null && lastNoGPSLocation != null) { // New location has no no-GPS location: adopt last no-GPS location. This is set // directly into location because we do not want to notify COARSE clients. location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); } Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed"); return; } lastLocation.set(location); // Update last known coarse interval location if enough time has passed. Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider); Loading @@ -2653,7 +2699,7 @@ public class LocationManagerService extends ILocationManager.Stub { // Don't ever return a coarse location that is more recent than the allowed update // interval (i.e. don't allow an app to keep registering and unregistering for // location updates to overcome the minimum interval). noGPSLocation = Location noGPSLocation = lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); // Skip if there are no UpdateRecords for this provider. Loading Loading @@ -2778,6 +2824,30 @@ public class LocationManagerService extends ILocationManager.Stub { } } /** * Updates last location with the given location * * @param location new location to update * @param provider Location provider to update for */ private void updateLastLocationLocked(Location location, String provider) { Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); Location lastNoGPSLocation; Location lastLocation = mLastLocation.get(provider); if (lastLocation == null) { lastLocation = new Location(provider); mLastLocation.put(provider, lastLocation); } else { lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); if (noGPSLocation == null && lastNoGPSLocation != null) { // New location has no no-GPS location: adopt last no-GPS location. This is set // directly into location because we do not want to notify COARSE clients. location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); } } lastLocation.set(location); } private class LocationWorkerHandler extends Handler { public LocationWorkerHandler(Looper looper) { super(looper, null, true); Loading Loading
location/java/android/location/ILocationManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ interface ILocationManager boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName); void flushGnssBatch(String packageName); boolean stopGnssBatch(); boolean injectLocation(in Location location); // --- deprecated --- List<String> getAllProviders(); Loading
location/java/android/location/LocationManager.java +29 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import java.util.List; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.LOCATION_HARDWARE; /** * This class provides access to the system location services. These Loading Loading @@ -882,6 +883,34 @@ public class LocationManager { requestLocationUpdates(request, null, null, intent); } /** * Set the last known location with a new location. * * <p>A privileged client can inject a {@link Location} if it has a better estimate of what * the recent location is. This is especially useful when the device boots up and the GPS * chipset is in the process of getting the first fix. If the client has cached the location, * it can inject the {@link Location}, so if an app requests for a {@link Location} from {@link * #getLastKnownLocation(String)}, the location information is still useful before getting * the first fix.</p> * * <p> Useful in products like Auto. * * @param newLocation newly available {@link Location} object * @return true if update was successful, false if not * * @throws SecurityException if no suitable permission is present * * @hide */ @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION}) public boolean injectLocation(Location newLocation) { try { return mService.injectLocation(newLocation); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private ListenerTransport wrapListener(LocationListener listener, Looper looper) { if (listener == null) return null; synchronized (mListeners) { Loading
services/core/java/com/android/server/LocationManagerService.java +87 −17 Original line number Diff line number Diff line Loading @@ -2254,6 +2254,64 @@ public class LocationManagerService extends ILocationManager.Stub { } } /** * Provides an interface to inject and set the last location if location is not available * currently. * * This helps in cases where the product (Cars for example) has saved the last known location * before powering off. This interface lets the client inject the saved location while the GPS * chipset is getting its first fix, there by improving user experience. * * @param location - Location object to inject * @return true if update was successful, false if not */ @Override public boolean injectLocation(Location location) { mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to inject location"); mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, "Access Fine Location permission not granted to inject Location"); if (location == null) { if (D) { Log.d(TAG, "injectLocation(): called with null location"); } return false; } LocationProviderInterface p = null; String provider = location.getProvider(); if (provider != null) { p = mProvidersByName.get(provider); } if (p == null) { if (D) { Log.d(TAG, "injectLocation(): unknown provider"); } return false; } synchronized (mLock) { if (!isAllowedByCurrentUserSettingsLocked(provider)) { if (D) { Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId); } return false; } else { // NOTE: If last location is already available, location is not injected. If // provider's normal source (like a GPS chipset) have already provided an output, // there is no need to inject this location. if (mLastLocation.get(provider) == null) { updateLastLocationLocked(location, provider); } else { if (D) { Log.d(TAG, "injectLocation(): Location exists. Not updating"); } return false; } } } return true; } @Override public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, String packageName) { Loading Loading @@ -2614,30 +2672,18 @@ public class LocationManagerService extends ILocationManager.Stub { private void handleLocationChangedLocked(Location location, boolean passive) { if (D) Log.d(TAG, "incoming location: " + location); long now = SystemClock.elapsedRealtime(); String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); // Skip if the provider is unknown. LocationProviderInterface p = mProvidersByName.get(provider); if (p == null) return; // Update last known locations Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); Location lastNoGPSLocation; updateLastLocationLocked(location, provider); // mLastLocation should have been updated from the updateLastLocationLocked call above. Location lastLocation = mLastLocation.get(provider); if (lastLocation == null) { lastLocation = new Location(provider); mLastLocation.put(provider, lastLocation); } else { lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); if (noGPSLocation == null && lastNoGPSLocation != null) { // New location has no no-GPS location: adopt last no-GPS location. This is set // directly into location because we do not want to notify COARSE clients. location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); } Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed"); return; } lastLocation.set(location); // Update last known coarse interval location if enough time has passed. Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider); Loading @@ -2653,7 +2699,7 @@ public class LocationManagerService extends ILocationManager.Stub { // Don't ever return a coarse location that is more recent than the allowed update // interval (i.e. don't allow an app to keep registering and unregistering for // location updates to overcome the minimum interval). noGPSLocation = Location noGPSLocation = lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); // Skip if there are no UpdateRecords for this provider. Loading Loading @@ -2778,6 +2824,30 @@ public class LocationManagerService extends ILocationManager.Stub { } } /** * Updates last location with the given location * * @param location new location to update * @param provider Location provider to update for */ private void updateLastLocationLocked(Location location, String provider) { Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); Location lastNoGPSLocation; Location lastLocation = mLastLocation.get(provider); if (lastLocation == null) { lastLocation = new Location(provider); mLastLocation.put(provider, lastLocation); } else { lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); if (noGPSLocation == null && lastNoGPSLocation != null) { // New location has no no-GPS location: adopt last no-GPS location. This is set // directly into location because we do not want to notify COARSE clients. location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation); } } lastLocation.set(location); } private class LocationWorkerHandler extends Handler { public LocationWorkerHandler(Looper looper) { super(looper, null, true); Loading