aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/cyanogenmod/lockclock/weather
diff options
context:
space:
mode:
authorDvTonder <david.vantonder@gmail.com>2013-01-08 16:25:09 -0500
committerDanny Baumann <dannybaumann@web.de>2013-01-18 09:27:54 +0100
commit1dc51e521b868dcda27fad1d93a041913b0efa38 (patch)
tree84a66c94e1f372990be3de05af2d831f0db2a3f9 /src/com/cyanogenmod/lockclock/weather
parentf9c9c2850954bca9023993bf22a1355a40779835 (diff)
downloadandroid_packages_apps_LockClock-1dc51e521b868dcda27fad1d93a041913b0efa38.tar.gz
android_packages_apps_LockClock-1dc51e521b868dcda27fad1d93a041913b0efa38.tar.bz2
android_packages_apps_LockClock-1dc51e521b868dcda27fad1d93a041913b0efa38.zip
Chronus: Optimize widget loading/display
Completely refactors the Calendar handling and changes the refresh interval from every minute to the minimum of either the next weather refresh or the next event start/end. It also now detects more events (new calendar entry, deleted calendar entry, location change, timezone change etc) Patch set 7 : Change the startup of the provider to only update the required panels on enabling the appwigdet and updates This further reduces the number of times the widget refreshes itself, now limited only to actual events Patch set 8 : Change the weather refresh time to be absolute, not relative to current time Patch set 9 : Refactor the calendar to use a CalendarInfo class that maintains a static list of events. This allows the refreshing of the lock screen widget without querying the calendar provider every time the screen turns on Patch set 10: Simplified onReceive loading/updating of widget with additional tweaks to handling deleted widgets and a fix to the refresh timer calculations including a check of the lookahead window. Patch set 11: Change the alarmservice to wake the CPU and do the update if the device is sleeping. This way, since the updates are so infrequent now, it makes sense to ensure things are updated (if needed) when the user turns the screen on after a while. Patch set 12: Change application ID to an ID registered for Chronus Patch set 13: Store the returned WOEID in sharedPreferences it if its valid and retrieve the previously stored one if not. This allows for the querying of weather data even though the Yahoo Placefinder service API limit has been exceeded and it returns an invalid XML result on geocode query. Patch set 14: Add a flag to determine when we want the real placefinder result or the cached result is also OK Patch set 15: Final comments and code formatting cleanup Patch set 16: Factor out weather fetching to separate service to decouple weather fetching from widget update. Also optimize a lot of code. Patch set 17: Fix alarms refresh and optimize calendar query and weather refresh behaviour. Patch set 18: Unify debug flags Change-Id: I0496dad356c92fb26ad7289268327b27b365b6cd
Diffstat (limited to 'src/com/cyanogenmod/lockclock/weather')
-rw-r--r--src/com/cyanogenmod/lockclock/weather/WeatherInfo.java261
-rw-r--r--src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java276
-rw-r--r--src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java113
-rw-r--r--src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java35
4 files changed, 533 insertions, 152 deletions
diff --git a/src/com/cyanogenmod/lockclock/weather/WeatherInfo.java b/src/com/cyanogenmod/lockclock/weather/WeatherInfo.java
index bb4a5fa..420900d 100644
--- a/src/com/cyanogenmod/lockclock/weather/WeatherInfo.java
+++ b/src/com/cyanogenmod/lockclock/weather/WeatherInfo.java
@@ -17,99 +17,208 @@
package com.cyanogenmod.lockclock.weather;
import android.content.Context;
+import android.content.res.Resources;
+
import com.cyanogenmod.lockclock.R;
+import com.cyanogenmod.lockclock.misc.Preferences;
+
+import java.text.DecimalFormat;
+import java.util.Date;
public class WeatherInfo {
+ private static final long serialVersionUID = 1L;
- public static final String NODATA = "-";
-
- public String city, forecast_date, condition, condition_code, temp, temp_unit,
- humidity, wind, wind_dir, speed_unit, low, high;
- public long last_sync;
-
- public WeatherInfo() {
- this.city = NODATA;
- this.forecast_date = NODATA;
- this.condition = NODATA;
- this.condition_code = NODATA;
- this.temp = NODATA;
- this.temp_unit = NODATA;
- this.humidity = NODATA;
- this.wind = NODATA;
- this.wind_dir = NODATA;
- this.speed_unit = NODATA;
- this.low = NODATA;
- this.high = NODATA;
- this.last_sync = 0;
- }
+ private static final DecimalFormat sNoDigitsFormat = new DecimalFormat("0");
- public WeatherInfo(Context context, String city, String fdate, String condition, String condition_code,
- String temp, String temp_unit, String humidity,
- String wind, String wind_dir, String speed_unit,
- String low, String high, long last_sync) {
+ private Context mContext;
+
+ private String city;
+ private String forecastDate;
+ private String condition;
+ private int conditionCode;
+ private float temperature;
+ private float lowTemperature;
+ private float highTemperature;
+ private String tempUnit;
+ private float humidity;
+ private float wind;
+ private int windDirection;
+ private String speedUnit;
+ private long timestamp;
+
+ public WeatherInfo(Context context,
+ String city, String fdate, String condition, int conditionCode,
+ float temp, float low, float high, String tempUnit, float humidity,
+ float wind, int windDir, String speedUnit, long timestamp) {
+ this.mContext = context;
this.city = city;
- this.forecast_date = fdate;
+ this.forecastDate = fdate;
this.condition = condition;
- this.condition_code = condition_code;
- this.humidity = humidity + "%";
- this.wind = calcDirection(context, wind_dir) + " " + trimSpeed(wind) + speed_unit;
- this.speed_unit = speed_unit;
- this.last_sync = last_sync;
- // Only the current temperature gets the temp_unit added.
- this.temp_unit = temp_unit;
- this.temp = temp + "°" + temp_unit;
- this.low = low + "°";
- this.high = high + "°";
+ this.conditionCode = conditionCode;
+ this.humidity = humidity;
+ this.wind = wind;
+ this.windDirection = windDir;
+ this.speedUnit = speedUnit;
+ this.timestamp = timestamp;
+ this.temperature = temp;
+ this.lowTemperature = low;
+ this.highTemperature = high;
+ this.tempUnit = tempUnit;
+ }
+
+ public int getConditionResource() {
+ boolean alternativeIcons = Preferences.useAlternateWeatherIcons(mContext);
+ final String prefix = alternativeIcons ? "weather2_" : "weather_";
+ final Resources res = mContext.getResources();
+ final int resId = res.getIdentifier(prefix + conditionCode, "drawable", mContext.getPackageName());
+
+ if (resId != 0) {
+ return resId;
+ }
+
+ return alternativeIcons ? R.drawable.weather2_na : R.drawable.weather_na;
}
- /**
- * find the optimal weather string (helper function for translation)
- *
- * @param conditionCode condition code from Yahoo (this is the main
- * identifier which will be used to find a matching translation
- * in the project's resources
- * @param providedString
- * @return either the defaultString (which should be Yahoo's weather
- * condition text), or the translated version from resources
- */
- public static String getTranslatedConditionString(Context context, int conditionCode,
- String providedString) {
- int resID = context.getResources().getIdentifier("weather_" + conditionCode, "string",
- context.getPackageName());
- return (resID != 0) ? context.getResources().getString(resID) : providedString;
+ public String getCity() {
+ return city;
}
- private String calcDirection(Context context, String degrees) {
- try {
- int deg = Integer.parseInt(degrees);
- if (deg >= 338 || deg <= 22)
- return context.getResources().getString(R.string.weather_N);
- else if (deg < 68)
- return context.getResources().getString(R.string.weather_NE);
- else if (deg < 113)
- return context.getResources().getString(R.string.weather_E);
- else if (deg < 158)
- return context.getResources().getString(R.string.weather_SE);
- else if (deg < 203)
- return context.getResources().getString(R.string.weather_S);
- else if (deg < 248)
- return context.getResources().getString(R.string.weather_SW);
- else if (deg < 293)
- return context.getResources().getString(R.string.weather_W);
- else if (deg < 338)
- return context.getResources().getString(R.string.weather_NW);
- else
- return "";
- } catch (NumberFormatException e) {
+ public String getCondition() {
+ final Resources res = mContext.getResources();
+ final int resId = res.getIdentifier("weather_" + conditionCode, "string", mContext.getPackageName());
+
+ if (resId != 0) {
+ return res.getString(resId);
+ }
+
+ return condition;
+ }
+
+ public Date getTimestamp() {
+ return new Date(timestamp);
+ }
+
+ private String getFormattedValue(float value, String unit) {
+ if (Float.isNaN(highTemperature)) {
+ return "-";
+ }
+ return sNoDigitsFormat.format(value) + unit;
+ }
+
+ public String getFormattedTemperature() {
+ return getFormattedValue(temperature, "°" + tempUnit);
+ }
+
+ public String getFormattedLow() {
+ return getFormattedValue(lowTemperature, "°");
+ }
+
+ public String getFormattedHigh() {
+ return getFormattedValue(highTemperature, "°");
+ }
+
+ public String getFormattedHumidity() {
+ return getFormattedValue(humidity, "%");
+ }
+
+ public String getFormattedWindSpeed() {
+ return getFormattedValue(wind, speedUnit);
+ }
+
+ public String getWindDirection() {
+ int resId;
+
+ if (windDirection < 0) {
return "";
}
+
+ if (windDirection < 23) resId = R.string.weather_N;
+ else if (windDirection < 68) resId = R.string.weather_NE;
+ else if (windDirection < 113) resId = R.string.weather_E;
+ else if (windDirection < 158) resId = R.string.weather_SE;
+ else if (windDirection < 203) resId = R.string.weather_S;
+ else if (windDirection < 248) resId = R.string.weather_SW;
+ else if (windDirection < 293) resId = R.string.weather_W;
+ else if (windDirection < 338) resId = R.string.weather_NW;
+ else resId = R.string.weather_N;
+
+ return mContext.getString(resId);
}
- private String trimSpeed(String speed) {
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("WeatherInfo for ");
+ builder.append(city);
+ builder.append("@ ");
+ builder.append(getTimestamp());
+ builder.append(": ");
+ builder.append(getCondition());
+ builder.append("(");
+ builder.append(conditionCode);
+ builder.append("), temperature ");
+ builder.append(getFormattedTemperature());
+ builder.append(", low ");
+ builder.append(getFormattedLow());
+ builder.append(", high ");
+ builder.append(getFormattedHigh());
+ builder.append(", humidity ");
+ builder.append(getFormattedHumidity());
+ builder.append(", wind ");
+ builder.append(getFormattedWindSpeed());
+ builder.append(" at ");
+ builder.append(getWindDirection());
+ return builder.toString();
+ }
+
+ public String toSerializedString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(city).append('|');
+ builder.append(forecastDate).append('|');
+ builder.append(condition).append('|');
+ builder.append(conditionCode).append('|');
+ builder.append(temperature).append('|');
+ builder.append(lowTemperature).append('|');
+ builder.append(highTemperature).append('|');
+ builder.append(tempUnit).append('|');
+ builder.append(humidity).append('|');
+ builder.append(wind).append('|');
+ builder.append(windDirection).append('|');
+ builder.append(speedUnit).append('|');
+ builder.append(timestamp);
+ return builder.toString();
+ }
+
+ public static WeatherInfo fromSerializedString(Context context, String input) {
+ if (input == null) {
+ return null;
+ }
+
+ String[] parts = input.split("\\|");
+ if (parts == null || parts.length != 13) {
+ return null;
+ }
+
+ int conditionCode, windDirection;
+ long timestamp;
+ float temperature, low, high, humidity, wind;
+
try {
- return String.valueOf(Math.round(Float.parseFloat(speed)));
+ conditionCode = Integer.parseInt(parts[3]);
+ temperature = Float.parseFloat(parts[4]);
+ low = Float.parseFloat(parts[5]);
+ high = Float.parseFloat(parts[6]);
+ humidity = Float.parseFloat(parts[8]);
+ wind = Float.parseFloat(parts[9]);
+ windDirection = Integer.parseInt(parts[10]);
+ timestamp = Long.parseLong(parts[12]);
} catch (NumberFormatException e) {
- return "";
+ return null;
}
+
+ return new WeatherInfo(context,
+ /* city */ parts[0], /* date */ parts[1], /* condition */ parts[2],
+ conditionCode, temperature, low, high, /* tempUnit */ parts[7],
+ humidity, wind, windDirection, /* speedUnit */ parts[11], timestamp);
}
}
diff --git a/src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java b/src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java
new file mode 100644
index 0000000..3e24dd7
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed 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 com.cyanogenmod.lockclock.weather;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.cyanogenmod.lockclock.ClockWidgetProvider;
+import com.cyanogenmod.lockclock.misc.Constants;
+import com.cyanogenmod.lockclock.misc.Preferences;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.w3c.dom.Document;
+
+public class WeatherUpdateService extends Service {
+ private static final String TAG = "WeatherUpdateService";
+ private static final boolean D = Constants.DEBUG;
+
+ private static final String URL_YAHOO_API_WEATHER = "http://weather.yahooapis.com/forecastrss?w=%s&u=";
+
+ public static final String ACTION_FORCE_UPDATE = "com.cyanogenmod.lockclock.action.FORCE_WEATHER_UPDATE";
+
+ private WeatherUpdateTask mTask;
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (D) Log.v(TAG, "Got intent " + intent);
+
+ if (mTask != null && mTask.getStatus() != AsyncTask.Status.FINISHED) {
+ if (D) Log.v(TAG, "Weather update is still active, not starting new update");
+ return START_REDELIVER_INTENT;
+ }
+
+ boolean force = ACTION_FORCE_UPDATE.equals(intent.getAction());
+ if (force) {
+ Preferences.setCachedWeatherInfo(this, 0, null);
+ }
+ if (!shouldUpdate(force)) {
+ Log.d(TAG, "Service started, but shouldn't update ... stopping");
+ stopSelf();
+ return START_NOT_STICKY;
+ }
+
+ mTask = new WeatherUpdateTask();
+ mTask.execute();
+
+ return START_REDELIVER_INTENT;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mTask != null && mTask.getStatus() != AsyncTask.Status.FINISHED) {
+ mTask.cancel(true);
+ mTask = null;
+ }
+ }
+
+ private boolean shouldUpdate(boolean force) {
+ ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
+ NetworkInfo info = cm.getActiveNetworkInfo();
+
+ if (info == null || !info.isConnected()) {
+ if (D) Log.d(TAG, "No network connection is available for weather update");
+ return false;
+ }
+
+ if (!Preferences.showWeather(this)) {
+ if (D) Log.v(TAG, "Weather isn't shown, skip update");
+ return false;
+ }
+
+ long interval = Preferences.weatherRefreshIntervalInMs(this);
+ if (interval == 0 && !force) {
+ if (D) Log.v(TAG, "Interval set to manual and update not forced, skip update");
+ return false;
+ }
+
+ long now = System.currentTimeMillis();
+ long lastUpdate = Preferences.lastWeatherUpdateTimestamp(this);
+ long due = lastUpdate + interval;
+
+ if (D) Log.d(TAG, "Now " + now + " due " + due + "(" + new Date(due) + ")");
+
+ if (lastUpdate != 0 && now < due) {
+ if (D) Log.v(TAG, "Weather update is not due yet");
+ return false;
+ }
+
+ return true;
+ }
+
+ private class WeatherUpdateTask extends AsyncTask<Void, Void, WeatherInfo> {
+ private WakeLock mWakeLock;
+ private Context mContext;
+
+ private static final int RESULT_SUCCESS = 0;
+ private static final int RESULT_FAILURE = 1;
+ private static final int RESULT_CANCELLED = 2;
+
+ public WeatherUpdateTask() {
+ PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mContext = WeatherUpdateService.this;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ mWakeLock.acquire();
+ }
+
+ private String getWoeidForCustomLocation(String location) {
+ // first try with the cached woeid, no need to constantly query constant information
+ String woeid = Preferences.getCachedWoeid(mContext);
+ if (woeid == null) {
+ woeid = YahooPlaceFinder.geoCode(mContext, location);
+ }
+ if (D) Log.v(TAG, "Yahoo location code for " + location + " is " + woeid);
+ return woeid;
+ }
+
+ private String getWoeidForCurrentLocation(Location location) {
+ String woeid = YahooPlaceFinder.reverseGeoCode(mContext,
+ location.getLatitude(), location.getLongitude());
+ if (woeid == null) {
+ // we couldn't fetch up-to-date information, fall back to cache
+ woeid = Preferences.getCachedWoeid(mContext);
+ }
+ if (D) Log.v(TAG, "Yahoo location code for current geolocation " + location + " is " + woeid);
+ return woeid;
+ }
+
+ private Location getCurrentLocation() {
+ LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+ Location location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
+ if (D) Log.v(TAG, "Current location is " + location);
+ return location;
+ }
+
+ private Document getDocument(String woeid) {
+ boolean celcius = Preferences.useMetricUnits(mContext);
+ String urlWithUnit = URL_YAHOO_API_WEATHER + (celcius ? "c" : "f");
+
+ try {
+ return new HttpRetriever().getDocumentFromURL(String.format(urlWithUnit, woeid));
+ } catch (IOException e) {
+ Log.e(TAG, "Couldn't fetch weather data", e);
+ }
+ return null;
+ }
+
+ @Override
+ protected WeatherInfo doInBackground(Void... params) {
+ String customLocation = null;
+ String woeid;
+
+ if (Preferences.useCustomWeatherLocation(mContext)) {
+ customLocation = Preferences.customWeatherLocation(mContext);
+ }
+
+ if (customLocation != null) {
+ woeid = getWoeidForCustomLocation(customLocation);
+ } else {
+ Location location = getCurrentLocation();
+ woeid = getWoeidForCurrentLocation(location);
+ }
+
+ if (woeid == null || isCancelled()) {
+ return null;
+ }
+
+ Document doc = getDocument(woeid);
+ if (doc == null || isCancelled()) {
+ return null;
+ }
+
+ return new WeatherXmlParser(mContext).parseWeatherResponse(doc);
+ }
+
+ @Override
+ protected void onPostExecute(WeatherInfo result) {
+ finish(result);
+ }
+
+ @Override
+ protected void onCancelled() {
+ finish(null);
+ }
+
+ private void finish(WeatherInfo result) {
+ if (result != null) {
+ long now = System.currentTimeMillis();
+ Preferences.setCachedWeatherInfo(mContext, now, result);
+ scheduleUpdate(mContext, Preferences.weatherRefreshIntervalInMs(mContext));
+
+ Intent updateIntent = new Intent(mContext, ClockWidgetProvider.class);
+ sendBroadcast(updateIntent);
+ } else if (isCancelled()) {
+ /* cancelled, likely due to lost network - we'll get restarted
+ * when network comes back */
+ } else {
+ /* failure, schedule next download in 30 minutes */
+ long interval = 30 * 60 * 1000;
+ scheduleUpdate(mContext, interval);
+ }
+
+ mWakeLock.release();
+ stopSelf();
+ }
+ }
+
+ private static void scheduleUpdate(Context context, long timeFromNow) {
+ AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ long due = System.currentTimeMillis() + timeFromNow;
+
+ if (D) Log.v(TAG, "Scheduling next update at " + new Date(due));
+ am.set(AlarmManager.RTC_WAKEUP, due, getUpdateIntent(context, false));
+ }
+
+ public static void scheduleNextUpdate(Context context) {
+ long lastUpdate = Preferences.lastWeatherUpdateTimestamp(context);
+ if (lastUpdate == 0) {
+ scheduleUpdate(context, 0);
+ } else {
+ long interval = Preferences.weatherRefreshIntervalInMs(context);
+ scheduleUpdate(context, lastUpdate + interval - System.currentTimeMillis());
+ }
+ }
+
+ public static PendingIntent getUpdateIntent(Context context, boolean force) {
+ Intent i = new Intent(context, WeatherUpdateService.class);
+ if (force) {
+ i.setAction(ACTION_FORCE_UPDATE);
+ }
+ return PendingIntent.getService(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ public static void cancelUpdates(Context context) {
+ AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ am.cancel(getUpdateIntent(context, true));
+ am.cancel(getUpdateIntent(context, false));
+ }
+}
diff --git a/src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java b/src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java
index 50c2c98..0a1643f 100644
--- a/src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java
+++ b/src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java
@@ -69,90 +69,67 @@ public class WeatherXmlParser {
mContext = context;
}
+ private String getValueForAttribute(Element root, String tagName, String attributeName) {
+ NamedNodeMap node = root.getElementsByTagName(tagName).item(0).getAttributes();
+ if (node == null) {
+ return null;
+ }
+ return node.getNamedItem(attributeName).getNodeValue();
+ }
+
+ private float getFloatForAttribute(Element root, String tagName, String attributeName)
+ throws NumberFormatException {
+ String value = getValueForAttribute(root, tagName, attributeName);
+ if (value == null) {
+ return Float.NaN;
+ }
+ return Float.parseFloat(value);
+ }
+
+ private int getIntForAttribute(Element root, String tagName, String attributeName)
+ throws NumberFormatException {
+ String value = getValueForAttribute(root, tagName, attributeName);
+ if (value == null) {
+ return -1;
+ }
+ return Integer.parseInt(value);
+ }
+
public WeatherInfo parseWeatherResponse(Document docWeather) {
if (docWeather == null) {
Log.e(TAG, "Invalid doc weather");
return null;
}
- String strCity = null;
- String strDate = null;
- String strCondition = null;
- String strCondition_code = null;
- String strTemp = null;
- String strTempUnit = null;
- String strHumidity = null;
- String strWindSpeed = null;
- String strWindDir = null;
- String strSpeedUnit = null;
- String strHigh = null;
- String strLow = null;
-
try {
Element root = docWeather.getDocumentElement();
root.normalize();
- NamedNodeMap locationNode = root.getElementsByTagName(PARAM_YAHOO_LOCATION).item(0)
- .getAttributes();
- if (locationNode != null) {
- strCity = locationNode.getNamedItem(ATT_YAHOO_CITY).getNodeValue();
- }
-
- NamedNodeMap unitNode = root.getElementsByTagName(PARAM_YAHOO_UNIT).item(0)
- .getAttributes();
-
- if (locationNode != null) {
- strTempUnit = unitNode.getNamedItem(ATT_YAHOO_TEMP_UNIT).getNodeValue();
- strSpeedUnit = unitNode.getNamedItem(ATT_YAHOO_SPEED).getNodeValue();
- }
-
- NamedNodeMap atmosNode = root.getElementsByTagName(PARAM_YAHOO_ATMOSPHERE).item(0)
- .getAttributes();
- if (atmosNode != null) {
- strHumidity = atmosNode.getNamedItem(ATT_YAHOO_HUMIDITY).getNodeValue();
- }
-
- NamedNodeMap conditionNode = root.getElementsByTagName(PARAM_YAHOO_CONDITION).item(0)
- .getAttributes();
- if (conditionNode != null) {
- strCondition = conditionNode.getNamedItem(ATT_YAHOO_TEXT).getNodeValue();
- strCondition_code = conditionNode.getNamedItem(ATT_YAHOO_CODE).getNodeValue();
- strCondition = WeatherInfo.getTranslatedConditionString(mContext, Integer.parseInt(strCondition_code), strCondition);
- strTemp = conditionNode.getNamedItem(ATT_YAHOO_TEMP).getNodeValue();
- strDate = conditionNode.getNamedItem(ATT_YAHOO_DATE).getNodeValue();
- }
-
- NamedNodeMap temNode = root.getElementsByTagName(PARAM_YAHOO_WIND).item(0)
- .getAttributes();
- if (temNode != null) {
- strWindSpeed = temNode.getNamedItem(ATT_YAHOO_SPEED).getNodeValue();
- strWindDir = temNode.getNamedItem(ATT_YAHOO_DIRECTION).getNodeValue();
- }
-
- NamedNodeMap fcNode = root.getElementsByTagName(PARAM_YAHOO_FORECAST).item(0).getAttributes();
- if (fcNode != null) {
- strHigh = fcNode.getNamedItem(ATT_YAHOO_TODAY_HIGH).getNodeValue();
- strLow = fcNode.getNamedItem(ATT_YAHOO_TODAY_LOW).getNodeValue();
- }
+ WeatherInfo w = new WeatherInfo(mContext,
+ /* city */ getValueForAttribute(root, PARAM_YAHOO_LOCATION, ATT_YAHOO_CITY),
+ /* forecastDate */ getValueForAttribute(root, PARAM_YAHOO_CONDITION, ATT_YAHOO_DATE),
+ /* condition */ getValueForAttribute(root, PARAM_YAHOO_CONDITION, ATT_YAHOO_TEXT),
+ /* conditionCode */ getIntForAttribute(root, PARAM_YAHOO_CONDITION, ATT_YAHOO_CODE),
+ /* temperature */ getFloatForAttribute(root, PARAM_YAHOO_CONDITION, ATT_YAHOO_TEMP),
+ /* low */ getFloatForAttribute(root, PARAM_YAHOO_FORECAST, ATT_YAHOO_TODAY_LOW),
+ /* high */ getFloatForAttribute(root, PARAM_YAHOO_FORECAST, ATT_YAHOO_TODAY_HIGH),
+ /* tempUnit */ getValueForAttribute(root, PARAM_YAHOO_UNIT, ATT_YAHOO_TEMP_UNIT),
+ /* humidity */ getFloatForAttribute(root, PARAM_YAHOO_ATMOSPHERE, ATT_YAHOO_HUMIDITY),
+ /* wind */ getFloatForAttribute(root, PARAM_YAHOO_WIND, ATT_YAHOO_SPEED),
+ /* windDir */ getIntForAttribute(root, PARAM_YAHOO_WIND, ATT_YAHOO_DIRECTION),
+ /* speedUnit */ getValueForAttribute(root, PARAM_YAHOO_UNIT, ATT_YAHOO_SPEED),
+ System.currentTimeMillis());
+
+ Log.d(TAG, "Weather updated: " + w);
+ return w;
} catch (Exception e) {
- Log.e(TAG, "Something wrong with parser data: " + e.toString());
+ Log.e(TAG, "Couldn't parse Yahoo weather XML", e);
return null;
}
-
- /* Weather info */
- WeatherInfo yahooWeatherInfo = new WeatherInfo(mContext, strCity, strDate, strCondition, strCondition_code, strTemp,
- strTempUnit, strHumidity, strWindSpeed, strWindDir, strSpeedUnit, strLow, strHigh, System.currentTimeMillis());
-
- Log.d(TAG, "Weather updated for " + strCity + ": " + strDate + ", " + strCondition + "(" + strCondition_code
- + "), " + strTemp + strTempUnit + ", " + strHumidity + "% humidity, " + ", wind: " + strWindDir + " at "
- + strWindSpeed + strSpeedUnit + ", low: " + strLow + strTempUnit + " high: " + strHigh + strTempUnit);
-
- return yahooWeatherInfo;
}
public String parsePlaceFinderResponse(String response) {
try {
-
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(response)));
@@ -170,7 +147,7 @@ public class WeatherXmlParser {
}
}
} catch (Exception e) {
- Log.e(TAG, e.toString());
+ Log.e(TAG, "Couldn't parse Yahoo place finder XML", e);
}
return null;
}
diff --git a/src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java b/src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java
index 569cef1..c2b3f0d 100644
--- a/src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java
+++ b/src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2013 The CyanogenMod Project (DvTonder)
* Copyright (C) 2012 The AOKP Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,25 +18,43 @@
package com.cyanogenmod.lockclock.weather;
import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.cyanogenmod.lockclock.misc.Preferences;
public class YahooPlaceFinder {
- private static final String YAHOO_API_BASE_REV_URL = "http://where.yahooapis.com/geocode?appid=jYkTZp64&q=%1$s,+%2$s&gflags=R";
- private static final String YAHOO_API_BASE_URL = "http://where.yahooapis.com/geocode?appid=jYkTZp64&q=%1$s";
+ private static final String YAHOO_API_BASE_REV_URL = "http://where.yahooapis.com/geocode?appid=EKvCnl4k&q=%1$s,+%2$s&gflags=R";
+ private static final String YAHOO_API_BASE_URL = "http://where.yahooapis.com/geocode?appid=EKvCnl4k&q=%1$s";
public static String reverseGeoCode(Context c, double latitude, double longitude) {
-
String url = String.format(YAHOO_API_BASE_REV_URL, String.valueOf(latitude),
String.valueOf(longitude));
String response = new HttpRetriever().retrieve(url);
- return new WeatherXmlParser(c).parsePlaceFinderResponse(response);
-
+ if (response == null) {
+ return null;
+ }
+
+ String woeid = new WeatherXmlParser(c).parsePlaceFinderResponse(response);
+ if (woeid != null) {
+ // cache the result for potential reuse - the placefinder service API is rate limited
+ Preferences.setCachedWoeid(c, woeid);
+ }
+ return woeid;
}
- public static String GeoCode(Context c, String location) {
+ public static String geoCode(Context c, String location) {
String url = String.format(YAHOO_API_BASE_URL, location).replace(' ', '+');
String response = new HttpRetriever().retrieve(url);
- return new WeatherXmlParser(c).parsePlaceFinderResponse(response);
+ if (response == null) {
+ return null;
+ }
+
+ String woeid = new WeatherXmlParser(c).parsePlaceFinderResponse(response);
+ if (woeid != null) {
+ // cache the result for potential reuse - the placefinder service API is rate limited
+ Preferences.setCachedWoeid(c, woeid);
+ }
+ return woeid;
}
-
}