167e1eb686439afba13be3d6e02786ebb07b359daSteve Block/*
267e1eb686439afba13be3d6e02786ebb07b359daSteve Block * Copyright (C) 2009 The Android Open Source Project
367e1eb686439afba13be3d6e02786ebb07b359daSteve Block *
467e1eb686439afba13be3d6e02786ebb07b359daSteve Block * Licensed under the Apache License, Version 2.0 (the "License");
567e1eb686439afba13be3d6e02786ebb07b359daSteve Block * you may not use this file except in compliance with the License.
667e1eb686439afba13be3d6e02786ebb07b359daSteve Block * You may obtain a copy of the License at
767e1eb686439afba13be3d6e02786ebb07b359daSteve Block *
867e1eb686439afba13be3d6e02786ebb07b359daSteve Block *      http://www.apache.org/licenses/LICENSE-2.0
967e1eb686439afba13be3d6e02786ebb07b359daSteve Block *
1067e1eb686439afba13be3d6e02786ebb07b359daSteve Block * Unless required by applicable law or agreed to in writing, software
1167e1eb686439afba13be3d6e02786ebb07b359daSteve Block * distributed under the License is distributed on an "AS IS" BASIS,
1267e1eb686439afba13be3d6e02786ebb07b359daSteve Block * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1367e1eb686439afba13be3d6e02786ebb07b359daSteve Block * See the License for the specific language governing permissions and
1467e1eb686439afba13be3d6e02786ebb07b359daSteve Block * limitations under the License.
1567e1eb686439afba13be3d6e02786ebb07b359daSteve Block */
1667e1eb686439afba13be3d6e02786ebb07b359daSteve Block
1767e1eb686439afba13be3d6e02786ebb07b359daSteve Blockpackage android.webkit;
1867e1eb686439afba13be3d6e02786ebb07b359daSteve Block
1967e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.app.ActivityThread;
2067e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.content.Context;
2167e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.location.Location;
2267e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.location.LocationListener;
2367e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.location.LocationManager;
2467e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.location.LocationProvider;
2567e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.os.Bundle;
2667e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.util.Log;
2767e1eb686439afba13be3d6e02786ebb07b359daSteve Blockimport android.webkit.WebViewCore;
2867e1eb686439afba13be3d6e02786ebb07b359daSteve Block
2967e1eb686439afba13be3d6e02786ebb07b359daSteve Block
3067e1eb686439afba13be3d6e02786ebb07b359daSteve Block/**
3167e1eb686439afba13be3d6e02786ebb07b359daSteve Block * Implements the Java side of GeolocationServiceAndroid.
3267e1eb686439afba13be3d6e02786ebb07b359daSteve Block */
330691ad50ca6b7a2968a0b95e1e9bb7228dd47d65Grace Klobafinal class GeolocationService implements LocationListener {
3467e1eb686439afba13be3d6e02786ebb07b359daSteve Block
3567e1eb686439afba13be3d6e02786ebb07b359daSteve Block    // Log tag
3667e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private static final String TAG = "geolocationService";
3767e1eb686439afba13be3d6e02786ebb07b359daSteve Block
3867e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private long mNativeObject;
3967e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private LocationManager mLocationManager;
4067e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private boolean mIsGpsEnabled;
4167e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private boolean mIsRunning;
4267e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private boolean mIsNetworkProviderAvailable;
4367e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private boolean mIsGpsProviderAvailable;
4467e1eb686439afba13be3d6e02786ebb07b359daSteve Block
4567e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
4667e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Constructor
47074c08c4ebbba0875549496829ee7872dd153ee8Steve Block     * @param context The context from which we obtain the system service.
4867e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param nativeObject The native object to which this object will report position updates and
4967e1eb686439afba13be3d6e02786ebb07b359daSteve Block     *     errors.
5067e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
51074c08c4ebbba0875549496829ee7872dd153ee8Steve Block    public GeolocationService(Context context, long nativeObject) {
5267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        mNativeObject = nativeObject;
5367e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // Register newLocationAvailable with platform service.
5467e1eb686439afba13be3d6e02786ebb07b359daSteve Block        mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
5567e1eb686439afba13be3d6e02786ebb07b359daSteve Block        if (mLocationManager == null) {
5667e1eb686439afba13be3d6e02786ebb07b359daSteve Block            Log.e(TAG, "Could not get location manager.");
5767e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
5867e1eb686439afba13be3d6e02786ebb07b359daSteve Block     }
5967e1eb686439afba13be3d6e02786ebb07b359daSteve Block
6067e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
6167e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Start listening for location updates.
6267e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
633d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block    public boolean start() {
6467e1eb686439afba13be3d6e02786ebb07b359daSteve Block        registerForLocationUpdates();
6567e1eb686439afba13be3d6e02786ebb07b359daSteve Block        mIsRunning = true;
663d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block        return mIsNetworkProviderAvailable || mIsGpsProviderAvailable;
6767e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
6867e1eb686439afba13be3d6e02786ebb07b359daSteve Block
6967e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
7067e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Stop listening for location updates.
7167e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
7267e1eb686439afba13be3d6e02786ebb07b359daSteve Block    public void stop() {
7367e1eb686439afba13be3d6e02786ebb07b359daSteve Block        unregisterFromLocationUpdates();
7467e1eb686439afba13be3d6e02786ebb07b359daSteve Block        mIsRunning = false;
7567e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
7667e1eb686439afba13be3d6e02786ebb07b359daSteve Block
7767e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
7867e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Sets whether to use the GPS.
7967e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param enable Whether to use the GPS.
8067e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
8167e1eb686439afba13be3d6e02786ebb07b359daSteve Block    public void setEnableGps(boolean enable) {
8267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        if (mIsGpsEnabled != enable) {
8367e1eb686439afba13be3d6e02786ebb07b359daSteve Block            mIsGpsEnabled = enable;
8467e1eb686439afba13be3d6e02786ebb07b359daSteve Block            if (mIsRunning) {
8567e1eb686439afba13be3d6e02786ebb07b359daSteve Block                // There's no way to unregister from a single provider, so we can
8667e1eb686439afba13be3d6e02786ebb07b359daSteve Block                // only unregister from all, then reregister with all but the GPS.
8767e1eb686439afba13be3d6e02786ebb07b359daSteve Block                unregisterFromLocationUpdates();
8867e1eb686439afba13be3d6e02786ebb07b359daSteve Block                registerForLocationUpdates();
893d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                // Check that the providers are still available after we re-register.
903d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                maybeReportError("The last location provider is no longer available");
9167e1eb686439afba13be3d6e02786ebb07b359daSteve Block            }
9267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
9367e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
9467e1eb686439afba13be3d6e02786ebb07b359daSteve Block
9567e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
9667e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * LocationListener implementation.
9767e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Called when the location has changed.
9867e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param location The new location, as a Location object.
9967e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
10067e1eb686439afba13be3d6e02786ebb07b359daSteve Block    public void onLocationChanged(Location location) {
10167e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // Callbacks from the system location sevice are queued to this thread, so it's possible
10267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // that we receive callbacks after unregistering. At this point, the native object will no
10367e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // longer exist.
10467e1eb686439afba13be3d6e02786ebb07b359daSteve Block        if (mIsRunning) {
10567e1eb686439afba13be3d6e02786ebb07b359daSteve Block            nativeNewLocationAvailable(mNativeObject, location);
10667e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
10767e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
10867e1eb686439afba13be3d6e02786ebb07b359daSteve Block
10967e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
11067e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * LocationListener implementation.
11167e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Called when the provider status changes.
11267e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param provider The name of the provider.
11367e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param status The new status of the provider.
11467e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param extras an optional Bundle with provider specific data.
11567e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
11667e1eb686439afba13be3d6e02786ebb07b359daSteve Block    public void onStatusChanged(String providerName, int status, Bundle extras) {
11767e1eb686439afba13be3d6e02786ebb07b359daSteve Block        boolean isAvailable = (status == LocationProvider.AVAILABLE);
11867e1eb686439afba13be3d6e02786ebb07b359daSteve Block        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
11967e1eb686439afba13be3d6e02786ebb07b359daSteve Block            mIsNetworkProviderAvailable = isAvailable;
12067e1eb686439afba13be3d6e02786ebb07b359daSteve Block        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
12167e1eb686439afba13be3d6e02786ebb07b359daSteve Block            mIsGpsProviderAvailable = isAvailable;
12267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
12367e1eb686439afba13be3d6e02786ebb07b359daSteve Block        maybeReportError("The last location provider is no longer available");
12467e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
12567e1eb686439afba13be3d6e02786ebb07b359daSteve Block
12667e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
12767e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * LocationListener implementation.
12867e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Called when the provider is enabled.
12967e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param provider The name of the location provider that is now enabled.
13067e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
13167e1eb686439afba13be3d6e02786ebb07b359daSteve Block    public void onProviderEnabled(String providerName) {
13267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // No need to notify the native side. It's enough to start sending
13367e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // valid position fixes again.
13467e1eb686439afba13be3d6e02786ebb07b359daSteve Block        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
13567e1eb686439afba13be3d6e02786ebb07b359daSteve Block            mIsNetworkProviderAvailable = true;
13667e1eb686439afba13be3d6e02786ebb07b359daSteve Block        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
13767e1eb686439afba13be3d6e02786ebb07b359daSteve Block            mIsGpsProviderAvailable = true;
13867e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
13967e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
14067e1eb686439afba13be3d6e02786ebb07b359daSteve Block
14167e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
14267e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * LocationListener implementation.
14367e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Called when the provider is disabled.
14467e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * @param provider The name of the location provider that is now disabled.
14567e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
14667e1eb686439afba13be3d6e02786ebb07b359daSteve Block    public void onProviderDisabled(String providerName) {
14767e1eb686439afba13be3d6e02786ebb07b359daSteve Block        if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
14867e1eb686439afba13be3d6e02786ebb07b359daSteve Block            mIsNetworkProviderAvailable = false;
14967e1eb686439afba13be3d6e02786ebb07b359daSteve Block        } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
15067e1eb686439afba13be3d6e02786ebb07b359daSteve Block            mIsGpsProviderAvailable = false;
15167e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
15267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        maybeReportError("The last location provider was disabled");
15367e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
15467e1eb686439afba13be3d6e02786ebb07b359daSteve Block
15567e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
15667e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Registers this object with the location service.
15767e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
15867e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private void registerForLocationUpdates() {
1594afcd2e9d65f67a06e5afb4140b909885ebe2e1cSteve Block        try {
1603d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block            // Registration may fail if providers are not present on the device.
1613d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block            try {
1623d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
1633d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                mIsNetworkProviderAvailable = true;
1643d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block            } catch(IllegalArgumentException e) { }
1654afcd2e9d65f67a06e5afb4140b909885ebe2e1cSteve Block            if (mIsGpsEnabled) {
1663d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                try {
1673d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                    mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
1683d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                    mIsGpsProviderAvailable = true;
1693d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block                } catch(IllegalArgumentException e) { }
1704afcd2e9d65f67a06e5afb4140b909885ebe2e1cSteve Block            }
1714afcd2e9d65f67a06e5afb4140b909885ebe2e1cSteve Block        } catch(SecurityException e) {
1724afcd2e9d65f67a06e5afb4140b909885ebe2e1cSteve Block            Log.e(TAG, "Caught security exception registering for location updates from system. " +
1734afcd2e9d65f67a06e5afb4140b909885ebe2e1cSteve Block                "This should only happen in DumpRenderTree.");
17467e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
17567e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
17667e1eb686439afba13be3d6e02786ebb07b359daSteve Block
17767e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
17867e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Unregisters this object from the location service.
17967e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
18067e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private void unregisterFromLocationUpdates() {
18167e1eb686439afba13be3d6e02786ebb07b359daSteve Block        mLocationManager.removeUpdates(this);
1823d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block        mIsNetworkProviderAvailable = false;
1833d9e066ab3bbb184a9651d47ace5fe4c1626287fSteve Block        mIsGpsProviderAvailable = false;
18467e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
18567e1eb686439afba13be3d6e02786ebb07b359daSteve Block
18667e1eb686439afba13be3d6e02786ebb07b359daSteve Block    /**
18767e1eb686439afba13be3d6e02786ebb07b359daSteve Block     * Reports an error if neither the network nor the GPS provider is available.
18867e1eb686439afba13be3d6e02786ebb07b359daSteve Block     */
18967e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private void maybeReportError(String message) {
19067e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // Callbacks from the system location sevice are queued to this thread, so it's possible
19167e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // that we receive callbacks after unregistering. At this point, the native object will no
19267e1eb686439afba13be3d6e02786ebb07b359daSteve Block        // longer exist.
19367e1eb686439afba13be3d6e02786ebb07b359daSteve Block        if (mIsRunning && !mIsNetworkProviderAvailable && !mIsGpsProviderAvailable) {
19467e1eb686439afba13be3d6e02786ebb07b359daSteve Block            nativeNewErrorAvailable(mNativeObject, message);
19567e1eb686439afba13be3d6e02786ebb07b359daSteve Block        }
19667e1eb686439afba13be3d6e02786ebb07b359daSteve Block    }
19767e1eb686439afba13be3d6e02786ebb07b359daSteve Block
19867e1eb686439afba13be3d6e02786ebb07b359daSteve Block    // Native functions
19967e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private static native void nativeNewLocationAvailable(long nativeObject, Location location);
20067e1eb686439afba13be3d6e02786ebb07b359daSteve Block    private static native void nativeNewErrorAvailable(long nativeObject, String message);
20167e1eb686439afba13be3d6e02786ebb07b359daSteve Block}
202