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.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;
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;
60 public void onCreate(final Bundle savedInstanceState) {
61 super.onCreate(savedInstanceState);
63 this.getActivity().deleteFile(WEATHER_DATA_FILE);
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(
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,
86 public void onActivityCreated(final Bundle savedInstanceState) {
87 super.onActivityCreated(savedInstanceState);
89 final ListView listWeatherView = (ListView) this.getActivity().findViewById(
90 R.id.weather_main_list_view);
92 final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(this.getActivity(),
93 R.layout.weather_main_entry_list);
95 final Collection<WeatherOverviewEntry> entries = this.createEmptyEntriesList();
97 adapter.addAll(entries);
98 listWeatherView.setAdapter(adapter);
100 if (savedInstanceState != null) {
102 final WeatherData weatherData = (WeatherData) savedInstanceState
103 .getSerializable("weatherData");
105 this.storeWeatherDataToFile(weatherData);
106 } catch (final IOException e) {
107 ((ErrorMessage) WeatherInformationOverviewFragment.this
109 .createErrorDialog(R.string.error_dialog_generic_error);
115 public void onSaveInstanceState(final Bundle savedInstanceState) {
118 WeatherData weatherData = null;
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);
131 if (weatherData != null) {
132 savedInstanceState.putSerializable("weatherData", weatherData);
135 super.onSaveInstanceState(savedInstanceState);
139 public void getWeather() {
141 GeocodingData geocodingData = null;
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);
154 if (geocodingData != null) {
155 final IJPOSWeatherParser JPOSWeatherParser = new JPOSWeatherParser();
156 final WeatherService weatherService = new WeatherService(
158 final AndroidHttpClient httpClient = AndroidHttpClient
159 .newInstance("Android Weather Information Agent");
160 final WeatherHTTPClient HTTPweatherClient = new WeatherHTTPClient(
163 final WeatherTask weatherTask = new WeatherTask(HTTPweatherClient, weatherService);
166 weatherTask.execute(geocodingData);
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);
178 Bitmap picture = null;
180 if (weatherData.getWeather().getIcon() != null) {
181 picture= BitmapFactory.decodeByteArray(
182 weatherData.getIconData(), 0,
183 weatherData.getIconData().length);
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;
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);
204 listWeatherView.setAdapter(null);
205 adapter.addAll(entries);
206 listWeatherView.setAdapter(adapter);
210 public void onResume() {
213 final SharedPreferences sharedPreferences = PreferenceManager
214 .getDefaultSharedPreferences(this.getActivity());
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;
225 this.mIsFahrenheit = true;
229 // 2. Update current data on display.
230 WeatherData weatherData = null;
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);
242 if (weatherData != null) {
243 this.updateWeatherData(weatherData);
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(
253 if (!languagePreferenceValue.equals(this.mLanguage)) {
254 this.mLanguage = languagePreferenceValue;
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;
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));
276 protected void onPreExecute() {
277 this.newFragment.show(WeatherInformationOverviewFragment.this.getActivity()
278 .getFragmentManager(), "progressDialog");
282 protected WeatherData doInBackground(final Object... params) {
283 WeatherData weatherData = null;
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);
299 this.weatherHTTPClient.close();
306 protected void onPostExecute(final WeatherData weatherData) {
307 this.weatherHTTPClient.close();
309 this.newFragment.dismiss();
311 if (weatherData != null) {
313 this.onPostExecuteThrowable(weatherData);
314 } catch (final IOException e) {
315 Log.e(TAG, "WeatherTask onPostExecute exception: ", e);
316 ((ErrorMessage) WeatherInformationOverviewFragment.this
318 .createErrorDialog(R.string.error_dialog_generic_error);
321 ((ErrorMessage) WeatherInformationOverviewFragment.this
323 .createErrorDialog(R.string.error_dialog_generic_error);
328 protected void onCancelled(final WeatherData weatherData) {
329 this.weatherHTTPClient.close();
331 ((ErrorMessage) WeatherInformationOverviewFragment.this.getActivity())
332 .createErrorDialog(R.string.error_dialog_connection_tiemout);
335 private WeatherData doInBackgroundThrowable(final Object... params)
336 throws ClientProtocolException, MalformedURLException,
337 URISyntaxException, IOException, JSONException {
338 final SharedPreferences sharedPreferences = PreferenceManager
339 .getDefaultSharedPreferences(WeatherInformationOverviewFragment.this
342 final String keyPreference = WeatherInformationOverviewFragment.this
343 .getActivity().getString(
344 R.string.weather_preferences_language_key);
345 final String languagePreferenceValue = sharedPreferences.getString(keyPreference, "");
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);
356 final String jsonData = this.weatherHTTPClient.retrieveJSONDataFromAPI(new URL(url));
359 final WeatherData weatherData = this.weatherService.retrieveDataFromJPOS(jsonData);
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);
374 private void onPostExecuteThrowable(final WeatherData weatherData)
375 throws FileNotFoundException, IOException {
376 WeatherInformationOverviewFragment.this.storeWeatherDataToFile(weatherData);
378 WeatherInformationOverviewFragment.this.updateWeatherData(weatherData);
382 private List<WeatherOverviewEntry> createEmptyEntriesList() {
383 final List<WeatherOverviewEntry> entries = new ArrayList<WeatherOverviewEntry>();
384 final SimpleDateFormat dateFormat = new SimpleDateFormat("MM.dd", Locale.getDefault());
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);
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);
402 ObjectOutputStream oos = null;
404 oos = new ObjectOutputStream(persistenceFile);
406 oos.writeObject(weatherData);
414 private WeatherData restoreWeatherDataFromFile() throws StreamCorruptedException,
415 FileNotFoundException, IOException, ClassNotFoundException {
416 final InputStream persistenceFile = this.getActivity().openFileInput(
419 ObjectInputStream ois = null;
421 ois = new ObjectInputStream(persistenceFile);
423 return (WeatherData) ois.readObject();
431 private GeocodingData restoreGeocodingDataFromFile()
432 throws StreamCorruptedException, FileNotFoundException,
433 IOException, ClassNotFoundException {
434 final InputStream persistenceFile = this.getActivity()
435 .openFileInput(WEATHER_GEOCODING_FILE);
437 ObjectInputStream ois = null;
439 ois = new ObjectInputStream(persistenceFile);
441 return (GeocodingData) ois.readObject();