<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
+ android:logo="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="de.example.exampletdd.WeatherInformationActivity"
- android:label="@string/app_name"
android:hardwareAccelerated="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</activity>
<activity
- android:label="@string/app_name"
android:name=".WeatherInformationPreferencesActivity"
- android:theme="@android:style/Theme.Holo">
+ android:parentActivityName="de.example.exampletdd.WeatherInformationActivity">
<intent-filter >
<action android:name="android.intent.action.WEATHERINFORMATIONSETTINGS" />
<category android:name="android.intent.category.LAUNCHER" />
android:layout_width="match_parent"
android:layout_height="match_parent"
class="de.example.exampletdd.fragment.WeatherInformationDataFragment"
- tools:layout="@layout/fragment_main" />
+ tools:layout="@layout/weather_data_list" />
</FrameLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_data_entry_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="normal" />
+
+ <TextView
+ android:id="@+id/weather_data_entry_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold" />
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:id="@+id/weather_picture"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:contentDescription="@string/icon_weather_description"
+ android:scaleType="fitCenter"
+ android:src="@drawable/ic_launcher" />
+
+ <ListView
+ android:id="@+id/weather_data_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ </ListView>
+
+
+</LinearLayout>
+
+
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
<item
android:id="@+id/weather_menu_settings"
android:menuCategory="system"
android:visible="true"
android:checkable="false"
android:enabled="true"
- android:showAsAction="collapseActionView">
+ android:showAsAction="never">
</item>
+
</menu>
<string name="app_name">Weather Information</string>
<string name="action_settings">Settings</string>
+ <string name="action_search">City,country</string>
<string name="button_weather">Get weather</string>
<string name="uri_api_coord">http://api.openweathermap.org/data/{0}/weather?lat={1}&lon={2}</string>
<string name="uri_api_city">http://api.openweathermap.org/data/{0}/weather?q={1}</string>
<string name="text_field_city">City name</string>
<string name="text_field_latitude">Latitude</string>
<string name="text_field_longitude">Longitude</string>
- <string name="text_field_sun_rise">Sun rise time</string>
- <string name="text_field_sun_set">Sun set time</string>
- <string name="text_field_description">Weather description</string>
- <string name="text_field_tem">Temperature</string>
- <string name="text_field_tem_min">Min temperature</string>
- <string name="text_field_tem_max">Max temperature</string>
+ <string name="text_field_sun_rise">Sun rise time:</string>
+ <string name="text_field_sun_set">Sun set time:</string>
+ <string name="text_field_description">Weather description:</string>
+ <string name="text_field_tem">Temperature:</string>
+ <string name="text_field_tem_min">Min temperature:</string>
+ <string name="text_field_tem_max">Max temperature:</string>
+ <string name="text_field_cloudiness">Cloudiness:</string>
+ <string name="text_field_rain_time">Rain time:</string>
+ <string name="text_field_rain_amount">Rain amount:</string>
+ <string name="text_field_wind_speed">Wind speed:</string>
+ <string name="text_field_humidity">Humidity in %:</string>
<string name="button_ok">OK</string>
<string name="error_dialog_connection_tiemout">Connection error timeout</string>
<string name="error_dialog_generic_error">Impossible to receive weather data.</string>
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
- PreferenceManager.setDefaultValues(this, R.xml.weather_preferences,
- false);
+ PreferenceManager.setDefaultValues(this, R.xml.weather_preferences, false);
final ActionBar actionBar = this.getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
- actionBar.setTitle(this.getResources().getString(R.string.header_action_bar));
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_USE_LOGO, ActionBar.DISPLAY_USE_LOGO);
+ // actionBar.setTitle(this.getResources().getString(R.string.header_action_bar));
+ actionBar.setDisplayHomeAsUpEnabled(true);
// Better using xml files? How to deal with savedInstanceState with xml files?
// final WeatherDataFragment weatherDataFragment = new WeatherDataFragment();
--- /dev/null
+package de.example.exampletdd.fragment;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+import de.example.exampletdd.R;
+
+public class WeatherDataAdapter extends ArrayAdapter<WeatherDataEntry> {
+ private final int resource;
+
+ public WeatherDataAdapter(final Context context, final int resource) {
+ super(context, 0);
+
+ this.resource = resource;
+ }
+
+ @Override
+ public View getView(final int position, final View convertView,
+ final ViewGroup parent) {
+
+ // We need to get the best view (re-used if possible) and then
+ // retrieve its corresponding ViewHolder, which optimizes lookup
+ // efficiency
+ final View view = this.getWorkingView(convertView);
+ final ViewHolder viewHolder = this.getViewHolder(view);
+ final WeatherDataEntry entry = this.getItem(position);
+
+
+ // Setting the text view
+ viewHolder.headerView.setText(entry.getHeader());
+ viewHolder.bodyView.setText(entry.getBody());
+
+
+ return view;
+ }
+
+ private View getWorkingView(final View convertView) {
+ // The workingView is basically just the convertView re-used if possible
+ // or inflated new if not possible
+ View workingView = null;
+
+ if(null == convertView) {
+ final Context context = this.getContext();
+ final LayoutInflater inflater = (LayoutInflater)context.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+
+ workingView = inflater.inflate(this.resource, null);
+ } else {
+ workingView = convertView;
+ }
+
+ return workingView;
+ }
+
+ private ViewHolder getViewHolder(final View workingView) {
+ // The viewHolder allows us to avoid re-looking up view references
+ // Since views are recycled, these references will never change
+ final Object tag = workingView.getTag();
+ ViewHolder viewHolder = null;
+
+
+ if((null == tag) || !(tag instanceof ViewHolder)) {
+ viewHolder = new ViewHolder();
+
+ viewHolder.headerView = (TextView) workingView
+ .findViewById(R.id.weather_data_entry_header);
+ viewHolder.bodyView = (TextView) workingView
+ .findViewById(R.id.weather_data_entry_body);
+
+ workingView.setTag(viewHolder);
+
+ } else {
+ viewHolder = (ViewHolder) tag;
+ }
+
+ return viewHolder;
+ }
+
+ /**
+ * ViewHolder allows us to avoid re-looking up view references
+ * Since views are recycled, these references will never change
+ */
+ private static class ViewHolder {
+ public TextView headerView;
+ public TextView bodyView;
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.fragment;
+
+public class WeatherDataEntry {
+ private final String header;
+ private final String body;
+
+ public WeatherDataEntry(final String header, final String body) {
+ this.header = header;
+ this.body = body;
+ }
+
+ public String getHeader() {
+ return this.header;
+ }
+
+ public String getBody() {
+ return this.body;
+ }
+
+}
import java.net.URL;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.ArrayList;
+import java.util.Collection;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import android.app.Fragment;
import android.content.SharedPreferences;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.ImageView;
+import android.widget.ListView;
import de.example.exampletdd.R;
import de.example.exampletdd.activityinterface.ErrorMessage;
import de.example.exampletdd.activityinterface.OnClickButtons;
import de.example.exampletdd.service.WeatherService;
public class WeatherInformationDataFragment extends Fragment implements OnClickButtons {
+ private WeatherDataAdapter mAdapter;
private boolean isFahrenheit;
- private EditText weatherDescription;
- private EditText temperature;
- private EditText maxTemperature;
- private EditText minTemperature;
- private EditText sunRise;
- private EditText sunSet;
- private ImageView imageIcon;
@Override
public View onCreateView(final LayoutInflater inflater,
final ViewGroup container, final Bundle savedInstanceState) {
- final View rootView = inflater.inflate(R.layout.fragment_main,
+ final View rootView = inflater.inflate(R.layout.weather_data_list,
container, false);
-
- this.weatherDescription = (EditText) rootView.findViewById(R.id.editTextWeatherDescription);
- this.temperature = (EditText) rootView.findViewById(R.id.editTextTemperature);
- this.maxTemperature = (EditText) rootView.findViewById(R.id.editTextMaxTemperature);
- this.minTemperature = (EditText) rootView.findViewById(R.id.editTextMinTemperature);
- this.sunRise = (EditText) rootView.findViewById(R.id.editTextSunRise);
- this.sunSet = (EditText) rootView.findViewById(R.id.editTextSunSet);
- this.imageIcon = (ImageView) rootView.findViewById(R.id.imageIcon);
-
return rootView;
}
@Override
+ public void onActivityCreated(final Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ final ListView listWeatherView = (ListView) this.getActivity().findViewById(
+ R.id.weather_data_list_view);
+
+ this.mAdapter = new WeatherDataAdapter(this.getActivity(),
+ R.layout.weather_data_entry_list);
+
+ final Collection<WeatherDataEntry> entries = new ArrayList<WeatherDataEntry>();
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_description), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_tem), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_tem_max), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_tem_min), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_sun_rise), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_sun_set), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_cloudiness), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_rain_time), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_rain_amount), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_wind_speed), ""));
+ entries.add(new WeatherDataEntry(this.getString(R.string.text_field_humidity), ""));
+
+ this.mAdapter.addAll(entries);
+ listWeatherView.setAdapter(this.mAdapter);
+ }
+
+ @Override
public void onClickGetWeather(final View v) {
final IJPOSWeatherParser JPOSWeatherParser = new JPOSWeatherParser();
final WeatherTask weatherTask = new WeatherTask(HTTPweatherClient, weatherService);
- final EditText cityCountry = (EditText) this.getActivity()
- .findViewById(R.id.editTextCity);
- weatherTask.execute(cityCountry.getText().toString());
+ weatherTask.execute("London,uk");
}
public void updateWeatherData(final WeatherData weatherData) {
final double tempUnits = this.isFahrenheit ? 0 : 273.15;
if (weatherData.getWeather() != null) {
- this.weatherDescription.setText(weatherData.getWeather()
- .getDescription());
- double conversion = weatherData.getMain().getTemp();
- conversion = conversion - tempUnits;
- this.temperature.setText(tempFormatter.format(conversion));
- conversion = weatherData.getMain().getMaxTemp();
- conversion = conversion - tempUnits;
- this.maxTemperature.setText(tempFormatter.format(conversion));
- conversion = weatherData.getMain().getMinTemp();
- conversion = conversion - tempUnits;
- this.minTemperature.setText(tempFormatter.format(conversion));
+
}
if (weatherData.getSystem() != null) {
- long unixTime = weatherData.getSystem().getSunRiseTime();
- Date unixDate = new Date(unixTime * 1000L);
- String dateFormatUnix = dateFormat.format(unixDate);
- this.sunRise.setText(dateFormatUnix);
-
- unixTime = weatherData.getSystem().getSunSetTime();
- unixDate = new Date(unixTime * 1000L);
- dateFormatUnix = dateFormat.format(unixDate);
- this.sunSet.setText(dateFormatUnix);
+
}
if (weatherData.getIconData() != null) {
- final Bitmap icon = BitmapFactory.decodeByteArray(
- weatherData.getIconData(), 0,
- weatherData.getIconData().length);
- this.imageIcon.setImageBitmap(icon);
+
}
}
--- /dev/null
+package de.example.exampletdd.fragment;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.http.client.ClientProtocolException;
+import org.json.JSONException;
+
+import android.app.Fragment;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.http.AndroidHttpClient;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ImageView;
+import de.example.exampletdd.R;
+import de.example.exampletdd.activityinterface.ErrorMessage;
+import de.example.exampletdd.activityinterface.OnClickButtons;
+import de.example.exampletdd.httpclient.WeatherHTTPClient;
+import de.example.exampletdd.model.WeatherData;
+import de.example.exampletdd.parser.IJPOSWeatherParser;
+import de.example.exampletdd.parser.JPOSWeatherParser;
+import de.example.exampletdd.service.WeatherService;
+
+public class WeatherInformationDataFragmentDeprecated extends Fragment implements OnClickButtons {
+ private boolean isFahrenheit;
+ private EditText weatherDescription;
+ private EditText temperature;
+ private EditText maxTemperature;
+ private EditText minTemperature;
+ private EditText sunRise;
+ private EditText sunSet;
+ private ImageView imageIcon;
+
+
+ @Override
+ public View onCreateView(final LayoutInflater inflater,
+ final ViewGroup container, final Bundle savedInstanceState) {
+ final View rootView = inflater.inflate(R.layout.fragment_main,
+ container, false);
+
+
+ this.weatherDescription = (EditText) rootView.findViewById(R.id.editTextWeatherDescription);
+ this.temperature = (EditText) rootView.findViewById(R.id.editTextTemperature);
+ this.maxTemperature = (EditText) rootView.findViewById(R.id.editTextMaxTemperature);
+ this.minTemperature = (EditText) rootView.findViewById(R.id.editTextMinTemperature);
+ this.sunRise = (EditText) rootView.findViewById(R.id.editTextSunRise);
+ this.sunSet = (EditText) rootView.findViewById(R.id.editTextSunSet);
+ this.imageIcon = (ImageView) rootView.findViewById(R.id.imageIcon);
+
+ return rootView;
+ }
+
+ @Override
+ public void onClickGetWeather(final View v) {
+
+ final IJPOSWeatherParser JPOSWeatherParser = new JPOSWeatherParser();
+ final WeatherService weatherService = new WeatherService(
+ JPOSWeatherParser);
+ final AndroidHttpClient httpClient = AndroidHttpClient
+ .newInstance("Android Weather Information Agent");
+ final WeatherHTTPClient HTTPweatherClient = new WeatherHTTPClient(
+ httpClient);
+
+ final WeatherTask weatherTask = new WeatherTask(HTTPweatherClient, weatherService);
+
+ final EditText cityCountry = (EditText) this.getActivity()
+ .findViewById(R.id.editTextCity);
+
+ weatherTask.execute(cityCountry.getText().toString());
+ }
+
+ public void updateWeatherData(final WeatherData weatherData) {
+ final DecimalFormat tempFormatter = new DecimalFormat("#####.#####");
+ final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss Z");
+ final double tempUnits = this.isFahrenheit ? 0 : 273.15;
+
+ if (weatherData.getWeather() != null) {
+ this.weatherDescription.setText(weatherData.getWeather()
+ .getDescription());
+ double conversion = weatherData.getMain().getTemp();
+ conversion = conversion - tempUnits;
+ this.temperature.setText(tempFormatter.format(conversion));
+ conversion = weatherData.getMain().getMaxTemp();
+ conversion = conversion - tempUnits;
+ this.maxTemperature.setText(tempFormatter.format(conversion));
+ conversion = weatherData.getMain().getMinTemp();
+ conversion = conversion - tempUnits;
+ this.minTemperature.setText(tempFormatter.format(conversion));
+ }
+
+ if (weatherData.getSystem() != null) {
+ long unixTime = weatherData.getSystem().getSunRiseTime();
+ Date unixDate = new Date(unixTime * 1000L);
+ String dateFormatUnix = dateFormat.format(unixDate);
+ this.sunRise.setText(dateFormatUnix);
+
+ unixTime = weatherData.getSystem().getSunSetTime();
+ unixDate = new Date(unixTime * 1000L);
+ dateFormatUnix = dateFormat.format(unixDate);
+ this.sunSet.setText(dateFormatUnix);
+ }
+
+ if (weatherData.getIconData() != null) {
+ final Bitmap icon = BitmapFactory.decodeByteArray(
+ weatherData.getIconData(), 0,
+ weatherData.getIconData().length);
+ this.imageIcon.setImageBitmap(icon);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this.getActivity());
+
+ final String unitsKey = this.getResources().getString(
+ R.string.weather_preferences_units_key);
+ final String units = sharedPreferences.getString(unitsKey, "");
+ final String celsius = this.getResources().getString(
+ R.string.weather_preferences_units_celsius);
+ if (units.equals(celsius)) {
+ this.isFahrenheit = false;
+ } else {
+ this.isFahrenheit = true;
+ }
+ }
+
+ public class WeatherTask extends AsyncTask<Object, Void, WeatherData> {
+ private static final String TAG = "JSONWeatherTask";
+ private final WeatherHTTPClient weatherHTTPClient;
+ private final WeatherService weatherService;
+
+ public WeatherTask(final WeatherHTTPClient weatherHTTPClient,
+ final WeatherService weatherService) {
+ this.weatherHTTPClient = weatherHTTPClient;
+ this.weatherService = weatherService;
+ }
+
+ @Override
+ protected WeatherData doInBackground(final Object... params) {
+ WeatherData weatherData = null;
+
+ try {
+ weatherData = this.doInBackgroundThrowable(params);
+ } catch (final ClientProtocolException e) {
+ Log.e(TAG, "WeatherHTTPClient exception: ", e);
+ } catch (final MalformedURLException e) {
+ Log.e(TAG, "Syntax URL exception: ", e);
+ } catch (final URISyntaxException e) {
+ Log.e(TAG, "WeatherHTTPClient exception: ", e);
+ } catch (final IOException e) {
+ Log.e(TAG, "WeatherHTTPClient exception: ", e);
+ } catch (final JSONException e) {
+ Log.e(TAG, "WeatherService exception: ", e);
+ } finally {
+ this.weatherHTTPClient.close();
+ }
+
+ return weatherData;
+ }
+
+ @Override
+ protected void onPostExecute(final WeatherData weatherData) {
+ if (weatherData != null) {
+ WeatherInformationDataFragmentDeprecated.this.updateWeatherData(weatherData);
+ } else {
+ ((ErrorMessage) WeatherInformationDataFragmentDeprecated.this.getActivity())
+ .createErrorDialog(R.string.error_dialog_generic_error);
+ }
+
+ this.weatherHTTPClient.close();
+ }
+
+ @Override
+ protected void onCancelled(final WeatherData weatherData) {
+ this.onCancelled();
+ ((ErrorMessage) WeatherInformationDataFragmentDeprecated.this.getActivity())
+ .createErrorDialog(R.string.error_dialog_connection_tiemout);
+
+ this.weatherHTTPClient.close();
+ }
+
+ private WeatherData doInBackgroundThrowable(final Object... params)
+ throws ClientProtocolException, MalformedURLException,
+ URISyntaxException, IOException, JSONException {
+ final String cityCountry = (String) params[0];
+ final String urlAPICity = WeatherInformationDataFragmentDeprecated.this.getResources()
+ .getString(R.string.uri_api_city);
+ final String APIVersion = WeatherInformationDataFragmentDeprecated.this.getResources()
+ .getString(R.string.api_version);
+ String url = this.weatherService.createURIAPICityCountry(
+ cityCountry, urlAPICity, APIVersion);
+
+
+ final String jsonData = this.weatherHTTPClient.retrieveJSONDataFromAPI(new URL(url));
+
+
+ final WeatherData weatherData = this.weatherService.retrieveWeather(jsonData);
+
+
+ final String icon = weatherData.getWeather().getIcon();
+ final String urlAPIicon = WeatherInformationDataFragmentDeprecated.this
+ .getResources().getString(R.string.uri_api_icon);
+ url = this.weatherService.createURIAPIicon(icon, urlAPIicon);
+ final byte[] iconData = this.weatherHTTPClient
+ .retrieveDataFromAPI(new URL(url)).toByteArray();
+ weatherData.setIconData(iconData);
+
+
+ return weatherData;
+ }
+ }
+}