diff --git a/app/build.gradle b/app/build.gradle index 4d476dfe..9618e3f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -29,5 +29,7 @@ dependencies { compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:design:22.2.0' compile 'com.android.support:recyclerview-v7:22.2.0' + compile 'com.google.android.apps.muzei:muzei-api:2.0' compile 'com.google.android.gms:play-services-gcm:7.5.0' + compile 'com.google.android.gms:play-services-location:7.5.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1ae3cdd4..a8893d32 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -39,6 +39,9 @@ android:protectionLevel="signature" /> + + + + + + + + + + + = 300 && weatherId <= 321) { stringId = R.string.condition_3xx; - } else switch(weatherId) { + } else switch (weatherId) { case 500: stringId = R.string.condition_500; break; @@ -502,6 +502,42 @@ public static String getStringForWeatherCondition(Context context, int weatherId return context.getString(stringId); } + /* + * Helper method to provide the correct image according to the weather condition id returned + * by the OpenWeatherMap call. + * + * @param weatherId from OpenWeatherMap API response + * @return A string URL to an appropriate image or null if no mapping is found + */ + public static String getImageUrlForWeatherCondition(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 "http://upload.wikimedia.org/wikipedia/commons/2/28/Thunderstorm_in_Annemasse,_France.jpg"; + } else if (weatherId >= 300 && weatherId <= 321) { + return "http://upload.wikimedia.org/wikipedia/commons/a/a0/Rain_on_leaf_504605006.jpg"; + } else if (weatherId >= 500 && weatherId <= 504) { + return "http://upload.wikimedia.org/wikipedia/commons/6/6c/Rain-on-Thassos.jpg"; + } else if (weatherId == 511) { + return "http://upload.wikimedia.org/wikipedia/commons/b/b8/Fresh_snow.JPG"; + } else if (weatherId >= 520 && weatherId <= 531) { + return "http://upload.wikimedia.org/wikipedia/commons/6/6c/Rain-on-Thassos.jpg"; + } else if (weatherId >= 600 && weatherId <= 622) { + return "http://upload.wikimedia.org/wikipedia/commons/b/b8/Fresh_snow.JPG"; + } else if (weatherId >= 701 && weatherId <= 761) { + return "http://upload.wikimedia.org/wikipedia/commons/e/e6/Westminster_fog_-_London_-_UK.jpg"; + } else if (weatherId == 761 || weatherId == 781) { + return "http://upload.wikimedia.org/wikipedia/commons/d/dc/Raised_dust_ahead_of_a_severe_thunderstorm_1.jpg"; + } else if (weatherId == 800) { + return "http://upload.wikimedia.org/wikipedia/commons/7/7e/A_few_trees_and_the_sun_(6009964513).jpg"; + } else if (weatherId == 801) { + return "http://upload.wikimedia.org/wikipedia/commons/e/e7/Cloudy_Blue_Sky_(5031259890).jpg"; + } else if (weatherId >= 802 && weatherId <= 804) { + return "http://upload.wikimedia.org/wikipedia/commons/5/54/Cloudy_hills_in_Elis,_Greece_2.jpg"; + } + return null; + } + /** * Returns true if the network is available or about to become available. * diff --git a/app/src/main/java/com/example/android/sunshine/app/muzei/WeatherMuzeiSource.java b/app/src/main/java/com/example/android/sunshine/app/muzei/WeatherMuzeiSource.java new file mode 100644 index 00000000..dcfc24cb --- /dev/null +++ b/app/src/main/java/com/example/android/sunshine/app/muzei/WeatherMuzeiSource.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 The Android Open Source 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.example.android.sunshine.app.muzei; + +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; + +import com.example.android.sunshine.app.MainActivity; +import com.example.android.sunshine.app.Utility; +import com.example.android.sunshine.app.data.WeatherContract; +import com.example.android.sunshine.app.sync.SunshineSyncAdapter; +import com.google.android.apps.muzei.api.Artwork; +import com.google.android.apps.muzei.api.MuzeiArtSource; + +/** + * Muzei source that changes your background based on the current weather conditions + */ +public class WeatherMuzeiSource extends MuzeiArtSource { + private static final String[] FORECAST_COLUMNS = new String[]{ + WeatherContract.WeatherEntry.COLUMN_WEATHER_ID, + WeatherContract.WeatherEntry.COLUMN_SHORT_DESC + }; + // these indices must match the projection + private static final int INDEX_WEATHER_ID = 0; + private static final int INDEX_SHORT_DESC = 1; + + public WeatherMuzeiSource() { + super("WeatherMuzeiSource"); + } + + @Override + protected void onHandleIntent(Intent intent) { + super.onHandleIntent(intent); + boolean dataUpdated = intent != null && + SunshineSyncAdapter.ACTION_DATA_UPDATED.equals(intent.getAction()); + if (dataUpdated && isEnabled()) { + onUpdate(UPDATE_REASON_OTHER); + } + } + + @Override + protected void onUpdate(int reason) { + String location = Utility.getPreferredLocation(this); + Uri weatherForLocationUri = WeatherContract.WeatherEntry.buildWeatherLocationWithStartDate( + location, System.currentTimeMillis()); + Cursor cursor = getContentResolver().query(weatherForLocationUri, FORECAST_COLUMNS, null, + null, WeatherContract.WeatherEntry.COLUMN_DATE + " ASC"); + if (cursor.moveToFirst()) { + int weatherId = cursor.getInt(INDEX_WEATHER_ID); + String desc = cursor.getString(INDEX_SHORT_DESC); + + String imageUrl = Utility.getImageUrlForWeatherCondition(weatherId); + // Only publish a new wallpaper if we have a valid image + if (imageUrl != null) { + publishArtwork(new Artwork.Builder() + .imageUri(Uri.parse(imageUrl)) + .title(desc) + .byline(location) + .viewIntent(new Intent(this, MainActivity.class)) + .build()); + } + } + cursor.close(); + } +} 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 c9275d0e..5968effe 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 @@ -34,6 +34,7 @@ import com.example.android.sunshine.app.R; import com.example.android.sunshine.app.Utility; import com.example.android.sunshine.app.data.WeatherContract; +import com.example.android.sunshine.app.muzei.WeatherMuzeiSource; import org.json.JSONArray; import org.json.JSONException; @@ -341,6 +342,7 @@ private void getWeatherDataFromJson(String forecastJsonStr, new String[] {Long.toString(dayTime.setJulianDay(julianStartDay-1))}); updateWidgets(); + updateMuzei(); notifyWeather(); } Log.d(LOG_TAG, "Sync Complete. " + cVVector.size() + " Inserted"); @@ -361,6 +363,16 @@ private void updateWidgets() { context.sendBroadcast(dataUpdatedIntent); } + private void updateMuzei() { + // Muzei is only compatible with Jelly Bean MR1+ devices, so there's no need to update the + // Muzei background on lower API level devices + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + Context context = getContext(); + context.startService(new Intent(ACTION_DATA_UPDATED) + .setClass(context, WeatherMuzeiSource.class)); + } + } + private void notifyWeather() { Context context = getContext(); //checking the last update and notify if it' the first of the day diff --git a/app/src/main/res/drawable-hdpi/ic_current_location.png b/app/src/main/res/drawable-hdpi/ic_current_location.png new file mode 100644 index 00000000..85e38726 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_current_location.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_current_location.png b/app/src/main/res/drawable-mdpi/ic_current_location.png new file mode 100644 index 00000000..5684aa7d Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_current_location.png differ diff --git a/app/src/main/res/drawable-nodpi/ic_muzei.png b/app/src/main/res/drawable-nodpi/ic_muzei.png new file mode 100755 index 00000000..b0fe3c49 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/ic_muzei.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_current_location.png b/app/src/main/res/drawable-xhdpi/ic_current_location.png new file mode 100644 index 00000000..7faa3455 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_current_location.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_current_location.png b/app/src/main/res/drawable-xxhdpi/ic_current_location.png new file mode 100644 index 00000000..d3a1ab08 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_current_location.png differ diff --git a/app/src/main/res/layout/pref_current_location.xml b/app/src/main/res/layout/pref_current_location.xml new file mode 100644 index 00000000..a5d79382 --- /dev/null +++ b/app/src/main/res/layout/pref_current_location.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 74e7690a..cd9580a9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -48,6 +48,9 @@ 94043 + + Use my location + Invalid Location (%1$s)" Validating Location... (%1$s)" @@ -140,6 +143,9 @@ Sunshine Today Sunshine Details + + Today\'s weather + No Weather Information Available No weather information available. The network is not available to fetch weather data.