diff --git a/js/ui/cordova/plugins/org.apache.cordova.geolocation/src/android/CordovaLocationListener.java b/js/ui/cordova/plugins/org.apache.cordova.geolocation/src/android/CordovaLocationListener.java new file mode 100644 index 0000000..f0f70fe --- /dev/null +++ b/js/ui/cordova/plugins/org.apache.cordova.geolocation/src/android/CordovaLocationListener.java @@ -0,0 +1,251 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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 org.apache.cordova.geolocation; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import org.apache.cordova.CallbackContext; + +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.util.Log; + +public class CordovaLocationListener implements LocationListener { + public static int PERMISSION_DENIED = 1; + public static int POSITION_UNAVAILABLE = 2; + public static int TIMEOUT = 3; + + protected LocationManager locationManager; + private GeoBroker owner; + protected boolean running = false; + + public HashMap watches = new HashMap(); + private List callbacks = new ArrayList(); + + private Timer timer = null; + + private String TAG = "[Cordova Location Listener]"; + + public CordovaLocationListener(LocationManager manager, GeoBroker broker, String tag) { + this.locationManager = manager; + this.owner = broker; + this.TAG = tag; + } + + protected void fail(int code, String message) { + this.cancelTimer(); + for (CallbackContext callbackContext: this.callbacks) + { + this.owner.fail(code, message, callbackContext, false); + } + if(this.owner.isGlobalListener(this) && this.watches.size() == 0) + { + Log.d(TAG, "Stopping global listener"); + this.stop(); + } + this.callbacks.clear(); + + Iterator it = this.watches.values().iterator(); + while (it.hasNext()) { + this.owner.fail(code, message, it.next(), true); + } + } + + private void win(Location loc) { + this.cancelTimer(); + for (CallbackContext callbackContext: this.callbacks) + { + this.owner.win(loc, callbackContext, false); + } + if(this.owner.isGlobalListener(this) && this.watches.size() == 0) + { + Log.d(TAG, "Stopping global listener"); + this.stop(); + } + this.callbacks.clear(); + + Iterator it = this.watches.values().iterator(); + while (it.hasNext()) { + this.owner.win(loc, it.next(), true); + } + } + + /** + * Location Listener Methods + */ + + /** + * Called when the provider is disabled by the user. + * + * @param provider + */ + public void onProviderDisabled(String provider) { + Log.d(TAG, "Location provider '" + provider + "' disabled."); + this.fail(POSITION_UNAVAILABLE, "GPS provider disabled."); + } + + /** + * Called when the provider is enabled by the user. + * + * @param provider + */ + public void onProviderEnabled(String provider) { + Log.d(TAG, "Location provider "+ provider + " has been enabled"); + } + + /** + * Called when the provider status changes. This method is called when a + * provider is unable to fetch a location or if the provider has recently + * become available after a period of unavailability. + * + * @param provider + * @param status + * @param extras + */ + public void onStatusChanged(String provider, int status, Bundle extras) { + Log.d(TAG, "The status of the provider " + provider + " has changed"); + if (status == 0) { + Log.d(TAG, provider + " is OUT OF SERVICE"); + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Provider " + provider + " is out of service."); + } + else if (status == 1) { + Log.d(TAG, provider + " is TEMPORARILY_UNAVAILABLE"); + } + else { + Log.d(TAG, provider + " is AVAILABLE"); + } + } + + /** + * Called when the location has changed. + * + * @param location + */ + public void onLocationChanged(Location location) { + Log.d(TAG, "The location has been updated!"); + this.win(location); + } + + // PUBLIC + + public int size() { + return this.watches.size() + this.callbacks.size(); + } + + public void addWatch(String timerId, CallbackContext callbackContext) { + this.watches.put(timerId, callbackContext); + if (this.size() == 1) { + this.start(); + } + } + public void addCallback(CallbackContext callbackContext, int timeout) { + if(this.timer == null) { + this.timer = new Timer(); + } + this.timer.schedule(new LocationTimeoutTask(callbackContext, this), timeout); + this.callbacks.add(callbackContext); + if (this.size() == 1) { + this.start(); + } + } + public void clearWatch(String timerId) { + if (this.watches.containsKey(timerId)) { + this.watches.remove(timerId); + } + if (this.size() == 0) { + this.stop(); + } + } + + /** + * Destroy listener. + */ + public void destroy() { + this.stop(); + } + + // LOCAL + + /** + * Start requesting location updates. + * + * @param interval + */ + protected void start() { + if (!this.running) { + if (this.locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { + this.running = true; + this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 10, this); + } else { + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Network provider is not available."); + } + } + } + + /** + * Stop receiving location updates. + */ + private void stop() { + this.cancelTimer(); + if (this.running) { + this.locationManager.removeUpdates(this); + this.running = false; + } + } + + private void cancelTimer() { + if(this.timer != null) { + this.timer.cancel(); + this.timer.purge(); + this.timer = null; + } + } + + private class LocationTimeoutTask extends TimerTask { + + private CallbackContext callbackContext = null; + private CordovaLocationListener listener = null; + + public LocationTimeoutTask(CallbackContext callbackContext, CordovaLocationListener listener) { + this.callbackContext = callbackContext; + this.listener = listener; + } + + @Override + public void run() { + for (CallbackContext callbackContext: listener.callbacks) { + if(this.callbackContext == callbackContext) { + listener.callbacks.remove(callbackContext); + break; + } + } + + if(listener.size() == 0) { + listener.stop(); + } + } + } +}