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.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;
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);
82 listWeatherView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
85 public boolean onCreateActionMode(final ActionMode mode,
91 public boolean onPrepareActionMode(final ActionMode mode,
97 public boolean onActionItemClicked(final ActionMode mode,
98 final MenuItem item) {
103 public void onDestroyActionMode(final ActionMode mode) {
107 public void onItemCheckedStateChanged(
108 final ActionMode mode, final int position,
109 final long id, final boolean checked) {
113 if (savedInstanceState != null) {
115 final WeatherData weatherData = (WeatherData) savedInstanceState
116 .getSerializable("weatherData");
118 this.storeWeatherDataToFile(weatherData);
119 } catch (final IOException e) {
120 ((ErrorMessage) WeatherInformationOverviewFragment.this
122 .createErrorDialog(R.string.error_dialog_generic_error);
126 this.setHasOptionsMenu(false);
128 final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(
129 this.getActivity(), R.layout.weather_main_entry_list);
131 final Collection<WeatherOverviewEntry> entries = this
132 .createEmptyEntriesList();
134 this.setListAdapter(null);
135 adapter.addAll(entries);
136 this.setListAdapter(adapter);
137 this.setListShown(true);
138 this.setListShownNoAnimation(true);
142 public void onSaveInstanceState(final Bundle savedInstanceState) {
145 WeatherData weatherData = null;
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);
158 if (weatherData != null) {
159 savedInstanceState.putSerializable("weatherData", weatherData);
162 super.onSaveInstanceState(savedInstanceState);
166 public void getWeather() {
168 GeocodingData geocodingData = null;
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);
181 if (geocodingData != null) {
182 final IJPOSWeatherParser JPOSWeatherParser = new JPOSWeatherParser();
183 final WeatherService weatherService = new WeatherService(
185 final AndroidHttpClient httpClient = AndroidHttpClient
186 .newInstance("Android Weather Information Agent");
187 final WeatherHTTPClient HTTPweatherClient = new WeatherHTTPClient(
190 final WeatherTask weatherTask = new WeatherTask(HTTPweatherClient, weatherService);
193 weatherTask.execute(geocodingData);
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);
203 // Bitmap picture = null;
205 // if (weatherData.getWeather().getIcon() != null) {
206 // picture= BitmapFactory.decodeByteArray(
207 // weatherData.getIconData(), 0,
208 // weatherData.getIconData().length);
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;
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);
236 this.setListAdapter(null);
237 adapter.addAll(entries);
238 this.setListAdapter(adapter);
242 public void onResume() {
245 final SharedPreferences sharedPreferences = PreferenceManager
246 .getDefaultSharedPreferences(this.getActivity());
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;
257 this.mIsFahrenheit = true;
261 // 2. Update current data on display.
262 WeatherData weatherData = null;
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);
274 if (weatherData != null) {
275 this.updateWeatherData(weatherData);
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(
285 if (!languagePreferenceValue.equals(this.mLanguage)) {
286 this.mLanguage = languagePreferenceValue;
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;
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));
308 protected void onPreExecute() {
309 this.newFragment.show(WeatherInformationOverviewFragment.this.getActivity()
310 .getFragmentManager(), "progressDialog");
314 protected WeatherData doInBackground(final Object... params) {
315 WeatherData weatherData = null;
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);
331 this.weatherHTTPClient.close();
338 protected void onPostExecute(final WeatherData weatherData) {
339 this.weatherHTTPClient.close();
341 this.newFragment.dismiss();
343 if (weatherData != null) {
345 this.onPostExecuteThrowable(weatherData);
346 } catch (final IOException e) {
347 Log.e(TAG, "WeatherTask onPostExecute exception: ", e);
348 ((ErrorMessage) WeatherInformationOverviewFragment.this
350 .createErrorDialog(R.string.error_dialog_generic_error);
353 ((ErrorMessage) WeatherInformationOverviewFragment.this
355 .createErrorDialog(R.string.error_dialog_generic_error);
360 protected void onCancelled(final WeatherData weatherData) {
361 this.weatherHTTPClient.close();
363 ((ErrorMessage) WeatherInformationOverviewFragment.this.getActivity())
364 .createErrorDialog(R.string.error_dialog_connection_tiemout);
367 private WeatherData doInBackgroundThrowable(final Object... params)
368 throws ClientProtocolException, MalformedURLException,
369 URISyntaxException, IOException, JSONException {
370 final SharedPreferences sharedPreferences = PreferenceManager
371 .getDefaultSharedPreferences(WeatherInformationOverviewFragment.this
374 final String keyPreference = WeatherInformationOverviewFragment.this
375 .getActivity().getString(
376 R.string.weather_preferences_language_key);
377 final String languagePreferenceValue = sharedPreferences.getString(keyPreference, "");
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);
388 final String jsonData = this.weatherHTTPClient.retrieveJSONDataFromAPI(new URL(url));
391 final WeatherData weatherData = this.weatherService.retrieveDataFromJPOS(jsonData);
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);
406 private void onPostExecuteThrowable(final WeatherData weatherData)
407 throws FileNotFoundException, IOException {
408 WeatherInformationOverviewFragment.this.storeWeatherDataToFile(weatherData);
410 WeatherInformationOverviewFragment.this.updateWeatherData(weatherData);
414 private List<WeatherOverviewEntry> createEmptyEntriesList() {
415 final List<WeatherOverviewEntry> entries = new ArrayList<WeatherOverviewEntry>();
416 final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM d", Locale.getDefault());
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);
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);
434 ObjectOutputStream oos = null;
436 oos = new ObjectOutputStream(persistenceFile);
438 oos.writeObject(weatherData);
446 private WeatherData restoreWeatherDataFromFile() throws StreamCorruptedException,
447 FileNotFoundException, IOException, ClassNotFoundException {
448 final InputStream persistenceFile = this.getActivity().openFileInput(
451 ObjectInputStream ois = null;
453 ois = new ObjectInputStream(persistenceFile);
455 return (WeatherData) ois.readObject();
463 private GeocodingData restoreGeocodingDataFromFile()
464 throws StreamCorruptedException, FileNotFoundException,
465 IOException, ClassNotFoundException {
466 final InputStream persistenceFile = this.getActivity()
467 .openFileInput(WEATHER_GEOCODING_FILE);
469 ObjectInputStream ois = null;
471 ois = new ObjectInputStream(persistenceFile);
473 return (GeocodingData) ois.readObject();