82945a81490719ba13bd972496841aca4bdd0ade
[JavaForFun] /
1 package de.example.exampletdd.fragment.overview;
2
3 import java.io.FileNotFoundException;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.ObjectInputStream;
7 import java.io.ObjectOutputStream;
8 import java.io.OutputStream;
9 import java.io.StreamCorruptedException;
10 import java.net.MalformedURLException;
11 import java.net.URISyntaxException;
12 import java.net.URL;
13 import java.text.DecimalFormat;
14 import java.text.NumberFormat;
15 import java.text.SimpleDateFormat;
16 import java.util.ArrayList;
17 import java.util.Calendar;
18 import java.util.Collection;
19 import java.util.Date;
20 import java.util.List;
21 import java.util.Locale;
22
23 import org.apache.http.client.ClientProtocolException;
24 import org.json.JSONException;
25
26 import android.app.DialogFragment;
27 import android.app.Fragment;
28 import android.content.Context;
29 import android.content.SharedPreferences;
30 import android.graphics.Bitmap;
31 import android.graphics.BitmapFactory;
32 import android.net.http.AndroidHttpClient;
33 import android.os.AsyncTask;
34 import android.os.Bundle;
35 import android.preference.PreferenceManager;
36 import android.util.Log;
37 import android.view.LayoutInflater;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.widget.ListView;
41 import de.example.exampletdd.R;
42 import de.example.exampletdd.activityinterface.ErrorMessage;
43 import de.example.exampletdd.activityinterface.GetWeather;
44 import de.example.exampletdd.fragment.ProgressDialogFragment;
45 import de.example.exampletdd.httpclient.WeatherHTTPClient;
46 import de.example.exampletdd.model.GeocodingData;
47 import de.example.exampletdd.model.WeatherData;
48 import de.example.exampletdd.parser.IJPOSWeatherParser;
49 import de.example.exampletdd.parser.JPOSWeatherParser;
50 import de.example.exampletdd.service.WeatherService;
51
52 public class WeatherInformationOverviewFragment extends Fragment implements GetWeather {
53     private static final String WEATHER_DATA_FILE = "weatherdata.file";
54     private static final String WEATHER_GEOCODING_FILE = "weathergeocoding.file";
55     private static final String TAG = "WeatherInformationOverviewFragment";
56     private boolean mIsFahrenheit;
57     private String mLanguage;
58
59     @Override
60     public void onCreate(final Bundle savedInstanceState) {
61         super.onCreate(savedInstanceState);
62
63         this.getActivity().deleteFile(WEATHER_DATA_FILE);
64
65         final SharedPreferences sharedPreferences = PreferenceManager
66                 .getDefaultSharedPreferences(this.getActivity());
67         final String keyPreference = this.getResources().getString(
68                 R.string.weather_preferences_language_key);
69         this.mLanguage = sharedPreferences.getString(
70                 keyPreference, "");
71     }
72
73     @Override
74     public View onCreateView(final LayoutInflater inflater,
75             final ViewGroup container, final Bundle savedInstanceState) {
76         // TODO: In activity_main.xml you can see: tools:layout="@layout/weather_data_list"
77         // So, probably this line is not required. I guess you can do the same
78         // by xml or by means of this code. Test it!!!
79         final View rootView = inflater.inflate(R.layout.weather_main_list,
80                 container, false);
81
82         return rootView;
83     }
84
85     @Override
86     public void onActivityCreated(final Bundle savedInstanceState) {
87         super.onActivityCreated(savedInstanceState);
88
89         final ListView listWeatherView = (ListView) this.getActivity().findViewById(
90                 R.id.weather_main_list_view);
91
92         final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(this.getActivity(),
93                 R.layout.weather_main_entry_list);
94
95         final Collection<WeatherOverviewEntry> entries = this.createEmptyEntriesList();
96
97         adapter.addAll(entries);
98         listWeatherView.setAdapter(adapter);
99
100         if (savedInstanceState != null) {
101             // Restore state
102             final WeatherData weatherData = (WeatherData) savedInstanceState
103                     .getSerializable("weatherData");
104             try {
105                 this.storeWeatherDataToFile(weatherData);
106             } catch (final IOException e) {
107                 ((ErrorMessage) WeatherInformationOverviewFragment.this
108                         .getActivity())
109                         .createErrorDialog(R.string.error_dialog_generic_error);
110             }
111         }
112     }
113
114     @Override
115     public void onSaveInstanceState(final Bundle savedInstanceState) {
116
117         // Save state
118         WeatherData weatherData = null;
119         try {
120             weatherData = this.restoreWeatherDataFromFile();
121         } catch (final StreamCorruptedException e) {
122             Log.e(TAG, "onResume exception: ", e);
123         } catch (final FileNotFoundException e) {
124             Log.e(TAG, "onResume exception: ", e);
125         } catch (final IOException e) {
126             Log.e(TAG, "onResume exception: ", e);
127         } catch (final ClassNotFoundException e) {
128             Log.e(TAG, "onResume exception: ", e);
129         }
130
131         if (weatherData != null) {
132             savedInstanceState.putSerializable("weatherData", weatherData);
133         }
134
135         super.onSaveInstanceState(savedInstanceState);
136     }
137
138     @Override
139     public void getWeather() {
140
141         GeocodingData geocodingData = null;
142         try {
143             geocodingData = this.restoreGeocodingDataFromFile();
144         } catch (final StreamCorruptedException e) {
145             Log.e(TAG, "onResume exception: ", e);
146         } catch (final FileNotFoundException e) {
147             Log.e(TAG, "onResume exception: ", e);
148         } catch (final IOException e) {
149             Log.e(TAG, "onResume exception: ", e);
150         } catch (final ClassNotFoundException e) {
151             Log.e(TAG, "onResume exception: ", e);
152         }
153
154         if (geocodingData != null) {
155             final IJPOSWeatherParser JPOSWeatherParser = new JPOSWeatherParser();
156             final WeatherService weatherService = new WeatherService(
157                     JPOSWeatherParser);
158             final AndroidHttpClient httpClient = AndroidHttpClient
159                     .newInstance("Android Weather Information Agent");
160             final WeatherHTTPClient HTTPweatherClient = new WeatherHTTPClient(
161                     httpClient);
162
163             final WeatherTask weatherTask = new WeatherTask(HTTPweatherClient, weatherService);
164
165
166             weatherTask.execute(geocodingData);
167         }
168     }
169
170     @Override
171     public void updateWeatherData(final WeatherData weatherData) {
172         final List<WeatherOverviewEntry> entries = this.createEmptyEntriesList();
173         final ListView listWeatherView = (ListView) this.getActivity().findViewById(
174                 R.id.weather_main_list_view);
175         final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(this.getActivity(),
176                 R.layout.weather_main_entry_list);
177
178         Bitmap picture = null;
179
180         if (weatherData.getWeather().getIcon() != null) {
181             picture= BitmapFactory.decodeByteArray(
182                     weatherData.getIconData(), 0,
183                     weatherData.getIconData().length);
184         }
185
186         final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.getDefault());
187         tempFormatter.applyPattern("#####.#####");
188         final SimpleDateFormat dateFormat = new SimpleDateFormat("MM.dd", Locale.getDefault());
189         final double tempUnits = this.mIsFahrenheit ? 0 : 273.15;
190         double conversion = weatherData.getMain().getTemp();
191         conversion = conversion - tempUnits;
192
193         final Calendar now = Calendar.getInstance();
194         if (weatherData.getWeather() != null) {
195             for (int i = 0; i<15; i++) {
196                 final Date day = now.getTime();
197                 entries.set(i, new WeatherOverviewEntry(
198                         "DATE: " + dateFormat.format(day),
199                         tempFormatter.format(conversion), picture));
200                 now.add(Calendar.DAY_OF_MONTH, -1);
201             }
202         }
203
204         listWeatherView.setAdapter(null);
205         adapter.addAll(entries);
206         listWeatherView.setAdapter(adapter);
207     }
208
209     @Override
210     public void onResume() {
211         super.onResume();
212
213         final SharedPreferences sharedPreferences = PreferenceManager
214                 .getDefaultSharedPreferences(this.getActivity());
215
216         // 1. Update units of measurement.
217         String keyPreference = this.getResources().getString(
218                 R.string.weather_preferences_units_key);
219         final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
220         final String celsius = this.getResources().getString(
221                 R.string.weather_preferences_units_celsius);
222         if (unitsPreferenceValue.equals(celsius)) {
223             this.mIsFahrenheit = false;
224         } else {
225             this.mIsFahrenheit = true;
226         }
227
228
229         // 2. Update current data on display.
230         WeatherData weatherData = null;
231         try {
232             weatherData = this.restoreWeatherDataFromFile();
233         } catch (final StreamCorruptedException e) {
234             Log.e(TAG, "onResume exception: ", e);
235         } catch (final FileNotFoundException e) {
236             Log.e(TAG, "onResume exception: ", e);
237         } catch (final IOException e) {
238             Log.e(TAG, "onResume exception: ", e);
239         } catch (final ClassNotFoundException e) {
240             Log.e(TAG, "onResume exception: ", e);
241         }
242         if (weatherData != null) {
243             this.updateWeatherData(weatherData);
244         }
245
246
247         // 3. If language changed, try to retrieve new data for new language
248         // (new strings with the chosen language)
249         keyPreference = this.getResources().getString(
250                 R.string.weather_preferences_language_key);
251         final String languagePreferenceValue = sharedPreferences.getString(
252                 keyPreference, "");
253         if (!languagePreferenceValue.equals(this.mLanguage)) {
254             this.mLanguage = languagePreferenceValue;
255             this.getWeather();
256         }
257     }
258
259     public class WeatherTask extends AsyncTask<Object, Void, WeatherData> {
260         private static final String TAG = "WeatherTask";
261         private final WeatherHTTPClient weatherHTTPClient;
262         private final WeatherService weatherService;
263         private final DialogFragment newFragment;
264
265         public WeatherTask(final WeatherHTTPClient weatherHTTPClient,
266                 final WeatherService weatherService) {
267             this.weatherHTTPClient = weatherHTTPClient;
268             this.weatherService = weatherService;
269             this.newFragment = ProgressDialogFragment.newInstance(
270                     R.string.progress_dialog_get_remote_data,
271                     WeatherInformationOverviewFragment.this
272                     .getString(R.string.progress_dialog_generic_message));
273         }
274
275         @Override
276         protected void onPreExecute() {
277             this.newFragment.show(WeatherInformationOverviewFragment.this.getActivity()
278                     .getFragmentManager(), "progressDialog");
279         }
280
281         @Override
282         protected WeatherData doInBackground(final Object... params) {
283             WeatherData weatherData = null;
284
285             try {
286                 weatherData = this.doInBackgroundThrowable(params);
287             } catch (final ClientProtocolException e) {
288                 Log.e(TAG, "doInBackground exception: ", e);
289             } catch (final MalformedURLException e) {
290                 Log.e(TAG, "doInBackground exception: ", e);
291             } catch (final URISyntaxException e) {
292                 Log.e(TAG, "doInBackground exception: ", e);
293             } catch (final IOException e) {
294                 // logger infrastructure swallows UnknownHostException :/
295                 Log.e(TAG, "doInBackground exception: " + e.getMessage(), e);
296             } catch (final JSONException e) {
297                 Log.e(TAG, "doInBackground exception: ", e);
298             } finally {
299                 this.weatherHTTPClient.close();
300             }
301
302             return weatherData;
303         }
304
305         @Override
306         protected void onPostExecute(final WeatherData weatherData) {
307             this.weatherHTTPClient.close();
308
309             this.newFragment.dismiss();
310
311             if (weatherData != null) {
312                 try {
313                     this.onPostExecuteThrowable(weatherData);
314                 } catch (final IOException e) {
315                     Log.e(TAG, "WeatherTask onPostExecute exception: ", e);
316                     ((ErrorMessage) WeatherInformationOverviewFragment.this
317                             .getActivity())
318                             .createErrorDialog(R.string.error_dialog_generic_error);
319                 }
320             } else {
321                 ((ErrorMessage) WeatherInformationOverviewFragment.this
322                         .getActivity())
323                         .createErrorDialog(R.string.error_dialog_generic_error);
324             }
325         }
326
327         @Override
328         protected void onCancelled(final WeatherData weatherData) {
329             this.weatherHTTPClient.close();
330
331             ((ErrorMessage) WeatherInformationOverviewFragment.this.getActivity())
332             .createErrorDialog(R.string.error_dialog_connection_tiemout);
333         }
334
335         private WeatherData doInBackgroundThrowable(final Object... params)
336                 throws ClientProtocolException, MalformedURLException,
337                 URISyntaxException, IOException, JSONException {
338             final SharedPreferences sharedPreferences = PreferenceManager
339                     .getDefaultSharedPreferences(WeatherInformationOverviewFragment.this
340                             .getActivity());
341
342             final String keyPreference = WeatherInformationOverviewFragment.this
343                     .getActivity().getString(
344                             R.string.weather_preferences_language_key);
345             final String languagePreferenceValue = sharedPreferences.getString(keyPreference, "");
346
347             final GeocodingData geocodingData = (GeocodingData) params[0];
348             final String urlAPICoord = WeatherInformationOverviewFragment.this.getResources()
349                     .getString(R.string.uri_api_coord);
350             final String APIVersion = WeatherInformationOverviewFragment.this.getResources()
351                     .getString(R.string.api_version);
352             String url = this.weatherService.createURIAPICoord(geocodingData.getLatitude(),
353                     geocodingData.getLongitude(), urlAPICoord, APIVersion, languagePreferenceValue);
354
355
356             final String jsonData = this.weatherHTTPClient.retrieveJSONDataFromAPI(new URL(url));
357
358
359             final WeatherData weatherData = this.weatherService.retrieveDataFromJPOS(jsonData);
360
361
362             final String icon = weatherData.getWeather().getIcon();
363             final String urlAPIicon = WeatherInformationOverviewFragment.this
364                     .getResources().getString(R.string.uri_api_icon);
365             url = this.weatherService.createURIAPIicon(icon, urlAPIicon);
366             final byte[] iconData = this.weatherHTTPClient
367                     .retrieveDataFromAPI(new URL(url)).toByteArray();
368             weatherData.setIconData(iconData);
369
370
371             return weatherData;
372         }
373
374         private void onPostExecuteThrowable(final WeatherData weatherData)
375                 throws FileNotFoundException, IOException {
376             WeatherInformationOverviewFragment.this.storeWeatherDataToFile(weatherData);
377
378             WeatherInformationOverviewFragment.this.updateWeatherData(weatherData);
379         }
380     }
381
382     private List<WeatherOverviewEntry> createEmptyEntriesList() {
383         final List<WeatherOverviewEntry> entries = new ArrayList<WeatherOverviewEntry>();
384         final SimpleDateFormat dateFormat = new SimpleDateFormat("MM.dd", Locale.getDefault());
385
386         final Calendar now = Calendar.getInstance();
387         for (int i = 0; i<15; i++) {
388             final Date day = now.getTime();
389             entries.add(i, new WeatherOverviewEntry(
390                     "DATE: " + dateFormat.format(day), null, null));
391             now.add(Calendar.DAY_OF_MONTH, -1);
392         }
393
394         return entries;
395     }
396
397     private void storeWeatherDataToFile(final WeatherData weatherData)
398             throws FileNotFoundException, IOException {
399         final OutputStream persistenceFile = this.getActivity().openFileOutput(
400                 WEATHER_DATA_FILE, Context.MODE_PRIVATE);
401
402         ObjectOutputStream oos = null;
403         try {
404             oos = new ObjectOutputStream(persistenceFile);
405
406             oos.writeObject(weatherData);
407         } finally {
408             if (oos != null) {
409                 oos.close();
410             }
411         }
412     }
413
414     private WeatherData restoreWeatherDataFromFile() throws StreamCorruptedException,
415     FileNotFoundException, IOException, ClassNotFoundException {
416         final InputStream persistenceFile = this.getActivity().openFileInput(
417                 WEATHER_DATA_FILE);
418
419         ObjectInputStream ois = null;
420         try {
421             ois = new ObjectInputStream(persistenceFile);
422
423             return (WeatherData) ois.readObject();
424         } finally {
425             if (ois != null) {
426                 ois.close();
427             }
428         }
429     }
430
431     private GeocodingData restoreGeocodingDataFromFile()
432             throws StreamCorruptedException, FileNotFoundException,
433             IOException, ClassNotFoundException {
434         final InputStream persistenceFile = this.getActivity()
435                 .openFileInput(WEATHER_GEOCODING_FILE);
436
437         ObjectInputStream ois = null;
438         try {
439             ois = new ObjectInputStream(persistenceFile);
440
441             return (GeocodingData) ois.readObject();
442         } finally {
443             if (ois != null) {
444                 ois.close();
445             }
446         }
447     }
448 }