ed192761440329e79ecf5e1a36c322e1310cbd95
[JavaForFun] /
1 package name.gumartinm.weather.information.fragment.current;
2
3 import java.io.IOException;
4 import java.net.MalformedURLException;
5 import java.net.URISyntaxException;
6 import java.net.URL;
7 import java.text.DecimalFormat;
8 import java.text.NumberFormat;
9 import java.text.SimpleDateFormat;
10 import java.util.Date;
11 import java.util.Locale;
12
13 import org.apache.http.client.ClientProtocolException;
14
15 import android.content.BroadcastReceiver;
16 import android.content.Context;
17 import android.content.Intent;
18 import android.content.IntentFilter;
19 import android.content.SharedPreferences;
20 import android.graphics.Bitmap;
21 import android.graphics.BitmapFactory;
22 import android.net.http.AndroidHttpClient;
23 import android.os.AsyncTask;
24 import android.os.Bundle;
25 import android.preference.PreferenceManager;
26 import android.support.v4.app.Fragment;
27 import android.support.v4.content.LocalBroadcastManager;
28 import android.util.Log;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.ImageView;
33 import android.widget.ProgressBar;
34 import android.widget.TextView;
35
36 import com.fasterxml.jackson.core.JsonParseException;
37 import name.gumartinm.weather.information.R;
38 import name.gumartinm.weather.information.httpclient.CustomHTTPClient;
39 import name.gumartinm.weather.information.model.DatabaseQueries;
40 import name.gumartinm.weather.information.model.WeatherLocation;
41 import name.gumartinm.weather.information.model.currentweather.Current;
42 import name.gumartinm.weather.information.parser.JPOSCurrentParser;
43 import name.gumartinm.weather.information.service.IconsList;
44 import name.gumartinm.weather.information.service.PermanentStorage;
45 import name.gumartinm.weather.information.service.ServiceCurrentParser;
46 import name.gumartinm.weather.information.widget.WidgetProvider;
47
48 public class CurrentFragment extends Fragment {
49     private static final String TAG = "CurrentFragment";
50     private BroadcastReceiver mReceiver;
51
52     @Override
53     public void onCreate(final Bundle savedInstanceState) {
54         super.onCreate(savedInstanceState);
55     }
56
57     @Override
58     public View onCreateView(LayoutInflater inflater, ViewGroup container,
59                              Bundle savedInstanceState) {
60     
61         // Inflate the layout for this fragment
62         return inflater.inflate(R.layout.weather_current_fragment, container, false);
63     }
64     
65     @Override
66     public void onActivityCreated(final Bundle savedInstanceState) {
67         super.onActivityCreated(savedInstanceState);
68
69         if (savedInstanceState != null) {
70                 // Restore UI state
71             final Current current = (Current) savedInstanceState.getSerializable("Current");
72
73             if (current != null) {
74                 final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
75                 store.saveCurrent(current);
76             }
77         }     
78         
79         this.setHasOptionsMenu(false);
80
81         this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
82         this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
83         this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);   
84     }
85
86     @Override
87     public void onResume() {
88         super.onResume();
89
90
91         this.mReceiver = new BroadcastReceiver() {
92
93                         @Override
94                         public void onReceive(final Context context, final Intent intent) {
95                                 final String action = intent.getAction();
96                                 if (action.equals("name.gumartinm.weather.information.UPDATECURRENT")) {
97                                         final Current currentRemote = (Current) intent.getSerializableExtra("current");
98
99                                         if (currentRemote != null) {
100
101                                                 // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask.
102                                                 final DatabaseQueries query = new DatabaseQueries(context.getApplicationContext());
103                                     final WeatherLocation weatherLocation = query.queryDataBase();
104                                     final PermanentStorage store = new PermanentStorage(context.getApplicationContext());
105                                     final Current current = store.getCurrent();
106
107                                     if (current == null || !CurrentFragment.this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
108                                         // 2. Update UI.
109                                         CurrentFragment.this.updateUI(currentRemote);
110
111                                         // 3. Update current data.
112                                                         store.saveCurrent(currentRemote);
113
114                             // 4. Update location data.
115                             weatherLocation.setLastCurrentUIUpdate(new Date());
116                             query.updateDataBase(weatherLocation);
117                                     }
118
119                                         } else {
120                                                 // Empty UI and show error message
121                                                 CurrentFragment.this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
122                                                 CurrentFragment.this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
123                                                 CurrentFragment.this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.VISIBLE);
124                                         }
125                                 }
126                         }
127         };
128
129         // Register receiver
130         final IntentFilter filter = new IntentFilter();
131         filter.addAction("name.gumartinm.weather.information.UPDATECURRENT");
132         LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext())
133                                                         .registerReceiver(this.mReceiver, filter);
134
135         // Empty UI
136         this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
137         
138         final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext());
139         final WeatherLocation weatherLocation = query.queryDataBase();
140         if (weatherLocation == null) {
141             // Nothing to do.
142                 // Show error message
143                 final ProgressBar progress = (ProgressBar) getActivity().findViewById(R.id.weather_current_progressbar);
144                 progress.setVisibility(View.GONE);
145                         final TextView errorMessage = (TextView) getActivity().findViewById(R.id.weather_current_error_message);
146                 errorMessage.setVisibility(View.VISIBLE);
147             return;
148         }
149
150         // If is new location update widgets.
151         if (weatherLocation.getIsNew()) {
152             WidgetProvider.refreshAllAppWidgets(this.getActivity().getApplicationContext());
153             // Update location data.
154             weatherLocation.setIsNew(false);
155             query.updateDataBase(weatherLocation);
156         }
157
158
159         final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
160         final Current current = store.getCurrent();
161
162         if (current != null && this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
163             this.updateUI(current);
164         } else {
165             // Load remote data (aynchronous)
166             // Gets the data from the web.
167                 this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
168                 this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
169             final CurrentTask task = new CurrentTask(
170                         this.getActivity().getApplicationContext(),
171                     new CustomHTTPClient(AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")),
172                     new ServiceCurrentParser(new JPOSCurrentParser()));
173
174             task.execute(weatherLocation.getLatitude(), weatherLocation.getLongitude());
175         }
176     }
177
178     @Override
179     public void onSaveInstanceState(final Bundle savedInstanceState) {
180
181         // Save UI state
182         final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
183         final Current current = store.getCurrent();
184
185         if (current != null) {
186             savedInstanceState.putSerializable("Current", current);
187         }
188
189         super.onSaveInstanceState(savedInstanceState);
190     }
191
192     @Override
193     public void onPause() {
194         LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver);
195
196         super.onPause();
197     }
198
199     private interface UnitsConversor {
200         
201         public double doConversion(final double value);
202     }
203
204     private void updateUI(final Current current) {
205         
206         final SharedPreferences sharedPreferences = PreferenceManager
207                 .getDefaultSharedPreferences(this.getActivity().getApplicationContext());
208
209         // TODO: repeating the same code in Overview, Specific and Current!!!
210         // 1. Update units of measurement.
211         // 1.1 Temperature
212         String tempSymbol;
213         UnitsConversor tempUnitsConversor;
214         String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
215         String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
216         String unitsPreferenceValue = sharedPreferences.getString(
217                 keyPreference, this.getString(R.string.weather_preferences_temperature_celsius));
218         if (unitsPreferenceValue.equals(values[0])) {
219                 tempSymbol = values[0];
220                 tempUnitsConversor = new UnitsConversor(){
221
222                                 @Override
223                                 public double doConversion(final double value) {
224                                         return value - 273.15;
225                                 }
226                         
227                 };
228         } else if (unitsPreferenceValue.equals(values[1])) {
229                 tempSymbol = values[1];
230                 tempUnitsConversor = new UnitsConversor(){
231
232                                 @Override
233                                 public double doConversion(final double value) {
234                                         return (value * 1.8) - 459.67;
235                                 }
236                         
237                 };
238         } else {
239                 tempSymbol = values[2];
240                 tempUnitsConversor = new UnitsConversor(){
241
242                                 @Override
243                                 public double doConversion(final double value) {
244                                         return value;
245                                 }
246                         
247                 };
248         }
249
250         // 1.2 Wind
251         String windSymbol;
252         UnitsConversor windUnitsConversor;
253         keyPreference = this.getResources().getString(R.string.weather_preferences_wind_key);
254         values = this.getResources().getStringArray(R.array.weather_preferences_wind);
255         unitsPreferenceValue = sharedPreferences.getString(
256                 keyPreference, this.getString(R.string.weather_preferences_wind_meters));
257         if (unitsPreferenceValue.equals(values[0])) {
258                 windSymbol = values[0];
259                 windUnitsConversor = new UnitsConversor(){
260
261                         @Override
262                         public double doConversion(double value) {
263                                 return value;
264                         }       
265                 };
266         } else {
267                 windSymbol = values[1];
268                 windUnitsConversor = new UnitsConversor(){
269
270                         @Override
271                         public double doConversion(double value) {
272                                 return value * 2.237;
273                         }       
274                 };
275         }
276
277         // 1.3 Pressure
278         String pressureSymbol;
279         UnitsConversor pressureUnitsConversor;
280         keyPreference = this.getResources().getString(R.string.weather_preferences_pressure_key);
281         values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
282         unitsPreferenceValue = sharedPreferences.getString(
283                 keyPreference, this.getString(R.string.weather_preferences_pressure_pascal));
284         if (unitsPreferenceValue.equals(values[0])) {
285                 pressureSymbol = values[0];
286                 pressureUnitsConversor = new UnitsConversor(){
287
288                         @Override
289                         public double doConversion(double value) {
290                                 return value;
291                         }       
292                 };
293         } else {
294                 pressureSymbol = values[1];
295                 pressureUnitsConversor = new UnitsConversor(){
296
297                         @Override
298                         public double doConversion(double value) {
299                                 return value / 113.25d;
300                         }       
301                 };
302         }
303
304
305         // 2. Formatters
306         final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
307         tempFormatter.applyPattern("#####.#####");
308         final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.US);
309
310         
311         // 3. Prepare data for UI.
312         String tempMax = "";
313         if (current.getMain().getTemp_max() != null) {
314             double conversion = (Double) current.getMain().getTemp_max();
315             conversion = tempUnitsConversor.doConversion(conversion);
316             tempMax = tempFormatter.format(conversion) + tempSymbol;
317         }
318         String tempMin = "";
319         if (current.getMain().getTemp_min() != null) {
320             double conversion = (Double) current.getMain().getTemp_min();
321             conversion = tempUnitsConversor.doConversion(conversion);
322             tempMin = tempFormatter.format(conversion) + tempSymbol;
323         }
324         Bitmap picture;
325         if ((current.getWeather().size() > 0)
326                 && (current.getWeather().get(0).getIcon() != null)
327                 && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
328             final String icon = current.getWeather().get(0).getIcon();
329             picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
330                     .getResourceDrawable());
331         } else {
332             picture = BitmapFactory.decodeResource(this.getResources(),
333                     R.drawable.weather_severe_alert);
334         }
335
336         String description = this.getString(R.string.text_field_description_when_error);
337         if (current.getWeather().size() > 0) {
338             description = current.getWeather().get(0).getDescription();
339         }
340
341         String humidityValue = "";
342         if ((current.getMain() != null)
343                 && (current.getMain().getHumidity() != null)) {
344             final double conversion = (Double) current.getMain().getHumidity();
345             humidityValue = tempFormatter.format(conversion);
346         }
347         String pressureValue = "";
348         if ((current.getMain() != null)
349                 && (current.getMain().getPressure() != null)) {
350             double conversion = (Double) current.getMain().getPressure();
351             conversion = pressureUnitsConversor.doConversion(conversion);
352             pressureValue = tempFormatter.format(conversion);
353         }
354         String windValue = "";
355         if ((current.getWind() != null)
356                 && (current.getWind().getSpeed() != null)) {
357             double conversion = (Double) current.getWind().getSpeed();
358             conversion = windUnitsConversor.doConversion(conversion);
359             windValue = tempFormatter.format(conversion);
360         }
361         String rainValue = "";
362         if ((current.getRain() != null)
363                 && (current.getRain().get3h() != null)) {
364             final double conversion = (Double) current.getRain().get3h();
365             rainValue = tempFormatter.format(conversion);
366         }
367         String cloudsValue = "";
368         if ((current.getClouds() != null)
369                 && (current.getClouds().getAll() != null)) {
370             final double conversion = (Double) current.getClouds().getAll();
371             cloudsValue = tempFormatter.format(conversion);
372         }
373         String snowValue = "";
374         if ((current.getSnow() != null)
375                 && (current.getSnow().get3h() != null)) {
376             final double conversion = (Double) current.getSnow().get3h();
377             snowValue = tempFormatter.format(conversion);
378         }
379         String feelsLike = "";
380         if (current.getMain().getTemp() != null) {
381             double conversion = (Double) current.getMain().getTemp();
382             conversion = tempUnitsConversor.doConversion(conversion);
383             feelsLike = tempFormatter.format(conversion);
384         }
385         String sunRiseTime = "";
386         if (current.getSys().getSunrise() != null) {
387             final long unixTime = (Long) current.getSys().getSunrise();
388             final Date unixDate = new Date(unixTime * 1000L);
389             sunRiseTime = dateFormat.format(unixDate);
390         }
391         String sunSetTime = "";
392         if (current.getSys().getSunset() != null) {
393             final long unixTime = (Long) current.getSys().getSunset();
394             final Date unixDate = new Date(unixTime * 1000L);
395             sunSetTime = dateFormat.format(unixDate);
396         }
397
398
399         // 4. Update UI.
400         final TextView tempMaxView = (TextView) getActivity().findViewById(R.id.weather_current_temp_max);
401         tempMaxView.setText(tempMax);
402         final TextView tempMinView = (TextView) getActivity().findViewById(R.id.weather_current_temp_min);
403         tempMinView.setText(tempMin);
404         final ImageView pictureView = (ImageView) getActivity().findViewById(R.id.weather_current_picture);
405         pictureView.setImageBitmap(picture);    
406         
407         final TextView descriptionView = (TextView) getActivity().findViewById(R.id.weather_current_description);
408         descriptionView.setText(description);
409         
410         ((TextView) getActivity().findViewById(R.id.weather_current_humidity_value)).setText(humidityValue);
411         ((TextView) getActivity().findViewById(R.id.weather_current_humidity_units)).setText(
412                         this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
413         
414         ((TextView) getActivity().findViewById(R.id.weather_current_pressure_value)).setText(pressureValue);
415         ((TextView) getActivity().findViewById(R.id.weather_current_pressure_units)).setText(pressureSymbol);
416         
417         ((TextView) getActivity().findViewById(R.id.weather_current_wind_value)).setText(windValue);
418         ((TextView) getActivity().findViewById(R.id.weather_current_wind_units)).setText(windSymbol);
419         
420         ((TextView) getActivity().findViewById(R.id.weather_current_rain_value)).setText(rainValue);
421         ((TextView) getActivity().findViewById(R.id.weather_current_rain_units)).setText(
422                         this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
423         
424         ((TextView) getActivity().findViewById(R.id.weather_current_clouds_value)).setText(cloudsValue);
425         ((TextView) getActivity().findViewById(R.id.weather_current_clouds_units)).setText(
426                         this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
427         
428         ((TextView) getActivity().findViewById(R.id.weather_current_snow_value)).setText(snowValue);
429         ((TextView) getActivity().findViewById(R.id.weather_current_snow_units)).setText(
430                         this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
431         
432         ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_value)).setText(feelsLike);
433         ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_units)).setText(tempSymbol);
434         
435         ((TextView) getActivity().findViewById(R.id.weather_current_sunrise_value)).setText(sunRiseTime);
436
437         ((TextView) getActivity().findViewById(R.id.weather_current_sunset_value)).setText(sunSetTime);
438         
439         this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.VISIBLE);
440         this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
441         this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);       
442     }
443     
444     private boolean isDataFresh(final Date lastUpdate) {
445         if (lastUpdate == null) {
446                 return false;
447         }
448         
449         final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
450                         this.getActivity().getApplicationContext());
451         final String keyPreference = this.getString(R.string.weather_preferences_refresh_interval_key);
452         final String refresh = sharedPreferences.getString(
453                         keyPreference,
454                         this.getResources().getStringArray(R.array.weather_preferences_refresh_interval)[0]);
455         final Date currentTime = new Date();
456         if (((currentTime.getTime() - lastUpdate.getTime())) < Long.valueOf(refresh)) {
457                 return true;
458         }
459         
460         return false;
461     }
462
463     private class CurrentTask extends AsyncTask<Object, Void, Current> {
464         // Store the context passed to the AsyncTask when the system instantiates it.
465         private final Context localContext;
466         final CustomHTTPClient HTTPClient;
467         final ServiceCurrentParser weatherService;
468
469         public CurrentTask(final Context context, final CustomHTTPClient HTTPClient,
470                         final ServiceCurrentParser weatherService) {
471                 this.localContext = context;
472             this.HTTPClient = HTTPClient;
473             this.weatherService = weatherService;
474         }
475
476         @Override
477         protected Current doInBackground(final Object... params) {
478                 final double latitude = (Double) params[0];
479             final double longitude = (Double) params[1];
480   
481             Current current = null;
482             try {
483                 current = this.doInBackgroundThrowable(latitude, longitude);
484             } catch (final JsonParseException e) {
485                 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
486             } catch (final ClientProtocolException e) {
487                 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
488             } catch (final MalformedURLException e) {
489                 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
490             } catch (final URISyntaxException e) {
491                 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
492             } catch (final IOException e) {
493                 // logger infrastructure swallows UnknownHostException :/
494                 Log.e(TAG, "CurrentTask doInBackground exception: " + e.getMessage(), e);
495             } finally {
496                 HTTPClient.close();
497             }
498
499             return current;
500         }
501
502         private Current doInBackgroundThrowable(final double latitude, final double longitude)
503                         throws URISyntaxException, ClientProtocolException, JsonParseException, IOException {
504
505                 final String APIVersion = localContext.getResources().getString(R.string.api_version);
506             final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_today);
507             final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, latitude, longitude);
508             final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
509             final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
510
511             return weatherService.retrieveCurrentFromJPOS(jsonData);
512         }
513
514         @Override
515         protected void onPostExecute(final Current current) {
516
517             // Call updateUI on the UI thread.
518             final Intent currentData = new Intent("name.gumartinm.weather.information.UPDATECURRENT");
519             currentData.putExtra("current", current);
520             LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(currentData);
521         }
522     }
523 }