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