package com.blackice.control.service; import android.app.IntentService; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.location.Criteria; import android.location.Location; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; import android.util.Log; import com.blackice.control.R; import com.blackice.control.WeatherInfo; import com.blackice.control.util.Helpers; import com.blackice.control.util.WeatherPrefs; import com.blackice.control.xml.WeatherXmlParser; import org.w3c.dom.Document; import java.io.IOException; import java.lang.StringBuilder; public class WeatherService extends IntentService { Handler mMainThreadHandler = null; public static final String TAG = "WeatherService"; public static final String PREFS_NAME = "WeatherServicePreferences"; public static final String INTENT_WEATHER_REQUEST = "com.blackice.control.INTENT_WEATHER_REQUEST"; public static final String INTENT_WEATHER_UPDATE = "com.blackice.control.INTENT_WEATHER_UPDATE"; public static final String INTENT_EXTRA_ISMANUAL = "com.blackice.control.INTENT_EXTRA_ISMANUAL"; public static final String INTENT_EXTRA_TYPE = "com.blackice.control.INTENT_EXTRA_TYPE"; public static final String INTENT_EXTRA_NEWLOCATION = "com.blackice.control.INTENT_EXTRA_NEWLOCATION"; public static final String EXTRA_CITY = "city"; public static final String EXTRA_FORECAST_DATE = "forecast_date"; public static final String EXTRA_CONDITION = "condition"; public static final String EXTRA_LAST_UPDATE = "datestamp"; public static final String EXTRA_CONDITION_CODE = "condition_code"; public static final String EXTRA_TEMP = "temp"; public static final String EXTRA_HUMIDITY = "humidity"; public static final String EXTRA_WIND = "wind"; public static final String EXTRA_LOW = "todays_low"; public static final String EXTRA_HIGH = "todays_high"; private static final String URL_YAHOO_API_WEATHER = "http://weather.yahooapis.com/forecastrss?w=%s&u="; private HttpRetriever httpRetriever = null; public WeatherService() { super("WeatherService"); httpRetriever = new HttpRetriever(); mMainThreadHandler = new Handler(); } // Fix for a stupid AsyncTask bug // See http://code.google.com/p/android/issues/detail?id=20915 private void makeToast(final String msg) { mMainThreadHandler.post(new Runnable() { @Override public void run() { Helpers.msgShort(getApplicationContext(), msg); } }); } @Override protected void onHandleIntent(Intent intent) { WeatherInfo w = null; String extra = null; String action = intent.getAction(); String woeid = null; Context context = getApplicationContext(); if (Settings.System.getInt(getContentResolver(), Settings.System.USE_WEATHER, 0) == 0) { stopSelf(); return; } if (!Settings.Secure.isLocationProviderEnabled( getContentResolver(), LocationManager.NETWORK_PROVIDER) && !WeatherPrefs.getUseCustomLocation(getApplicationContext())) { stopSelf(); return; } if (action != null && action.equals(INTENT_WEATHER_REQUEST)) { // custom location boolean useCustomLoc = WeatherPrefs.getUseCustomLocation(getApplicationContext()); String customLoc = WeatherPrefs.getCustomLocation(getApplicationContext()); boolean manual = false; Bundle extras = intent.getExtras(); if (extras != null) { manual = extras.getBoolean(INTENT_EXTRA_ISMANUAL, false); } if (customLoc != null && useCustomLoc) { woeid = YahooPlaceFinder.GeoCode(getApplicationContext(), customLoc); // network location } else { // do not attempt to get a location without data boolean networkAvailable = Helpers.isNetworkAvailable(getApplicationContext()); if(networkAvailable) { final LocationManager locationManager = (LocationManager) this .getSystemService(Context.LOCATION_SERVICE); Criteria crit = new Criteria(); crit.setAccuracy(Criteria.ACCURACY_COARSE); String bestProvider = locationManager.getBestProvider(crit, true); if (!intent.hasExtra(INTENT_EXTRA_NEWLOCATION)) { intent.putExtra(INTENT_EXTRA_NEWLOCATION, true); PendingIntent pi = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); if (bestProvider != null) { locationManager.requestSingleUpdate(bestProvider, pi); } else { if (manual) { makeToast(context.getString(R.string.location_unavailable)); } } return; } Location loc = null; if (bestProvider != null) { loc = locationManager.getLastKnownLocation(bestProvider); } else { loc = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER); } try { woeid = YahooPlaceFinder.reverseGeoCode(getApplicationContext(), loc.getLatitude(), loc.getLongitude()); } catch (Exception e) { e.printStackTrace(); } } else { if (manual) { makeToast(context.getString(R.string.location_unavailable)); } stopSelf(); return; } } try { w = parseXml(getDocument(woeid)); if (w != null) { sendBroadcast(w); updateLatest(w); } } catch (Exception e) { Log.e(TAG, "ohnoes: " + e.getMessage()); } } stopSelf(); } private Document getDocument(String woeid) { try { boolean celcius = WeatherPrefs.getUseCelcius(getApplicationContext()); String urlWithDegreeUnit; if (celcius) { urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "c"; } else { urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "f"; } return httpRetriever.getDocumentFromURL(String.format(urlWithDegreeUnit, woeid)); } catch (IOException e) { Log.e(TAG, e.toString()); } return null; } private WeatherInfo parseXml(Document wDoc) { try { return new WeatherXmlParser(getApplicationContext()).parseWeatherResponse(wDoc); } catch (Exception e) { e.printStackTrace(); Log.w(TAG, "Couldn't connect to Yahoo to get weather data."); } return null; } private void sendBroadcast(WeatherInfo w) { Intent broadcast = new Intent(INTENT_WEATHER_UPDATE); w.timestamp = Helpers.getTimestamp(getApplicationContext()); try { broadcast.putExtra(EXTRA_CITY, w.city); broadcast.putExtra(EXTRA_CONDITION, w.condition); broadcast.putExtra(EXTRA_LAST_UPDATE, w.timestamp); broadcast.putExtra(EXTRA_CONDITION_CODE, w.condition_code); broadcast.putExtra(EXTRA_FORECAST_DATE, w.forecast_date); broadcast.putExtra(EXTRA_HUMIDITY, w.humidity); broadcast.putExtra(EXTRA_TEMP, w.temp); broadcast.putExtra(EXTRA_WIND, w.wind); broadcast.putExtra(EXTRA_LOW, w.low); broadcast.putExtra(EXTRA_HIGH, w.high); } catch (Exception e) { e.printStackTrace(); } getApplicationContext().sendBroadcast(broadcast); } private void updateLatest(WeatherInfo w) { SharedPreferences settings = getApplicationContext().getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putString("city", w.city); editor.putString("condition", w.condition); editor.putString("timestamp", w.timestamp); editor.putString("condition_code", w.condition_code); editor.putString("forecast_date", w.forecast_date); editor.putString("humidity", w.humidity); editor.putString("temp", w.temp); editor.putString("wind", w.wind); editor.putString("low", w.low); editor.putString("high", w.high); editor.commit(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } }