RelativeLayout sucks!!!
authorgu.martinm@gmail.com <gu.martinm@gmail.com>
Wed, 9 Apr 2014 21:03:25 +0000 (23:03 +0200)
committergu.martinm@gmail.com <gu.martinm@gmail.com>
Wed, 9 Apr 2014 21:03:25 +0000 (23:03 +0200)
12 files changed:
res/layout/activity_main.xml [deleted file]
res/layout/weather_main.xml [new file with mode: 0644]
res/layout/weather_main_entry_list.xml [new file with mode: 0644]
res/layout/weather_main_list.xml [new file with mode: 0644]
src/de/example/exampletdd/WeatherInformationActivity.java
src/de/example/exampletdd/fragment/overview/WeatherInformationOverviewFragment.java [new file with mode: 0644]
src/de/example/exampletdd/fragment/overview/WeatherOverviewAdapter.java [new file with mode: 0644]
src/de/example/exampletdd/fragment/overview/WeatherOverviewEntry.java [new file with mode: 0644]
src/de/example/exampletdd/parser/JPOSWeatherParser.java
src/de/example/exampletdd/provider/WeatherInformationIndexer.java [new file with mode: 0644]
src/de/example/exampletdd/provider/WeatherInformationOpenHelper.java [new file with mode: 0644]
src/de/example/exampletdd/provider/WeatherInformationProvider.java [new file with mode: 0644]

diff --git a/res/layout/activity_main.xml b/res/layout/activity_main.xml
deleted file mode 100644 (file)
index c3dbbfd..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/container"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:context="de.example.exampletdd.WeatherInformationActivity"
-    tools:ignore="MergeRootFrame" >
-
-    <fragment
-        android:id="@+id/weather_data_frag"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        class="de.example.exampletdd.fragment.WeatherInformationDataFragment"
-        tools:layout="@layout/weather_data_list" />
-
-</FrameLayout>
diff --git a/res/layout/weather_main.xml b/res/layout/weather_main.xml
new file mode 100644 (file)
index 0000000..8ce309b
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="de.example.exampletdd.WeatherInformationActivity"
+    tools:ignore="MergeRootFrame" >
+
+    <fragment
+        android:id="@+id/weather_overview_fragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        class="de.example.exampletdd.fragment.overview.WeatherInformationOverviewFragment"
+        tools:layout="@layout/weather_main_list" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/weather_main_entry_list.xml b/res/layout/weather_main_entry_list.xml
new file mode 100644 (file)
index 0000000..56ea95e
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout 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_main_entry_date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignTop="@+id/weather_main_entry_temperature"
+        android:layout_alignBottom="@+id/weather_main_entry_temperature"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textStyle="bold"
+        android:textSize="14sp"
+        android:textAlignment="center"
+        android:text="Date" />
+
+    <TextView
+        android:id="@+id/weather_main_entry_temperature"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@+id/weather_main_entry_image"
+        android:layout_alignTop="@+id/weather_main_entry_image"
+        android:layout_toRightOf="@+id/weather_main_entry_date"
+        android:text="Temperature"
+        android:textAlignment="center"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textSize="14sp"
+        android:textStyle="normal" />
+    
+    
+    <ImageView
+        android:id="@+id/weather_main_entry_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@+id/weather_main_entry_temperature"
+        android:layout_alignParentRight="true"
+        android:contentDescription="@string/icon_weather_description"
+        android:orientation="vertical"
+        android:src="@drawable/ic_launcher" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/weather_main_list.xml b/res/layout/weather_main_list.xml
new file mode 100644 (file)
index 0000000..1537e10
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout 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" >
+    
+
+    <ListView
+        android:id="@+id/weather_main_list_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+    </ListView>
+    
+</RelativeLayout>
index 8c19117..9864454 100644 (file)
@@ -19,7 +19,7 @@ import android.view.MenuItem;
 import de.example.exampletdd.activityinterface.ErrorMessage;
 import de.example.exampletdd.activityinterface.GetWeather;
 import de.example.exampletdd.fragment.ErrorDialogFragment;
-import de.example.exampletdd.fragment.WeatherInformationDataFragment;
+import de.example.exampletdd.fragment.overview.WeatherInformationOverviewFragment;
 import de.example.exampletdd.model.GeocodingData;
 
 public class WeatherInformationActivity extends Activity implements ErrorMessage {
@@ -30,7 +30,7 @@ public class WeatherInformationActivity extends Activity implements ErrorMessage
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        this.setContentView(R.layout.activity_main);
+        this.setContentView(R.layout.weather_main);
 
         PreferenceManager.setDefaultValues(this, R.xml.weather_preferences, false);
 
@@ -47,8 +47,8 @@ public class WeatherInformationActivity extends Activity implements ErrorMessage
         //      this.getFragmentManager().beginTransaction()
         //      .add(R.id.container, weatherDataFragment).commit();
         // }
-        final WeatherInformationDataFragment weatherDataFragment = (WeatherInformationDataFragment) this
-                .getFragmentManager().findFragmentById(R.id.weather_data_frag);
+        final WeatherInformationOverviewFragment weatherDataFragment = (WeatherInformationOverviewFragment) this
+                .getFragmentManager().findFragmentById(R.id.weather_overview_fragment);
 
         this.mGetWeather = weatherDataFragment;
     }
diff --git a/src/de/example/exampletdd/fragment/overview/WeatherInformationOverviewFragment.java b/src/de/example/exampletdd/fragment/overview/WeatherInformationOverviewFragment.java
new file mode 100644 (file)
index 0000000..82945a8
--- /dev/null
@@ -0,0 +1,448 @@
+package de.example.exampletdd.fragment.overview;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.StreamCorruptedException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.http.client.ClientProtocolException;
+import org.json.JSONException;
+
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+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.ListView;
+import de.example.exampletdd.R;
+import de.example.exampletdd.activityinterface.ErrorMessage;
+import de.example.exampletdd.activityinterface.GetWeather;
+import de.example.exampletdd.fragment.ProgressDialogFragment;
+import de.example.exampletdd.httpclient.WeatherHTTPClient;
+import de.example.exampletdd.model.GeocodingData;
+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 WeatherInformationOverviewFragment extends Fragment implements GetWeather {
+    private static final String WEATHER_DATA_FILE = "weatherdata.file";
+    private static final String WEATHER_GEOCODING_FILE = "weathergeocoding.file";
+    private static final String TAG = "WeatherInformationOverviewFragment";
+    private boolean mIsFahrenheit;
+    private String mLanguage;
+
+    @Override
+    public void onCreate(final Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        this.getActivity().deleteFile(WEATHER_DATA_FILE);
+
+        final SharedPreferences sharedPreferences = PreferenceManager
+                .getDefaultSharedPreferences(this.getActivity());
+        final String keyPreference = this.getResources().getString(
+                R.string.weather_preferences_language_key);
+        this.mLanguage = sharedPreferences.getString(
+                keyPreference, "");
+    }
+
+    @Override
+    public View onCreateView(final LayoutInflater inflater,
+            final ViewGroup container, final Bundle savedInstanceState) {
+        // TODO: In activity_main.xml you can see: tools:layout="@layout/weather_data_list"
+        // So, probably this line is not required. I guess you can do the same
+        // by xml or by means of this code. Test it!!!
+        final View rootView = inflater.inflate(R.layout.weather_main_list,
+                container, false);
+
+        return rootView;
+    }
+
+    @Override
+    public void onActivityCreated(final Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        final ListView listWeatherView = (ListView) this.getActivity().findViewById(
+                R.id.weather_main_list_view);
+
+        final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(this.getActivity(),
+                R.layout.weather_main_entry_list);
+
+        final Collection<WeatherOverviewEntry> entries = this.createEmptyEntriesList();
+
+        adapter.addAll(entries);
+        listWeatherView.setAdapter(adapter);
+
+        if (savedInstanceState != null) {
+            // Restore state
+            final WeatherData weatherData = (WeatherData) savedInstanceState
+                    .getSerializable("weatherData");
+            try {
+                this.storeWeatherDataToFile(weatherData);
+            } catch (final IOException e) {
+                ((ErrorMessage) WeatherInformationOverviewFragment.this
+                        .getActivity())
+                        .createErrorDialog(R.string.error_dialog_generic_error);
+            }
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(final Bundle savedInstanceState) {
+
+        // Save state
+        WeatherData weatherData = null;
+        try {
+            weatherData = this.restoreWeatherDataFromFile();
+        } catch (final StreamCorruptedException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final FileNotFoundException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final IOException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final ClassNotFoundException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        }
+
+        if (weatherData != null) {
+            savedInstanceState.putSerializable("weatherData", weatherData);
+        }
+
+        super.onSaveInstanceState(savedInstanceState);
+    }
+
+    @Override
+    public void getWeather() {
+
+        GeocodingData geocodingData = null;
+        try {
+            geocodingData = this.restoreGeocodingDataFromFile();
+        } catch (final StreamCorruptedException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final FileNotFoundException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final IOException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final ClassNotFoundException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        }
+
+        if (geocodingData != null) {
+            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);
+
+
+            weatherTask.execute(geocodingData);
+        }
+    }
+
+    @Override
+    public void updateWeatherData(final WeatherData weatherData) {
+        final List<WeatherOverviewEntry> entries = this.createEmptyEntriesList();
+        final ListView listWeatherView = (ListView) this.getActivity().findViewById(
+                R.id.weather_main_list_view);
+        final WeatherOverviewAdapter adapter = new WeatherOverviewAdapter(this.getActivity(),
+                R.layout.weather_main_entry_list);
+
+        Bitmap picture = null;
+
+        if (weatherData.getWeather().getIcon() != null) {
+            picture= BitmapFactory.decodeByteArray(
+                    weatherData.getIconData(), 0,
+                    weatherData.getIconData().length);
+        }
+
+        final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.getDefault());
+        tempFormatter.applyPattern("#####.#####");
+        final SimpleDateFormat dateFormat = new SimpleDateFormat("MM.dd", Locale.getDefault());
+        final double tempUnits = this.mIsFahrenheit ? 0 : 273.15;
+        double conversion = weatherData.getMain().getTemp();
+        conversion = conversion - tempUnits;
+
+        final Calendar now = Calendar.getInstance();
+        if (weatherData.getWeather() != null) {
+            for (int i = 0; i<15; i++) {
+                final Date day = now.getTime();
+                entries.set(i, new WeatherOverviewEntry(
+                        "DATE: " + dateFormat.format(day),
+                        tempFormatter.format(conversion), picture));
+                now.add(Calendar.DAY_OF_MONTH, -1);
+            }
+        }
+
+        listWeatherView.setAdapter(null);
+        adapter.addAll(entries);
+        listWeatherView.setAdapter(adapter);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        final SharedPreferences sharedPreferences = PreferenceManager
+                .getDefaultSharedPreferences(this.getActivity());
+
+        // 1. Update units of measurement.
+        String keyPreference = this.getResources().getString(
+                R.string.weather_preferences_units_key);
+        final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+        final String celsius = this.getResources().getString(
+                R.string.weather_preferences_units_celsius);
+        if (unitsPreferenceValue.equals(celsius)) {
+            this.mIsFahrenheit = false;
+        } else {
+            this.mIsFahrenheit = true;
+        }
+
+
+        // 2. Update current data on display.
+        WeatherData weatherData = null;
+        try {
+            weatherData = this.restoreWeatherDataFromFile();
+        } catch (final StreamCorruptedException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final FileNotFoundException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final IOException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        } catch (final ClassNotFoundException e) {
+            Log.e(TAG, "onResume exception: ", e);
+        }
+        if (weatherData != null) {
+            this.updateWeatherData(weatherData);
+        }
+
+
+        // 3. If language changed, try to retrieve new data for new language
+        // (new strings with the chosen language)
+        keyPreference = this.getResources().getString(
+                R.string.weather_preferences_language_key);
+        final String languagePreferenceValue = sharedPreferences.getString(
+                keyPreference, "");
+        if (!languagePreferenceValue.equals(this.mLanguage)) {
+            this.mLanguage = languagePreferenceValue;
+            this.getWeather();
+        }
+    }
+
+    public class WeatherTask extends AsyncTask<Object, Void, WeatherData> {
+        private static final String TAG = "WeatherTask";
+        private final WeatherHTTPClient weatherHTTPClient;
+        private final WeatherService weatherService;
+        private final DialogFragment newFragment;
+
+        public WeatherTask(final WeatherHTTPClient weatherHTTPClient,
+                final WeatherService weatherService) {
+            this.weatherHTTPClient = weatherHTTPClient;
+            this.weatherService = weatherService;
+            this.newFragment = ProgressDialogFragment.newInstance(
+                    R.string.progress_dialog_get_remote_data,
+                    WeatherInformationOverviewFragment.this
+                    .getString(R.string.progress_dialog_generic_message));
+        }
+
+        @Override
+        protected void onPreExecute() {
+            this.newFragment.show(WeatherInformationOverviewFragment.this.getActivity()
+                    .getFragmentManager(), "progressDialog");
+        }
+
+        @Override
+        protected WeatherData doInBackground(final Object... params) {
+            WeatherData weatherData = null;
+
+            try {
+                weatherData = this.doInBackgroundThrowable(params);
+            } catch (final ClientProtocolException e) {
+                Log.e(TAG, "doInBackground exception: ", e);
+            } catch (final MalformedURLException e) {
+                Log.e(TAG, "doInBackground exception: ", e);
+            } catch (final URISyntaxException e) {
+                Log.e(TAG, "doInBackground exception: ", e);
+            } catch (final IOException e) {
+                // logger infrastructure swallows UnknownHostException :/
+                Log.e(TAG, "doInBackground exception: " + e.getMessage(), e);
+            } catch (final JSONException e) {
+                Log.e(TAG, "doInBackground exception: ", e);
+            } finally {
+                this.weatherHTTPClient.close();
+            }
+
+            return weatherData;
+        }
+
+        @Override
+        protected void onPostExecute(final WeatherData weatherData) {
+            this.weatherHTTPClient.close();
+
+            this.newFragment.dismiss();
+
+            if (weatherData != null) {
+                try {
+                    this.onPostExecuteThrowable(weatherData);
+                } catch (final IOException e) {
+                    Log.e(TAG, "WeatherTask onPostExecute exception: ", e);
+                    ((ErrorMessage) WeatherInformationOverviewFragment.this
+                            .getActivity())
+                            .createErrorDialog(R.string.error_dialog_generic_error);
+                }
+            } else {
+                ((ErrorMessage) WeatherInformationOverviewFragment.this
+                        .getActivity())
+                        .createErrorDialog(R.string.error_dialog_generic_error);
+            }
+        }
+
+        @Override
+        protected void onCancelled(final WeatherData weatherData) {
+            this.weatherHTTPClient.close();
+
+            ((ErrorMessage) WeatherInformationOverviewFragment.this.getActivity())
+            .createErrorDialog(R.string.error_dialog_connection_tiemout);
+        }
+
+        private WeatherData doInBackgroundThrowable(final Object... params)
+                throws ClientProtocolException, MalformedURLException,
+                URISyntaxException, IOException, JSONException {
+            final SharedPreferences sharedPreferences = PreferenceManager
+                    .getDefaultSharedPreferences(WeatherInformationOverviewFragment.this
+                            .getActivity());
+
+            final String keyPreference = WeatherInformationOverviewFragment.this
+                    .getActivity().getString(
+                            R.string.weather_preferences_language_key);
+            final String languagePreferenceValue = sharedPreferences.getString(keyPreference, "");
+
+            final GeocodingData geocodingData = (GeocodingData) params[0];
+            final String urlAPICoord = WeatherInformationOverviewFragment.this.getResources()
+                    .getString(R.string.uri_api_coord);
+            final String APIVersion = WeatherInformationOverviewFragment.this.getResources()
+                    .getString(R.string.api_version);
+            String url = this.weatherService.createURIAPICoord(geocodingData.getLatitude(),
+                    geocodingData.getLongitude(), urlAPICoord, APIVersion, languagePreferenceValue);
+
+
+            final String jsonData = this.weatherHTTPClient.retrieveJSONDataFromAPI(new URL(url));
+
+
+            final WeatherData weatherData = this.weatherService.retrieveDataFromJPOS(jsonData);
+
+
+            final String icon = weatherData.getWeather().getIcon();
+            final String urlAPIicon = WeatherInformationOverviewFragment.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;
+        }
+
+        private void onPostExecuteThrowable(final WeatherData weatherData)
+                throws FileNotFoundException, IOException {
+            WeatherInformationOverviewFragment.this.storeWeatherDataToFile(weatherData);
+
+            WeatherInformationOverviewFragment.this.updateWeatherData(weatherData);
+        }
+    }
+
+    private List<WeatherOverviewEntry> createEmptyEntriesList() {
+        final List<WeatherOverviewEntry> entries = new ArrayList<WeatherOverviewEntry>();
+        final SimpleDateFormat dateFormat = new SimpleDateFormat("MM.dd", Locale.getDefault());
+
+        final Calendar now = Calendar.getInstance();
+        for (int i = 0; i<15; i++) {
+            final Date day = now.getTime();
+            entries.add(i, new WeatherOverviewEntry(
+                    "DATE: " + dateFormat.format(day), null, null));
+            now.add(Calendar.DAY_OF_MONTH, -1);
+        }
+
+        return entries;
+    }
+
+    private void storeWeatherDataToFile(final WeatherData weatherData)
+            throws FileNotFoundException, IOException {
+        final OutputStream persistenceFile = this.getActivity().openFileOutput(
+                WEATHER_DATA_FILE, Context.MODE_PRIVATE);
+
+        ObjectOutputStream oos = null;
+        try {
+            oos = new ObjectOutputStream(persistenceFile);
+
+            oos.writeObject(weatherData);
+        } finally {
+            if (oos != null) {
+                oos.close();
+            }
+        }
+    }
+
+    private WeatherData restoreWeatherDataFromFile() throws StreamCorruptedException,
+    FileNotFoundException, IOException, ClassNotFoundException {
+        final InputStream persistenceFile = this.getActivity().openFileInput(
+                WEATHER_DATA_FILE);
+
+        ObjectInputStream ois = null;
+        try {
+            ois = new ObjectInputStream(persistenceFile);
+
+            return (WeatherData) ois.readObject();
+        } finally {
+            if (ois != null) {
+                ois.close();
+            }
+        }
+    }
+
+    private GeocodingData restoreGeocodingDataFromFile()
+            throws StreamCorruptedException, FileNotFoundException,
+            IOException, ClassNotFoundException {
+        final InputStream persistenceFile = this.getActivity()
+                .openFileInput(WEATHER_GEOCODING_FILE);
+
+        ObjectInputStream ois = null;
+        try {
+            ois = new ObjectInputStream(persistenceFile);
+
+            return (GeocodingData) ois.readObject();
+        } finally {
+            if (ois != null) {
+                ois.close();
+            }
+        }
+    }
+}
diff --git a/src/de/example/exampletdd/fragment/overview/WeatherOverviewAdapter.java b/src/de/example/exampletdd/fragment/overview/WeatherOverviewAdapter.java
new file mode 100644 (file)
index 0000000..43fae28
--- /dev/null
@@ -0,0 +1,97 @@
+package de.example.exampletdd.fragment.overview;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.example.exampletdd.R;
+
+public class WeatherOverviewAdapter extends ArrayAdapter<WeatherOverviewEntry> {
+    private final int resource;
+
+    public WeatherOverviewAdapter(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 WeatherOverviewEntry entry = this.getItem(position);
+
+
+        // Setting the text view
+        viewHolder.dateView.setText(entry.getDate());
+        viewHolder.temperatureView.setText(entry.getTemperature());
+        // Set image view
+        viewHolder.pictureView.setImageBitmap(entry.getPicture());
+
+
+        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.dateView = (TextView) workingView
+                    .findViewById(R.id.weather_main_entry_date);
+            viewHolder.temperatureView = (TextView) workingView
+                    .findViewById(R.id.weather_main_entry_temperature);
+            viewHolder.pictureView = (ImageView) workingView
+                    .findViewById(R.id.weather_main_entry_image);
+
+            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 dateView;
+        public TextView temperatureView;
+        public ImageView pictureView;
+    }
+
+}
diff --git a/src/de/example/exampletdd/fragment/overview/WeatherOverviewEntry.java b/src/de/example/exampletdd/fragment/overview/WeatherOverviewEntry.java
new file mode 100644 (file)
index 0000000..f56fce6
--- /dev/null
@@ -0,0 +1,28 @@
+package de.example.exampletdd.fragment.overview;
+
+import android.graphics.Bitmap;
+
+public class WeatherOverviewEntry {
+    private final String date;
+    private final String temperature;
+    private final Bitmap picture;
+
+    public WeatherOverviewEntry(final String date, final String temperature,
+            final Bitmap picture) {
+        this.date = date;
+        this.temperature = temperature;
+        this.picture = picture;
+    }
+
+    public String getDate() {
+        return this.date;
+    }
+
+    public String getTemperature() {
+        return this.temperature;
+    }
+
+    public Bitmap getPicture() {
+        return this.picture;
+    }
+}
index 7c2f6ff..21c0a1c 100644 (file)
@@ -12,6 +12,10 @@ public class JPOSWeatherParser implements IJPOSWeatherParser {
     public WeatherData retrieveWeatherFromJPOS(final String jsonData) throws JSONException {
         final JSONObject jsonWeatherData = new JSONObject(jsonData);
 
+        // TODO: return always objects. Using null values the app will be able
+        // to find out if there is or not data. In case of null value will
+        // not show anything on GUI (empty textbox for example)
+
         JSONObject jsonObject = jsonWeatherData.getJSONObject("coord");
         final double longitude = jsonObject.getDouble("lon");
         final double latitude = jsonObject.getDouble("lat");
diff --git a/src/de/example/exampletdd/provider/WeatherInformationIndexer.java b/src/de/example/exampletdd/provider/WeatherInformationIndexer.java
new file mode 100644 (file)
index 0000000..d398daa
--- /dev/null
@@ -0,0 +1,28 @@
+package de.example.exampletdd.provider;
+
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+public class WeatherInformationIndexer {
+
+    // This class cannot be instantiated
+    private WeatherInformationIndexer() {}
+
+    public static final class Index implements BaseColumns {
+
+        // This class cannot be instantiated
+        private Index() {}
+
+        /**
+         * The content URI base for a single index. Callers must
+         * append a numeric note id to this Uri to retrieve an index
+         */
+        public static final Uri CONTENT_ID_URI_BASE
+        = Uri.parse("content://de.example.exampletdd.provider/indexer/");
+
+        /**
+         * The table name offered by this provider
+         */
+        public static final String TABLE_NAME = "indexer";
+    }
+}
diff --git a/src/de/example/exampletdd/provider/WeatherInformationOpenHelper.java b/src/de/example/exampletdd/provider/WeatherInformationOpenHelper.java
new file mode 100644 (file)
index 0000000..6741f26
--- /dev/null
@@ -0,0 +1,44 @@
+package de.example.exampletdd.provider;
+
+import android.content.Context;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public class WeatherInformationOpenHelper extends SQLiteOpenHelper {
+    private static final String TAG = "WeatherInformationOpenHelper";
+
+    private static final String DATABASE_NAME = "weatherinformation.db";
+    private static final int DATABASE_VERSION = 1;
+
+    WeatherInformationOpenHelper(final Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+    }
+
+    public WeatherInformationOpenHelper(final Context context, final String name,
+            final CursorFactory factory, final int version) {
+        super(context, name, factory, version);
+        // TODO Auto-generated constructor stub
+    }
+
+    public WeatherInformationOpenHelper(final Context context, final String name,
+            final CursorFactory factory, final int version,
+            final DatabaseErrorHandler errorHandler) {
+        super(context, name, factory, version, errorHandler);
+        // TODO Auto-generated constructor stub
+    }
+
+    @Override
+    public void onCreate(final SQLiteDatabase db) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
+        // TODO Auto-generated method stub
+
+    }
+
+}
diff --git a/src/de/example/exampletdd/provider/WeatherInformationProvider.java b/src/de/example/exampletdd/provider/WeatherInformationProvider.java
new file mode 100644 (file)
index 0000000..25d5045
--- /dev/null
@@ -0,0 +1,50 @@
+package de.example.exampletdd.provider;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class WeatherInformationProvider extends ContentProvider {
+    public WeatherInformationProvider() {
+    }
+
+    @Override
+    public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
+        // Implement this to handle requests to delete one or more rows.
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public String getType(final Uri uri) {
+        // TODO: Implement this to handle requests for the MIME type of the data
+        // at the given URI.
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public Uri insert(final Uri uri, final ContentValues values) {
+        // TODO: Implement this to handle requests to insert a new row.
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public boolean onCreate() {
+        // TODO: Implement this to initialize your content provider on startup.
+        return false;
+    }
+
+    @Override
+    public Cursor query(final Uri uri, final String[] projection, final String selection,
+            final String[] selectionArgs, final String sortOrder) {
+        // TODO: Implement this to handle query requests from clients.
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    @Override
+    public int update(final Uri uri, final ContentValues values, final String selection,
+            final String[] selectionArgs) {
+        // TODO: Implement this to handle requests to update one or more rows.
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+}