Home | History | Annotate | Download | only in webkit
      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      */
     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      */
     63     public boolean start() {
     64         registerForLocationUpdates();
     65         mIsRunning = true;
     66         return mIsNetworkProviderAvailable || mIsGpsProviderAvailable;
     67     }
     68 
     69     /**
     70      * Stop listening for location updates.
     71      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    199     private static native void nativeNewLocationAvailable(long nativeObject, Location location);
    200     private static native void nativeNewErrorAvailable(long nativeObject, String message);
    201 }
    202