From 822d52bb4b37909a29430b0f6d94309970acb90f Mon Sep 17 00:00:00 2001 From: Dan Galpin Date: Sun, 24 May 2015 17:47:02 -0700 Subject: [PATCH] Integrate Glide to load weather art icons from an external source --- app/build.gradle | 1 + .../android/sunshine/app/DetailFragment.java | 7 +++- .../android/sunshine/app/ForecastAdapter.java | 19 +++++++--- .../example/android/sunshine/app/Utility.java | 37 +++++++++++++++++++ .../app/sync/SunshineSyncAdapter.java | 32 +++++++++++++++- app/src/main/res/layout/fragment_detail.xml | 3 +- .../main/res/layout/fragment_detail_wide.xml | 3 +- .../main/res/layout/list_item_forecast.xml | 3 +- .../res/layout/list_item_forecast_today.xml | 3 +- app/src/main/res/values/dimens.xml | 2 + app/src/main/res/values/strings.xml | 3 ++ 11 files changed, 101 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 28b1396..c83808d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,6 +21,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.github.bumptech.glide:glide:3.5.2' compile 'com.android.support:appcompat-v7:21.0.2' compile 'com.android.support:support-annotations:22.0.0' } diff --git a/app/src/main/java/com/example/android/sunshine/app/DetailFragment.java b/app/src/main/java/com/example/android/sunshine/app/DetailFragment.java index 04ff14d..0c88c6f 100644 --- a/app/src/main/java/com/example/android/sunshine/app/DetailFragment.java +++ b/app/src/main/java/com/example/android/sunshine/app/DetailFragment.java @@ -34,6 +34,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.bumptech.glide.Glide; import com.example.android.sunshine.app.data.WeatherContract; import com.example.android.sunshine.app.data.WeatherContract.WeatherEntry; @@ -184,7 +185,11 @@ public class DetailFragment extends Fragment implements LoaderManager.LoaderCall int weatherId = data.getInt(COL_WEATHER_CONDITION_ID); // Use weather art image - mIconView.setImageResource(Utility.getArtResourceForWeatherCondition(weatherId)); + Glide.with(this) + .load(Utility.getArtUrlForWeatherCondition(getActivity(), weatherId)) + .error(Utility.getArtResourceForWeatherCondition(weatherId)) + .crossFade() + .into(mIconView); // Read date from cursor and update views for day of week and date long date = data.getLong(COL_WEATHER_DATE); diff --git a/app/src/main/java/com/example/android/sunshine/app/ForecastAdapter.java b/app/src/main/java/com/example/android/sunshine/app/ForecastAdapter.java index 6c200ad..0b404e2 100644 --- a/app/src/main/java/com/example/android/sunshine/app/ForecastAdapter.java +++ b/app/src/main/java/com/example/android/sunshine/app/ForecastAdapter.java @@ -24,6 +24,8 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.bumptech.glide.Glide; + /** * {@link ForecastAdapter} exposes a list of weather forecasts * from a {@link Cursor} to a {@link android.widget.ListView}. @@ -91,20 +93,27 @@ public class ForecastAdapter extends CursorAdapter { int viewType = getItemViewType(cursor.getPosition()); int weatherId = cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID); + int fallbackIconId; switch (viewType) { case VIEW_TYPE_TODAY: { // Get weather icon - viewHolder.iconView.setImageResource(Utility.getArtResourceForWeatherCondition( - weatherId)); + fallbackIconId = Utility.getArtResourceForWeatherCondition( + weatherId); break; } - case VIEW_TYPE_FUTURE_DAY: { + default: { // Get weather icon - viewHolder.iconView.setImageResource(Utility.getIconResourceForWeatherCondition( - weatherId)); + fallbackIconId = Utility.getIconResourceForWeatherCondition( + weatherId); break; } } + + Glide.with(mContext) + .load(Utility.getArtUrlForWeatherCondition(mContext, weatherId)) + .error(fallbackIconId) + .crossFade() + .into(viewHolder.iconView); // Read date from cursor long dateInMillis = cursor.getLong(ForecastFragment.COL_WEATHER_DATE); diff --git a/app/src/main/java/com/example/android/sunshine/app/Utility.java b/app/src/main/java/com/example/android/sunshine/app/Utility.java index 2e76fb7..73f424a 100644 --- a/app/src/main/java/com/example/android/sunshine/app/Utility.java +++ b/app/src/main/java/com/example/android/sunshine/app/Utility.java @@ -216,6 +216,43 @@ public class Utility { return -1; } + /** + * Helper method to provide the art urls according to the weather condition id returned + * by the OpenWeatherMap call. + * + * @param context Context to use for retrieving the URL format + * @param weatherId from OpenWeatherMap API response + * @return url for the corresponding weather artwork. null if no relation is found. + */ + public static String getArtUrlForWeatherCondition(Context context, int weatherId) { + // Based on weather code data found at: + // http://bugs.openweathermap.org/projects/api/wiki/Weather_Condition_Codes + if (weatherId >= 200 && weatherId <= 232) { + return context.getString(R.string.format_art_url, "storm"); + } else if (weatherId >= 300 && weatherId <= 321) { + return context.getString(R.string.format_art_url, "light_rain"); + } else if (weatherId >= 500 && weatherId <= 504) { + return context.getString(R.string.format_art_url, "rain"); + } else if (weatherId == 511) { + return context.getString(R.string.format_art_url, "snow"); + } else if (weatherId >= 520 && weatherId <= 531) { + return context.getString(R.string.format_art_url, "rain"); + } else if (weatherId >= 600 && weatherId <= 622) { + return context.getString(R.string.format_art_url, "snow"); + } else if (weatherId >= 701 && weatherId <= 761) { + return context.getString(R.string.format_art_url, "fog"); + } else if (weatherId == 761 || weatherId == 781) { + return context.getString(R.string.format_art_url, "storm"); + } else if (weatherId == 800) { + return context.getString(R.string.format_art_url, "clear"); + } else if (weatherId == 801) { + return context.getString(R.string.format_art_url, "light_clouds"); + } else if (weatherId >= 802 && weatherId <= 804) { + return context.getString(R.string.format_art_url, "clouds"); + } + return null; + } + /** * Helper method to provide the art resource id according to the weather condition id returned * by the OpenWeatherMap call. diff --git a/app/src/main/java/com/example/android/sunshine/app/sync/SunshineSyncAdapter.java b/app/src/main/java/com/example/android/sunshine/app/sync/SunshineSyncAdapter.java index 0ce1a77..21e39e0 100644 --- a/app/src/main/java/com/example/android/sunshine/app/sync/SunshineSyncAdapter.java +++ b/app/src/main/java/com/example/android/sunshine/app/sync/SunshineSyncAdapter.java @@ -2,6 +2,7 @@ package com.example.android.sunshine.app.sync; import android.accounts.Account; import android.accounts.AccountManager; +import android.annotation.SuppressLint; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.AbstractThreadedSyncAdapter; @@ -28,6 +29,7 @@ import android.support.v4.app.TaskStackBuilder; import android.text.format.Time; import android.util.Log; +import com.bumptech.glide.Glide; import com.example.android.sunshine.app.MainActivity; import com.example.android.sunshine.app.R; import com.example.android.sunshine.app.Utility; @@ -46,6 +48,7 @@ import java.lang.annotation.RetentionPolicy; import java.net.HttpURLConnection; import java.net.URL; import java.util.Vector; +import java.util.concurrent.ExecutionException; public class SunshineSyncAdapter extends AbstractThreadedSyncAdapter { public final String LOG_TAG = SunshineSyncAdapter.class.getSimpleName(); @@ -377,8 +380,33 @@ public class SunshineSyncAdapter extends AbstractThreadedSyncAdapter { int iconId = Utility.getIconResourceForWeatherCondition(weatherId); Resources resources = context.getResources(); - Bitmap largeIcon = BitmapFactory.decodeResource(resources, - Utility.getArtResourceForWeatherCondition(weatherId)); + int artResourceId = Utility.getArtResourceForWeatherCondition(weatherId); + String artUrl = Utility.getArtUrlForWeatherCondition(context, weatherId); + + // On Honeycomb and higher devices, we can retrieve the size of the large icon + // Prior to that, we use a fixed size + @SuppressLint("InlinedApi") + int largeIconWidth = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB + ? resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_width) + : resources.getDimensionPixelSize(R.dimen.notification_large_icon_default); + @SuppressLint("InlinedApi") + int largeIconHeight = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB + ? resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_height) + : resources.getDimensionPixelSize(R.dimen.notification_large_icon_default); + + // Retrieve the large icon + Bitmap largeIcon; + try { + largeIcon = Glide.with(context) + .load(artUrl) + .asBitmap() + .error(artResourceId) + .fitCenter() + .into(largeIconWidth, largeIconHeight).get(); + } catch (InterruptedException | ExecutionException e) { + Log.e(LOG_TAG, "Error retrieving large icon from " + artUrl, e); + largeIcon = BitmapFactory.decodeResource(resources, artResourceId); + } String title = context.getString(R.string.app_name); // Define the text of the forecast. diff --git a/app/src/main/res/layout/fragment_detail.xml b/app/src/main/res/layout/fragment_detail.xml index 29c2793..be69a26 100644 --- a/app/src/main/res/layout/fragment_detail.xml +++ b/app/src/main/res/layout/fragment_detail.xml @@ -83,7 +83,8 @@ + android:layout_height="wrap_content" + android:adjustViewBounds="true" /> + android:layout_width="wrap_content" + android:adjustViewBounds="true" /> + android:layout_height="wrap_content" + android:adjustViewBounds="true"/> diff --git a/app/src/main/res/layout/list_item_forecast_today.xml b/app/src/main/res/layout/list_item_forecast_today.xml index 76daab3..55e0353 100644 --- a/app/src/main/res/layout/list_item_forecast_today.xml +++ b/app/src/main/res/layout/list_item_forecast_today.xml @@ -71,7 +71,8 @@ android:id="@+id/list_item_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal"/> + android:layout_gravity="center_horizontal" + android:adjustViewBounds="true"/> 16dp 16dp + + 48dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f83ebc9..f0b386a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -81,6 +81,9 @@ imperial + + https://raw.githubusercontent.com/udacity/Sunshine-Version-2/sunshine_master/app/src/main/res/drawable-xxhdpi/art_%s.png + Today