/* * Copyright (c) 2013 The MITRE Corporation, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this work 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.mitre.svmp.client; 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.os.Looper; import android.service.textservice.SpellCheckerService; import android.util.Log; import org.mitre.svmp.apprtc.AppRTCClient; import org.mitre.svmp.common.Utility; import org.mitre.svmp.protocol.SVMPProtocol.*; import org.mitre.svmp.services.SessionService; import java.util.HashMap; import java.util.Iterator; import java.util.List; /** * @author Joe Portner */ public class LocationHandler { private static final String TAG = LocationHandler.class.getName(); private SessionService service; private LocationManager lm; private Looper looper; // keeps track of what LocationListeners there are for a given LocationProvider private HashMap<String,SVMPLocationListener> locationListeners = new HashMap<String, SVMPLocationListener>(); public LocationHandler(SessionService service) { this.service = service; lm = (LocationManager) service.getSystemService(Context.LOCATION_SERVICE); looper = Looper.myLooper(); } public void removeLUpdates(String provider) { if( locationListeners.containsKey(provider) ) lm.removeUpdates(locationListeners.get(provider)); } public void initLocationUpdates() { sendLocationProviderMessages(); } public void cleanupLocationUpdates(){ // loop through location listeners and remove subscriptions for each one Iterator it = locationListeners.entrySet().iterator(); while (it.hasNext()) { HashMap.Entry pairs = (HashMap.Entry)it.next(); lm.removeUpdates((LocationListener)pairs.getValue()); it.remove(); // avoids a ConcurrentModificationException } } protected SVMPLocationListener getListenerSingle(String provider) { // generate a unique name for this key (each single subscription is disposed after receiving one update) String uniqueName = provider + String.format("%.3f", System.currentTimeMillis() / 1000.0); // add a listener for this key locationListeners.put( uniqueName, new SVMPLocationListener(uniqueName, true) ); return locationListeners.get(uniqueName); } protected SVMPLocationListener getListenerLongTerm(String provider) { // if the HashMap doesn't contain a listener for this key, add one if( !locationListeners.containsKey(provider) ) locationListeners.put( provider, new SVMPLocationListener(provider, false) ); return locationListeners.get(provider); } // called when a LocationListener triggers, converts the data and sends it to the VM public void onLocationChanged(Location location) { Request request = Utility.toRequest_LocationUpdate(location); // send the Request to the VM service.sendMessage(request); } // called when a onProviderEnabled or onProviderDisabled triggers, converts the data and sends it to the VM public void onProviderEnabled(String s, boolean isEnabled) { Request request = Utility.toRequest_LocationProviderEnabled(s, isEnabled); // send the Request to the VM service.sendMessage(request); } // called when a onStatusChanged triggers, converts the data and sends it to the VM public void onStatusChanged(String s, int i, Bundle bundle) { Request request = Utility.toRequest_LocationProviderStatus(s, i, bundle); // send the Request to the VM service.sendMessage(request); } private void sendLocationProviderMessages() { // loop through all location providers List<String> providerNames = lm.getAllProviders(); for(String providerName : providerNames){ // skip the Passive provider if( !providerName.equals(LocationManager.PASSIVE_PROVIDER) ) { //get the provider information and package it into a Request LocationProvider provider = lm.getProvider(providerName); Request request = Utility.toRequest_LocationProviderInfo(provider); // send the Request to the VM service.sendMessage(request); } } } public void handleLocationResponse(Response response) { LocationResponse locationResponse = response.getLocationResponse(); // a response can either be to subscribe or to unsubscribe if( locationResponse.getType() == LocationResponse.LocationResponseType.SUBSCRIBE ) { LocationSubscribe locationSubscribe = locationResponse.getSubscribe(); String provider = locationSubscribe.getProvider(); // a subscribe request can either be one-time or long-term if( locationSubscribe.getType() == LocationSubscribe.LocationSubscribeType.SINGLE_UPDATE ) { LocationListener locationListener = getListenerSingle(provider); lm.requestSingleUpdate( provider, locationListener, looper ); } else if( locationSubscribe.getType() == LocationSubscribe.LocationSubscribeType.MULTIPLE_UPDATES ) { LocationListener locationListener = getListenerLongTerm(provider); lm.requestLocationUpdates( provider, locationSubscribe.getMinTime(), locationSubscribe.getMinDistance(), locationListener, looper ); } } else if( locationResponse.getType() == LocationResponse.LocationResponseType.UNSUBSCRIBE ) { LocationUnsubscribe locationUnsubscribe = locationResponse.getUnsubscribe(); // unsubscribe from location updates for this provider // (we only get unsubscribe requests for long-term subscriptions) String provider = locationUnsubscribe.getProvider(); removeLUpdates(provider); } } class SVMPLocationListener implements LocationListener { private String key; private boolean singleShot; public SVMPLocationListener(String key, boolean singleShot) { this.key = key; this.singleShot = singleShot; } @Override public void onLocationChanged(Location location) { Log.d(TAG, "onLocationChanged: Provider(" + location.getProvider() + "), singleShot(" + singleShot + "), " + location.toString()); LocationHandler.this.onLocationChanged(location); // if this is a singleshot update, we don't need this listener anymore; remove it if( singleShot ) { lm.removeUpdates(this); locationListeners.remove(key); } } @Override public void onStatusChanged(String s, int i, Bundle bundle) { Log.d(TAG, "onStatusChanged: Provider(" + s + ") Status(" + i + ")"); LocationHandler.this.onStatusChanged(s, i, bundle); } @Override public void onProviderEnabled(String s) { Log.d(TAG, "onProviderEnabled: Provider(" + s + ")"); LocationHandler.this.onProviderEnabled(s, true); } @Override public void onProviderDisabled(String s) { Log.d(TAG, "onProviderDisabled: Provider(" + s + ")"); LocationHandler.this.onProviderEnabled(s, false); } } }