/** * Created with IntelliJ IDEA. * User: gemengqin * Date: 10/2/13 * Time: 2:46 PM * To change this template use File | Settings | File Templates. */ package com.onemore.karungguniapp.LBS; import android.location.*; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; public class LocationHelper { public static final int MESSAGE_CODE_LOCATION_FOUND = 1; public static final int MESSAGE_CODE_LOCATION_NULL = 2; public static final int MESSAGE_CODE_PROVIDER_NOT_PRESENT = 3; private static final int FIX_RECENT_BUFFER_TIME = 30000; private LocationManager locationMgr; private LocationListener locationListener; private Handler handler; private Runnable handlerCallback; private String providerName; private String logTag; /** * Construct with a LocationManager, and a Handler to pass back Messages via. * * @param locationMgr * @param handler */ public LocationHelper(LocationManager locationMgr, Handler handler, String logTag) { this.locationMgr = locationMgr; this.locationListener = new LocationListenerImpl(); this.handler = handler; this.handlerCallback = new Thread() { public void run() { endListenForLocation(null); } }; Criteria criteria = new Criteria(); // use Criteria to get provider (and could use COARSE, but doesn't work in emulator) // (FINE will use EITHER network/gps, whichever is the best enabled match, except in emulator must be gps) // (NOTE: network won't work unless enabled - Settings->Location & Security Settings->Use wireless networks) criteria.setAccuracy(Criteria.ACCURACY_FINE); this.providerName = locationMgr.getBestProvider(criteria, true); this.logTag = logTag; } /** * Invoke the process of getting the current Location. * Expect Messages to be returned via the Handler passed in at construction with results. * * @param durationSeconds amount of time to poll for location updates */ public void getCurrentLocation(int durationSeconds) { if (this.providerName == null) { // return 2/0/0 if provider is not enabled Log.d(logTag, "Location provideName null, provider is not enabled or not present."); sendLocationToHandler(MESSAGE_CODE_PROVIDER_NOT_PRESENT, 0, 0); return; } // first check last KNOWN location (and if the fix is recent enough, use it) // NOTE -- this does NOT WORK in the Emulator // (if you send a DDMS "manual" time or geo fix, you get correct DATE, // but fix time starts at 00:00 and seems to increment by 1 second each time sent) // to test this section (getLastLocation being recent enough), you need to use a real device Location lastKnown = locationMgr.getLastKnownLocation(providerName); if (lastKnown != null && lastKnown.getTime() >= (System.currentTimeMillis() - FIX_RECENT_BUFFER_TIME)) { Log.d(logTag, "Last known location recent, using it: " + lastKnown.toString()); // return lastKnown lat/long on Message via Handler sendLocationToHandler(MESSAGE_CODE_LOCATION_FOUND, (int) (lastKnown.getLatitude() * 1e6), (int) (lastKnown.getLongitude() * 1e6)); } else { // last known is relatively old, or doesn't exist, use a LocationListener // and wait for a location update for X seconds Log.d(logTag, "Last location NOT recent, setting up location listener to get newer update."); listenForLocation(providerName, durationSeconds); } } private void sendLocationToHandler(int msgId, int lat, int lon) { Message msg = Message.obtain(handler, msgId, lat, lon); handler.sendMessage(msg); } private void listenForLocation(String providerName, int durationSeconds) { locationMgr.requestLocationUpdates(providerName, 0, 0, locationListener); handler.postDelayed(handlerCallback, durationSeconds * 1000); } private void endListenForLocation(Location loc) { locationMgr.removeUpdates(locationListener); handler.removeCallbacks(handlerCallback); if (loc != null) { sendLocationToHandler(MESSAGE_CODE_LOCATION_FOUND, (int) (loc.getLatitude() * 1e6), (int) (loc.getLongitude() * 1e6)); } else { sendLocationToHandler(MESSAGE_CODE_LOCATION_NULL, 0, 0); } } private class LocationListenerImpl implements LocationListener { @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.d(logTag, "Location status changed to:" + status); switch (status) { case LocationProvider.AVAILABLE: break; case LocationProvider.TEMPORARILY_UNAVAILABLE: break; case LocationProvider.OUT_OF_SERVICE: endListenForLocation(null); } } @Override public void onLocationChanged(Location loc) { if (loc == null) { return; } Log.d(logTag, "Location changed to:" + loc.toString()); endListenForLocation(loc); } @Override public void onProviderDisabled(String provider) { endListenForLocation(null); } @Override public void onProviderEnabled(String provider) { } } }