Android Open Source - DashClockWidget Yahoo Weather Api Client






From Project

Back to project page DashClockWidget.

License

The source code is released under:

Apache License

If you think the Android project DashClockWidget listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2013 Google Inc.// w w  w  .  j ava2s . co  m
 *
 * 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.google.android.apps.dashclock.weather;

import android.location.Location;
import android.text.TextUtils;
import android.util.Pair;

import com.google.android.apps.dashclock.LogUtils;
import com.google.android.apps.dashclock.Utils;

import net.nurik.roman.dashclock.R;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import static com.google.android.apps.dashclock.LogUtils.LOGD;
import static com.google.android.apps.dashclock.LogUtils.LOGE;
import static com.google.android.apps.dashclock.LogUtils.LOGW;

/**
 * Client code for the Yahoo! Weather RSS feeds and GeoPlanet API.
 */
class YahooWeatherApiClient {
    private static final String TAG = LogUtils.makeLogTag(YahooWeatherApiClient.class);

    private static String sWeatherUnits;

    private static XmlPullParserFactory sXmlPullParserFactory;

    private static final int MAX_SEARCH_RESULTS = 10;

    static {
        try {
            sXmlPullParserFactory = XmlPullParserFactory.newInstance();
            sXmlPullParserFactory.setNamespaceAware(true);
        } catch (XmlPullParserException e) {
            LOGE(TAG, "Could not instantiate XmlPullParserFactory", e);
        }
    }

    public static void setWeatherUnits(String weatherUnits) {
        sWeatherUnits = weatherUnits;
    }

    public static WeatherData getWeatherForLocationInfo(LocationInfo locationInfo)
            throws CantGetWeatherException {
        // Loop through the woeids (they're in descending precision order) until weather data
        // is found.
        for (String woeid : locationInfo.woeids) {
            LOGD(TAG, "Trying WOEID: " + woeid);
            WeatherData data = YahooWeatherApiClient.getWeatherForWoeid(woeid, locationInfo.town);
            if (data != null
                    && data.conditionCode != WeatherData.INVALID_CONDITION
                    && data.temperature != WeatherData.INVALID_TEMPERATURE) {
                return data;
            }
        }

        // No weather could be found :(
        throw new CantGetWeatherException(true, R.string.no_weather_data);
    }

    public static WeatherData getWeatherForWoeid(String woeid, String town)
            throws CantGetWeatherException {
        HttpURLConnection connection = null;
        try {
            // TODO: proper http library
            connection = Utils.openUrlConnection(buildWeatherQueryUrl(woeid));
            XmlPullParser xpp = sXmlPullParserFactory.newPullParser();
            xpp.setInput(new InputStreamReader(connection.getInputStream()));

            WeatherData data = new WeatherData();
            boolean hasTodayForecast = false;
            int eventType = xpp.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                if (eventType == XmlPullParser.START_TAG
                        && "condition".equals(xpp.getName())) {
                    for (int i = xpp.getAttributeCount() - 1; i >= 0; i--) {
                        if ("temp".equals(xpp.getAttributeName(i))) {
                            data.temperature = Integer.parseInt(xpp.getAttributeValue(i));
                        } else if ("code".equals(xpp.getAttributeName(i))) {
                            data.conditionCode = Integer.parseInt(xpp.getAttributeValue(i));
                        } else if ("text".equals(xpp.getAttributeName(i))) {
                            data.conditionText = xpp.getAttributeValue(i);
                        }
                    }
                } else if (eventType == XmlPullParser.START_TAG
                        && "forecast".equals(xpp.getName())
                        && !hasTodayForecast) {
                    // TODO: verify this is the forecast for today (this currently assumes the
                    // first forecast is today's forecast)
                    hasTodayForecast = true;
                    for (int i = xpp.getAttributeCount() - 1; i >= 0; i--) {
                        if ("code".equals(xpp.getAttributeName(i))) {
                            data.todayForecastConditionCode
                                    = Integer.parseInt(xpp.getAttributeValue(i));
                        } else if ("low".equals(xpp.getAttributeName(i))) {
                            data.low = Integer.parseInt(xpp.getAttributeValue(i));
                        } else if ("high".equals(xpp.getAttributeName(i))) {
                            data.high = Integer.parseInt(xpp.getAttributeValue(i));
                        } else if ("text".equals(xpp.getAttributeName(i))) {
                            data.forecastText = xpp.getAttributeValue(i);
                        }
                    }
                } else if (eventType == XmlPullParser.START_TAG
                        && "location".equals(xpp.getName())) {
                    String cityOrVillage = "--";
                    String region = null;
                    String country = "--";
                    for (int i = xpp.getAttributeCount() - 1; i >= 0; i--) {
                        if ("city".equals(xpp.getAttributeName(i))) {
                            cityOrVillage = xpp.getAttributeValue(i);
                        } else if ("region".equals(xpp.getAttributeName(i))) {
                            region = xpp.getAttributeValue(i);
                        } else if ("country".equals(xpp.getAttributeName(i))) {
                            country = xpp.getAttributeValue(i);
                        }
                    }

                    if (TextUtils.isEmpty(region)) {
                        // If no region is available, show the country. Otherwise, don't
                        // show country information.
                        region = country;
                    }

                    if (!TextUtils.isEmpty(town) && !town.equals(cityOrVillage)) {
                        // If a town is available and it's not equivalent to the city name,
                        // show it.
                        cityOrVillage = cityOrVillage + ", " + town;
                    }

                    data.location = cityOrVillage + ", " + region;
                }
                eventType = xpp.next();
            }

            if (TextUtils.isEmpty(data.location)) {
                data.location = town;
            }

            return data;

        } catch (IOException e) {
            throw new CantGetWeatherException(true, R.string.no_weather_data,
                    "Error parsing weather feed XML.", e);
        } catch (NumberFormatException e) {
            throw new CantGetWeatherException(true, R.string.no_weather_data,
                    "Error parsing weather feed XML.", e);
        } catch (XmlPullParserException e) {
            throw new CantGetWeatherException(true, R.string.no_weather_data,
                    "Error parsing weather feed XML.", e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    public static LocationInfo getLocationInfo(Location location) throws CantGetWeatherException {
        LocationInfo li = new LocationInfo();

        // first=tagname (admin1, locality3) second=woeid
        String primaryWoeid = null;
        List<Pair<String,String>> alternateWoeids = new ArrayList<Pair<String, String>>();

        HttpURLConnection connection = null;
        try {
            connection = Utils.openUrlConnection(buildPlaceSearchUrl(location));
            XmlPullParser xpp = sXmlPullParserFactory.newPullParser();
            xpp.setInput(new InputStreamReader(connection.getInputStream()));

            boolean inWoe = false;
            boolean inTown = false;
            int eventType = xpp.getEventType();

            while (eventType != XmlPullParser.END_DOCUMENT) {
                String tagName = xpp.getName();

                if (eventType == XmlPullParser.START_TAG && "woeid".equals(tagName)) {
                    inWoe = true;
                } else if (eventType == XmlPullParser.TEXT && inWoe) {
                    primaryWoeid = xpp.getText();
                }

                if (eventType == XmlPullParser.START_TAG &&
                        (tagName.startsWith("locality") || tagName.startsWith("admin"))) {
                    for (int i = xpp.getAttributeCount() - 1; i >= 0; i--) {
                        String attrName = xpp.getAttributeName(i);
                        if ("type".equals(attrName)
                                && "Town".equals(xpp.getAttributeValue(i))) {
                            inTown = true;
                        } else if ("woeid".equals(attrName)) {
                            String woeid = xpp.getAttributeValue(i);
                            if (!TextUtils.isEmpty(woeid)) {
                                alternateWoeids.add(
                                        new Pair<String, String>(tagName, woeid));
                            }
                        }
                    }
                } else if (eventType == XmlPullParser.TEXT && inTown) {
                    li.town = xpp.getText();
                }

                if (eventType == XmlPullParser.END_TAG) {
                    inWoe = false;
                    inTown = false;
                }

                eventType = xpp.next();
            }

            // Add the primary woeid if it was found.
            if (!TextUtils.isEmpty(primaryWoeid)) {
                li.woeids.add(primaryWoeid);
            }

            // Sort by descending tag name to order by decreasing precision
            // (locality3, locality2, locality1, admin3, admin2, admin1, etc.)
            Collections.sort(alternateWoeids, new Comparator<Pair<String, String>>() {
                @Override
                public int compare(Pair<String, String> pair1, Pair<String, String> pair2) {
                    return pair1.first.compareTo(pair2.first);
                }
            });

            for (Pair<String, String> pair : alternateWoeids) {
                li.woeids.add(pair.second);
            }

            if (li.woeids.size() > 0) {
                return li;
            }

            throw new CantGetWeatherException(true, R.string.no_weather_data,
                    "No WOEIDs found nearby.");

        } catch (IOException e) {
            throw new CantGetWeatherException(true, R.string.no_weather_data,
                    "Error parsing place search XML", e);
        } catch (XmlPullParserException e) {
            throw new CantGetWeatherException(true, R.string.no_weather_data,
                    "Error parsing place search XML", e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    private static final int PARSE_STATE_NONE = 0;
    private static final int PARSE_STATE_PLACE = 1;
    private static final int PARSE_STATE_WOEID = 2;
    private static final int PARSE_STATE_NAME = 3;
    private static final int PARSE_STATE_COUNTRY = 4;
    private static final int PARSE_STATE_ADMIN1 = 5;

    public static List<LocationSearchResult> findLocationsAutocomplete(String startsWith) {
        LOGD(TAG, "Autocompleting locations starting with '" + startsWith + "'");

        List<LocationSearchResult> results = new ArrayList<LocationSearchResult>();

        HttpURLConnection connection = null;
        try {
            connection = Utils.openUrlConnection(buildPlaceSearchStartsWithUrl(startsWith));
            XmlPullParser xpp = sXmlPullParserFactory.newPullParser();
            xpp.setInput(new InputStreamReader(connection.getInputStream()));

            LocationSearchResult result = null;
            String name = null, country = null, admin1 = null;
            StringBuilder sb = new StringBuilder();

            int state = PARSE_STATE_NONE;
            int eventType = xpp.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                String tagName = xpp.getName();

                if (eventType == XmlPullParser.START_TAG) {
                    switch (state) {
                        case PARSE_STATE_NONE:
                            if ("place".equals(tagName)) {
                                state = PARSE_STATE_PLACE;
                                result = new LocationSearchResult();
                                name = country = admin1 = null;
                            }
                            break;

                        case PARSE_STATE_PLACE:
                            if ("name".equals(tagName)) {
                                state = PARSE_STATE_NAME;
                            } else if ("woeid".equals(tagName)) {
                                state = PARSE_STATE_WOEID;
                            } else if ("country".equals(tagName)) {
                                state = PARSE_STATE_COUNTRY;
                            } else if ("admin1".equals(tagName)) {
                                state = PARSE_STATE_ADMIN1;
                            }
                            break;
                    }

                } else if (eventType == XmlPullParser.TEXT) {
                    switch (state) {
                        case PARSE_STATE_WOEID:
                            result.woeid = xpp.getText();
                            break;

                        case PARSE_STATE_NAME:
                            name = xpp.getText();
                            break;

                        case PARSE_STATE_COUNTRY:
                            country = xpp.getText();
                            break;

                        case PARSE_STATE_ADMIN1:
                            admin1 = xpp.getText();
                            break;
                    }

                } else if (eventType == XmlPullParser.END_TAG) {
                    if ("place".equals(tagName)) {
//                        // Sort by descending tag name to order by decreasing precision
//                        // (locality3, locality2, locality1, admin3, admin2, admin1, etc.)
//                        Collections.sort(alternateWoeids, new Comparator<Pair<String, String>>() {
//                            @Override
//                            public int compare(Pair<String, String> pair1,
//                                    Pair<String, String> pair2) {
//                                return pair1.first.compareTo(pair2.first);
//                            }
//                        });
                        sb.setLength(0);
                        if (!TextUtils.isEmpty(name)) {
                            sb.append(name);
                        }
                        if (!TextUtils.isEmpty(admin1)) {
                            if (sb.length() > 0) {
                                sb.append(", ");
                            }
                            sb.append(admin1);
                        }
                        result.displayName = sb.toString();
                        result.country = country;
                        results.add(result);
                        state = PARSE_STATE_NONE;

                    } else if (state != PARSE_STATE_NONE) {
                        state = PARSE_STATE_PLACE;
                    }
                }

                eventType = xpp.next();
            }

        } catch (IOException e) {
            LOGW(TAG, "Error parsing place search XML");
        } catch (XmlPullParserException e) {
            LOGW(TAG, "Error parsing place search XML");
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }

        return results;
    }

    private static String buildWeatherQueryUrl(String woeid) {
        // http://developer.yahoo.com/weather/
        return "http://weather.yahooapis.com/forecastrss?w=" + woeid + "&u=" + sWeatherUnits;
    }

    private static String buildPlaceSearchUrl(Location l) {
        // GeoPlanet API
        return "http://where.yahooapis.com/v1/places.q('"
                + l.getLatitude() + "," + l.getLongitude() + "')"
                + "?appid=" + YahooWeatherApiConfig.APP_ID;
    }

    private static String buildPlaceSearchStartsWithUrl(String startsWith) {
        // GeoPlanet API
        startsWith = startsWith.replaceAll("[^\\w ]+", "").replaceAll(" ", "%20");
        return "http://where.yahooapis.com/v1/places.q('" + startsWith + "%2A');"
                + "count=" + MAX_SEARCH_RESULTS
                + "?appid=" + YahooWeatherApiConfig.APP_ID;
    }

    public static class LocationInfo {
        // Sorted by decreasing precision
        // (point of interest, locality3, locality2, locality1, admin3, admin2, admin1, etc.)
        List<String> woeids = new ArrayList<String>();
        String town;
    }

    public static class LocationSearchResult {
        String woeid;
        String displayName;
        String country;
    }
}




Java Source Code List

com.example.dashclock.exampleextension.ExampleExtension.java
com.example.dashclock.exampleextension.ExampleSettingsActivity.java
com.google.android.apps.dashclock.BackupAgent.java
com.google.android.apps.dashclock.DashClockService.java
com.google.android.apps.dashclock.DaydreamService.java
com.google.android.apps.dashclock.ExtensionHost.java
com.google.android.apps.dashclock.ExtensionManager.java
com.google.android.apps.dashclock.ExtensionPackageChangeReceiver.java
com.google.android.apps.dashclock.HelpUtils.java
com.google.android.apps.dashclock.LogAttachmentProvider.java
com.google.android.apps.dashclock.LogUtils.java
com.google.android.apps.dashclock.PeriodicExtensionRefreshReceiver.java
com.google.android.apps.dashclock.Utils.java
com.google.android.apps.dashclock.WidgetClickProxyActivity.java
com.google.android.apps.dashclock.WidgetProvider.java
com.google.android.apps.dashclock.api.DashClockExtension.java
com.google.android.apps.dashclock.api.ExtensionData.java
com.google.android.apps.dashclock.api.VisibleExtension.java
com.google.android.apps.dashclock.api.package-info.java
com.google.android.apps.dashclock.calendar.CalendarExtension.java
com.google.android.apps.dashclock.calendar.CalendarSelectionPreference.java
com.google.android.apps.dashclock.calendar.CalendarSettingsActivity.java
com.google.android.apps.dashclock.configuration.AppChooserPreference.java
com.google.android.apps.dashclock.configuration.AppearanceConfig.java
com.google.android.apps.dashclock.configuration.BaseSettingsActivity.java
com.google.android.apps.dashclock.configuration.ColorPreference.java
com.google.android.apps.dashclock.configuration.ConfigurationActivity.java
com.google.android.apps.dashclock.configuration.ConfigureAdvancedFragment.java
com.google.android.apps.dashclock.configuration.ConfigureAppearanceFragment.java
com.google.android.apps.dashclock.configuration.ConfigureDaydreamFragment.java
com.google.android.apps.dashclock.configuration.ConfigureExtensionsFragment.java
com.google.android.apps.dashclock.configuration.DaydreamProxyActivity.java
com.google.android.apps.dashclock.gmail.GmailContract.java
com.google.android.apps.dashclock.gmail.GmailExtension.java
com.google.android.apps.dashclock.gmail.GmailSettingsActivity.java
com.google.android.apps.dashclock.nextalarm.NextAlarmExtension.java
com.google.android.apps.dashclock.nextalarm.NextAlarmSettingsActivity.java
com.google.android.apps.dashclock.phone.MissedCallsExtension.java
com.google.android.apps.dashclock.phone.SmsExtension.java
com.google.android.apps.dashclock.phone.TelephonyProviderConstants.java
com.google.android.apps.dashclock.render.DashClockRenderer.java
com.google.android.apps.dashclock.render.SimpleRenderer.java
com.google.android.apps.dashclock.render.SimpleViewBuilder.java
com.google.android.apps.dashclock.render.ViewBuilder.java
com.google.android.apps.dashclock.render.WidgetRemoteViewsFactoryService.java
com.google.android.apps.dashclock.render.WidgetRenderer.java
com.google.android.apps.dashclock.render.WidgetViewBuilder.java
com.google.android.apps.dashclock.ui.DragGripView.java
com.google.android.apps.dashclock.ui.EdgeEffectUtil.java
com.google.android.apps.dashclock.ui.PagerPositionStrip.java
com.google.android.apps.dashclock.ui.SimplePagedTabsHelper.java
com.google.android.apps.dashclock.ui.SwipeDismissListViewTouchListener.java
com.google.android.apps.dashclock.ui.UndoBarController.java
com.google.android.apps.dashclock.weather.CantGetWeatherException.java
com.google.android.apps.dashclock.weather.WeatherData.java
com.google.android.apps.dashclock.weather.WeatherExtension.java
com.google.android.apps.dashclock.weather.WeatherLocationPreference.java
com.google.android.apps.dashclock.weather.WeatherRetryReceiver.java
com.google.android.apps.dashclock.weather.WeatherSettingsActivity.java
com.google.android.apps.dashclock.weather.YahooWeatherApiClient.java
com.google.android.apps.dashclock.weather.YahooWeatherApiConfig.java