summaryrefslogtreecommitdiffstats
path: root/core/java/android/webkit/GeolocationService.java
blob: 24306f407b90abce2976b8aa0d9083afcbbe724c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.webkit;

import android.app.ActivityThread;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewCore;


/**
 * Implements the Java side of GeolocationServiceAndroid.
 */
final class GeolocationService implements LocationListener {

    // Log tag
    private static final String TAG = "geolocationService";

    private long mNativeObject;
    private LocationManager mLocationManager;
    private boolean mIsGpsEnabled;
    private boolean mIsRunning;
    private boolean mIsNetworkProviderAvailable;
    private boolean mIsGpsProviderAvailable;

    /**
     * Constructor
     * @param nativeObject The native object to which this object will report position updates and
     *     errors.
     */
    public GeolocationService(long nativeObject) {
        mNativeObject = nativeObject;
        // Register newLocationAvailable with platform service.
        ActivityThread thread = ActivityThread.systemMain();
        Context context = thread.getApplication();
        mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        if (mLocationManager == null) {
            Log.e(TAG, "Could not get location manager.");
        }
     }

    /**
     * Start listening for location updates.
     */
    public void start() {
        registerForLocationUpdates();
        mIsRunning = true;
    }

    /**
     * Stop listening for location updates.
     */
    public void stop() {
        unregisterFromLocationUpdates();
        mIsRunning = false;
    }

    /**
     * Sets whether to use the GPS.
     * @param enable Whether to use the GPS.
     */
    public void setEnableGps(boolean enable) {
        if (mIsGpsEnabled != enable) {
            mIsGpsEnabled = enable;
            if (mIsRunning) {
                // There's no way to unregister from a single provider, so we can
                // only unregister from all, then reregister with all but the GPS.
                unregisterFromLocationUpdates();
                registerForLocationUpdates();
            }
        }
    }

    /**
     * LocationListener implementation.
     * Called when the location has changed.
     * @param location The new location, as a Location object.
     */
    public void onLocationChanged(Location location) {
        // Callbacks from the system location sevice are queued to this thread, so it's possible
        // that we receive callbacks after unregistering. At this point, the native object will no
        // longer exist.
        if (mIsRunning) {
            nativeNewLocationAvailable(mNativeObject, location);
        }
    }

    /**
     * LocationListener implementation.
     * Called when the provider status changes.
     * @param provider The name of the provider.
     * @param status The new status of the provider.
     * @param extras an optional Bundle with provider specific data.
     */
    public void onStatusChanged(String providerName, int status, Bundle extras) {
        boolean isAvailable = (status == LocationProvider.AVAILABLE);
        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
            mIsNetworkProviderAvailable = isAvailable;
        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
            mIsGpsProviderAvailable = isAvailable;
        }
        maybeReportError("The last location provider is no longer available");
    }

    /**
     * LocationListener implementation.
     * Called when the provider is enabled.
     * @param provider The name of the location provider that is now enabled.
     */
    public void onProviderEnabled(String providerName) {
        // No need to notify the native side. It's enough to start sending
        // valid position fixes again.
        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
            mIsNetworkProviderAvailable = true;
        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
            mIsGpsProviderAvailable = true;
        }
    }

    /**
     * LocationListener implementation.
     * Called when the provider is disabled.
     * @param provider The name of the location provider that is now disabled.
     */
    public void onProviderDisabled(String providerName) {
        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
            mIsNetworkProviderAvailable = false;
        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
            mIsGpsProviderAvailable = false;
        }
        maybeReportError("The last location provider was disabled");
    }

    /**
     * Registers this object with the location service.
     */
    private void registerForLocationUpdates() {
        try {
            mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
            mIsNetworkProviderAvailable = true;
            if (mIsGpsEnabled) {
                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
                mIsGpsProviderAvailable = true;
            }
        } catch(SecurityException e) {
            Log.e(TAG, "Caught security exception registering for location updates from system. " +
                "This should only happen in DumpRenderTree.");
        }
    }

    /**
     * Unregisters this object from the location service.
     */
    private void unregisterFromLocationUpdates() {
        mLocationManager.removeUpdates(this);
    }

    /**
     * Reports an error if neither the network nor the GPS provider is available.
     */
    private void maybeReportError(String message) {
        // Callbacks from the system location sevice are queued to this thread, so it's possible
        // that we receive callbacks after unregistering. At this point, the native object will no
        // longer exist.
        if (mIsRunning && !mIsNetworkProviderAvailable && !mIsGpsProviderAvailable) {
            nativeNewErrorAvailable(mNativeObject, message);
        }
    }

    // Native functions
    private static native void nativeNewLocationAvailable(long nativeObject, Location location);
    private static native void nativeNewErrorAvailable(long nativeObject, String message);
}