1 /* 2 * Copyright (C) 2017 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 com.googlecode.android_scripting.facade; 18 19 import android.app.Service; 20 import android.content.Context; 21 import android.location.Address; 22 import android.location.Geocoder; 23 import android.location.Location; 24 import android.location.LocationListener; 25 import android.location.LocationManager; 26 import android.os.Bundle; 27 28 import com.google.common.collect.Maps; 29 import com.googlecode.android_scripting.jsonrpc.RpcReceiver; 30 import com.googlecode.android_scripting.rpc.Rpc; 31 import com.googlecode.android_scripting.rpc.RpcDefault; 32 import com.googlecode.android_scripting.rpc.RpcParameter; 33 import com.googlecode.android_scripting.rpc.RpcStartEvent; 34 import com.googlecode.android_scripting.rpc.RpcStopEvent; 35 36 import java.io.IOException; 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.Map.Entry; 41 42 /** 43 * This facade exposes the LocationManager related functionality.<br> 44 * <br> 45 * <b>Overview</b><br> 46 * Once activated by 'startLocating' the LocationFacade attempts to return location data collected 47 * via GPS or the cell network. If neither are available the last known location may be retrieved. 48 * If both are available the format of the returned data is:<br> 49 * {u'network': {u'altitude': 0, u'provider': u'network', u'longitude': -0.38509020000000002, 50 * u'time': 1297079691231L, u'latitude': 52.410557300000001, u'speed': 0, u'accuracy': 75}, u'gps': 51 * {u'altitude': 51, u'provider': u'gps', u'longitude': -0.38537094593048096, u'time': 52 * 1297079709000L, u'latitude': 52.41076922416687, u'speed': 0, u'accuracy': 24}}<br> 53 * If neither are available {} is returned. <br> 54 * Example (python):<br> 55 * 56 * <pre> 57 * import android, time 58 * droid = android.Android() 59 * droid.startLocating() 60 * time.sleep(15) 61 * loc = droid.readLocation().result 62 * if loc = {}: 63 * loc = getLastKnownLocation().result 64 * if loc != {}: 65 * try: 66 * n = loc['gps'] 67 * except KeyError: 68 * n = loc['network'] 69 * la = n['latitude'] 70 * lo = n['longitude'] 71 * address = droid.geocode(la, lo).result 72 * droid.stopLocating() 73 * </pre> 74 * 75 * The address format is:<br> 76 * [{u'thoroughfare': u'Some Street', u'locality': u'Some Town', u'sub_admin_area': u'Some Borough', 77 * u'admin_area': u'Some City', u'feature_name': u'House Numbers', u'country_code': u'GB', 78 * u'country_name': u'United Kingdom', u'postal_code': u'ST1 1'}] 79 * 80 */ 81 public class LocationFacade extends RpcReceiver { 82 private final EventFacade mEventFacade; 83 private final Service mService; 84 private final Map<String, Location> mLocationUpdates; 85 private final LocationManager mLocationManager; 86 private final Geocoder mGeocoder; 87 88 private final LocationListener mLocationListener = new LocationListener() { 89 @Override 90 public synchronized void onLocationChanged(Location location) { 91 mLocationUpdates.put(location.getProvider(), location); 92 Map<String, Location> copy = Maps.newHashMap(); 93 for (Entry<String, Location> entry : mLocationUpdates.entrySet()) { 94 copy.put(entry.getKey(), entry.getValue()); 95 } 96 mEventFacade.postEvent("location", copy); 97 } 98 99 @Override 100 public void onProviderDisabled(String provider) { 101 } 102 103 @Override 104 public void onProviderEnabled(String provider) { 105 } 106 107 @Override 108 public void onStatusChanged(String provider, int status, Bundle extras) { 109 } 110 }; 111 112 public LocationFacade(FacadeManager manager) { 113 super(manager); 114 mService = manager.getService(); 115 mEventFacade = manager.getReceiver(EventFacade.class); 116 mGeocoder = new Geocoder(mService); 117 mLocationManager = (LocationManager) mService.getSystemService(Context.LOCATION_SERVICE); 118 mLocationUpdates = new HashMap<String, Location>(); 119 } 120 121 @Override 122 public void shutdown() { 123 stopLocating(); 124 } 125 126 @Rpc(description = "Returns availables providers on the phone") 127 public List<String> locationProviders() { 128 return mLocationManager.getAllProviders(); 129 } 130 131 @Rpc(description = "Ask if provider is enabled") 132 public boolean locationProviderEnabled( 133 @RpcParameter(name = "provider", description = "Name of location provider") String provider) { 134 return mLocationManager.isProviderEnabled(provider); 135 } 136 137 @Rpc(description = "Starts collecting location data.") 138 @RpcStartEvent("location") 139 public void startLocating( 140 @RpcParameter(name = "minDistance", description = "minimum time between updates in milliseconds") @RpcDefault("60000") Integer minUpdateTime, 141 @RpcParameter(name = "minUpdateDistance", description = "minimum distance between updates in meters") @RpcDefault("30") Integer minUpdateDistance) { 142 for (String provider : mLocationManager.getAllProviders()) { 143 mLocationManager.requestLocationUpdates(provider, minUpdateTime, minUpdateDistance, 144 mLocationListener, mService.getMainLooper()); 145 } 146 } 147 148 @Rpc(description = "Returns the current location as indicated by all available providers.", returns = "A map of location information by provider.") 149 public Map<String, Location> readLocation() { 150 return mLocationUpdates; 151 } 152 153 @Rpc(description = "Stops collecting location data.") 154 @RpcStopEvent("location") 155 public synchronized void stopLocating() { 156 mLocationManager.removeUpdates(mLocationListener); 157 mLocationUpdates.clear(); 158 } 159 160 @Rpc(description = "Returns the last known location of the device.", returns = "A map of location information by provider.") 161 public Map<String, Location> getLastKnownLocation() { 162 Map<String, Location> location = new HashMap<String, Location>(); 163 for (String provider : mLocationManager.getAllProviders()) { 164 location.put(provider, mLocationManager.getLastKnownLocation(provider)); 165 } 166 return location; 167 } 168 169 @Rpc(description = "Returns a list of addresses for the given latitude and longitude.", returns = "A list of addresses.") 170 public List<Address> geocode( 171 @RpcParameter(name = "latitude") Double latitude, 172 @RpcParameter(name = "longitude") Double longitude, 173 @RpcParameter(name = "maxResults", description = "maximum number of results") @RpcDefault("1") Integer maxResults) 174 throws IOException { 175 return mGeocoder.getFromLocation(latitude, longitude, maxResults); 176 } 177 } 178