</intent-filter>
</activity>
<activity
- android:name="de.example.exampletdd.WeatherInformationMapActivity"
+ android:name="de.example.exampletdd.MapActivity"
android:parentActivityName="de.example.exampletdd.WeatherTabsActivity" >
<intent-filter>
<action android:name="android.intent.action.WEATHERINFORMATIONMAP" />
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/weather_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="bottom"
- tools:context="de.example.exampletdd.WeatherInformationMapActivity" >
+ android:layout_gravity="center"
+ tools:context="de.example.exampletdd.MapActivity" >
<TextView
- android:id="@+id/weather_map_citycountry_data"
- android:layout_width="match_parent"
+ android:id="@+id/weather_map_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="City"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textIsSelectable="false"
+ android:textStyle="bold|normal" />
+ <TextView
+ android:id="@+id/weather_map_country"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="top"
- android:text="City,country"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@+id/weather_map_city"
+ android:paddingStart="5dp"
+ android:paddingEnd="5dp"
+ android:text="country"
android:textAlignment="textStart"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false"
android:textStyle="bold|normal" />
+
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@+id/weather_map_country"
+ android:layout_above="@+id/weather_map_button_savelocation" />
+
+
+ <Button
+ android:id="@+id/weather_map_button_savelocation"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:layout_toStartOf="@+id/weather_map_aux"
+ android:onClick="onClickSaveLocation"
+ android:textAlignment="center"
+ android:text="@string/weather_map_button_savelocation" />
+ <View
+ android:id="@+id/weather_map_aux"
+ android:layout_width="0dp"
+ android:layout_height="1dp"
+ android:layout_centerHorizontal="true" />
+ <Button
+ android:id="@+id/weather_map_button_getlocation"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
- android:layout_below="@+id/weather_map_citycountry_data" />
-
+ android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@+id/weather_map_aux"
+ android:onClick="onClickGetLocation"
+ android:textAlignment="center"
+ android:text="@string/weather_map_button_getlocation" />
</RelativeLayout>
<string name="title_section1">Section 1</string>
<string name="title_section2">Section 2</string>
<string name="title_section3">Section 3</string>
-
+ <string name="weather_map_button_savelocation">Save Location</string>
+ <string name="weather_map_button_getlocation">Get Location</string>
</resources>
--- /dev/null
+package de.example.exampletdd;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+import android.app.ActionBar;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.location.Address;
+import android.location.Geocoder;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
+import com.google.android.gms.maps.MapFragment;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import de.example.exampletdd.fragment.ErrorDialogFragment;
+import de.example.exampletdd.model.WeatherLocation;
+import de.example.exampletdd.model.WeatherLocationContract;
+import de.example.exampletdd.model.WeatherLocationDbHelper;
+import de.example.exampletdd.model.WeatherLocationDbQueries;
+
+public class MapActivity extends FragmentActivity {
+ private GoogleMap mMap;
+ // TODO: read and store from different threads
+ private Marker mMarker;
+ private WeatherLocation mRestoreUI;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.setContentView(R.layout.weather_map);
+
+ final MapFragment mapFragment = (MapFragment) this.getFragmentManager()
+ .findFragmentById(R.id.map);
+
+ this.mMap = mapFragment.getMap();
+ this.mMap.setMyLocationEnabled(false);
+ this.mMap.getUiSettings().setCompassEnabled(false);
+ this.mMap.setOnMapLongClickListener(new OnMapLongClickListener() {
+
+ @Override
+ public void onMapLongClick(final LatLng point) {
+ final LocationAsyncTask geocoderAsyncTask = new LocationAsyncTask();
+ geocoderAsyncTask.execute(point.latitude, point.longitude);
+ }
+ });
+ }
+
+ @Override
+ protected void onRestoreInstanceState(final Bundle savedInstanceState) {
+ // Instead of restoring the state during onCreate() you may choose to
+ // implement onRestoreInstanceState(), which the system calls after the
+ // onStart() method. The system calls onRestoreInstanceState() only if
+ // there is a saved state to restore, so you do not need to check whether
+ // the Bundle is null:
+ super.onRestoreInstanceState(savedInstanceState);
+
+ // Restore UI state
+ this.mRestoreUI = (WeatherLocation) savedInstanceState.getSerializable("WeatherLocation");
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final ActionBar actionBar = this.getActionBar();
+ // TODO: string resource
+ actionBar.setTitle("Mark your location");
+
+ WeatherLocation weatherLocation;
+ if (this.mRestoreUI != null) {
+ // Restore UI state
+ weatherLocation = this.mRestoreUI;
+ // just once
+ this.mRestoreUI = null;
+ } else {
+ weatherLocation = queryDataBase();
+ }
+
+ if (weatherLocation != null) {
+ this.updateMap(weatherLocation);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
+ // Save UI state
+ if (this.mMarker != null) {
+ final TextView city = (TextView) this.findViewById(R.id.weather_map_city);
+ final TextView country = (TextView) this.findViewById(R.id.weather_map_country);
+ final String cityString = city.getText().toString();
+ final String countryString = country.getText().toString();
+
+ final LatLng point = this.mMarker.getPosition();
+ double latitude = point.latitude;
+ double longitude = point.longitude;
+
+ final WeatherLocation location = new WeatherLocation.Builder().
+ setCity(cityString).setCountry(countryString).
+ setLatitude(latitude).setLongitude(longitude).
+ build();
+ savedInstanceState.putSerializable("WeatherLocation", location);
+ }
+
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ public void onClickSaveLocation(final View v) {
+
+ }
+
+ public void onClickGetLocation(final View v) {
+
+ }
+
+ private WeatherLocation queryDataBase() {
+ final String selection = WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED + " = ?";
+ final String[] selectionArgs = { "1" };
+ final String[] projection = {
+ WeatherLocationContract.WeatherLocation._ID,
+ WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY,
+ WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY,
+ WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED,
+ WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE,
+ WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE,
+ WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE,
+ WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE
+ };
+
+ final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this);
+ try {
+ final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper);
+ final WeatherLocationDbQueries.DoQuery doQuery = new WeatherLocationDbQueries.DoQuery() {
+
+ @Override
+ public WeatherLocation doQuery(final Cursor cursor) {
+ String city = cursor.getString(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY));
+ String country = cursor.getString(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY));
+ double latitude = cursor.getDouble(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE));
+ double longitude = cursor.getDouble(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE));
+
+ return new WeatherLocation.Builder().
+ setCity(city).setCountry(country).
+ setLatitude(latitude).setLongitude(longitude).
+ build();
+ }
+
+ };
+
+ return queryDb.queryDataBase(
+ WeatherLocationContract.WeatherLocation.TABLE_NAME, projection,
+ selectionArgs, selection, doQuery);
+ } finally {
+ dbHelper.close();
+ }
+ }
+
+ private void updateMap(final WeatherLocation weatherLocation) {
+
+ final TextView city = (TextView) this.findViewById(R.id.weather_map_city);
+ final TextView country = (TextView) this.findViewById(R.id.weather_map_country);
+ city.setText(weatherLocation.getCity());
+ country.setText(weatherLocation.getCountry());
+
+ final LatLng point = new LatLng(weatherLocation.getLatitude(), weatherLocation.getLongitude());
+ this.mMap.clear();
+ if (this.mMarker == null) {
+ this.mMarker = this.mMap.addMarker(new MarkerOptions().position(point).draggable(true));
+ } else {
+ // Just one marker on map
+ this.mMarker.setPosition(point);
+ }
+ this.mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(point, 5));
+ this.mMap.animateCamera(CameraUpdateFactory.zoomIn());
+ this.mMap.animateCamera(CameraUpdateFactory.zoomTo(8), 2000, null);
+ }
+
+ private class LocationAsyncTask extends AsyncTask<Object, Void, WeatherLocation> {
+ private static final String TAG = "LocationAsyncTask";
+
+ @Override
+ protected WeatherLocation doInBackground(final Object... params) {
+ final double latitude = (Double) params[0];
+ final double longitude = (Double) params[1];
+
+ WeatherLocation weatherLocation = null;
+ try {
+ weatherLocation = this.getLocation(latitude, longitude);
+ } catch (final IOException e) {
+ Log.e(TAG, "LocationAsyncTask doInBackground exception: ", e);
+ }
+
+ return weatherLocation;
+ }
+
+ @Override
+ protected void onPostExecute(final WeatherLocation weatherLocation) {
+ // TODO: Is AsyncTask calling this method even when RunTimeException in doInBackground method?
+ // I hope so, otherwise I must catch(Throwable) in doInBackground method :(
+ if (weatherLocation == null) {
+ // TODO: if user changed activity, where is this going to appear?
+ final DialogFragment newFragment = ErrorDialogFragment.newInstance(R.string.error_dialog_location_error);
+ newFragment.show(MapActivity.this.getSupportFragmentManager(),
+ "errorDialog");
+ return;
+ }
+
+ MapActivity.this.updateMap(weatherLocation);
+ }
+
+ private WeatherLocation getLocation(final double latitude, final double longitude) throws IOException {
+ final Geocoder geocoder = new Geocoder(MapActivity.this, Locale.US);
+ final List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
+
+ // Default values
+ String city = MapActivity.this.getString(R.string.city_not_found);
+ String country = MapActivity.this.getString(R.string.country_not_found);
+ if (addresses == null || addresses.size() <= 0) {
+ if (addresses.get(0).getLocality() != null) {
+ city = addresses.get(0).getLocality();
+ }
+ if(addresses.get(0).getCountryName() != null) {
+ country = addresses.get(0).getCountryName();
+ }
+ }
+
+ return new WeatherLocation.Builder().
+ setLatitude(latitude).setLongitude(longitude).
+ setCity(city).setCountry(country).
+ build();
+ }
+
+ }
+}
public void onResume() {
super.onResume();
- final ActionBar actionBar = this.getActionBar();
-
// TODO: retrive data from data base (like I do on WindowsPhone 8)
// 1. Update title.
final GeocodingData geocodingData = new GeocodingData.Builder().build();
: geocodingData.getCity();
final String country = (geocodingData.getCountry() == null) ? this.getString(R.string.country_not_found)
: geocodingData.getCountry();
+ final ActionBar actionBar = this.getActionBar();
+ // TODO: I18N and comma :/
actionBar.setTitle(city + "," + country);
}
}
+++ /dev/null
-package de.example.exampletdd;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-import android.app.ActionBar;
-import android.location.Address;
-import android.location.Geocoder;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.FragmentActivity;
-import android.util.Log;
-import android.widget.TextView;
-
-import com.google.android.gms.maps.CameraUpdateFactory;
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
-import com.google.android.gms.maps.MapFragment;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.Marker;
-import com.google.android.gms.maps.model.MarkerOptions;
-
-import de.example.exampletdd.fragment.ErrorDialogFragment;
-import de.example.exampletdd.fragment.ProgressDialogFragment;
-import de.example.exampletdd.model.GeocodingData;
-import de.example.exampletdd.service.ServicePersistenceStorage;
-
-public class WeatherInformationMapActivity extends FragmentActivity {
- private GoogleMap mMap;
- private Marker mMarker;
- private ServicePersistenceStorage mWeatherServicePersistenceFile;
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- this.setContentView(R.layout.weather_map);
-
- final MapFragment mapFragment = (MapFragment) this.getFragmentManager()
- .findFragmentById(R.id.map);
-
- this.mMap = mapFragment.getMap();
- this.mMap.setMyLocationEnabled(false);
- this.mMap.getUiSettings().setCompassEnabled(false);
- this.mMap.setOnMapLongClickListener(new LongClickListener());
-
- this.mWeatherServicePersistenceFile = new ServicePersistenceStorage(this);
-
- final GeocodingData geocodingData = this.mWeatherServicePersistenceFile.getGeocodingData();
-
- if (geocodingData != null) {
- final LatLng point = new LatLng(
- geocodingData.getLatitude(), geocodingData.getLongitude());
- this.mMap.clear();
- this.mMarker = this.mMap.addMarker(new MarkerOptions().position(point).draggable(true));
-
- this.mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(point, 5));
- this.mMap.animateCamera(CameraUpdateFactory.zoomIn());
- this.mMap.animateCamera(CameraUpdateFactory.zoomTo(8), 2000, null);
-
- final TextView cityCountry = (TextView) WeatherInformationMapActivity.this
- .findViewById(R.id.weather_map_citycountry_data);
- final String city = (geocodingData.getCity() == null) ? this.getString(R.string.city_not_found)
- : geocodingData.getCity();
- final String country = (geocodingData.getCountry() == null) ? this.getString(R.string.country_not_found)
- : geocodingData.getCountry();
- cityCountry.setText(city + "," + country);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- final ActionBar actionBar = this.getActionBar();
-
- actionBar.setTitle("Mark your location");
- }
-
- private class LongClickListener implements OnMapLongClickListener {
-
- @Override
- public void onMapLongClick(final LatLng point) {
- final GeocoderAsyncTask geocoderAsyncTask = new GeocoderAsyncTask();
- geocoderAsyncTask.execute(point.latitude, point.longitude);
- }
- }
-
- public class GeocoderAsyncTask extends AsyncTask<Object, Void, GeocodingData> {
- private static final String TAG = "GeocoderAsyncTask";
- private final DialogFragment newFragment;
-
- public GeocoderAsyncTask() {
- this.newFragment = ProgressDialogFragment
- .newInstance(R.string.progress_dialog_get_remote_data,
- WeatherInformationMapActivity.this.getString(R.string.progress_dialog_generic_message));
- }
-
- @Override
- protected void onPreExecute() {
- this.newFragment.show(WeatherInformationMapActivity.this.getSupportFragmentManager(),
- "progressDialog");
- }
-
- @Override
- protected GeocodingData doInBackground(final Object... params) {
- final double latitude = (Double) params[0];
- final double longitude = (Double) params[1];
-
-
- GeocodingData geocodingData = null;
- try {
- geocodingData = this.getGeocodingData(latitude, longitude);
- } catch (final IOException e) {
- Log.e(TAG, "doInBackground exception: ", e);
- }
-
- return geocodingData;
- }
-
- @Override
- protected void onPostExecute(final GeocodingData geocodingData) {
- this.newFragment.dismiss();
-
- if (geocodingData == null) {
- final DialogFragment newFragment = ErrorDialogFragment.newInstance(R.string.error_dialog_location_error);
- newFragment.show(WeatherInformationMapActivity.this.getSupportFragmentManager(),
- "errorDialog");
-
- return;
- }
-
- try {
- this.onPostExecuteThrowable(geocodingData);
- } catch (final FileNotFoundException e) {
- Log.e(TAG, "GeocoderAsyncTask onPostExecute exception: ", e);
- final DialogFragment newFragment = ErrorDialogFragment.newInstance(R.string.error_dialog_location_error);
- newFragment.show(WeatherInformationMapActivity.this.getSupportFragmentManager(),
- "errorDialog");
- } catch (final IOException e) {
- Log.e(TAG, "GeocoderAsyncTask onPostExecute exception: ", e);
- final DialogFragment newFragment = ErrorDialogFragment.newInstance(R.string.error_dialog_location_error);
- newFragment.show(WeatherInformationMapActivity.this.getSupportFragmentManager(),
- "errorDialog");
- }
- }
-
- private void onPostExecuteThrowable(final GeocodingData geocodingData)
- throws FileNotFoundException, IOException {
-
- WeatherInformationMapActivity.this.mWeatherServicePersistenceFile.storeGeocodingData(geocodingData);
-
- final String city = (geocodingData.getCity() == null) ?
- WeatherInformationMapActivity.this.getString(R.string.city_not_found)
- : geocodingData.getCity();
- final String country = (geocodingData.getCountry() == null) ?
- WeatherInformationMapActivity.this.getString(R.string.country_not_found)
- : geocodingData.getCountry();
- final TextView cityCountry = (TextView) WeatherInformationMapActivity.this
- .findViewById(R.id.weather_map_citycountry_data);
- cityCountry.setText(city + "," + country);
-
- final LatLng point = new LatLng(geocodingData.getLatitude(), geocodingData.getLongitude());
- if (WeatherInformationMapActivity.this.mMarker == null) {
- WeatherInformationMapActivity.this.mMarker = WeatherInformationMapActivity.this.mMap.addMarker
- (new MarkerOptions().position(point).draggable(true));
- } else {
- WeatherInformationMapActivity.this.mMarker.setPosition(point);
- }
- }
-
- private GeocodingData getGeocodingData(final double latitude, final double longitude) throws IOException {
- final Geocoder geocoder = new Geocoder(WeatherInformationMapActivity.this, Locale.US);
- final List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
-
- if (addresses == null) {
- return null;
- }
-
- if (addresses.size() <= 0) {
- return null;
- }
-
- return new GeocodingData.Builder().setLatitude(latitude)
- .setLongitude(longitude)
- .setCity(addresses.get(0).getLocality())
- .setCountry(addresses.get(0).getCountryName())
- .build();
- }
-
- }
-}
this.startActivity(intent);
return true;
} else if (itemId == R.id.weather_menu_map) {
- intent = new Intent("de.example.exampletdd.WEATHERINFO")
- .setComponent(new ComponentName("de.example.exampletdd",
- "de.example.exampletdd.WeatherInformationMapActivity"));
+ intent = new Intent("de.example.exampletdd.WEATHERINFO").
+ setComponent(new ComponentName("de.example.exampletdd",
+ "de.example.exampletdd.MapActivity"));
this.startActivity(intent);
return true;
} else {
super.onResume();
final ActionBar actionBar = this.getActionBar();
-
+
// TODO: retrive data from data base (like I do on WindowsPhone 8)
// 1. Update title.
final GeocodingData geocodingData = new GeocodingData.Builder().build();
: geocodingData.getCity();
final String country = (geocodingData.getCountry() == null) ? this.getString(R.string.country_not_found)
: geocodingData.getCountry();
+ // TODO: I18N and comma :/
actionBar.setTitle(city + "," + country);
}
@Override
protected void onPostExecute(final Current current) {
-
+ // TODO: Is AsyncTask calling this method even when RunTimeException in doInBackground method?
+ // I hope so, otherwise I must catch(Throwable) in doInBackground method :(
if (current == null) {
// Nothing to do
// TODO: Should I show some error message? I am not doing it on WP8 Should I do it on WP8?
@Override
protected void onPostExecute(final Forecast forecast) {
-
+ // TODO: Is AsyncTask calling this method even when RunTimeException in doInBackground method?
+ // I hope so, otherwise I must catch(Throwable) in doInBackground method :(
if (forecast == null) {
// Nothing to do
// TODO: Should I show some error message? I am not doing it on WP8 Should I do it on WP8?
--- /dev/null
+package de.example.exampletdd.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+public class WeatherLocation implements Serializable {
+ private static final long serialVersionUID = 1379832318334553377L;
+ private final String city;
+ private final String country;
+ private final double latitude;
+ private final double longitude;
+ private final Date lastCurrentUIUpdate;
+ private final Date lastForecastUIUpdate;
+
+ public static class Builder {
+ private String mCity;
+ private String mCountry;
+ private double mLatitude;
+ private double mLongitude;
+ private Date mlastCurrentUIUpdate;
+ private Date mlastForecastUIUpdate;
+
+ public Builder setCity(final String city) {
+ this.mCity = city;
+ return this;
+ }
+
+ public Builder setCountry(final String country) {
+ this.mCountry = country;
+ return this;
+ }
+
+ public Builder setLatitude(final double latitude) {
+ this.mLatitude = latitude;
+ return this;
+ }
+
+ public Builder setLongitude(final double longitude) {
+ this.mLongitude = longitude;
+ return this;
+ }
+
+ public Builder setlastCurrentUIUpdate(final Date lastCurrentUIUpdate) {
+ this.mlastCurrentUIUpdate = lastCurrentUIUpdate;
+ return this;
+ }
+
+ public Builder setlastForecastUIUpdate(final Date lastForecastUIUpdate) {
+ this.mlastForecastUIUpdate = lastForecastUIUpdate;
+ return this;
+ }
+
+ public WeatherLocation build() {
+ return new WeatherLocation(this);
+ }
+ }
+
+ private WeatherLocation(final Builder builder) {
+ this.city = builder.mCity;
+ this.country = builder.mCountry;
+ this.latitude = builder.mLatitude;
+ this.longitude = builder.mLongitude;
+ this.lastCurrentUIUpdate = builder.mlastCurrentUIUpdate;
+ this.lastForecastUIUpdate = builder.mlastForecastUIUpdate;
+ }
+
+ public String getCity() {
+ return this.city;
+ }
+
+ public String getCountry() {
+ return this.country;
+ }
+
+ public double getLatitude() {
+ return this.latitude;
+ }
+
+ public double getLongitude() {
+ return this.longitude;
+ }
+
+ public Date getlastCurrentUIUpdate() {
+ return this.lastCurrentUIUpdate;
+ }
+
+ public Date getlastForecastUIUpdate() {
+ return this.lastForecastUIUpdate;
+ }
+}
--- /dev/null
+package de.example.exampletdd.model;
+
+import android.provider.BaseColumns;
+
+public class WeatherLocationContract {
+
+ // This class can't be instantiated
+ private WeatherLocationContract() {}
+
+ public static final class WeatherLocation implements BaseColumns {
+
+ // This class can't be instantiated
+ private WeatherLocation() {}
+
+ public static final String TABLE_NAME = "locations";
+
+ public static final String COLUMN_NAME_IS_SELECTED = "isSelected";
+
+ public static final String COLUMN_NAME_LATITUDE = "latitude";
+
+ public static final String COLUMN_NAME_LONGITUDE = "longitude";
+
+ public static final String COLUMN_NAME_COUNTRY = "country";
+
+ public static final String COLUMN_NAME_CITY = "city";
+
+ public static final String COLUMN_NAME_LAST_FORECAST_UI_UPDATE = "lastForecastUpdate";
+
+ public static final String COLUMN_NAME_LAST_CURRENT_UI_UPDATE = "lastCurrentUpdate";
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.model;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+public class WeatherLocationDbHelper extends SQLiteOpenHelper {
+ private static final String TAG = "LocationDbHelper";
+ public static final int DATABASE_VERSION = 1;
+ public static final String DATABASE_NAME = "Location.db";
+
+ public WeatherLocationDbHelper(final Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(final SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + WeatherLocationContract.WeatherLocation.TABLE_NAME + " ("
+ + WeatherLocationContract.WeatherLocation._ID + " INTEGER PRIMARY KEY, "
+ + WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY + " TEXT" + " NOT NULL, "
+ + WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY + " TEXT" + " NOT NULL, "
+ + WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED + " INTEGER" + " NOT NULL, "
+ + WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE + " INTEGER, "
+ + WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE + " INTEGER, "
+ + WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE + " REAL" + " NOT NULL, "
+ + WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE + " REAL" + " NOT NULL "
+ + ");");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ + newVersion + ", which will destroy all old data");
+
+ // Kills the table and existing data
+ db.execSQL("DROP TABLE IF EXISTS " + WeatherLocationContract.WeatherLocation.TABLE_NAME);
+
+ // Recreates the database with a new version
+ onCreate(db);
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.model;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public class WeatherLocationDbQueries {
+ private final SQLiteOpenHelper mDbHelper;
+
+ public interface DoQuery {
+
+ public WeatherLocation doQuery(final Cursor cursor);
+ }
+
+ public WeatherLocationDbQueries(final SQLiteOpenHelper dbHelper) {
+ this.mDbHelper = dbHelper;
+ }
+
+ // TODO: right now it can be used just once
+ public WeatherLocation queryDataBase(String table,
+ final String[] projection, final String[] selectionArgs,
+ final String selection, final DoQuery doQuery) {
+ // TODO: execute around idiom? I miss try/finally with resources
+ final SQLiteDatabase db = this.mDbHelper.getReadableDatabase();
+ try {
+ final Cursor cursor = db.query(table, projection, selection, selectionArgs, null, null, null);
+ try {
+ if (!cursor.moveToFirst()) {
+ return null;
+ }
+ else {
+ return doQuery.doQuery(cursor);
+ }
+ } finally {
+ cursor.close();
+ }
+ } finally {
+ db.close();
+ }
+ }
+}