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