5311017d1e7538a5665a2f55be1ac592060f0887
[JavaForFun] /
1 package name.gumartinm.weather.information.widget;
2
3 import android.app.IntentService;
4 import android.app.PendingIntent;
5 import android.appwidget.AppWidgetManager;
6 import android.content.Context;
7 import android.content.Intent;
8 import android.graphics.Bitmap;
9 import android.graphics.BitmapFactory;
10 import android.net.Uri;
11 import android.net.http.AndroidHttpClient;
12 import android.support.v4.app.TaskStackBuilder;
13 import android.util.Log;
14 import android.view.View;
15 import android.widget.RemoteViews;
16
17 import com.fasterxml.jackson.core.JsonParseException;
18 import name.gumartinm.weather.information.R;
19 import name.gumartinm.weather.information.httpclient.CustomHTTPClient;
20 import name.gumartinm.weather.information.model.DatabaseQueries;
21 import name.gumartinm.weather.information.model.WeatherLocation;
22 import name.gumartinm.weather.information.model.currentweather.Current;
23 import name.gumartinm.weather.information.parser.JPOSCurrentParser;
24 import name.gumartinm.weather.information.service.IconsList;
25 import name.gumartinm.weather.information.service.PermanentStorage;
26 import name.gumartinm.weather.information.service.ServiceCurrentParser;
27
28 import org.apache.http.client.ClientProtocolException;
29
30 import java.io.IOException;
31 import java.net.MalformedURLException;
32 import java.net.URISyntaxException;
33 import java.net.URL;
34 import java.text.DecimalFormat;
35 import java.text.NumberFormat;
36 import java.util.Date;
37 import java.util.Locale;
38
39 public class WidgetIntentService extends IntentService {
40         private static final String TAG = "WidgetIntentService";
41     private static final long UPDATE_TIME_RATE = 86400000L;
42
43         public WidgetIntentService() {
44                 super("WIS-Thread");
45         }
46
47         @Override
48         protected void onHandleIntent(final Intent intent) {
49                 Log.i(TAG, "onHandleIntent");
50                 final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
51                 final boolean isRefreshAppWidget = intent.getBooleanExtra("refreshAppWidget", false);
52
53                 if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
54                         // Nothing to do. Something went wrong. Show error.
55                         return;
56                 }
57
58
59                 final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
60                 final WeatherLocation weatherLocation = query.queryDataBase();
61                 
62                 if (weatherLocation == null) {
63                         // Nothing to do. Show error.
64                         final RemoteViews view = this.makeErrorView(appWidgetId);
65                         this.updateWidget(view, appWidgetId);
66                         return;
67                 }
68
69         // TODO: improve this code. Too tired right now...
70                 if (!isRefreshAppWidget) {
71             RemoteViews view;
72
73             final PermanentStorage store = new PermanentStorage(this.getApplicationContext());
74             final Current current = store.getWidgetCurrentData(appWidgetId);
75             if (current != null) {
76                 // Update UI.
77                 view = this.makeView(current, weatherLocation, appWidgetId);
78             } else {
79                 // Show error.
80                 view = this.makeErrorView(appWidgetId);
81             }
82             this.updateWidget(view, appWidgetId);
83                 } else {
84             RemoteViews view;
85
86             final Current current = this.getRemoteCurrent(weatherLocation);
87             if (current != null) {
88                 // Update UI.
89                 view = this.makeView(current, weatherLocation, appWidgetId);
90
91                 final PermanentStorage store = new PermanentStorage(this.getApplicationContext());
92                 store.saveWidgetCurrentData(current, appWidgetId);
93             } else {
94                 // Show error.
95                 view = this.makeErrorView(appWidgetId);
96             }
97             this.updateWidget(view, appWidgetId);
98                 }
99         }
100
101     public static void deleteWidgetCurrentData(final Context context, final int appWidgetId) {
102         final PermanentStorage store = new PermanentStorage(context.getApplicationContext());
103
104         store.removeWidgetCurrentData(appWidgetId);
105     }
106
107         private Current getRemoteCurrent(final WeatherLocation weatherLocation) {
108
109                 final ServiceCurrentParser weatherService = new ServiceCurrentParser(new JPOSCurrentParser());
110                 final CustomHTTPClient HTTPClient = new CustomHTTPClient(
111                                 AndroidHttpClient.newInstance(this.getString(R.string.http_client_agent)));
112
113                 try {
114                         return this.getRemoteCurrentThrowable(weatherLocation, HTTPClient, weatherService);
115
116                 } catch (final JsonParseException e) {
117                         Log.e(TAG, "doInBackground exception: ", e);
118                 } catch (final ClientProtocolException e) {
119                         Log.e(TAG, "doInBackground exception: ", e);
120                 } catch (final MalformedURLException e) {
121                         Log.e(TAG, "doInBackground exception: ", e);
122                 } catch (final URISyntaxException e) {
123                         Log.e(TAG, "doInBackground exception: ", e);
124                 } catch (final IOException e) {
125                         // logger infrastructure swallows UnknownHostException :/
126                         Log.e(TAG, "doInBackground exception: " + e.getMessage(), e);
127                 } finally {
128                         HTTPClient.close();
129                 }
130
131                 return null;
132         }
133
134         private Current getRemoteCurrentThrowable(final WeatherLocation weatherLocation,
135                         final CustomHTTPClient HTTPClient, final ServiceCurrentParser weatherService)
136                                         throws ClientProtocolException, MalformedURLException, URISyntaxException,
137                                         JsonParseException, IOException {
138
139                 final String APIVersion = this.getResources().getString(R.string.api_version);
140
141                 final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today);
142                 final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion,
143                                 weatherLocation.getLatitude(), weatherLocation.getLongitude());
144                 final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
145                 final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
146
147                 return weatherService.retrieveCurrentFromJPOS(jsonData);
148         }
149
150     private interface UnitsConversor {
151         
152         public double doConversion(final double value);
153     }
154     
155         private RemoteViews makeView(final Current current, final WeatherLocation weatherLocation, final int appWidgetId) {
156
157                 // TODO: repeating the same code in Overview, Specific and Current!!!
158                 // 1. Update units of measurement.
159
160         UnitsConversor tempUnitsConversor;
161         String keyPreference = this.getApplicationContext().getString(R.string.widget_preferences_temperature_units_key);
162         String realKeyPreference = keyPreference + "_" + appWidgetId;
163         // What was saved to permanent storage (or default values if it is the first time)
164         final int tempValue = this.getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE).getInt(realKeyPreference, 0);
165         final String tempSymbol = this.getResources().getStringArray(R.array.weather_preferences_temperature)[tempValue];
166         if (tempValue == 0) {
167                 tempUnitsConversor = new UnitsConversor(){
168
169                                 @Override
170                                 public double doConversion(final double value) {
171                                         return value - 273.15;
172                                 }
173
174                 };
175         } else if (tempValue == 1) {
176                 tempUnitsConversor = new UnitsConversor(){
177
178                                 @Override
179                                 public double doConversion(final double value) {
180                                         return (value * 1.8) - 459.67;
181                                 }
182
183                 };
184         } else {
185                 tempUnitsConversor = new UnitsConversor(){
186
187                                 @Override
188                                 public double doConversion(final double value) {
189                                         return value;
190                                 }
191
192                 };
193         }
194
195
196         // 2. Update country.
197         keyPreference = this.getApplicationContext().getString(R.string.widget_preferences_country_switch_key);
198         realKeyPreference = keyPreference + "_" + appWidgetId;
199         // What was saved to permanent storage (or default values if it is the first time)
200         final boolean isCountry = this.getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE)
201                 .getBoolean(realKeyPreference, false);
202
203
204                 // 3. Formatters
205                 final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
206                 tempFormatter.applyPattern("#####.#####");
207
208
209                 // 4. Prepare data for RemoteViews.
210                 String tempMax = "";
211                 if (current.getMain().getTemp_max() != null) {
212                         double conversion = (Double) current.getMain().getTemp_max();
213                         conversion = tempUnitsConversor.doConversion(conversion);
214                         tempMax = tempFormatter.format(conversion) + tempSymbol;
215                 }
216                 String tempMin = "";
217                 if (current.getMain().getTemp_min() != null) {
218                         double conversion = (Double) current.getMain().getTemp_min();
219                         conversion = tempUnitsConversor.doConversion(conversion);
220                         tempMin = tempFormatter.format(conversion) + tempSymbol;
221                 }
222                 Bitmap picture;
223                 if ((current.getWeather().size() > 0)
224                                 && (current.getWeather().get(0).getIcon() != null)
225                                 && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
226                         final String icon = current.getWeather().get(0).getIcon();
227                         picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
228                                         .getResourceDrawable());
229                 } else {
230                         picture = BitmapFactory.decodeResource(this.getResources(),
231                                         R.drawable.weather_severe_alert);
232                 }
233                 final String city = weatherLocation.getCity();
234                 final String country = weatherLocation.getCountry();
235
236                 // 5. Insert data in RemoteViews.
237                 final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget);
238                 remoteView.setImageViewBitmap(R.id.weather_appwidget_image, picture);
239                 remoteView.setTextViewText(R.id.weather_appwidget_temperature_max, tempMax);
240                 remoteView.setTextViewText(R.id.weather_appwidget_temperature_min, tempMin);
241                 remoteView.setTextViewText(R.id.weather_appwidget_city, city);
242         if (!isCountry) {
243             remoteView.setViewVisibility(R.id.weather_appwidget_country, View.GONE);
244         } else {
245             // TODO: It is as if Android had a view cache. If I did not set VISIBLE value,
246             // the country field would be gone forever... :/
247             remoteView.setViewVisibility(R.id.weather_appwidget_country, View.VISIBLE);
248             remoteView.setTextViewText(R.id.weather_appwidget_country, country);
249         }
250
251
252                 // 6. Activity launcher.
253                 final Intent resultIntent =  new Intent(this.getApplicationContext(), WidgetConfigure.class);
254                 resultIntent.putExtra("actionFromUser", true);
255                 resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
256     //    resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK );
257                 // From: http://stackoverflow.com/questions/4011178/multiple-instances-of-widget-only-updating-last-widget
258                 final Uri data = Uri.withAppendedPath(Uri.parse("PAIN" + "://widget/id/") ,String.valueOf(appWidgetId));
259                 resultIntent.setData(data);
260
261                 final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
262                 // Adds the back stack for the Intent (but not the Intent itself)
263                 stackBuilder.addParentStack(WidgetConfigure.class);
264                 // Adds the Intent that starts the Activity to the top of the stack
265                 stackBuilder.addNextIntent(resultIntent);
266                 final PendingIntent resultPendingIntent =
267                                 stackBuilder.getPendingIntent(
268                                                 0,
269                                                 PendingIntent.FLAG_UPDATE_CURRENT
270                                                 );
271                 remoteView.setOnClickPendingIntent(R.id.weather_appwidget, resultPendingIntent);
272 //        final PendingIntent resultPendingIntent = PendingIntent.getActivity(
273 //                this.getApplicationContext(),
274 //                0,
275 //                resultIntent,
276 //                PendingIntent.FLAG_UPDATE_CURRENT);
277 //        remoteView.setOnClickPendingIntent(R.id.weather_appwidget, resultPendingIntent);
278                 
279                 return remoteView;
280         }
281         
282         private RemoteViews makeErrorView(final int appWidgetId) {
283                 final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget_error);
284
285                 // 6. Activity launcher.
286                 final Intent resultIntent =  new Intent(this.getApplicationContext(), WidgetConfigure.class);
287                 resultIntent.putExtra("actionFromUser", true);
288                 resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
289 //        resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK );
290                 // From: http://stackoverflow.com/questions/4011178/multiple-instances-of-widget-only-updating-last-widget
291                 final Uri data = Uri.withAppendedPath(Uri.parse("PAIN" + "://widget/id/") ,String.valueOf(appWidgetId));
292                 resultIntent.setData(data);
293
294                 final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
295                 // Adds the back stack for the Intent (but not the Intent itself)
296                 stackBuilder.addParentStack(WidgetConfigure.class);
297                 // Adds the Intent that starts the Activity to the top of the stack
298                 stackBuilder.addNextIntent(resultIntent);
299                 final PendingIntent resultPendingIntent =
300                                 stackBuilder.getPendingIntent(
301                                                 0,
302                                                 PendingIntent.FLAG_UPDATE_CURRENT
303                                                 );
304         remoteView.setOnClickPendingIntent(R.id.weather_appwidget_error, resultPendingIntent);
305 //        final PendingIntent resultPendingIntent = PendingIntent.getActivity(
306 //                this.getApplicationContext(),
307 //                0,
308 //                resultIntent,
309 //                PendingIntent.FLAG_UPDATE_CURRENT);
310 //              remoteView.setOnClickPendingIntent(R.id.weather_appwidget_error, resultPendingIntent);
311
312                 return remoteView;
313         }
314
315         private void updateWidget(final RemoteViews remoteView, final int appWidgetId) {
316                 
317                 final AppWidgetManager manager = AppWidgetManager.getInstance(this.getApplicationContext());
318                 manager.updateAppWidget(appWidgetId, remoteView);
319         }
320         
321 //      private void updateWidgets(final RemoteViews remoteView) {
322 //              
323 //              final ComponentName widgets = new ComponentName(this.getApplicationContext(), WidgetProvider.class);
324 //              final AppWidgetManager manager = AppWidgetManager.getInstance(this.getApplicationContext());
325 //              manager.updateAppWidget(widgets, remoteView);
326 //      }
327 }