OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.device.geolocation; |
| 6 |
| 7 import android.content.Context; |
| 8 import android.location.Criteria; |
| 9 import android.location.Location; |
| 10 import android.location.LocationListener; |
| 11 import android.location.LocationManager; |
| 12 import android.os.Bundle; |
| 13 |
| 14 import org.chromium.base.Log; |
| 15 import org.chromium.base.ThreadUtils; |
| 16 |
| 17 import java.util.List; |
| 18 |
| 19 /** |
| 20 * This is a LocationProvider using Android APIs [1]. It is a separate class for
clarity |
| 21 * so that it can manage all processing completely on the UI thread. The contain
er class |
| 22 * ensures that the start/stop calls into this class are done on the UI thread. |
| 23 * |
| 24 * [1] https://developer.android.com/reference/android/location/package-summary.
html |
| 25 */ |
| 26 public class LocationProviderAndroid |
| 27 implements LocationListener, LocationProviderFactory.LocationProvider { |
| 28 private static final String TAG = "cr_LocationProvider"; |
| 29 |
| 30 private Context mContext; |
| 31 private LocationManager mLocationManager; |
| 32 private boolean mIsRunning; |
| 33 |
| 34 LocationProviderAndroid(Context context) { |
| 35 mContext = context; |
| 36 } |
| 37 |
| 38 @Override |
| 39 public void start(boolean enableHighAccuracy) { |
| 40 unregisterFromLocationUpdates(); |
| 41 registerForLocationUpdates(enableHighAccuracy); |
| 42 } |
| 43 |
| 44 @Override |
| 45 public void stop() { |
| 46 unregisterFromLocationUpdates(); |
| 47 } |
| 48 |
| 49 @Override |
| 50 public boolean isRunning() { |
| 51 return mIsRunning; |
| 52 } |
| 53 |
| 54 @Override |
| 55 public void onLocationChanged(Location location) { |
| 56 // Callbacks from the system location service are queued to this thread,
so it's |
| 57 // possible that we receive callbacks after unregistering. At this point
, the |
| 58 // native object will no longer exist. |
| 59 if (mIsRunning) { |
| 60 updateNewLocation(location); |
| 61 } |
| 62 } |
| 63 |
| 64 @Override |
| 65 public void onStatusChanged(String provider, int status, Bundle extras) {} |
| 66 |
| 67 @Override |
| 68 public void onProviderEnabled(String provider) {} |
| 69 |
| 70 @Override |
| 71 public void onProviderDisabled(String provider) {} |
| 72 |
| 73 private void ensureLocationManagerCreated() { |
| 74 if (mLocationManager != null) return; |
| 75 mLocationManager = (LocationManager) mContext.getSystemService(Context.L
OCATION_SERVICE); |
| 76 if (mLocationManager == null) { |
| 77 Log.e(TAG, "Could not get location manager."); |
| 78 } |
| 79 } |
| 80 |
| 81 /** |
| 82 * Registers this object with the location service. |
| 83 */ |
| 84 private void registerForLocationUpdates(boolean enableHighAccuracy) { |
| 85 ensureLocationManagerCreated(); |
| 86 if (usePassiveOneShotLocation()) return; |
| 87 |
| 88 assert !mIsRunning; |
| 89 mIsRunning = true; |
| 90 |
| 91 // We're running on the main thread. The C++ side is responsible to |
| 92 // bounce notifications to the Geolocation thread as they arrive in the
mainLooper. |
| 93 try { |
| 94 Criteria criteria = new Criteria(); |
| 95 if (enableHighAccuracy) criteria.setAccuracy(Criteria.ACCURACY_FINE)
; |
| 96 mLocationManager.requestLocationUpdates( |
| 97 0, 0, criteria, this, ThreadUtils.getUiThreadLooper()); |
| 98 } catch (SecurityException e) { |
| 99 Log.e(TAG, |
| 100 "Caught security exception while registering for location up
dates " |
| 101 + "from the system. The application does not have su
fficient " |
| 102 + "geolocation permissions."); |
| 103 unregisterFromLocationUpdates(); |
| 104 // Propagate an error to JavaScript, this can happen in case of WebV
iew |
| 105 // when the embedding app does not have sufficient permissions. |
| 106 LocationProviderAdapter.newErrorAvailable("application does not have
sufficient " |
| 107 + "geolocation permissions."); |
| 108 } catch (IllegalArgumentException e) { |
| 109 Log.e(TAG, "Caught IllegalArgumentException registering for location
updates."); |
| 110 unregisterFromLocationUpdates(); |
| 111 assert false; |
| 112 } |
| 113 } |
| 114 |
| 115 /** |
| 116 * Unregisters this object from the location service. |
| 117 */ |
| 118 private void unregisterFromLocationUpdates() { |
| 119 if (mIsRunning) { |
| 120 mIsRunning = false; |
| 121 mLocationManager.removeUpdates(this); |
| 122 } |
| 123 } |
| 124 |
| 125 private void updateNewLocation(Location location) { |
| 126 LocationProviderAdapter.newLocationAvailable(location.getLatitude(), |
| 127 location.getLongitude(), location.getTime() / 1000.0, location.h
asAltitude(), |
| 128 location.getAltitude(), location.hasAccuracy(), location.getAccu
racy(), |
| 129 location.hasBearing(), location.getBearing(), location.hasSpeed(
), |
| 130 location.getSpeed()); |
| 131 } |
| 132 |
| 133 private boolean usePassiveOneShotLocation() { |
| 134 if (!isOnlyPassiveLocationProviderEnabled()) return false; |
| 135 |
| 136 // Do not request a location update if the only available location provi
der is |
| 137 // the passive one. Make use of the last known location and call |
| 138 // onLocationChanged directly. |
| 139 final Location location = |
| 140 mLocationManager.getLastKnownLocation(LocationManager.PASSIVE_PR
OVIDER); |
| 141 if (location != null) { |
| 142 ThreadUtils.runOnUiThread(new Runnable() { |
| 143 @Override |
| 144 public void run() { |
| 145 updateNewLocation(location); |
| 146 } |
| 147 }); |
| 148 } |
| 149 return true; |
| 150 } |
| 151 |
| 152 /* |
| 153 * Checks if the passive location provider is the only provider available |
| 154 * in the system. |
| 155 */ |
| 156 private boolean isOnlyPassiveLocationProviderEnabled() { |
| 157 List<String> providers = mLocationManager.getProviders(true); |
| 158 return providers != null && providers.size() == 1 |
| 159 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER); |
| 160 } |
| 161 } |
OLD | NEW |