2 * Copyright 2014 Gustavo Martin Morcuende
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package name.gumartinm.weather.information.fragment.current;
18 import java.io.IOException;
19 import java.net.MalformedURLException;
20 import java.net.URISyntaxException;
22 import java.text.DecimalFormat;
23 import java.text.NumberFormat;
24 import java.text.SimpleDateFormat;
25 import java.util.Date;
26 import java.util.Locale;
28 import org.apache.http.client.ClientProtocolException;
30 import android.content.BroadcastReceiver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.SharedPreferences;
35 import android.graphics.Bitmap;
36 import android.graphics.BitmapFactory;
37 import android.net.http.AndroidHttpClient;
38 import android.os.AsyncTask;
39 import android.os.Bundle;
40 import android.preference.PreferenceManager;
41 import android.support.v4.app.Fragment;
42 import android.support.v4.content.LocalBroadcastManager;
43 import android.util.Log;
44 import android.view.LayoutInflater;
45 import android.view.View;
46 import android.view.ViewGroup;
47 import android.widget.ImageView;
48 import android.widget.ProgressBar;
49 import android.widget.TextView;
51 import com.fasterxml.jackson.core.JsonParseException;
52 import name.gumartinm.weather.information.R;
53 import name.gumartinm.weather.information.httpclient.CustomHTTPClient;
54 import name.gumartinm.weather.information.model.DatabaseQueries;
55 import name.gumartinm.weather.information.model.WeatherLocation;
56 import name.gumartinm.weather.information.model.currentweather.Current;
57 import name.gumartinm.weather.information.parser.JPOSCurrentParser;
58 import name.gumartinm.weather.information.service.IconsList;
59 import name.gumartinm.weather.information.service.PermanentStorage;
60 import name.gumartinm.weather.information.service.ServiceCurrentParser;
61 import name.gumartinm.weather.information.widget.WidgetProvider;
63 public class CurrentFragment extends Fragment {
64 private static final String TAG = "CurrentFragment";
65 private BroadcastReceiver mReceiver;
68 public void onCreate(final Bundle savedInstanceState) {
69 super.onCreate(savedInstanceState);
73 public View onCreateView(LayoutInflater inflater, ViewGroup container,
74 Bundle savedInstanceState) {
76 // Inflate the layout for this fragment
77 return inflater.inflate(R.layout.weather_current_fragment, container, false);
81 public void onActivityCreated(final Bundle savedInstanceState) {
82 super.onActivityCreated(savedInstanceState);
84 if (savedInstanceState != null) {
86 final Current current = (Current) savedInstanceState.getSerializable("Current");
88 if (current != null) {
89 final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
90 store.saveCurrent(current);
94 this.setHasOptionsMenu(false);
96 this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
97 this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
98 this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
102 public void onResume() {
106 this.mReceiver = new BroadcastReceiver() {
109 public void onReceive(final Context context, final Intent intent) {
110 final String action = intent.getAction();
111 if (action.equals("name.gumartinm.weather.information.UPDATECURRENT")) {
112 final Current currentRemote = (Current) intent.getSerializableExtra("current");
114 if (currentRemote != null) {
116 // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask.
117 final DatabaseQueries query = new DatabaseQueries(context.getApplicationContext());
118 final WeatherLocation weatherLocation = query.queryDataBase();
119 final PermanentStorage store = new PermanentStorage(context.getApplicationContext());
120 final Current current = store.getCurrent();
122 if (current == null || !CurrentFragment.this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
124 CurrentFragment.this.updateUI(currentRemote);
126 // 3. Update current data.
127 store.saveCurrent(currentRemote);
129 // 4. Update location data.
130 weatherLocation.setLastCurrentUIUpdate(new Date());
131 query.updateDataBase(weatherLocation);
135 // Empty UI and show error message
136 CurrentFragment.this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
137 CurrentFragment.this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
138 CurrentFragment.this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.VISIBLE);
145 final IntentFilter filter = new IntentFilter();
146 filter.addAction("name.gumartinm.weather.information.UPDATECURRENT");
147 LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext())
148 .registerReceiver(this.mReceiver, filter);
151 this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
153 final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext());
154 final WeatherLocation weatherLocation = query.queryDataBase();
155 if (weatherLocation == null) {
157 // Show error message
158 final ProgressBar progress = (ProgressBar) getActivity().findViewById(R.id.weather_current_progressbar);
159 progress.setVisibility(View.GONE);
160 final TextView errorMessage = (TextView) getActivity().findViewById(R.id.weather_current_error_message);
161 errorMessage.setVisibility(View.VISIBLE);
165 // If is new location update widgets.
166 if (weatherLocation.getIsNew()) {
167 WidgetProvider.refreshAllAppWidgets(this.getActivity().getApplicationContext());
168 // Update location data.
169 weatherLocation.setIsNew(false);
170 query.updateDataBase(weatherLocation);
174 final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
175 final Current current = store.getCurrent();
177 if (current != null && this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
178 this.updateUI(current);
180 // Load remote data (aynchronous)
181 // Gets the data from the web.
182 this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
183 this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
184 final CurrentTask task = new CurrentTask(
185 this.getActivity().getApplicationContext(),
186 new CustomHTTPClient(AndroidHttpClient.newInstance(this.getString(R.string.http_client_agent))),
187 new ServiceCurrentParser(new JPOSCurrentParser()));
189 task.execute(weatherLocation.getLatitude(), weatherLocation.getLongitude());
194 public void onSaveInstanceState(final Bundle savedInstanceState) {
197 final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
198 final Current current = store.getCurrent();
200 if (current != null) {
201 savedInstanceState.putSerializable("Current", current);
204 super.onSaveInstanceState(savedInstanceState);
208 public void onPause() {
209 LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver);
214 private interface UnitsConversor {
216 public double doConversion(final double value);
219 private void updateUI(final Current current) {
221 final SharedPreferences sharedPreferences = PreferenceManager
222 .getDefaultSharedPreferences(this.getActivity().getApplicationContext());
224 // TODO: repeating the same code in Overview, Specific and Current!!!
225 // 1. Update units of measurement.
228 UnitsConversor tempUnitsConversor;
229 String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
230 String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
231 String unitsPreferenceValue = sharedPreferences.getString(
232 keyPreference, this.getString(R.string.weather_preferences_temperature_celsius));
233 if (unitsPreferenceValue.equals(values[0])) {
234 tempSymbol = values[0];
235 tempUnitsConversor = new UnitsConversor(){
238 public double doConversion(final double value) {
239 return value - 273.15;
243 } else if (unitsPreferenceValue.equals(values[1])) {
244 tempSymbol = values[1];
245 tempUnitsConversor = new UnitsConversor(){
248 public double doConversion(final double value) {
249 return (value * 1.8) - 459.67;
254 tempSymbol = values[2];
255 tempUnitsConversor = new UnitsConversor(){
258 public double doConversion(final double value) {
267 UnitsConversor windUnitsConversor;
268 keyPreference = this.getResources().getString(R.string.weather_preferences_wind_key);
269 values = this.getResources().getStringArray(R.array.weather_preferences_wind);
270 unitsPreferenceValue = sharedPreferences.getString(
271 keyPreference, this.getString(R.string.weather_preferences_wind_meters));
272 if (unitsPreferenceValue.equals(values[0])) {
273 windSymbol = values[0];
274 windUnitsConversor = new UnitsConversor(){
277 public double doConversion(double value) {
282 windSymbol = values[1];
283 windUnitsConversor = new UnitsConversor(){
286 public double doConversion(double value) {
287 return value * 2.237;
293 String pressureSymbol;
294 UnitsConversor pressureUnitsConversor;
295 keyPreference = this.getResources().getString(R.string.weather_preferences_pressure_key);
296 values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
297 unitsPreferenceValue = sharedPreferences.getString(
298 keyPreference, this.getString(R.string.weather_preferences_pressure_pascal));
299 if (unitsPreferenceValue.equals(values[0])) {
300 pressureSymbol = values[0];
301 pressureUnitsConversor = new UnitsConversor(){
304 public double doConversion(double value) {
309 pressureSymbol = values[1];
310 pressureUnitsConversor = new UnitsConversor(){
313 public double doConversion(double value) {
314 return value / 113.25d;
321 final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
322 tempFormatter.applyPattern("#####.#####");
323 final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.US);
326 // 3. Prepare data for UI.
328 if (current.getMain().getTemp_max() != null) {
329 double conversion = (Double) current.getMain().getTemp_max();
330 conversion = tempUnitsConversor.doConversion(conversion);
331 tempMax = tempFormatter.format(conversion) + tempSymbol;
334 if (current.getMain().getTemp_min() != null) {
335 double conversion = (Double) current.getMain().getTemp_min();
336 conversion = tempUnitsConversor.doConversion(conversion);
337 tempMin = tempFormatter.format(conversion) + tempSymbol;
340 if ((current.getWeather().size() > 0)
341 && (current.getWeather().get(0).getIcon() != null)
342 && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
343 final String icon = current.getWeather().get(0).getIcon();
344 picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
345 .getResourceDrawable());
347 picture = BitmapFactory.decodeResource(this.getResources(),
348 R.drawable.weather_severe_alert);
351 String description = this.getString(R.string.text_field_description_when_error);
352 if (current.getWeather().size() > 0) {
353 description = current.getWeather().get(0).getDescription();
356 String humidityValue = "";
357 if ((current.getMain() != null)
358 && (current.getMain().getHumidity() != null)) {
359 final double conversion = (Double) current.getMain().getHumidity();
360 humidityValue = tempFormatter.format(conversion);
362 String pressureValue = "";
363 if ((current.getMain() != null)
364 && (current.getMain().getPressure() != null)) {
365 double conversion = (Double) current.getMain().getPressure();
366 conversion = pressureUnitsConversor.doConversion(conversion);
367 pressureValue = tempFormatter.format(conversion);
369 String windValue = "";
370 if ((current.getWind() != null)
371 && (current.getWind().getSpeed() != null)) {
372 double conversion = (Double) current.getWind().getSpeed();
373 conversion = windUnitsConversor.doConversion(conversion);
374 windValue = tempFormatter.format(conversion);
376 String rainValue = "";
377 if ((current.getRain() != null)
378 && (current.getRain().get3h() != null)) {
379 final double conversion = (Double) current.getRain().get3h();
380 rainValue = tempFormatter.format(conversion);
382 String cloudsValue = "";
383 if ((current.getClouds() != null)
384 && (current.getClouds().getAll() != null)) {
385 final double conversion = (Double) current.getClouds().getAll();
386 cloudsValue = tempFormatter.format(conversion);
388 String snowValue = "";
389 if ((current.getSnow() != null)
390 && (current.getSnow().get3h() != null)) {
391 final double conversion = (Double) current.getSnow().get3h();
392 snowValue = tempFormatter.format(conversion);
394 String feelsLike = "";
395 if (current.getMain().getTemp() != null) {
396 double conversion = (Double) current.getMain().getTemp();
397 conversion = tempUnitsConversor.doConversion(conversion);
398 feelsLike = tempFormatter.format(conversion);
400 String sunRiseTime = "";
401 if (current.getSys().getSunrise() != null) {
402 final long unixTime = (Long) current.getSys().getSunrise();
403 final Date unixDate = new Date(unixTime * 1000L);
404 sunRiseTime = dateFormat.format(unixDate);
406 String sunSetTime = "";
407 if (current.getSys().getSunset() != null) {
408 final long unixTime = (Long) current.getSys().getSunset();
409 final Date unixDate = new Date(unixTime * 1000L);
410 sunSetTime = dateFormat.format(unixDate);
415 final TextView tempMaxView = (TextView) getActivity().findViewById(R.id.weather_current_temp_max);
416 tempMaxView.setText(tempMax);
417 final TextView tempMinView = (TextView) getActivity().findViewById(R.id.weather_current_temp_min);
418 tempMinView.setText(tempMin);
419 final ImageView pictureView = (ImageView) getActivity().findViewById(R.id.weather_current_picture);
420 pictureView.setImageBitmap(picture);
422 final TextView descriptionView = (TextView) getActivity().findViewById(R.id.weather_current_description);
423 descriptionView.setText(description);
425 ((TextView) getActivity().findViewById(R.id.weather_current_humidity_value)).setText(humidityValue);
426 ((TextView) getActivity().findViewById(R.id.weather_current_humidity_units)).setText(
427 this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
429 ((TextView) getActivity().findViewById(R.id.weather_current_pressure_value)).setText(pressureValue);
430 ((TextView) getActivity().findViewById(R.id.weather_current_pressure_units)).setText(pressureSymbol);
432 ((TextView) getActivity().findViewById(R.id.weather_current_wind_value)).setText(windValue);
433 ((TextView) getActivity().findViewById(R.id.weather_current_wind_units)).setText(windSymbol);
435 ((TextView) getActivity().findViewById(R.id.weather_current_rain_value)).setText(rainValue);
436 ((TextView) getActivity().findViewById(R.id.weather_current_rain_units)).setText(
437 this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
439 ((TextView) getActivity().findViewById(R.id.weather_current_clouds_value)).setText(cloudsValue);
440 ((TextView) getActivity().findViewById(R.id.weather_current_clouds_units)).setText(
441 this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
443 ((TextView) getActivity().findViewById(R.id.weather_current_snow_value)).setText(snowValue);
444 ((TextView) getActivity().findViewById(R.id.weather_current_snow_units)).setText(
445 this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
447 ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_value)).setText(feelsLike);
448 ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_units)).setText(tempSymbol);
450 ((TextView) getActivity().findViewById(R.id.weather_current_sunrise_value)).setText(sunRiseTime);
452 ((TextView) getActivity().findViewById(R.id.weather_current_sunset_value)).setText(sunSetTime);
454 this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.VISIBLE);
455 this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
456 this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
459 private boolean isDataFresh(final Date lastUpdate) {
460 if (lastUpdate == null) {
464 final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
465 this.getActivity().getApplicationContext());
466 final String keyPreference = this.getString(R.string.weather_preferences_refresh_interval_key);
467 final String refresh = sharedPreferences.getString(
469 this.getResources().getStringArray(R.array.weather_preferences_refresh_interval)[0]);
470 final Date currentTime = new Date();
471 if (((currentTime.getTime() - lastUpdate.getTime())) < Long.valueOf(refresh)) {
478 private class CurrentTask extends AsyncTask<Object, Void, Current> {
479 // Store the context passed to the AsyncTask when the system instantiates it.
480 private final Context localContext;
481 final CustomHTTPClient HTTPClient;
482 final ServiceCurrentParser weatherService;
484 public CurrentTask(final Context context, final CustomHTTPClient HTTPClient,
485 final ServiceCurrentParser weatherService) {
486 this.localContext = context;
487 this.HTTPClient = HTTPClient;
488 this.weatherService = weatherService;
492 protected Current doInBackground(final Object... params) {
493 final double latitude = (Double) params[0];
494 final double longitude = (Double) params[1];
496 Current current = null;
498 current = this.doInBackgroundThrowable(latitude, longitude);
499 } catch (final JsonParseException e) {
500 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
501 } catch (final ClientProtocolException e) {
502 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
503 } catch (final MalformedURLException e) {
504 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
505 } catch (final URISyntaxException e) {
506 Log.e(TAG, "CurrentTask doInBackground exception: ", e);
507 } catch (final IOException e) {
508 // logger infrastructure swallows UnknownHostException :/
509 Log.e(TAG, "CurrentTask doInBackground exception: " + e.getMessage(), e);
517 private Current doInBackgroundThrowable(final double latitude, final double longitude)
518 throws URISyntaxException, ClientProtocolException, JsonParseException, IOException {
520 final String APIVersion = localContext.getResources().getString(R.string.api_version);
521 final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_today);
522 final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, latitude, longitude);
523 final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
524 final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
526 return weatherService.retrieveCurrentFromJPOS(jsonData);
530 protected void onPostExecute(final Current current) {
532 // Call updateUI on the UI thread.
533 final Intent currentData = new Intent("name.gumartinm.weather.information.UPDATECURRENT");
534 currentData.putExtra("current", current);
535 LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(currentData);