1 package de.example.exampletdd.fragment.overview;
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;
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;
23 import org.apache.http.client.ClientProtocolException;
24 import org.json.JSONException;
26 import android.app.DialogFragment;
27 import android.app.ListFragment;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.SharedPreferences;
32 import android.graphics.Bitmap;
33 import android.graphics.BitmapFactory;
34 import android.net.http.AndroidHttpClient;
35 import android.os.AsyncTask;
36 import android.os.Bundle;
37 import android.preference.PreferenceManager;
38 import android.util.Log;
39 import android.view.View;
40 import android.widget.ListView;
41 import de.example.exampletdd.R;
42 import de.example.exampletdd.activityinterface.GetWeather;
43 import de.example.exampletdd.fragment.ErrorDialogFragment;
44 import de.example.exampletdd.fragment.ProgressDialogFragment;
45 import de.example.exampletdd.fragment.specific.WeatherInformationSpecificDataFragment;
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;
53 public class WeatherInformationOverviewFragment extends ListFragment implements
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;
62 public void onCreate(final Bundle savedInstanceState) {
63 super.onCreate(savedInstanceState);
65 this.getActivity().deleteFile(WEATHER_DATA_FILE);
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(
76 public void onActivityCreated(final Bundle savedInstanceState) {
77 super.onActivityCreated(savedInstanceState);
79 final ListView listWeatherView = this.getListView();
81 listWeatherView.setChoiceMode(ListView.CHOICE_MODE_NONE);
83 if (savedInstanceState != null) {
85 final WeatherData weatherData = (WeatherData) savedInstanceState
86 .getSerializable("weatherData");
88 this.storeWeatherDataToFile(weatherData);
89 } catch (final IOException e) {
90 final DialogFragment newFragment = ErrorDialogFragment
91 .newInstance(R.string.error_dialog_generic_error);
92 newFragment.show(this.getFragmentManager(), "errorDialog");
96 this.setHasOptionsMenu(false);
98 final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(
99 this.getActivity(), R.layout.weather_main_entry_list);
101 final Collection<WeatherOverviewEntry> entries = this
102 .createEmptyEntriesList();
104 this.setListAdapter(null);
105 adapter.addAll(entries);
106 this.setListAdapter(adapter);
107 this.setListShown(true);
108 this.setListShownNoAnimation(true);
112 public void onListItemClick(final ListView l, final View v, final int position, final long id) {
113 final WeatherInformationSpecificDataFragment fragment = (WeatherInformationSpecificDataFragment) getFragmentManager()
114 .findFragmentById(R.id.weather_specific_data__fragment);
115 if (fragment == null) {
117 final Intent intent = new Intent("de.example.exampletdd.WEATHERINFO").
118 setComponent(new ComponentName("de.example.exampletdd",
119 "de.example.exampletdd.specific.WeatherInformationSpecificDataActivity"));
120 WeatherInformationOverviewFragment.this.getActivity().startActivity(intent);
123 fragment.getWeather();
128 public void onSaveInstanceState(final Bundle savedInstanceState) {
131 WeatherData weatherData = null;
133 weatherData = this.restoreWeatherDataFromFile();
134 } catch (final StreamCorruptedException e) {
135 Log.e(TAG, "onResume exception: ", e);
136 } catch (final FileNotFoundException e) {
137 Log.e(TAG, "onResume exception: ", e);
138 } catch (final IOException e) {
139 Log.e(TAG, "onResume exception: ", e);
140 } catch (final ClassNotFoundException e) {
141 Log.e(TAG, "onResume exception: ", e);
144 if (weatherData != null) {
145 savedInstanceState.putSerializable("weatherData", weatherData);
148 super.onSaveInstanceState(savedInstanceState);
152 public void getWeather() {
154 GeocodingData geocodingData = null;
156 geocodingData = this.restoreGeocodingDataFromFile();
157 } catch (final StreamCorruptedException e) {
158 Log.e(TAG, "onResume exception: ", e);
159 } catch (final FileNotFoundException e) {
160 Log.e(TAG, "onResume exception: ", e);
161 } catch (final IOException e) {
162 Log.e(TAG, "onResume exception: ", e);
163 } catch (final ClassNotFoundException e) {
164 Log.e(TAG, "onResume exception: ", e);
167 if (geocodingData != null) {
168 final IJPOSWeatherParser JPOSWeatherParser = new JPOSWeatherParser();
169 final WeatherService weatherService = new WeatherService(
171 final AndroidHttpClient httpClient = AndroidHttpClient
172 .newInstance("Android Weather Information Agent");
173 final WeatherHTTPClient HTTPweatherClient = new WeatherHTTPClient(
176 final WeatherTask weatherTask = new WeatherTask(HTTPweatherClient, weatherService);
179 weatherTask.execute(geocodingData);
183 public void updateWeatherData(final WeatherData weatherData) {
184 final List<WeatherOverviewEntry> entries = this.createEmptyEntriesList();
185 final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(this.getActivity(),
186 R.layout.weather_main_entry_list);
188 // Bitmap picture = null;
190 // if (weatherData.getWeather().getIcon() != null) {
191 // picture= BitmapFactory.decodeByteArray(
192 // weatherData.getIconData(), 0,
193 // weatherData.getIconData().length);
196 final Bitmap picture = BitmapFactory.decodeResource(
197 this.getResources(), R.drawable.ic_02d);
198 final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.getDefault());
199 tempFormatter.applyPattern("#####.##");
200 final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM d", Locale.getDefault());
201 final double tempUnits = this.mIsFahrenheit ? 0 : 273.15;
202 double temp = weatherData.getMain().getTemp();
203 temp = temp - tempUnits;
204 double maxTemp = weatherData.getMain().getMaxTemp();
205 maxTemp = maxTemp - tempUnits;
206 double minTemp = weatherData.getMain().getMinTemp();
207 minTemp = minTemp - tempUnits;
209 final Calendar now = Calendar.getInstance();
210 if (weatherData.getWeather() != null) {
211 for (int i = 0; i<15; i++) {
212 final Date day = now.getTime();
213 entries.set(i, new WeatherOverviewEntry(dateFormat.format(day),
214 tempFormatter.format(temp), tempFormatter
215 .format(maxTemp), tempFormatter
216 .format(minTemp), picture));
217 now.add(Calendar.DAY_OF_MONTH, 1);
221 this.setListAdapter(null);
222 adapter.addAll(entries);
223 this.setListAdapter(adapter);
227 public void onResume() {
230 final SharedPreferences sharedPreferences = PreferenceManager
231 .getDefaultSharedPreferences(this.getActivity());
233 // 1. Update units of measurement.
234 String keyPreference = this.getResources().getString(
235 R.string.weather_preferences_units_key);
236 final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
237 final String celsius = this.getResources().getString(
238 R.string.weather_preferences_units_celsius);
239 if (unitsPreferenceValue.equals(celsius)) {
240 this.mIsFahrenheit = false;
242 this.mIsFahrenheit = true;
246 // 2. Update current data on display.
247 WeatherData weatherData = null;
249 weatherData = this.restoreWeatherDataFromFile();
250 } catch (final StreamCorruptedException e) {
251 Log.e(TAG, "onResume exception: ", e);
252 } catch (final FileNotFoundException e) {
253 Log.e(TAG, "onResume exception: ", e);
254 } catch (final IOException e) {
255 Log.e(TAG, "onResume exception: ", e);
256 } catch (final ClassNotFoundException e) {
257 Log.e(TAG, "onResume exception: ", e);
259 if (weatherData != null) {
260 this.updateWeatherData(weatherData);
264 // 3. If language changed, try to retrieve new data for new language
265 // (new strings with the chosen language)
266 keyPreference = this.getResources().getString(
267 R.string.weather_preferences_language_key);
268 final String languagePreferenceValue = sharedPreferences.getString(
270 if (!languagePreferenceValue.equals(this.mLanguage)) {
271 this.mLanguage = languagePreferenceValue;
276 public class WeatherTask extends AsyncTask<Object, Void, WeatherData> {
277 private static final String TAG = "WeatherTask";
278 private final WeatherHTTPClient weatherHTTPClient;
279 private final WeatherService weatherService;
280 private final DialogFragment newFragment;
282 public WeatherTask(final WeatherHTTPClient weatherHTTPClient,
283 final WeatherService weatherService) {
284 this.weatherHTTPClient = weatherHTTPClient;
285 this.weatherService = weatherService;
286 this.newFragment = ProgressDialogFragment.newInstance(
287 R.string.progress_dialog_get_remote_data,
288 WeatherInformationOverviewFragment.this
289 .getString(R.string.progress_dialog_generic_message));
293 protected void onPreExecute() {
294 this.newFragment.show(WeatherInformationOverviewFragment.this.getActivity()
295 .getFragmentManager(), "progressDialog");
299 protected WeatherData doInBackground(final Object... params) {
300 WeatherData weatherData = null;
303 weatherData = this.doInBackgroundThrowable(params);
304 } catch (final ClientProtocolException e) {
305 Log.e(TAG, "doInBackground exception: ", e);
306 } catch (final MalformedURLException e) {
307 Log.e(TAG, "doInBackground exception: ", e);
308 } catch (final URISyntaxException e) {
309 Log.e(TAG, "doInBackground exception: ", e);
310 } catch (final IOException e) {
311 // logger infrastructure swallows UnknownHostException :/
312 Log.e(TAG, "doInBackground exception: " + e.getMessage(), e);
313 } catch (final JSONException e) {
314 Log.e(TAG, "doInBackground exception: ", e);
316 this.weatherHTTPClient.close();
323 protected void onPostExecute(final WeatherData weatherData) {
324 this.weatherHTTPClient.close();
326 this.newFragment.dismiss();
328 if (weatherData != null) {
330 this.onPostExecuteThrowable(weatherData);
331 } catch (final IOException e) {
332 Log.e(TAG, "WeatherTask onPostExecute exception: ", e);
333 final DialogFragment newFragment = ErrorDialogFragment
334 .newInstance(R.string.error_dialog_generic_error);
335 newFragment.show(WeatherInformationOverviewFragment.this.getFragmentManager(), "errorDialog");
338 final DialogFragment newFragment = ErrorDialogFragment
339 .newInstance(R.string.error_dialog_generic_error);
340 newFragment.show(WeatherInformationOverviewFragment.this.getFragmentManager(), "errorDialog");
345 protected void onCancelled(final WeatherData weatherData) {
346 this.weatherHTTPClient.close();
348 final DialogFragment newFragment = ErrorDialogFragment
349 .newInstance(R.string.error_dialog_connection_tiemout);
350 newFragment.show(WeatherInformationOverviewFragment.this.getFragmentManager(), "errorDialog");
353 private WeatherData doInBackgroundThrowable(final Object... params)
354 throws ClientProtocolException, MalformedURLException,
355 URISyntaxException, IOException, JSONException {
356 final SharedPreferences sharedPreferences = PreferenceManager
357 .getDefaultSharedPreferences(WeatherInformationOverviewFragment.this
360 final String keyPreference = WeatherInformationOverviewFragment.this
361 .getActivity().getString(
362 R.string.weather_preferences_language_key);
363 final String languagePreferenceValue = sharedPreferences.getString(keyPreference, "");
365 final GeocodingData geocodingData = (GeocodingData) params[0];
366 final String urlAPICoord = WeatherInformationOverviewFragment.this.getResources()
367 .getString(R.string.uri_api_coord);
368 final String APIVersion = WeatherInformationOverviewFragment.this.getResources()
369 .getString(R.string.api_version);
370 String url = this.weatherService.createURIAPICoord(geocodingData.getLatitude(),
371 geocodingData.getLongitude(), urlAPICoord, APIVersion, languagePreferenceValue);
374 final String jsonData = this.weatherHTTPClient.retrieveJSONDataFromAPI(new URL(url));
377 final WeatherData weatherData = this.weatherService.retrieveDataFromJPOS(jsonData);
380 final String icon = weatherData.getWeather().getIcon();
381 final String urlAPIicon = WeatherInformationOverviewFragment.this
382 .getResources().getString(R.string.uri_api_icon);
383 url = this.weatherService.createURIAPIicon(icon, urlAPIicon);
384 final byte[] iconData = this.weatherHTTPClient
385 .retrieveDataFromAPI(new URL(url)).toByteArray();
386 weatherData.setIconData(iconData);
392 private void onPostExecuteThrowable(final WeatherData weatherData)
393 throws FileNotFoundException, IOException {
394 WeatherInformationOverviewFragment.this.storeWeatherDataToFile(weatherData);
396 WeatherInformationOverviewFragment.this.updateWeatherData(weatherData);
400 private List<WeatherOverviewEntry> createEmptyEntriesList() {
401 final List<WeatherOverviewEntry> entries = new ArrayList<WeatherOverviewEntry>();
402 final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM d", Locale.getDefault());
404 final Calendar now = Calendar.getInstance();
405 for (int i = 0; i<15; i++) {
406 final Date day = now.getTime();
407 entries.add(i, new WeatherOverviewEntry(dateFormat.format(day),
408 null, null, null, null));
409 now.add(Calendar.DAY_OF_MONTH, 1);
415 private void storeWeatherDataToFile(final WeatherData weatherData)
416 throws FileNotFoundException, IOException {
417 final OutputStream persistenceFile = this.getActivity().openFileOutput(
418 WEATHER_DATA_FILE, Context.MODE_PRIVATE);
420 ObjectOutputStream oos = null;
422 oos = new ObjectOutputStream(persistenceFile);
424 oos.writeObject(weatherData);
432 private WeatherData restoreWeatherDataFromFile() throws StreamCorruptedException,
433 FileNotFoundException, IOException, ClassNotFoundException {
434 final InputStream persistenceFile = this.getActivity().openFileInput(
437 ObjectInputStream ois = null;
439 ois = new ObjectInputStream(persistenceFile);
441 return (WeatherData) ois.readObject();
449 private GeocodingData restoreGeocodingDataFromFile()
450 throws StreamCorruptedException, FileNotFoundException,
451 IOException, ClassNotFoundException {
452 final InputStream persistenceFile = this.getActivity()
453 .openFileInput(WEATHER_GEOCODING_FILE);
455 ObjectInputStream ois = null;
457 ois = new ObjectInputStream(persistenceFile);
459 return (GeocodingData) ois.readObject();