aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDvTonder <david.vantonder@gmail.com>2013-12-09 22:06:49 -0500
committerDvTonder <david.vantonder@gmail.com>2013-12-09 22:06:49 -0500
commit5381fbab6824dc9f72da68ba28c6df7861503570 (patch)
treed366e9f791207d1783e7e2a1e8e4cf7af041608a /src
parent142abbc21d2b04dee9d643aa3f1ada8f499f8209 (diff)
downloadandroid_packages_apps_LockClock-5381fbab6824dc9f72da68ba28c6df7861503570.tar.gz
android_packages_apps_LockClock-5381fbab6824dc9f72da68ba28c6df7861503570.tar.bz2
android_packages_apps_LockClock-5381fbab6824dc9f72da68ba28c6df7861503570.zip
cLock: Forward port CM10.2 updates
Change-Id: Icec530485324193f76ac7bfe48ca5ca179bd0b7b
Diffstat (limited to 'src')
-rw-r--r--src/com/cyanogenmod/lockclock/ClockWidgetProvider.java2
-rwxr-xr-xsrc/com/cyanogenmod/lockclock/ClockWidgetService.java62
-rwxr-xr-xsrc/com/cyanogenmod/lockclock/misc/Constants.java5
-rw-r--r--src/com/cyanogenmod/lockclock/misc/Preferences.java6
-rw-r--r--src/com/cyanogenmod/lockclock/misc/WidgetUtils.java56
-rwxr-xr-xsrc/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java2
-rw-r--r--src/com/cyanogenmod/lockclock/weather/YahooWeatherProvider.java244
7 files changed, 250 insertions, 127 deletions
diff --git a/src/com/cyanogenmod/lockclock/ClockWidgetProvider.java b/src/com/cyanogenmod/lockclock/ClockWidgetProvider.java
index 30c1bda..d2265cb 100644
--- a/src/com/cyanogenmod/lockclock/ClockWidgetProvider.java
+++ b/src/com/cyanogenmod/lockclock/ClockWidgetProvider.java
@@ -63,6 +63,8 @@ public class ClockWidgetProvider extends AppWidgetProvider {
// Boot completed, schedule next weather update
} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ // On first boot lastUpdate will be 0 thus no need to force an update
+ // Subsequent boots will use cached data
WeatherUpdateService.scheduleNextUpdate(context);
// A widget has been deleted, prevent our handling and ask the super class handle it
diff --git a/src/com/cyanogenmod/lockclock/ClockWidgetService.java b/src/com/cyanogenmod/lockclock/ClockWidgetService.java
index 7726328..1698122 100755
--- a/src/com/cyanogenmod/lockclock/ClockWidgetService.java
+++ b/src/com/cyanogenmod/lockclock/ClockWidgetService.java
@@ -20,11 +20,13 @@ import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateFormat;
@@ -108,9 +110,20 @@ public class ClockWidgetService extends IntentService {
for (int id : mWidgetIds) {
boolean showCalendar = false;
+ // Determine if its a home or a lock screen widget
+ Bundle myOptions = mAppWidgetManager.getAppWidgetOptions (id);
+ boolean isKeyguard = false;
+ if (WidgetUtils.isTextClockAvailable()) {
+ // This is only available on API 17+, make sure we are not calling it on API16
+ // This generates an API level Lint warning, ignore it
+ int category = myOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
+ isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+ }
+ if (D) Log.d("TAG", "For Widget id " + id + " isKeyguard is set to " + isKeyguard);
+
// Determine which layout to use
boolean smallWidget = showWeather && showWeatherWhenMinimized
- && WidgetUtils.showSmallWidget(this, id, digitalClock);
+ && WidgetUtils.showSmallWidget(this, id, digitalClock, isKeyguard);
if (smallWidget) {
// The small widget is only shown if weather needs to be shown
// and there is not enough space for the full weather widget and
@@ -143,7 +156,7 @@ public class ClockWidgetService extends IntentService {
// Hide the calendar panel if not visible
remoteViews.setViewVisibility(R.id.calendar_panel, showCalendar ? View.VISIBLE : View.GONE);
- boolean canFitWeather = smallWidget || WidgetUtils.canFitWeather(this, id, digitalClock);
+ boolean canFitWeather = smallWidget || WidgetUtils.canFitWeather(this, id, digitalClock, isKeyguard);
// Now, if we need to show the actual weather, do so
if (showWeather && canFitWeather) {
WeatherInfo weatherInfo = Preferences.getCachedWeatherInfo(this);
@@ -378,6 +391,10 @@ public class ClockWidgetService extends IntentService {
int timestampColor = Preferences.weatherTimestampFontColor(this);
boolean colorIcons = Preferences.useAlternateWeatherIcons(this);
+ // Reset no weather visibility
+ weatherViews.setViewVisibility(R.id.weather_no_data, View.GONE);
+ weatherViews.setViewVisibility(R.id.weather_refresh, View.GONE);
+
// Weather Image
if (colorIcons) {
// No additional color overlays needed
@@ -438,27 +455,38 @@ public class ClockWidgetService extends IntentService {
* There is no data to display, display 'empty' fields and the 'Tap to reload' message
*/
private void setNoWeatherData(RemoteViews weatherViews, boolean smallWidget) {
- boolean defaultIcons = !Preferences.useAlternateWeatherIcons(this);
- final Resources res = getBaseContext().getResources();
int color = Preferences.weatherFontColor(this);
+ boolean firstRun = Preferences.isFirstWeatherUpdate(this);
- // Weather Image - Either the default or alternate set
- weatherViews.setImageViewResource(R.id.weather_image,
- defaultIcons ? R.drawable.weather_na : R.drawable.weather2_na);
-
+ // Hide the normal weather stuff
+ String noData = getString(R.string.weather_cannot_reach_provider, getString(R.string.weather_source));
+ weatherViews.setViewVisibility(R.id.weather_image, View.INVISIBLE);
if (!smallWidget) {
- weatherViews.setTextViewText(R.id.weather_city, res.getString(R.string.weather_no_data));
- weatherViews.setViewVisibility(R.id.weather_city, View.VISIBLE);
+ weatherViews.setViewVisibility(R.id.weather_city, View.GONE);
weatherViews.setViewVisibility(R.id.update_time, View.GONE);
- weatherViews.setTextColor(R.id.weather_city, color);
+ weatherViews.setViewVisibility(R.id.weather_temps_panel, View.GONE);
+ weatherViews.setViewVisibility(R.id.weather_condition, View.GONE);
+
+ // Set up the no data and refresh indicators
+ weatherViews.setTextViewText(R.id.weather_no_data, noData);
+ weatherViews.setTextViewText(R.id.weather_refresh, getString(R.string.weather_tap_to_refresh));
+ weatherViews.setTextColor(R.id.weather_no_data, color);
+ weatherViews.setTextColor(R.id.weather_refresh, color);
+
+ // For a better OOBE, dont show the no_data message if this is the first run
+ weatherViews.setViewVisibility(R.id.weather_no_data, firstRun ? View.GONE : View.VISIBLE);
+ weatherViews.setViewVisibility(R.id.weather_refresh, firstRun ? View.GONE : View.VISIBLE);
+ } else {
+ weatherViews.setTextViewText(R.id.weather_temp, firstRun ? null : noData);
+ weatherViews.setTextViewText(R.id.weather_condition, firstRun ? null : getString(R.string.weather_tap_to_refresh));
+ weatherViews.setTextColor(R.id.weather_temp, color);
+ weatherViews.setTextColor(R.id.weather_condition, color);
}
- weatherViews.setViewVisibility(R.id.weather_temps_panel, View.GONE);
- weatherViews.setTextViewText(R.id.weather_condition, res.getString(R.string.weather_tap_to_refresh));
- weatherViews.setTextColor(R.id.weather_condition, color);
-
- // Register an onClickListener on Weather
- setWeatherClickListener(weatherViews);
+ // Register an onClickListener on Weather with the default (Refresh) action
+ if (!firstRun) {
+ setWeatherClickListener(weatherViews);
+ }
}
private void setWeatherClickListener(RemoteViews weatherViews) {
diff --git a/src/com/cyanogenmod/lockclock/misc/Constants.java b/src/com/cyanogenmod/lockclock/misc/Constants.java
index 535dcb0..db1b89f 100755
--- a/src/com/cyanogenmod/lockclock/misc/Constants.java
+++ b/src/com/cyanogenmod/lockclock/misc/Constants.java
@@ -67,7 +67,10 @@ public class Constants {
public static final String WEATHER_LAST_UPDATE = "last_weather_update";
public static final String WEATHER_DATA = "weather_data";
- public static final int MAX_CALENDAR_ITEMS = 10;
+ // First run is used to hide the initial no-weather message for a better OOBE
+ public static final String WEATHER_FIRST_UPDATE = "weather_first_update";
+
+ public static final int MAX_CALENDAR_ITEMS = 30;
public static final long CALENDAR_UPCOMING_EVENTS_FROM_HOUR = 20L;
public static final int CALENDAR_FORMAT_TIME =
DateUtils.FORMAT_SHOW_TIME
diff --git a/src/com/cyanogenmod/lockclock/misc/Preferences.java b/src/com/cyanogenmod/lockclock/misc/Preferences.java
index 3cef8ff..a6c5c77 100644
--- a/src/com/cyanogenmod/lockclock/misc/Preferences.java
+++ b/src/com/cyanogenmod/lockclock/misc/Preferences.java
@@ -29,6 +29,10 @@ public class Preferences {
private Preferences() {
}
+ public static boolean isFirstWeatherUpdate(Context context) {
+ return getPrefs(context).getBoolean(Constants.WEATHER_FIRST_UPDATE, true);
+ }
+
public static boolean showDigitalClock(Context context) {
return getPrefs(context).getBoolean(Constants.CLOCK_DIGITAL, true);
}
@@ -166,6 +170,8 @@ public class Preferences {
SharedPreferences.Editor editor = getPrefs(context).edit();
editor.putLong(Constants.WEATHER_LAST_UPDATE, timestamp);
if (data != null) {
+ // We now have valid weather data to display
+ editor.putBoolean(Constants.WEATHER_FIRST_UPDATE, false);
editor.putString(Constants.WEATHER_DATA, data.toSerializedString());
}
editor.apply();
diff --git a/src/com/cyanogenmod/lockclock/misc/WidgetUtils.java b/src/com/cyanogenmod/lockclock/misc/WidgetUtils.java
index 242916e..465ddc2 100644
--- a/src/com/cyanogenmod/lockclock/misc/WidgetUtils.java
+++ b/src/com/cyanogenmod/lockclock/misc/WidgetUtils.java
@@ -32,6 +32,7 @@ import android.graphics.PorterDuffColorFilter;
import android.graphics.Bitmap.Config;
import android.os.Build;
import android.os.Bundle;
+import android.util.Log;
import android.util.TypedValue;
import com.cyanogenmod.lockclock.R;
@@ -41,6 +42,9 @@ public class WidgetUtils {
// Widget display and resizing related functionality
//===============================================================================================
+ private static final String TAG = "WidgetUtils";
+ private static final boolean D = Constants.DEBUG;
+
/**
* Load a resource by Id and overlay with a specified color
*/
@@ -60,7 +64,7 @@ public class WidgetUtils {
/**
* Decide whether to show the small Weather panel
*/
- public static boolean showSmallWidget(Context context, int id, boolean digitalClock) {
+ public static boolean showSmallWidget(Context context, int id, boolean digitalClock, boolean isKeyguard) {
Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(id);
if (options == null) {
// no data to make the calculation, show the list anyway
@@ -70,18 +74,32 @@ public class WidgetUtils {
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
int minHeightPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, minHeight,
resources.getDisplayMetrics());
- int neededFullSize = (int) resources.getDimension(
- digitalClock ? R.dimen.min_digital_weather_height : R.dimen.min_analog_weather_height);
+ int neededFullSize = 0;
+ if (isKeyguard) {
+ neededFullSize = (int) resources.getDimension(
+ digitalClock ? R.dimen.min_digital_weather_height_lock
+ : R.dimen.min_analog_weather_height_lock);
+ } else {
+ neededFullSize = (int) resources.getDimension(
+ digitalClock ? R.dimen.min_digital_weather_height
+ : R.dimen.min_analog_weather_height);
+ }
int neededSmallSize = (int) resources.getDimension(R.dimen.min_digital_widget_height);
// Check to see if the widget size is big enough, if it is return true.
- return (minHeightPx < neededFullSize && minHeightPx > neededSmallSize);
+ Boolean result = minHeightPx < neededFullSize && minHeightPx > neededSmallSize;
+ if (D) {
+ Log.d(TAG, "showSmallWidget: digital clock = " + digitalClock + " with minHeightPx = " + minHeightPx
+ + " and neededFullSize = " + neededFullSize + " and neededSmallSize = " + neededSmallSize);
+ Log.d(TAG, "showsmallWidget result = " + result);
+ }
+ return result;
}
/**
* Decide whether to show the full Weather panel
*/
- public static boolean canFitWeather(Context context, int id, boolean digitalClock) {
+ public static boolean canFitWeather(Context context, int id, boolean digitalClock, boolean isKeyguard) {
Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(id);
if (options == null) {
// no data to make the calculation, show the list anyway
@@ -91,11 +109,25 @@ public class WidgetUtils {
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
int minHeightPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, minHeight,
resources.getDisplayMetrics());
- int neededSize = (int) resources.getDimension(
- digitalClock ? R.dimen.min_digital_weather_height : R.dimen.min_analog_weather_height);
+ int neededSize = 0;
+ if (isKeyguard) {
+ neededSize = (int) resources.getDimension(
+ digitalClock ? R.dimen.min_digital_weather_height_lock
+ : R.dimen.min_analog_weather_height_lock);
+ } else {
+ neededSize = (int) resources.getDimension(
+ digitalClock ? R.dimen.min_digital_weather_height
+ : R.dimen.min_analog_weather_height);
+ }
// Check to see if the widget size is big enough, if it is return true.
- return (minHeightPx > neededSize);
+ Boolean result = minHeightPx > neededSize;
+ if (D) {
+ Log.d(TAG, "canFitWeather: digital clock = " + digitalClock + " with minHeightPx = "
+ + minHeightPx + " and neededSize = " + neededSize);
+ Log.d(TAG, "canFitWeather result = " + result);
+ }
+ return result;
}
/**
@@ -115,7 +147,13 @@ public class WidgetUtils {
digitalClock ? R.dimen.min_digital_calendar_height : R.dimen.min_analog_calendar_height);
// Check to see if the widget size is big enough, if it is return true.
- return (minHeightPx > neededSize);
+ Boolean result = minHeightPx > neededSize;
+ if (D) {
+ if (D) Log.d(TAG, "canFitCalendar: digital clock = " + digitalClock + " with minHeightPx = "
+ + minHeightPx + " and neededSize = " + neededSize);
+ Log.d(TAG, "canFitCalendar result = " + result);
+ }
+ return result;
}
/**
diff --git a/src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java b/src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java
index badf20b..94fca71 100755
--- a/src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java
+++ b/src/com/cyanogenmod/lockclock/weather/WeatherUpdateService.java
@@ -301,7 +301,7 @@ public class WeatherUpdateService extends Service {
public static void scheduleNextUpdate(Context context) {
long lastUpdate = Preferences.lastWeatherUpdateTimestamp(context);
if (lastUpdate == 0) {
- scheduleUpdate(context, 0, false);
+ scheduleUpdate(context, 0, true);
} else {
long interval = Preferences.weatherRefreshIntervalInMs(context);
scheduleUpdate(context, lastUpdate + interval - System.currentTimeMillis(), false);
diff --git a/src/com/cyanogenmod/lockclock/weather/YahooWeatherProvider.java b/src/com/cyanogenmod/lockclock/weather/YahooWeatherProvider.java
index 15addf6..dc714cb 100644
--- a/src/com/cyanogenmod/lockclock/weather/YahooWeatherProvider.java
+++ b/src/com/cyanogenmod/lockclock/weather/YahooWeatherProvider.java
@@ -26,45 +26,40 @@ import com.cyanogenmod.lockclock.misc.Preferences;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+import java.io.IOException;
+import java.io.StringReader;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Locale;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
public class YahooWeatherProvider implements WeatherProvider {
private static final String TAG = "YahooWeatherProvider";
private static final String URL_WEATHER =
- "http://query.yahooapis.com/v1/public/yql?format=json&q=" +
- Uri.encode("select * from weather.forecast where woeid =");
+ "http://weather.yahooapis.com/forecastrss?w=%s&u=%s";
private static final String URL_LOCATION =
"http://query.yahooapis.com/v1/public/yql?format=json&q=" +
Uri.encode("select woeid, postal, admin1, admin2, admin3, " +
"locality1, locality2, country from geo.places where " +
"(placetype = 7 or placetype = 8 or placetype = 9 " +
"or placetype = 10 or placetype = 11) and text =");
+ private static final String URL_PLACEFINDER =
+ "http://query.yahooapis.com/v1/public/yql?format=json&q=" +
+ Uri.encode("select woeid, city from geo.placefinder where gflags=\"R\" and text =");
private static final String[] LOCALITY_NAMES = new String[] {
"locality1", "locality2", "admin3", "admin2", "admin1"
};
- private static class YahooLocationResult extends LocationResult {
- private int score;
- };
- private static final Comparator<YahooLocationResult> LOCATION_COMPARATOR =
- new Comparator<YahooLocationResult>() {
- @Override
- public int compare(YahooLocationResult lhs, YahooLocationResult rhs) {
- if (lhs.score == rhs.score) {
- return 0;
- }
- // smaller score at the top
- return lhs.score < rhs.score ? -1 : 1;
- }
- };
-
private Context mContext;
public YahooWeatherProvider(Context context) {
@@ -76,106 +71,162 @@ public class YahooWeatherProvider implements WeatherProvider {
String locale = mContext.getResources().getConfiguration().locale.getCountry();
String params = "\"" + input + "\" and lang = \"" + locale + "\"";
String url = URL_LOCATION + Uri.encode(params);
- JSONArray places = fetchPlaceList(url);
-
- if (places == null) {
+ JSONObject jsonResults = fetchResults(url);
+ if (jsonResults == null) {
return null;
}
- return new ArrayList<LocationResult>(parsePlaces(places));
+ try {
+ JSONArray places = jsonResults.optJSONArray("place");
+ if (places == null) {
+ // Yahoo returns an object instead of an array when there's only one result
+ places = new JSONArray();
+ places.put(jsonResults.getJSONObject("place"));
+ }
+
+ ArrayList<LocationResult> results = new ArrayList<LocationResult>();
+ for (int i = 0; i < places.length(); i++) {
+ LocationResult result = parsePlace(places.getJSONObject(i));
+ if (result != null) {
+ results.add(result);
+ }
+ }
+ return results;
+ } catch (JSONException e) {
+ Log.e(TAG, "Received malformed places data", e);
+ }
+ return null;
}
public WeatherInfo getWeatherInfo(String id, String localizedCityName) {
String unit = Preferences.useMetricUnits(mContext) ? "c" : "f";
- String params = "\"" + id + "\" and u = \"" + unit + "\"";
- String url = URL_WEATHER + Uri.encode(params);
+ String url = String.format(URL_WEATHER, id, unit);
String response = HttpRetriever.retrieve(url);
if (response == null) {
return null;
}
+ SAXParserFactory factory = SAXParserFactory.newInstance();
try {
- JSONObject rootObject = new JSONObject(response);
- JSONObject results = rootObject.getJSONObject("query").getJSONObject("results");
- JSONObject data = results.getJSONObject("channel");
-
- String city = localizedCityName != null
- ? localizedCityName : data.getJSONObject("location").getString("city");
-
- JSONObject wind = data.getJSONObject("wind");
- JSONObject units = data.getJSONObject("units");
- JSONObject item = data.getJSONObject("item");
- JSONObject conditions = item.getJSONObject("condition");
- JSONObject forecast = item.getJSONArray("forecast").getJSONObject(0);
-
- WeatherInfo w = new WeatherInfo(mContext, id, city,
- /* forecastDate */ conditions.getString("date"),
- /* condition */ conditions.getString("text"),
- /* conditionCode */ conditions.getInt("code"),
- /* temperature */ (float) conditions.getDouble("temp"),
- /* low */ (float) forecast.getDouble("low"),
- /* high */ (float) forecast.getDouble("high"),
- /* tempUnit */ units.getString("temperature"),
- /* humidity */ (float) data.getJSONObject("atmosphere").getDouble("humidity"),
- /* wind */ (float) wind.optDouble("speed", -1),
- /* windDir */ wind.optInt("direction", -1),
- /* speedUnit */ units.getString("speed"),
- System.currentTimeMillis());
-
- Log.d(TAG, "Weather updated: " + w);
- return w;
- } catch (JSONException e) {
- Log.w(TAG, "Weather condition data is invalid.", e);
+ SAXParser parser = factory.newSAXParser();
+ StringReader reader = new StringReader(response);
+ WeatherHandler handler = new WeatherHandler();
+ parser.parse(new InputSource(reader), handler);
+
+ if (handler.isComplete()) {
+ WeatherInfo w = new WeatherInfo(mContext, id,
+ localizedCityName != null ? localizedCityName : handler.city, null,
+ handler.condition, handler.conditionCode, handler.temperature,
+ handler.forecasts.get(0).low, handler.forecasts.get(0).high,
+ handler.temperatureUnit, handler.humidity, handler.windSpeed,
+ handler.windDirection, handler.speedUnit,
+ System.currentTimeMillis());
+ Log.d(TAG, "Weather updated: " + w);
+ return w;
+ }
+ } catch (ParserConfigurationException e) {
+ Log.e(TAG, "Could not create XML parser", e);
+ } catch (SAXException e) {
+ Log.e(TAG, "Could not parse weather XML", e);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not parse weather XML", e);
}
return null;
}
+ private static class WeatherHandler extends DefaultHandler {
+ String city;
+ String temperatureUnit, speedUnit;
+ int windDirection, conditionCode;
+ float humidity, temperature, windSpeed;
+ String condition;
+ ArrayList<DayForecast> forecasts = new ArrayList<DayForecast>();
+
+ private static class DayForecast {
+ float low, high;
+ int conditionCode;
+ String condition;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ if (qName.equals("yweather:location")) {
+ city = attributes.getValue("city");
+ } else if (qName.equals("yweather:units")) {
+ temperatureUnit = attributes.getValue("temperature");
+ speedUnit = attributes.getValue("speed");
+ } else if (qName.equals("yweather:wind")) {
+ windDirection = (int) stringToFloat(attributes.getValue("direction"), -1);
+ windSpeed = stringToFloat(attributes.getValue("speed"), -1);
+ } else if (qName.equals("yweather:atmosphere")) {
+ humidity = stringToFloat(attributes.getValue("humidity"), -1);
+ } else if (qName.equals("yweather:condition")) {
+ condition = attributes.getValue("text");
+ conditionCode = (int) stringToFloat(attributes.getValue("code"), -1);
+ temperature = stringToFloat(attributes.getValue("temp"), Float.NaN);
+ } else if (qName.equals("yweather:forecast")) {
+ DayForecast day = new DayForecast();
+ day.low = stringToFloat(attributes.getValue("low"), Float.NaN);
+ day.high = stringToFloat(attributes.getValue("high"), Float.NaN);
+ day.condition = attributes.getValue("text");
+ day.conditionCode = (int) stringToFloat(attributes.getValue("code"), -1);
+ if (!Float.isNaN(day.low) && !Float.isNaN(day.high) && day.conditionCode >= 0) {
+ forecasts.add(day);
+ }
+ }
+ }
+ public boolean isComplete() {
+ return temperatureUnit != null && speedUnit != null && conditionCode >= 0
+ && !Float.isNaN(temperature) && !forecasts.isEmpty();
+ }
+ private float stringToFloat(String value, float defaultValue) {
+ try {
+ if (value != null) {
+ return Float.parseFloat(value);
+ }
+ } catch (NumberFormatException e) {
+ // fall through to the return line below
+ }
+ return defaultValue;
+ }
+ }
+
public WeatherInfo getWeatherInfo(Location location) {
- String formattedCoordinates = String.format(Locale.US, "\"%f %f\"",
- location.getLatitude(), location.getLongitude());
- String url = URL_LOCATION + Uri.encode(formattedCoordinates);
- JSONArray places = fetchPlaceList(url);
- if (places == null) {
+ String locale = mContext.getResources().getConfiguration().locale.getCountry();
+ String params = String.format(Locale.US, "\"%f %f\" and lang=\"%s\"",
+ location.getLatitude(), location.getLongitude(), locale);
+ String url = URL_PLACEFINDER + Uri.encode(params);
+ JSONObject results = fetchResults(url);
+ if (results == null) {
return null;
}
- List<YahooLocationResult> results = parsePlaces(places);
- Collections.sort(results, LOCATION_COMPARATOR);
+ try {
+ JSONObject result = results.getJSONObject("Result");
+ String woeid = result.getString("woeid");
+ String city = result.getString("city");
+
+ Log.d(TAG, "Resolved location " + location + " to " + city + " (" + woeid + ")");
- for (YahooLocationResult result : results) {
- Log.d(TAG, "Looking up weather for " + result.city + " (id=" + result.id
- + ", score=" + result.score + ")");
- WeatherInfo info = getWeatherInfo(result.id, result.city);
+ WeatherInfo info = getWeatherInfo(woeid, city);
if (info != null) {
// cache the result for potential reuse
// (the placefinder service API is rate limited)
- Preferences.setCachedLocationId(mContext, result.id);
+ Preferences.setCachedLocationId(mContext, woeid);
return info;
}
+ } catch (JSONException e) {
+ Log.e(TAG, "Received malformed placefinder data", e);
}
return null;
}
- private List<YahooLocationResult> parsePlaces(JSONArray places) {
- ArrayList<YahooLocationResult> results = new ArrayList<YahooLocationResult>();
- for (int i = 0; i < places.length(); i++) {
- try {
- YahooLocationResult result = parsePlace(places.getJSONObject(i));
- if (result != null) {
- results.add(result);
- }
- } catch (JSONException e) {
- Log.w(TAG, "Found invalid JSON place record, ignoring.", e);
- }
- }
- return results;
- }
-
- private YahooLocationResult parsePlace(JSONObject place) throws JSONException {
- YahooLocationResult result = new YahooLocationResult();
+ private LocationResult parsePlace(JSONObject place) throws JSONException {
+ LocationResult result = new LocationResult();
JSONObject country = place.getJSONObject("country");
result.id = place.getString("woeid");
@@ -185,11 +236,9 @@ public class YahooWeatherProvider implements WeatherProvider {
result.postal = place.getJSONObject("postal").getString("content");
}
- for (int i = 0; i < LOCALITY_NAMES.length; i++) {
- String locName = LOCALITY_NAMES[i];
- if (!place.isNull(locName)) {
- result.city = place.getJSONObject(locName).getString("content");
- result.score = i;
+ for (String name : LOCALITY_NAMES) {
+ if (!place.isNull(name)) {
+ result.city = place.getJSONObject(name).getString("content");
break;
}
}
@@ -201,22 +250,19 @@ public class YahooWeatherProvider implements WeatherProvider {
return result;
}
- private JSONArray fetchPlaceList(String url) {
+ private JSONObject fetchResults(String url) {
String response = HttpRetriever.retrieve(url);
if (response == null) {
return null;
}
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Request URL is " + url + ", response is " + response);
+ }
+
try {
JSONObject rootObject = new JSONObject(response);
- JSONObject results = rootObject.getJSONObject("query").getJSONObject("results");
- JSONArray places = results.optJSONArray("place");
- if (places == null) {
- // Yahoo returns an object instead of an array when there's only one result
- places = new JSONArray();
- places.put(results.getJSONObject("place"));
- }
- return places;
+ return rootObject.getJSONObject("query").getJSONObject("results");
} catch (JSONException e) {
Log.w(TAG, "Received malformed places data", e);
}