WeatherInformatio Android: map WIP
authorgu.martinm@gmail.com <gu.martinm@gmail.com>
Wed, 3 Sep 2014 18:25:29 +0000 (20:25 +0200)
committergu.martinm@gmail.com <gu.martinm@gmail.com>
Wed, 3 Sep 2014 18:25:29 +0000 (20:25 +0200)
13 files changed:
AndroidManifest.xml
res/layout/weather_map.xml
res/values/strings.xml
src/de/example/exampletdd/MapActivity.java [new file with mode: 0644]
src/de/example/exampletdd/SpecificActivity.java
src/de/example/exampletdd/WeatherInformationMapActivity.java [deleted file]
src/de/example/exampletdd/WeatherTabsActivity.java
src/de/example/exampletdd/fragment/current/CurrentFragment.java
src/de/example/exampletdd/fragment/overview/OverviewFragment.java
src/de/example/exampletdd/model/WeatherLocation.java [new file with mode: 0644]
src/de/example/exampletdd/model/WeatherLocationContract.java [new file with mode: 0644]
src/de/example/exampletdd/model/WeatherLocationDbHelper.java [new file with mode: 0644]
src/de/example/exampletdd/model/WeatherLocationDbQueries.java [new file with mode: 0644]

index 7fe4e82..9d74883 100644 (file)
@@ -75,7 +75,7 @@
             </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" />
index 32586c4..efffdd9 100644 (file)
@@ -1,29 +1,71 @@
 <?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>
index 624d86d..753fa31 100644 (file)
@@ -50,5 +50,6 @@
     <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>
diff --git a/src/de/example/exampletdd/MapActivity.java b/src/de/example/exampletdd/MapActivity.java
new file mode 100644 (file)
index 0000000..d18af04
--- /dev/null
@@ -0,0 +1,250 @@
+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();
+        }
+
+    }
+}
index 0079600..9465571 100644 (file)
@@ -24,8 +24,6 @@ public class SpecificActivity extends FragmentActivity {
     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();
@@ -34,6 +32,8 @@ public class SpecificActivity extends FragmentActivity {
                     : 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);  
         }
     }
diff --git a/src/de/example/exampletdd/WeatherInformationMapActivity.java b/src/de/example/exampletdd/WeatherInformationMapActivity.java
deleted file mode 100644 (file)
index 84b99d9..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-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();
-        }
-
-    }
-}
index 3a4152d..bf48f00 100644 (file)
@@ -102,9 +102,9 @@ public class WeatherTabsActivity extends FragmentActivity {
             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 {
@@ -125,7 +125,7 @@ public class WeatherTabsActivity extends FragmentActivity {
         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();
@@ -134,6 +134,7 @@ public class WeatherTabsActivity extends FragmentActivity {
                     : 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);  
         }
 
index 0aa078e..5bdd5fa 100644 (file)
@@ -328,7 +328,8 @@ public class CurrentFragment extends Fragment {
 
         @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?
index 0de0cf5..60af117 100644 (file)
@@ -306,7 +306,8 @@ public class OverviewFragment extends ListFragment {
 
         @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?
diff --git a/src/de/example/exampletdd/model/WeatherLocation.java b/src/de/example/exampletdd/model/WeatherLocation.java
new file mode 100644 (file)
index 0000000..ae21c8f
--- /dev/null
@@ -0,0 +1,91 @@
+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;
+    }
+}
diff --git a/src/de/example/exampletdd/model/WeatherLocationContract.java b/src/de/example/exampletdd/model/WeatherLocationContract.java
new file mode 100644 (file)
index 0000000..91e3472
--- /dev/null
@@ -0,0 +1,32 @@
+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";
+       }
+
+}
diff --git a/src/de/example/exampletdd/model/WeatherLocationDbHelper.java b/src/de/example/exampletdd/model/WeatherLocationDbHelper.java
new file mode 100644 (file)
index 0000000..8083516
--- /dev/null
@@ -0,0 +1,43 @@
+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);
+       }
+
+}
diff --git a/src/de/example/exampletdd/model/WeatherLocationDbQueries.java b/src/de/example/exampletdd/model/WeatherLocationDbQueries.java
new file mode 100644 (file)
index 0000000..82f7d1a
--- /dev/null
@@ -0,0 +1,41 @@
+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();
+        }
+    }
+}