1 /* 2 * Copyright (C) 2009 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.webkit; 18 19 import android.app.ActivityThread; 20 import android.content.Context; 21 import android.location.Location; 22 import android.location.LocationListener; 23 import android.location.LocationManager; 24 import android.location.LocationProvider; 25 import android.os.Bundle; 26 import android.util.Log; 27 import android.webkit.WebViewCore; 28 29 30 /** 31 * Implements the Java side of GeolocationServiceAndroid. 32 */ 33 final class GeolocationService implements LocationListener { 34 35 // Log tag 36 private static final String TAG = "geolocationService"; 37 38 private long mNativeObject; 39 private LocationManager mLocationManager; 40 private boolean mIsGpsEnabled; 41 private boolean mIsRunning; 42 private boolean mIsNetworkProviderAvailable; 43 private boolean mIsGpsProviderAvailable; 44 45 /** 46 * Constructor 47 * @param context The context from which we obtain the system service. 48 * @param nativeObject The native object to which this object will report position updates and 49 * errors. 50 */ GeolocationService(Context context, long nativeObject)51 public GeolocationService(Context context, long nativeObject) { 52 mNativeObject = nativeObject; 53 // Register newLocationAvailable with platform service. 54 mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 55 if (mLocationManager == null) { 56 Log.e(TAG, "Could not get location manager."); 57 } 58 } 59 60 /** 61 * Start listening for location updates. 62 */ start()63 public boolean start() { 64 registerForLocationUpdates(); 65 mIsRunning = true; 66 return mIsNetworkProviderAvailable || mIsGpsProviderAvailable; 67 } 68 69 /** 70 * Stop listening for location updates. 71 */ stop()72 public void stop() { 73 unregisterFromLocationUpdates(); 74 mIsRunning = false; 75 } 76 77 /** 78 * Sets whether to use the GPS. 79 * @param enable Whether to use the GPS. 80 */ setEnableGps(boolean enable)81 public void setEnableGps(boolean enable) { 82 if (mIsGpsEnabled != enable) { 83 mIsGpsEnabled = enable; 84 if (mIsRunning) { 85 // There's no way to unregister from a single provider, so we can 86 // only unregister from all, then reregister with all but the GPS. 87 unregisterFromLocationUpdates(); 88 registerForLocationUpdates(); 89 // Check that the providers are still available after we re-register. 90 maybeReportError("The last location provider is no longer available"); 91 } 92 } 93 } 94 95 /** 96 * LocationListener implementation. 97 * Called when the location has changed. 98 * @param location The new location, as a Location object. 99 */ onLocationChanged(Location location)100 public void onLocationChanged(Location location) { 101 // Callbacks from the system location sevice are queued to this thread, so it's possible 102 // that we receive callbacks after unregistering. At this point, the native object will no 103 // longer exist. 104 if (mIsRunning) { 105 nativeNewLocationAvailable(mNativeObject, location); 106 } 107 } 108 109 /** 110 * LocationListener implementation. 111 * Called when the provider status changes. 112 * @param provider The name of the provider. 113 * @param status The new status of the provider. 114 * @param extras an optional Bundle with provider specific data. 115 */ onStatusChanged(String providerName, int status, Bundle extras)116 public void onStatusChanged(String providerName, int status, Bundle extras) { 117 boolean isAvailable = (status == LocationProvider.AVAILABLE); 118 if (LocationManager.NETWORK_PROVIDER.equals(providerName)) { 119 mIsNetworkProviderAvailable = isAvailable; 120 } else if (LocationManager.GPS_PROVIDER.equals(providerName)) { 121 mIsGpsProviderAvailable = isAvailable; 122 } 123 maybeReportError("The last location provider is no longer available"); 124 } 125 126 /** 127 * LocationListener implementation. 128 * Called when the provider is enabled. 129 * @param provider The name of the location provider that is now enabled. 130 */ onProviderEnabled(String providerName)131 public void onProviderEnabled(String providerName) { 132 // No need to notify the native side. It's enough to start sending 133 // valid position fixes again. 134 if (LocationManager.NETWORK_PROVIDER.equals(providerName)) { 135 mIsNetworkProviderAvailable = true; 136 } else if (LocationManager.GPS_PROVIDER.equals(providerName)) { 137 mIsGpsProviderAvailable = true; 138 } 139 } 140 141 /** 142 * LocationListener implementation. 143 * Called when the provider is disabled. 144 * @param provider The name of the location provider that is now disabled. 145 */ onProviderDisabled(String providerName)146 public void onProviderDisabled(String providerName) { 147 if (LocationManager.NETWORK_PROVIDER.equals(providerName)) { 148 mIsNetworkProviderAvailable = false; 149 } else if (LocationManager.GPS_PROVIDER.equals(providerName)) { 150 mIsGpsProviderAvailable = false; 151 } 152 maybeReportError("The last location provider was disabled"); 153 } 154 155 /** 156 * Registers this object with the location service. 157 */ registerForLocationUpdates()158 private void registerForLocationUpdates() { 159 try { 160 // Registration may fail if providers are not present on the device. 161 try { 162 mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); 163 mIsNetworkProviderAvailable = true; 164 } catch(IllegalArgumentException e) { } 165 if (mIsGpsEnabled) { 166 try { 167 mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); 168 mIsGpsProviderAvailable = true; 169 } catch(IllegalArgumentException e) { } 170 } 171 } catch(SecurityException e) { 172 Log.e(TAG, "Caught security exception registering for location updates from system. " + 173 "This should only happen in DumpRenderTree."); 174 } 175 } 176 177 /** 178 * Unregisters this object from the location service. 179 */ unregisterFromLocationUpdates()180 private void unregisterFromLocationUpdates() { 181 mLocationManager.removeUpdates(this); 182 mIsNetworkProviderAvailable = false; 183 mIsGpsProviderAvailable = false; 184 } 185 186 /** 187 * Reports an error if neither the network nor the GPS provider is available. 188 */ maybeReportError(String message)189 private void maybeReportError(String message) { 190 // Callbacks from the system location sevice are queued to this thread, so it's possible 191 // that we receive callbacks after unregistering. At this point, the native object will no 192 // longer exist. 193 if (mIsRunning && !mIsNetworkProviderAvailable && !mIsGpsProviderAvailable) { 194 nativeNewErrorAvailable(mNativeObject, message); 195 } 196 } 197 198 // Native functions nativeNewLocationAvailable(long nativeObject, Location location)199 private static native void nativeNewLocationAvailable(long nativeObject, Location location); nativeNewErrorAvailable(long nativeObject, String message)200 private static native void nativeNewErrorAvailable(long nativeObject, String message); 201 } 202