From 564ddf06643cae5c489186069db6985834b8280a Mon Sep 17 00:00:00 2001 From: "gu.martinm@gmail.com" Date: Mon, 22 Sep 2014 21:52:52 +0200 Subject: [PATCH] WeatherInformation: notification with alarm --- AndroidManifest.xml | 2 +- res/layout/notification.xml | 63 ++++++++ res/values/arrays.xml | 20 +-- res/xml/weather_preferences.xml | 4 +- .../exampletdd/WeatherInformationBatch.java | 177 ++++++++++++++------- .../exampletdd/WeatherInformationBootReceiver.java | 40 +++-- .../fragment/current/CurrentFragment.java | 20 ++- .../fragment/overview/OverviewFragment.java | 22 +-- .../WeatherInformationPreferencesFragment.java | 113 +++++++++---- 9 files changed, 327 insertions(+), 134 deletions(-) create mode 100644 res/layout/notification.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9da7fb2..93b2253 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -84,7 +84,7 @@ + android:enabled="true"> diff --git a/res/layout/notification.xml b/res/layout/notification.xml new file mode 100644 index 0000000..cf741fd --- /dev/null +++ b/res/layout/notification.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/values/arrays.xml b/res/values/arrays.xml index e7a46df..5900023 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -69,17 +69,19 @@ 14-Day Forecast - 60 - 120 - 300 - 600 + 0 900 + 1800 + 3600 + 43200 + 86400 - 1 minute - 2 minutes - 5 minutes - 10 minutes - 15 minutes + no updates + fifteen minutes + half hour + one hour + half day + one day diff --git a/res/xml/weather_preferences.xml b/res/xml/weather_preferences.xml index 8ee76dc..c3449ab 100644 --- a/res/xml/weather_preferences.xml +++ b/res/xml/weather_preferences.xml @@ -14,10 +14,10 @@ android:entryValues="@array/weather_preferences_update_time_rate" android:key="@string/weather_preferences_update_time_rate_key" android:title="@string/weather_preferences_update_time_rate" - android:defaultValue="60" + android:defaultValue="0" android:persistent="true" android:selectable="true" - android:summary="1 minute"/> + android:summary="no updates"/> 0) { + description = current.getWeather().get(0).getDescription(); + } + + - // Update weather views. - final Intent updateCurrentWeather = new Intent( - "de.example.exampletdd.UPDATECURRENTWEATHER"); - LocalBroadcastManager.getInstance(WeatherInformationBatch.this).sendBroadcast( - updateCurrentWeather); - final Intent updateOverviewWeather = new Intent( - "de.example.exampletdd.UPDATEOVERVIEWWEATHER"); - LocalBroadcastManager.getInstance(WeatherInformationBatch.this).sendBroadcast( - updateOverviewWeather); - } - - private WeatherLocation queryDataBase() { + final Intent resultIntent = new Intent(this.getApplicationContext(), WeatherTabsActivity.class); + // The PendingIntent to launch our activity if the user selects this notification +// final PendingIntent contentIntent = PendingIntent.getActivity( +// this.getApplicationContext(), 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT); + // The stack builder object will contain an artificial back stack for the started Activity. + // This ensures that navigating backward from the Activity leads out of + // your application to the Home screen. + final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext()); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(WeatherTabsActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + final PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); - // TODO: repeating the same code!!! - final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this); - try { - final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper); - return queryDb.queryDataBase(); - } finally { - dbHelper.close(); - } + final NotificationManagerCompat notificationManager = + NotificationManagerCompat.from(this.getApplicationContext()); + + + final NotificationCompat.Builder notificationBuilder = + new NotificationCompat.Builder(this.getApplicationContext()) + .setSmallIcon(R.drawable.ic_launcher) + .setContentText(description) + .setContentTitle(this.getText(R.string.app_name)) + .setAutoCancel(true) + .setLocalOnly(true) + .setContentIntent(resultPendingIntent) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setNumber(666); + final Notification notification = notificationBuilder.build(); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + + // Send the notification. + // Sets an ID for the notification, so it can be updated (just in case) + int notifyID = 1; + notificationManager.notify(notifyID, notification); } } diff --git a/src/de/example/exampletdd/WeatherInformationBootReceiver.java b/src/de/example/exampletdd/WeatherInformationBootReceiver.java index 29852ba..a2a8f14 100644 --- a/src/de/example/exampletdd/WeatherInformationBootReceiver.java +++ b/src/de/example/exampletdd/WeatherInformationBootReceiver.java @@ -13,26 +13,38 @@ public class WeatherInformationBootReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { - // TODO: there should be some option in the application if user does not want to set - // alarm in boot time. - + if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { + + // Update Time Rate final SharedPreferences sharedPreferences = PreferenceManager .getDefaultSharedPreferences(context); final String keyPreference = context .getString(R.string.weather_preferences_update_time_rate_key); - final String updateTimeRate = sharedPreferences.getString(keyPreference, ""); - final int timeRate = Integer.valueOf(updateTimeRate); + final String updateTimeRate = sharedPreferences.getString(keyPreference, ""); + long chosenInterval = 0; + if (updateTimeRate.equals("900")) { + chosenInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES; + } else if (updateTimeRate.equals("1800")) { + chosenInterval = AlarmManager.INTERVAL_HALF_HOUR; + } else if (updateTimeRate.equals("3600")) { + chosenInterval = AlarmManager.INTERVAL_HOUR; + } else if (updateTimeRate.equals("43200")) { + chosenInterval = AlarmManager.INTERVAL_HALF_DAY; + } else if (updateTimeRate.equals("86400")) { + chosenInterval = AlarmManager.INTERVAL_DAY; + } - final AlarmManager alarmMgr = (AlarmManager) context - .getSystemService(Context.ALARM_SERVICE); - // TODO: better use some string instead of .class? In case I change the service class - // this could be a problem (I guess) - final Intent serviceIntent = new Intent(context, WeatherInformationBatch.class); - final PendingIntent alarmIntent = PendingIntent.getService(context, 0, serviceIntent, - PendingIntent.FLAG_UPDATE_CURRENT); - alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() - + (timeRate * 1000), (timeRate * 1000), alarmIntent); + if (chosenInterval != 0) { + final AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + // TODO: better use some string instead of .class? In case I change the service class + // this could be a problem (I guess) + final Intent serviceIntent = new Intent(context, WeatherInformationBatch.class); + final PendingIntent alarmIntent = PendingIntent.getService(context, 0, serviceIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + + chosenInterval, chosenInterval, alarmIntent); + } } } diff --git a/src/de/example/exampletdd/fragment/current/CurrentFragment.java b/src/de/example/exampletdd/fragment/current/CurrentFragment.java index cb21ffb..b9737a7 100644 --- a/src/de/example/exampletdd/fragment/current/CurrentFragment.java +++ b/src/de/example/exampletdd/fragment/current/CurrentFragment.java @@ -167,7 +167,7 @@ public class CurrentFragment extends Fragment { private void updateUI(final Current current) { final SharedPreferences sharedPreferences = PreferenceManager - .getDefaultSharedPreferences(this.getActivity()); + .getDefaultSharedPreferences(this.getActivity().getApplicationContext()); // TODO: repeating the same code in Overview, Specific and Current!!! // 1. Update units of measurement. @@ -332,13 +332,13 @@ public class CurrentFragment extends Fragment { private class CurrentTask extends AsyncTask { // Store the context passed to the AsyncTask when the system instantiates it. private final Context localContext; - final CustomHTTPClient weatherHTTPClient; + final CustomHTTPClient HTTPClient; final ServiceParser weatherService; - public CurrentTask(final Context context, final CustomHTTPClient weatherHTTPClient, + public CurrentTask(final Context context, final CustomHTTPClient HTTPClient, final ServiceParser weatherService) { this.localContext = context; - this.weatherHTTPClient = weatherHTTPClient; + this.HTTPClient = HTTPClient; this.weatherService = weatherService; } @@ -350,7 +350,7 @@ public class CurrentFragment extends Fragment { Current current = null; try { - current = this.doInBackgroundThrowable(latitude, longitude, weatherHTTPClient, weatherService); + current = this.doInBackgroundThrowable(latitude, longitude); } catch (final JsonParseException e) { Log.e(TAG, "CurrentTask doInBackground exception: ", e); } catch (final ClientProtocolException e) { @@ -363,22 +363,20 @@ public class CurrentFragment extends Fragment { // logger infrastructure swallows UnknownHostException :/ Log.e(TAG, "CurrentTask doInBackground exception: " + e.getMessage(), e); } finally { - weatherHTTPClient.close(); + HTTPClient.close(); } return current; } - private Current doInBackgroundThrowable(final double latitude, final double longitude, - final CustomHTTPClient HTTPClient, final ServiceParser serviceParser) + private Current doInBackgroundThrowable(final double latitude, final double longitude) throws URISyntaxException, ClientProtocolException, JsonParseException, IOException { final String APIVersion = localContext.getResources().getString(R.string.api_version); final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_today); final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, latitude, longitude); - final String jsonData = weatherHTTPClient.retrieveDataAsString(new URL(url)); - final Current current = weatherService - .retrieveCurrentFromJPOS(jsonData); + final String jsonData = HTTPClient.retrieveDataAsString(new URL(url)); + final Current current = weatherService.retrieveCurrentFromJPOS(jsonData); // TODO: what is this for? I guess I could skip it :/ final Calendar now = Calendar.getInstance(); current.setDate(now.getTime()); diff --git a/src/de/example/exampletdd/fragment/overview/OverviewFragment.java b/src/de/example/exampletdd/fragment/overview/OverviewFragment.java index 88d4863..28da6cf 100644 --- a/src/de/example/exampletdd/fragment/overview/OverviewFragment.java +++ b/src/de/example/exampletdd/fragment/overview/OverviewFragment.java @@ -127,6 +127,9 @@ public class OverviewFragment extends ListFragment { final WeatherLocation weatherLocation = query.queryDataBase(); if (weatherLocation == null) { // Nothing to do. + // Empty list and show error message (see setEmptyText in onCreate) + this.setListAdapter(null); + this.setListShownNoAnimation(true); return; } @@ -194,7 +197,7 @@ public class OverviewFragment extends ListFragment { private void updateUI(final Forecast forecastWeatherData) { final SharedPreferences sharedPreferences = PreferenceManager - .getDefaultSharedPreferences(this.getActivity()); + .getDefaultSharedPreferences(this.getActivity().getApplicationContext()); // TODO: repeating the same code in Overview, Specific and Current!!! // 1. Update units of measurement. @@ -306,13 +309,13 @@ public class OverviewFragment extends ListFragment { private class OverviewTask extends AsyncTask { // Store the context passed to the AsyncTask when the system instantiates it. private final Context localContext; - private final CustomHTTPClient weatherHTTPClient; + private final CustomHTTPClient HTTPClient; private final ServiceParser weatherService; - public OverviewTask(final Context context, final CustomHTTPClient weatherHTTPClient, + public OverviewTask(final Context context, final CustomHTTPClient HTTPClient, final ServiceParser weatherService) { this.localContext = context; - this.weatherHTTPClient = weatherHTTPClient; + this.HTTPClient = HTTPClient; this.weatherService = weatherService; } @@ -325,7 +328,7 @@ public class OverviewFragment extends ListFragment { Forecast forecast = null; try { - forecast = this.doInBackgroundThrowable(latitude, longitude, weatherHTTPClient, weatherService); + forecast = this.doInBackgroundThrowable(latitude, longitude); } catch (final JsonParseException e) { Log.e(TAG, "OverviewTask doInBackground exception: ", e); } catch (final ClientProtocolException e) { @@ -338,23 +341,22 @@ public class OverviewFragment extends ListFragment { // logger infrastructure swallows UnknownHostException :/ Log.e(TAG, "OverviewTask doInBackground exception: " + e.getMessage(), e); } finally { - weatherHTTPClient.close(); + HTTPClient.close(); } return forecast; } - private Forecast doInBackgroundThrowable(final double latitude, final double longitude, - final CustomHTTPClient HTTPClient, final ServiceParser serviceParser) + private Forecast doInBackgroundThrowable(final double latitude, final double longitude) throws URISyntaxException, ClientProtocolException, JsonParseException, IOException { final String APIVersion = localContext.getResources().getString(R.string.api_version); final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_forecast); // TODO: number as resource - final String url = serviceParser.createURIAPIForecast(urlAPI, APIVersion, latitude, longitude, "14"); + final String url = weatherService.createURIAPIForecast(urlAPI, APIVersion, latitude, longitude, "14"); final String jsonData = HTTPClient.retrieveDataAsString(new URL(url)); - return serviceParser.retrieveForecastFromJPOS(jsonData); + return weatherService.retrieveForecastFromJPOS(jsonData); } @Override diff --git a/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java b/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java index c4a7573..f8a4838 100644 --- a/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java +++ b/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java @@ -1,14 +1,20 @@ package de.example.exampletdd.fragment.preferences; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; +import android.os.SystemClock; import android.preference.Preference; import android.preference.PreferenceFragment; import de.example.exampletdd.R; +import de.example.exampletdd.WeatherInformationBatch; -public class WeatherInformationPreferencesFragment extends PreferenceFragment -implements OnSharedPreferenceChangeListener { +public class WeatherInformationPreferencesFragment extends PreferenceFragment + implements OnSharedPreferenceChangeListener { @Override public void onCreate(final Bundle savedInstanceState) { @@ -16,33 +22,39 @@ implements OnSharedPreferenceChangeListener { // Load the preferences from an XML resource this.addPreferencesFromResource(R.xml.weather_preferences); - - String keyPreference = this.getActivity().getString( + + + // Units of Measurement + String keyPreference = this.getActivity().getApplicationContext().getString( R.string.weather_preferences_units_key); Preference connectionPref = this.findPreference(keyPreference); connectionPref.setSummary(this.getPreferenceManager() .getSharedPreferences().getString(keyPreference, "")); - - keyPreference = this.getActivity().getString( + + // Update Time Rate + keyPreference = this.getActivity().getApplicationContext().getString( R.string.weather_preferences_update_time_rate_key); connectionPref = this.findPreference(keyPreference); String value = this.getPreferenceManager().getSharedPreferences() .getString(keyPreference, ""); String humanValue = ""; - if (value.equals("60")) { - humanValue = "1 minute"; - } else if (value.equals("120")) { - humanValue = "2 minutes"; - } else if (value.equals("300")) { - humanValue = "5 minutes"; - } else if (value.equals("600")) { - humanValue = "10 minutes"; + if (value.equals("0")) { + humanValue = "no updates"; } else if (value.equals("900")) { - humanValue = "15 minutes"; + humanValue = "fifteen minutes"; + } else if (value.equals("1800")) { + humanValue = "half hour"; + } else if (value.equals("3600")) { + humanValue = "one hour"; + } else if (value.equals("43200")) { + humanValue = "half day"; + } else if (value.equals("86400")) { + humanValue = "one day"; } connectionPref.setSummary(humanValue); - - keyPreference = this.getActivity().getString( + + // Forecast days number + keyPreference = this.getActivity().getApplicationContext().getString( R.string.weather_preferences_day_forecast_key); connectionPref = this.findPreference(keyPreference); value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, ""); @@ -75,7 +87,9 @@ implements OnSharedPreferenceChangeListener { @Override public void onSharedPreferenceChanged( final SharedPreferences sharedPreferences, final String key) { - String keyValue = this.getActivity().getString( + + // Units of Measurement + String keyValue = this.getActivity().getApplicationContext().getString( R.string.weather_preferences_units_key); if (key.equals(keyValue)) { @@ -84,26 +98,33 @@ implements OnSharedPreferenceChangeListener { return; } - keyValue = this.getActivity().getString(R.string.weather_preferences_update_time_rate_key); + // Update Time Rate + keyValue = this.getActivity().getApplicationContext().getString( + R.string.weather_preferences_update_time_rate_key); if (key.equals(keyValue)) { final Preference connectionPref = this.findPreference(key); final String value = sharedPreferences.getString(key, ""); String humanValue = ""; - if (value.equals("60")) { - humanValue = "1 minute"; - } else if (value.equals("120")) { - humanValue = "2 minutes"; - } else if (value.equals("300")) { - humanValue = "5 minutes"; - } else if (value.equals("600")) { - humanValue = "10 minutes"; + if (value.equals("0")) { + humanValue = "no updates"; } else if (value.equals("900")) { - humanValue = "15 minutes"; + humanValue = "fifteen minutes"; + } else if (value.equals("1800")) { + humanValue = "half hour"; + } else if (value.equals("3600")) { + humanValue = "one hour"; + } else if (value.equals("43200")) { + humanValue = "half day"; + } else if (value.equals("86400")) { + humanValue = "one day"; } + + this.updateAlarm(value); connectionPref.setSummary(humanValue); return; } + // Forecast days number keyValue = this.getActivity().getString( R.string.weather_preferences_day_forecast_key); if (key.equals(keyValue)) { @@ -123,4 +144,40 @@ implements OnSharedPreferenceChangeListener { } + private void updateAlarm(final String updateTimeRate) { + long chosenInterval = 0; + if (updateTimeRate.equals("900")) { + chosenInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES; + } else if (updateTimeRate.equals("1800")) { + chosenInterval = AlarmManager.INTERVAL_HALF_HOUR; + } else if (updateTimeRate.equals("3600")) { + chosenInterval = AlarmManager.INTERVAL_HOUR; + } else if (updateTimeRate.equals("43200")) { + chosenInterval = AlarmManager.INTERVAL_HALF_DAY; + } else if (updateTimeRate.equals("86400")) { + chosenInterval = AlarmManager.INTERVAL_DAY; + } + + final AlarmManager alarmMgr = + (AlarmManager) this.getActivity().getApplicationContext().getSystemService(Context.ALARM_SERVICE); + // TODO: better use some string instead of .class? In case I change the service class + // this could be a problem (I guess) + final Intent serviceIntent = + new Intent(this.getActivity().getApplicationContext(), WeatherInformationBatch.class); + final PendingIntent alarmIntent = + PendingIntent.getService( + this.getActivity().getApplicationContext(), + 0, + serviceIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + if (chosenInterval != 0) { + alarmMgr.setInexactRepeating( + AlarmManager.ELAPSED_REALTIME, + SystemClock.elapsedRealtime(), + chosenInterval, + alarmIntent); + } else { + alarmMgr.cancel(alarmIntent); + } + } } -- 2.1.4