From 289a9218025ea00278bccf3f9643f517d193eb2f Mon Sep 17 00:00:00 2001 From: "gu.martinm@gmail.com" Date: Sun, 28 Sep 2014 03:03:31 +0200 Subject: [PATCH] WeatherInformation: 1. Save forecast and current data to permanent storage. 2. Update widget from App when location changed (no working yet) --- AndroidManifest.xml | 10 +- res/xml/appwidget_provider.xml | 2 +- .../exampletdd/NotificationIntentService.java | 204 ++++++++++++++++++ .../exampletdd/WeatherInformationApplication.java | 45 ---- .../exampletdd/WeatherInformationBatch.java | 204 ------------------ .../exampletdd/WeatherInformationBootReceiver.java | 2 +- src/de/example/exampletdd/WidgetIntentService.java | 239 +++++++++++++++++++++ .../fragment/current/CurrentFragment.java | 35 +-- .../fragment/overview/OverviewFragment.java | 25 +-- .../WeatherInformationPreferencesFragment.java | 4 +- .../fragment/specific/SpecificFragment.java | 22 +- .../exampletdd/service/PermanentStorage.java | 140 ++++++++++++ .../widget/WeatherInformationWidgetProvider.java | 214 +----------------- 13 files changed, 639 insertions(+), 507 deletions(-) create mode 100644 src/de/example/exampletdd/NotificationIntentService.java delete mode 100644 src/de/example/exampletdd/WeatherInformationApplication.java delete mode 100644 src/de/example/exampletdd/WeatherInformationBatch.java create mode 100644 src/de/example/exampletdd/WidgetIntentService.java create mode 100644 src/de/example/exampletdd/service/PermanentStorage.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8cfc5c5..e49f556 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -34,7 +34,7 @@ - - + - @@ -98,12 +98,12 @@ - - diff --git a/res/xml/appwidget_provider.xml b/res/xml/appwidget_provider.xml index 396c70a..74390c6 100644 --- a/res/xml/appwidget_provider.xml +++ b/res/xml/appwidget_provider.xml @@ -9,5 +9,5 @@ android:initialLayout="@layout/appwidget" android:configure="de.example.exampletdd.widget.WeatherInformationWidgetConfigure" android:widgetCategory="home_screen|keyguard" - android:updatePeriodMillis="900000"> + android:updatePeriodMillis="3600000"> diff --git a/src/de/example/exampletdd/NotificationIntentService.java b/src/de/example/exampletdd/NotificationIntentService.java new file mode 100644 index 0000000..f953b53 --- /dev/null +++ b/src/de/example/exampletdd/NotificationIntentService.java @@ -0,0 +1,204 @@ +package de.example.exampletdd; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Calendar; +import java.util.Locale; + +import org.apache.http.client.ClientProtocolException; + +import android.app.IntentService; +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.http.AndroidHttpClient; +import android.preference.PreferenceManager; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; +import android.support.v4.app.TaskStackBuilder; +import android.util.Log; +import android.widget.RemoteViews; + +import com.fasterxml.jackson.core.JsonParseException; + +import de.example.exampletdd.httpclient.CustomHTTPClient; +import de.example.exampletdd.model.DatabaseQueries; +import de.example.exampletdd.model.WeatherLocation; +import de.example.exampletdd.model.currentweather.Current; +import de.example.exampletdd.parser.JPOSWeatherParser; +import de.example.exampletdd.service.IconsList; +import de.example.exampletdd.service.ServiceParser; + +public class NotificationIntentService extends IntentService { + private static final String TAG = "NotificationIntentService"; + + + public NotificationIntentService() { + super("NIS-Thread"); + } + + @Override + protected void onHandleIntent(final Intent intent) { + final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext()); + final WeatherLocation weatherLocation = query.queryDataBase(); + + if (weatherLocation != null) { + final ServiceParser weatherService = new ServiceParser(new JPOSWeatherParser()); + final CustomHTTPClient HTTPClient = new CustomHTTPClient( + AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")); + + Current current = null; + try { + current = this.doInBackgroundThrowable(weatherLocation, HTTPClient, weatherService); + + } catch (final JsonParseException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final ClientProtocolException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final MalformedURLException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final URISyntaxException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final IOException e) { + // logger infrastructure swallows UnknownHostException :/ + Log.e(TAG, "doInBackground exception: " + e.getMessage(), e); + } finally { + HTTPClient.close(); + } + + if (current != null) { + this.showNotification(current, weatherLocation); + } + } + } + + private Current doInBackgroundThrowable(final WeatherLocation weatherLocation, + final CustomHTTPClient HTTPClient, final ServiceParser weatherService) + throws ClientProtocolException, MalformedURLException, URISyntaxException, + JsonParseException, IOException { + + final String APIVersion = this.getResources().getString(R.string.api_version); + + final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today); + final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, + weatherLocation.getLatitude(), weatherLocation.getLongitude()); + 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()); + + return current; + } + + private void showNotification(final Current current, final WeatherLocation weatherLocation) { + final SharedPreferences sharedPreferences = PreferenceManager + .getDefaultSharedPreferences(this.getApplicationContext()); + + // TODO: repeating the same code in Overview, Specific and Current!!! + // 1. Update units of measurement. + boolean mIsFahrenheit = false; + final String keyPreference = this.getResources().getString( + R.string.weather_preferences_units_key); + final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, ""); + final String celsius = this.getResources().getString( + R.string.weather_preferences_units_celsius); + if (unitsPreferenceValue.equals(celsius)) { + mIsFahrenheit = false; + } else { + mIsFahrenheit = true; + } + final double tempUnits = mIsFahrenheit ? 0 : 273.15; + final String symbol = mIsFahrenheit ? "ºF" : "ºC"; + + + // 2. Formatters + final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); + tempFormatter.applyPattern("#####.#####"); + + + // 3. Prepare data for RemoteViews. + String tempMax = ""; + if (current.getMain().getTemp_max() != null) { + double conversion = (Double) current.getMain().getTemp_max(); + conversion = conversion - tempUnits; + tempMax = tempFormatter.format(conversion) + symbol; + } + String tempMin = ""; + if (current.getMain().getTemp_min() != null) { + double conversion = (Double) current.getMain().getTemp_min(); + conversion = conversion - tempUnits; + tempMin = tempFormatter.format(conversion) + symbol; + } + Bitmap picture; + if ((current.getWeather().size() > 0) + && (current.getWeather().get(0).getIcon() != null) + && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) { + final String icon = current.getWeather().get(0).getIcon(); + picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon) + .getResourceDrawable()); + } else { + picture = BitmapFactory.decodeResource(this.getResources(), + R.drawable.weather_severe_alert); + } + final String city = weatherLocation.getCity(); + final String country = weatherLocation.getCountry(); + + // 4. Insert data in RemoteViews. + final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.notification); + remoteView.setImageViewBitmap(R.id.weather_notification_image, picture); + remoteView.setTextViewText(R.id.weather_notification_temperature_max, tempMax); + remoteView.setTextViewText(R.id.weather_notification_temperature_min, tempMin); + remoteView.setTextViewText(R.id.weather_notification_city, city); + remoteView.setTextViewText(R.id.weather_notification_country, country); + + // 5. Activity launcher. + 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 + ); + + final NotificationManagerCompat notificationManager = + NotificationManagerCompat.from(this.getApplicationContext()); + + + // 6. Create notification. + final NotificationCompat.Builder notificationBuilder = + new NotificationCompat.Builder(this.getApplicationContext()) + .setContent(remoteView) + .setSmallIcon(R.drawable.ic_launcher) + .setAutoCancel(true) + .setLocalOnly(true) + .setWhen(System.currentTimeMillis()) + .setContentIntent(resultPendingIntent) + .setPriority(NotificationCompat.PRIORITY_DEFAULT); + + 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/WeatherInformationApplication.java b/src/de/example/exampletdd/WeatherInformationApplication.java deleted file mode 100644 index 679a2ca..0000000 --- a/src/de/example/exampletdd/WeatherInformationApplication.java +++ /dev/null @@ -1,45 +0,0 @@ -package de.example.exampletdd; - -import android.app.Application; -import de.example.exampletdd.model.currentweather.Current; -import de.example.exampletdd.model.forecastweather.Forecast; - -public class WeatherInformationApplication extends Application { - private Forecast mForecast; - private Current mCurrent; - private String mCity; - private String mCountry; - - - public void setForecast(final Forecast forecast) { - this.mForecast = forecast; - } - - public Forecast getForecast() { - return this.mForecast; - } - - public void setCurrent(final Current current) { - this.mCurrent = current; - } - - public Current getCurrent() { - return this.mCurrent; - } - - public void setCity(final String city) { - this.mCity = city; - } - - public String getCity() { - return this.mCity; - } - - public void setCountry(final String country) { - this.mCountry = country; - } - - public String getCountry() { - return this.mCountry; - } -} diff --git a/src/de/example/exampletdd/WeatherInformationBatch.java b/src/de/example/exampletdd/WeatherInformationBatch.java deleted file mode 100644 index afe42ab..0000000 --- a/src/de/example/exampletdd/WeatherInformationBatch.java +++ /dev/null @@ -1,204 +0,0 @@ -package de.example.exampletdd; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Calendar; -import java.util.Locale; - -import org.apache.http.client.ClientProtocolException; - -import android.app.IntentService; -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.http.AndroidHttpClient; -import android.preference.PreferenceManager; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.NotificationManagerCompat; -import android.support.v4.app.TaskStackBuilder; -import android.util.Log; -import android.widget.RemoteViews; - -import com.fasterxml.jackson.core.JsonParseException; - -import de.example.exampletdd.httpclient.CustomHTTPClient; -import de.example.exampletdd.model.DatabaseQueries; -import de.example.exampletdd.model.WeatherLocation; -import de.example.exampletdd.model.currentweather.Current; -import de.example.exampletdd.parser.JPOSWeatherParser; -import de.example.exampletdd.service.IconsList; -import de.example.exampletdd.service.ServiceParser; - -public class WeatherInformationBatch extends IntentService { - private static final String TAG = "WeatherInformationBatch"; - - - public WeatherInformationBatch() { - super("WIB-Thread"); - } - - @Override - protected void onHandleIntent(final Intent intent) { - final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext()); - final WeatherLocation weatherLocation = query.queryDataBase(); - - if (weatherLocation != null) { - final ServiceParser weatherService = new ServiceParser(new JPOSWeatherParser()); - final CustomHTTPClient HTTPClient = new CustomHTTPClient( - AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")); - - Current current = null; - try { - current = this.doInBackgroundThrowable(weatherLocation, HTTPClient, weatherService); - - } catch (final JsonParseException e) { - Log.e(TAG, "doInBackground exception: ", e); - } catch (final ClientProtocolException e) { - Log.e(TAG, "doInBackground exception: ", e); - } catch (final MalformedURLException e) { - Log.e(TAG, "doInBackground exception: ", e); - } catch (final URISyntaxException e) { - Log.e(TAG, "doInBackground exception: ", e); - } catch (final IOException e) { - // logger infrastructure swallows UnknownHostException :/ - Log.e(TAG, "doInBackground exception: " + e.getMessage(), e); - } finally { - HTTPClient.close(); - } - - if (current != null) { - this.showNotification(current, weatherLocation); - } - } - } - - private Current doInBackgroundThrowable(final WeatherLocation weatherLocation, - final CustomHTTPClient HTTPClient, final ServiceParser weatherService) - throws ClientProtocolException, MalformedURLException, URISyntaxException, - JsonParseException, IOException { - - final String APIVersion = this.getResources().getString(R.string.api_version); - - final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today); - final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, - weatherLocation.getLatitude(), weatherLocation.getLongitude()); - 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()); - - return current; - } - - private void showNotification(final Current current, final WeatherLocation weatherLocation) { - final SharedPreferences sharedPreferences = PreferenceManager - .getDefaultSharedPreferences(this.getApplicationContext()); - - // TODO: repeating the same code in Overview, Specific and Current!!! - // 1. Update units of measurement. - boolean mIsFahrenheit = false; - final String keyPreference = this.getResources().getString( - R.string.weather_preferences_units_key); - final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, ""); - final String celsius = this.getResources().getString( - R.string.weather_preferences_units_celsius); - if (unitsPreferenceValue.equals(celsius)) { - mIsFahrenheit = false; - } else { - mIsFahrenheit = true; - } - final double tempUnits = mIsFahrenheit ? 0 : 273.15; - final String symbol = mIsFahrenheit ? "ºF" : "ºC"; - - - // 2. Formatters - final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); - tempFormatter.applyPattern("#####.#####"); - - - // 3. Prepare data for RemoteViews. - String tempMax = ""; - if (current.getMain().getTemp_max() != null) { - double conversion = (Double) current.getMain().getTemp_max(); - conversion = conversion - tempUnits; - tempMax = tempFormatter.format(conversion) + symbol; - } - String tempMin = ""; - if (current.getMain().getTemp_min() != null) { - double conversion = (Double) current.getMain().getTemp_min(); - conversion = conversion - tempUnits; - tempMin = tempFormatter.format(conversion) + symbol; - } - Bitmap picture; - if ((current.getWeather().size() > 0) - && (current.getWeather().get(0).getIcon() != null) - && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) { - final String icon = current.getWeather().get(0).getIcon(); - picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon) - .getResourceDrawable()); - } else { - picture = BitmapFactory.decodeResource(this.getResources(), - R.drawable.weather_severe_alert); - } - final String city = weatherLocation.getCity(); - final String country = weatherLocation.getCountry(); - - // 4. Insert data in RemoteViews. - final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.notification); - remoteView.setImageViewBitmap(R.id.weather_notification_image, picture); - remoteView.setTextViewText(R.id.weather_notification_temperature_max, tempMax); - remoteView.setTextViewText(R.id.weather_notification_temperature_min, tempMin); - remoteView.setTextViewText(R.id.weather_notification_city, city); - remoteView.setTextViewText(R.id.weather_notification_country, country); - - // 5. Activity launcher. - 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 - ); - - final NotificationManagerCompat notificationManager = - NotificationManagerCompat.from(this.getApplicationContext()); - - - // 6. Create notification. - final NotificationCompat.Builder notificationBuilder = - new NotificationCompat.Builder(this.getApplicationContext()) - .setContent(remoteView) - .setSmallIcon(R.drawable.ic_launcher) - .setAutoCancel(true) - .setLocalOnly(true) - .setWhen(System.currentTimeMillis()) - .setContentIntent(resultPendingIntent) - .setPriority(NotificationCompat.PRIORITY_DEFAULT); - - 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 a2a8f14..a9c939a 100644 --- a/src/de/example/exampletdd/WeatherInformationBootReceiver.java +++ b/src/de/example/exampletdd/WeatherInformationBootReceiver.java @@ -39,7 +39,7 @@ public class WeatherInformationBootReceiver extends BroadcastReceiver { 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 Intent serviceIntent = new Intent(context, NotificationIntentService.class); final PendingIntent alarmIntent = PendingIntent.getService(context, 0, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT); alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() diff --git a/src/de/example/exampletdd/WidgetIntentService.java b/src/de/example/exampletdd/WidgetIntentService.java new file mode 100644 index 0000000..9ee67ac --- /dev/null +++ b/src/de/example/exampletdd/WidgetIntentService.java @@ -0,0 +1,239 @@ +package de.example.exampletdd; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Calendar; +import java.util.Locale; + +import org.apache.http.client.ClientProtocolException; + +import android.app.IntentService; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.ComponentName; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.http.AndroidHttpClient; +import android.preference.PreferenceManager; +import android.support.v4.app.TaskStackBuilder; +import android.util.Log; +import android.widget.RemoteViews; + +import com.fasterxml.jackson.core.JsonParseException; + +import de.example.exampletdd.httpclient.CustomHTTPClient; +import de.example.exampletdd.model.DatabaseQueries; +import de.example.exampletdd.model.WeatherLocation; +import de.example.exampletdd.model.currentweather.Current; +import de.example.exampletdd.parser.JPOSWeatherParser; +import de.example.exampletdd.service.IconsList; +import de.example.exampletdd.service.PermanentStorage; +import de.example.exampletdd.service.ServiceParser; + +public class WidgetIntentService extends IntentService { + private static final String TAG = "WidgetIntentService"; + + + public WidgetIntentService() { + super("WIS-Thread"); + } + + @Override + protected void onHandleIntent(final Intent intent) { + Log.i(TAG, "onHandleIntent"); + final int appWidgetId = intent.getIntExtra("appWidgetId", -666); + final boolean isUpdateByApp = intent.getBooleanExtra("updateByApp", false); + + final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext()); + final WeatherLocation weatherLocation = query.queryDataBase(); + + if (weatherLocation == null) { + // Nothing to do. + return; + } + + if (isUpdateByApp) { + this.updateByApp(weatherLocation); + } else { + this.updateByTimeout(weatherLocation, appWidgetId); + } + + } + + private void updateByApp(final WeatherLocation weatherLocation) { + final PermanentStorage store = new PermanentStorage(this.getApplicationContext()); + final Current current = store.getCurrent(); + final RemoteViews view = this.makeView(current, weatherLocation); + + this.updateWidgets(view); + } + + private void updateByTimeout(final WeatherLocation weatherLocation, final int appWidgetId) { + if (appWidgetId == -666) { + // Nothing to do. Something went wrong. + return; + } + + final Current current = this.getRemoteCurrent(weatherLocation); + if (current != null) { + final RemoteViews view = this.makeView(current, weatherLocation); + this.updateWidget(view, appWidgetId); + } else { + // TODO: show layout error in Widget + } + } + + private Current getRemoteCurrent(final WeatherLocation weatherLocation) { + + final ServiceParser weatherService = new ServiceParser(new JPOSWeatherParser()); + final CustomHTTPClient HTTPClient = new CustomHTTPClient( + AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")); + + try { + return this.getRemoteCurrentThrowable(weatherLocation, HTTPClient, weatherService); + + } catch (final JsonParseException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final ClientProtocolException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final MalformedURLException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final URISyntaxException e) { + Log.e(TAG, "doInBackground exception: ", e); + } catch (final IOException e) { + // logger infrastructure swallows UnknownHostException :/ + Log.e(TAG, "doInBackground exception: " + e.getMessage(), e); + } finally { + HTTPClient.close(); + } + + return null; + } + + private Current getRemoteCurrentThrowable(final WeatherLocation weatherLocation, + final CustomHTTPClient HTTPClient, final ServiceParser weatherService) + throws ClientProtocolException, MalformedURLException, URISyntaxException, + JsonParseException, IOException { + + final String APIVersion = this.getResources().getString(R.string.api_version); + + final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today); + final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, + weatherLocation.getLatitude(), weatherLocation.getLongitude()); + 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()); + + return current; + } + + private RemoteViews makeView(final Current current, final WeatherLocation weatherLocation) { + final SharedPreferences sharedPreferences = PreferenceManager + .getDefaultSharedPreferences(this.getApplicationContext()); + + // TODO: repeating the same code in Overview, Specific and Current!!! + // 1. Update units of measurement. + boolean mIsFahrenheit = false; + final String keyPreference = this.getResources().getString( + R.string.weather_preferences_units_key); + final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, ""); + final String celsius = this.getResources().getString( + R.string.weather_preferences_units_celsius); + if (unitsPreferenceValue.equals(celsius)) { + mIsFahrenheit = false; + } else { + mIsFahrenheit = true; + } + final double tempUnits = mIsFahrenheit ? 0 : 273.15; + final String symbol = mIsFahrenheit ? "ºF" : "ºC"; + + + // 2. Formatters + final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); + tempFormatter.applyPattern("#####.#####"); + + + // 3. Prepare data for RemoteViews. + String tempMax = ""; + if (current.getMain().getTemp_max() != null) { + double conversion = (Double) current.getMain().getTemp_max(); + conversion = conversion - tempUnits; + tempMax = tempFormatter.format(conversion) + symbol; + } + String tempMin = ""; + if (current.getMain().getTemp_min() != null) { + double conversion = (Double) current.getMain().getTemp_min(); + conversion = conversion - tempUnits; + tempMin = tempFormatter.format(conversion) + symbol; + } + Bitmap picture; + if ((current.getWeather().size() > 0) + && (current.getWeather().get(0).getIcon() != null) + && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) { + final String icon = current.getWeather().get(0).getIcon(); + picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon) + .getResourceDrawable()); + } else { + picture = BitmapFactory.decodeResource(this.getResources(), + R.drawable.weather_severe_alert); + } + final String city = weatherLocation.getCity(); + final String country = weatherLocation.getCountry(); + + // 4. Insert data in RemoteViews. + final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget); + remoteView.setImageViewBitmap(R.id.weather_appwidget_image, picture); + remoteView.setTextViewText(R.id.weather_appwidget_temperature_max, tempMax); + remoteView.setTextViewText(R.id.weather_appwidget_temperature_min, tempMin); + remoteView.setTextViewText(R.id.weather_appwidget_city, city); + remoteView.setTextViewText(R.id.weather_appwidget_country, country); + + // 5. Activity launcher. + 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 + ); + remoteView.setOnClickPendingIntent(R.id.weather_appwidget, resultPendingIntent); + + return remoteView; + } + + private void updateWidget(final RemoteViews remoteView, final int appWidgetId) { + + final AppWidgetManager manager = AppWidgetManager.getInstance(this); + manager.updateAppWidget(appWidgetId, remoteView); + + Log.i(TAG, "updateWidget updated"); + } + + private void updateWidgets(final RemoteViews remoteView) { + + final ComponentName widgets = new ComponentName("de.example.exampletdd.widget", AppWidgetProvider.class.getCanonicalName()); + final AppWidgetManager manager = AppWidgetManager.getInstance(this); + manager.updateAppWidget(widgets, remoteView); + + Log.i(TAG, "updateWidgets updated"); + } +} diff --git a/src/de/example/exampletdd/fragment/current/CurrentFragment.java b/src/de/example/exampletdd/fragment/current/CurrentFragment.java index 9b829f8..64d83a2 100644 --- a/src/de/example/exampletdd/fragment/current/CurrentFragment.java +++ b/src/de/example/exampletdd/fragment/current/CurrentFragment.java @@ -37,13 +37,14 @@ import android.widget.TextView; import com.fasterxml.jackson.core.JsonParseException; import de.example.exampletdd.R; -import de.example.exampletdd.WeatherInformationApplication; +import de.example.exampletdd.WidgetIntentService; import de.example.exampletdd.httpclient.CustomHTTPClient; import de.example.exampletdd.model.DatabaseQueries; import de.example.exampletdd.model.WeatherLocation; import de.example.exampletdd.model.currentweather.Current; import de.example.exampletdd.parser.JPOSWeatherParser; import de.example.exampletdd.service.IconsList; +import de.example.exampletdd.service.PermanentStorage; import de.example.exampletdd.service.ServiceParser; public class CurrentFragment extends Fragment { @@ -74,9 +75,8 @@ public class CurrentFragment extends Fragment { // TODO: Could it be better to store in global forecast data even if it is null value? // So, perhaps do not check for null value and always store in global variable. if (current != null) { - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - application.setCurrent(current); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + store.saveCurrent(current); } } @@ -106,18 +106,25 @@ public class CurrentFragment extends Fragment { // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask. final DatabaseQueries query = new DatabaseQueries(CurrentFragment.this.getActivity().getApplicationContext()); final WeatherLocation weatherLocation = query.queryDataBase(); - final WeatherInformationApplication application = - (WeatherInformationApplication) CurrentFragment.this.getActivity().getApplication(); - final Current current = application.getCurrent(); + final PermanentStorage store = new PermanentStorage(CurrentFragment.this.getActivity().getApplicationContext()); + final Current current = store.getCurrent(); if (current == null || !CurrentFragment.this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) { // 2. Update UI. CurrentFragment.this.updateUI(currentRemote); // 3. Update Data. - application.setCurrent(currentRemote); + store.saveCurrent(currentRemote); weatherLocation.setLastCurrentUIUpdate(new Date()); query.updateDataBase(weatherLocation); + + // 4. Update Widget's UI. + // TODO: Unable to start service intent not found U=0 WHYYYYYYYY? ANDROID SUCKSSSSSSS + final Intent intentWidget = new Intent(); + intentWidget.setClassName("de.example.exampletdd", WidgetIntentService.class.getCanonicalName()); + intent.putExtra("appWidgetId", 0); + intentWidget.putExtra("updateByApp", true); + CurrentFragment.this.getActivity().getApplicationContext().startService(intent); } } else { @@ -152,10 +159,9 @@ public class CurrentFragment extends Fragment { errorMessage.setVisibility(View.VISIBLE); return; } - - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - final Current current = application.getCurrent(); + + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + final Current current = store.getCurrent(); if (current != null && this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) { this.updateUI(current); @@ -180,9 +186,8 @@ public class CurrentFragment extends Fragment { public void onSaveInstanceState(final Bundle savedInstanceState) { // Save UI state - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - final Current current = application.getCurrent(); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + final Current current = store.getCurrent(); // TODO: Could it be better to save current data even if it is null value? // So, perhaps do not check for null value. diff --git a/src/de/example/exampletdd/fragment/overview/OverviewFragment.java b/src/de/example/exampletdd/fragment/overview/OverviewFragment.java index 907791d..c24bfdd 100644 --- a/src/de/example/exampletdd/fragment/overview/OverviewFragment.java +++ b/src/de/example/exampletdd/fragment/overview/OverviewFragment.java @@ -36,7 +36,6 @@ import android.widget.ListView; import com.fasterxml.jackson.core.JsonParseException; import de.example.exampletdd.R; -import de.example.exampletdd.WeatherInformationApplication; import de.example.exampletdd.fragment.specific.SpecificFragment; import de.example.exampletdd.httpclient.CustomHTTPClient; import de.example.exampletdd.model.DatabaseQueries; @@ -44,6 +43,7 @@ import de.example.exampletdd.model.WeatherLocation; import de.example.exampletdd.model.forecastweather.Forecast; import de.example.exampletdd.parser.JPOSWeatherParser; import de.example.exampletdd.service.IconsList; +import de.example.exampletdd.service.PermanentStorage; import de.example.exampletdd.service.ServiceParser; public class OverviewFragment extends ListFragment { @@ -69,9 +69,8 @@ public class OverviewFragment extends ListFragment { // TODO: Could it be better to store in global forecast data even if it is null value? // So, perhaps do not check for null value and always store in global variable. if (forecast != null) { - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - application.setForecast(forecast); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + store.saveForecast(forecast); } } @@ -99,16 +98,15 @@ public class OverviewFragment extends ListFragment { // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask. final DatabaseQueries query = new DatabaseQueries(OverviewFragment.this.getActivity().getApplicationContext()); final WeatherLocation weatherLocation = query.queryDataBase(); - final WeatherInformationApplication application = - (WeatherInformationApplication) OverviewFragment.this.getActivity().getApplication(); - final Forecast forecast = application.getForecast(); + final PermanentStorage store = new PermanentStorage(OverviewFragment.this.getActivity().getApplicationContext()); + final Forecast forecast = store.getForecast(); if (forecast == null || !OverviewFragment.this.isDataFresh(weatherLocation.getLastForecastUIUpdate())) { // 2. Update UI. OverviewFragment.this.updateUI(forecastRemote); // 3. Update Data. - application.setForecast(forecastRemote); + store.saveForecast(forecastRemote); weatherLocation.setLastForecastUIUpdate(new Date()); query.updateDataBase(weatherLocation); @@ -141,10 +139,10 @@ public class OverviewFragment extends ListFragment { return; } - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - final Forecast forecast = application.getForecast(); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + final Forecast forecast = store.getForecast(); + // TODO: store forecast data in permanent storage and check here if there is data in permanent storage if (forecast != null && this.isDataFresh(weatherLocation.getLastForecastUIUpdate())) { this.updateUI(forecast); } else { @@ -165,9 +163,8 @@ public class OverviewFragment extends ListFragment { public void onSaveInstanceState(final Bundle savedInstanceState) { // Save UI state - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - final Forecast forecast = application.getForecast(); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + final Forecast forecast = store.getForecast(); // TODO: Could it be better to save forecast data even if it is null value? // So, perhaps do not check for null value. diff --git a/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java b/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java index f8a4838..2b665e9 100644 --- a/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java +++ b/src/de/example/exampletdd/fragment/preferences/WeatherInformationPreferencesFragment.java @@ -11,7 +11,7 @@ import android.os.SystemClock; import android.preference.Preference; import android.preference.PreferenceFragment; import de.example.exampletdd.R; -import de.example.exampletdd.WeatherInformationBatch; +import de.example.exampletdd.NotificationIntentService; public class WeatherInformationPreferencesFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener { @@ -163,7 +163,7 @@ public class WeatherInformationPreferencesFragment extends PreferenceFragment // 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); + new Intent(this.getActivity().getApplicationContext(), NotificationIntentService.class); final PendingIntent alarmIntent = PendingIntent.getService( this.getActivity().getApplicationContext(), diff --git a/src/de/example/exampletdd/fragment/specific/SpecificFragment.java b/src/de/example/exampletdd/fragment/specific/SpecificFragment.java index dbe55e9..0a4cc93 100644 --- a/src/de/example/exampletdd/fragment/specific/SpecificFragment.java +++ b/src/de/example/exampletdd/fragment/specific/SpecificFragment.java @@ -19,9 +19,9 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import de.example.exampletdd.R; -import de.example.exampletdd.WeatherInformationApplication; import de.example.exampletdd.model.forecastweather.Forecast; import de.example.exampletdd.service.IconsList; +import de.example.exampletdd.service.PermanentStorage; public class SpecificFragment extends Fragment { private int mChosenDay; @@ -61,9 +61,8 @@ public class SpecificFragment extends Fragment { // TODO: Could it be better to store in global data forecast even if it is null value? // So, perhaps do not check for null value and always store in global variable. if (forecast != null) { - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - application.setForecast(forecast); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + store.saveForecast(forecast); } this.mChosenDay = savedInstanceState.getInt("mChosenDay"); @@ -76,9 +75,8 @@ public class SpecificFragment extends Fragment { public void onSaveInstanceState(final Bundle savedInstanceState) { // Save UI state - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - final Forecast forecast = application.getForecast(); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + final Forecast forecast = store.getForecast(); // TODO: Could it be better to save forecast data even if it is null value? // So, perhaps do not check for null value. @@ -97,9 +95,8 @@ public class SpecificFragment extends Fragment { * @param chosenDay */ public void updateUIByChosenDay(final int chosenDay) { - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - final Forecast forecast = application.getForecast(); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + final Forecast forecast = store.getForecast(); if (forecast != null) { this.updateUI(forecast, chosenDay); @@ -264,9 +261,8 @@ public class SpecificFragment extends Fragment { public void onResume() { super.onResume(); - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - final Forecast forecast = application.getForecast(); + final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext()); + final Forecast forecast = store.getForecast(); if (forecast != null) { this.updateUI(forecast, this.mChosenDay); diff --git a/src/de/example/exampletdd/service/PermanentStorage.java b/src/de/example/exampletdd/service/PermanentStorage.java new file mode 100644 index 0000000..49eac40 --- /dev/null +++ b/src/de/example/exampletdd/service/PermanentStorage.java @@ -0,0 +1,140 @@ +package de.example.exampletdd.service; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.StreamCorruptedException; + +import android.content.Context; +import android.util.Log; +import de.example.exampletdd.model.currentweather.Current; +import de.example.exampletdd.model.forecastweather.Forecast; + + +/** + * TODO: show some error message when there is no enough space for saving files. :/ + * + */ +public class PermanentStorage { + private static final String TAG = "PermanentStorage"; + private static final String CURRENT_DATA_FILE = "current.file"; + private static final String FORECAST_DATA_FILE = "forecast.file"; + private final Context context; + + public PermanentStorage(final Context context) { + this.context = context; + } + + public void saveCurrent(final Current current) { + + try { + this.saveObject(CURRENT_DATA_FILE, current); + } catch (FileNotFoundException e) { + Log.e(TAG, "saveCurrent exception: ", e); + } catch (IOException e) { + Log.e(TAG, "saveCurrent exception: ", e); + } + } + + public Current getCurrent() { + + try { + return (Current) this.getObject(CURRENT_DATA_FILE); + } catch (final StreamCorruptedException e) { + Log.e(TAG, "getCurrent exception: ", e); + } catch (final FileNotFoundException e) { + Log.e(TAG, "getCurrent exception: ", e); + } catch (final IOException e) { + Log.e(TAG, "getCurrent exception: ", e); + } catch (final ClassNotFoundException e) { + Log.e(TAG, "getCurrent exception: ", e); + } + + return null; + } + + public void saveForecast(final Forecast forecast) { + + try { + this.saveObject(FORECAST_DATA_FILE, forecast); + } catch (FileNotFoundException e) { + Log.e(TAG, "saveForecast exception: ", e); + } catch (IOException e) { + Log.e(TAG, "saveForecast exception: ", e); + } + } + + public Forecast getForecast() { + + try { + return (Forecast) this.getObject(FORECAST_DATA_FILE); + } catch (final StreamCorruptedException e) { + Log.e(TAG, "getForecast exception: ", e); + } catch (final FileNotFoundException e) { + Log.e(TAG, "getForecast exception: ", e); + } catch (final IOException e) { + Log.e(TAG, "getForecast exception: ", e); + } catch (final ClassNotFoundException e) { + Log.e(TAG, "getForecast exception: ", e); + } + + return null; + } + + private void saveObject(final String fileName, final Object objectToStore) + throws FileNotFoundException, IOException { + final String temporaryFileName = fileName.concat(".tmp"); + + final FileOutputStream tmpPersistFile = this.context.openFileOutput( + temporaryFileName, Context.MODE_PRIVATE); + try { + final ObjectOutputStream oos = new ObjectOutputStream(tmpPersistFile); + try { + oos.writeObject(objectToStore); + + // Don't fear the fsync! + // http://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/ + tmpPersistFile.flush(); + tmpPersistFile.getFD().sync(); + } finally { + oos.close(); + } + } finally { + tmpPersistFile.close(); + } + + this.renameFile(temporaryFileName, fileName); + } + + private Object getObject(final String fileName) throws StreamCorruptedException, FileNotFoundException, + IOException, ClassNotFoundException { + final InputStream persistFile = this.context.openFileInput(fileName); + try { + final ObjectInputStream ois = new ObjectInputStream(persistFile); + try { + return ois.readObject(); + } finally { + ois.close(); + } + } finally { + persistFile.close(); + } + } + + private void renameFile(final String fromFileName, final String toFileName) throws IOException { + final File filesDir = this.context.getFilesDir(); + final File fromFile = new File(filesDir, fromFileName); + final File toFile = new File(filesDir, toFileName); + if (!fromFile.renameTo(toFile)) { + if (!fromFile.delete()) { + throw new IOException("PermanentStorage, delete file error"); + } + throw new IOException("PermanentStorage, rename file error"); + } + } +} + diff --git a/src/de/example/exampletdd/widget/WeatherInformationWidgetProvider.java b/src/de/example/exampletdd/widget/WeatherInformationWidgetProvider.java index 553ba80..4c59fd5 100644 --- a/src/de/example/exampletdd/widget/WeatherInformationWidgetProvider.java +++ b/src/de/example/exampletdd/widget/WeatherInformationWidgetProvider.java @@ -1,52 +1,18 @@ package de.example.exampletdd.widget; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Calendar; -import java.util.Locale; - -import org.apache.http.client.ClientProtocolException; - -import android.app.IntentService; -import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.http.AndroidHttpClient; import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.v4.app.TaskStackBuilder; -import android.util.Log; -import android.widget.RemoteViews; - -import com.fasterxml.jackson.core.JsonParseException; - -import de.example.exampletdd.R; -import de.example.exampletdd.WeatherTabsActivity; -import de.example.exampletdd.httpclient.CustomHTTPClient; -import de.example.exampletdd.model.DatabaseQueries; -import de.example.exampletdd.model.WeatherLocation; -import de.example.exampletdd.model.currentweather.Current; -import de.example.exampletdd.parser.JPOSWeatherParser; -import de.example.exampletdd.service.IconsList; -import de.example.exampletdd.service.ServiceParser; +import de.example.exampletdd.WidgetIntentService; public class WeatherInformationWidgetProvider extends AppWidgetProvider { - private static final String TAG = "WeatherInformationWidgetProvider"; @Override public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) { - Log.d(TAG, "onUpdate"); // For each widget that needs an update, get the text that we should display: // - Create a RemoteViews object for it // - Set the text in the RemoteViews object @@ -55,16 +21,15 @@ public class WeatherInformationWidgetProvider extends AppWidgetProvider { for (int i=0; i 0) - && (current.getWeather().get(0).getIcon() != null) - && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) { - final String icon = current.getWeather().get(0).getIcon(); - picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon) - .getResourceDrawable()); - } else { - picture = BitmapFactory.decodeResource(this.getResources(), - R.drawable.weather_severe_alert); - } - final String city = weatherLocation.getCity(); - final String country = weatherLocation.getCountry(); - - // 4. Insert data in RemoteViews. - final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget); - remoteView.setImageViewBitmap(R.id.weather_appwidget_image, picture); - remoteView.setTextViewText(R.id.weather_appwidget_temperature_max, tempMax); - remoteView.setTextViewText(R.id.weather_appwidget_temperature_min, tempMin); - remoteView.setTextViewText(R.id.weather_appwidget_city, city); - remoteView.setTextViewText(R.id.weather_appwidget_country, country); - - // 5. Activity launcher. - 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 - ); - remoteView.setOnClickPendingIntent(R.id.weather_appwidget, resultPendingIntent); - - - // Push update for this widget to the home screen - final AppWidgetManager manager = AppWidgetManager.getInstance(this); - manager.updateAppWidget(appWidgetId, remoteView); - - Log.i("WordWidget.UpdateService", "widget updated"); - } + final Intent intent = new Intent(context, WidgetIntentService.class); + intent.putExtra("appWidgetId", appWidgetId); + context.startService(intent); } } -- 2.1.4