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