+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="de.example.exampletdd"
- android:installLocation="auto"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk
- android:maxSdkVersion="18"
- android:minSdkVersion="18"
- android:targetSdkVersion="18" />
-
- <uses-feature
- android:glEsVersion="0x00020000"
- android:required="true" />
-
- <!-- TODO: http://developer.android.com/guide/topics/manifest/supports-screens-element.html -->
- <!-- TODO: supporting multiple layouts/languages http://developer.android.com/guide/practices/screens_support.html -->
- <compatible-screens>
- <screen android:screenSize="normal" android:screenDensity="xhdpi" />
- </compatible-screens>
- <supports-screens android:smallScreens="false" />
-
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!--
- The following two permissions are not required to use
- Google Maps Android API v2, but are recommended.
- -->
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
-
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
-
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:logo="@drawable/ic_launcher"
- android:theme="@style/AppTheme"
- android:supportsRtl="false">
-
- <activity android:name="de.example.exampletdd.WeatherTabsActivity"
- android:hardwareAccelerated="false"
- android:uiOptions="splitActionBarWhenNarrow"
- android:launchMode="singleTop" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="de.example.exampletdd.WeatherInformationPreferencesActivity"
- android:parentActivityName="de.example.exampletdd.WeatherTabsActivity" >
- <intent-filter>
- <action android:name="android.intent.action.WEATHERINFORMATIONSETTINGS" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- <activity android:name="de.example.exampletdd.MapActivity"
- android:parentActivityName="de.example.exampletdd.WeatherTabsActivity" >
- <intent-filter>
- <action android:name="android.intent.action.WEATHERINFORMATIONMAP" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="de.example.exampletdd.SpecificActivity"
- android:parentActivityName="de.example.exampletdd.WeatherTabsActivity"
- android:exported="false" >
- <intent-filter>
- <action android:name="android.intent.action.WEATHERINFORMATIONSPECIFICDATA" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="de.example.exampletdd.widget.WidgetConfigure">
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
- </intent-filter>
- </activity>
-
- <receiver android:name="de.example.exampletdd.WeatherInformationBootReceiver"
- android:enabled="true">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"></action>
- </intent-filter>
- </receiver>
- <receiver android:name="de.example.exampletdd.widget.WidgetProvider" >
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
- </intent-filter>
- <meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_provider" />
- </receiver>
-
- <!-- Service to update Notification -->
- <service android:name="de.example.exampletdd.NotificationIntentService"
- android:exported="false"
- android:enabled="true" />
-
- <!-- Service to update Widget -->
- <service android:name="de.example.exampletdd.WidgetIntentService"
- android:exported="false"
- android:enabled="true" />
-
-
- <meta-data
- android:name="com.google.android.maps.v2.API_KEY"
- android:value="" />
- <meta-data
- android:name="com.google.android.gms.version"
- android:value="@integer/google_play_services_version" />
-
- </application>
-
-</manifest>
--- /dev/null
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 18
+ buildToolsVersion "20.0.0"
+
+ defaultConfig {
+ applicationId "de.example.exampletdd"
+ minSdkVersion 18
+ targetSdkVersion 18
+
+ testApplicationId "de.example.exampletdd.test"
+ testInstrumentationRunner "android.test.InstrumentationTestRunner"
+ }
+
+ buildTypes {
+ release {
+ runProguard false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+}
+
+dependencies {
+ compile 'com.android.support:support-v4:+'
+ compile 'com.google.android.gms:play-services:+'
+ compile files('libs/jackson-core-2.3.3.jar')
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<lint>
+</lint>
\ No newline at end of file
--- /dev/null
+package de.example.exampletdd.test;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+
+import de.example.exampletdd.model.WeatherData;
+import de.example.exampletdd.parser.JPOSWeatherParser;
+
+public class JPOSWeatherParserTest extends TestCase {
+ private JPOSWeatherParser jposWeatherParser;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ this.jposWeatherParser = new JPOSWeatherParser();
+ }
+
+ public void testRetrieveWeatherFromJPOS() throws JSONException {
+ // Arrange
+ final String jsonData = "{\"coord\":{\"lon\":139,\"lat\":35}}";
+ final double longitude = 139;
+ final double latitude = 35;
+ final WeatherData.Coord coord = new WeatherData.Coord(longitude, latitude);
+ final WeatherData expectedWeather = new WeatherData.Builder().setCoord(coord).build();
+
+ // Act
+ final WeatherData finalWeather = this.jposWeatherParser.retrieveWeatherFromJPOS(jsonData);
+
+ // Assert
+ assertEquals(expectedWeather.toString(), finalWeather.toString());
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.test;
+
+import android.content.Intent;
+import android.test.ActivityUnitTestCase;
+import android.widget.Button;
+import de.example.exampletdd.WeatherInformationActivity;
+
+public class WeatherInformationActivityUnitTest extends
+ ActivityUnitTestCase<WeatherInformationActivity> {
+
+ private WeatherInformationActivity activity;
+
+ public WeatherInformationActivityUnitTest() {
+ super(WeatherInformationActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final Intent intent = new Intent(this.getInstrumentation().getTargetContext(),
+ WeatherInformationActivity.class);
+ this.startActivity(intent, null, null);
+ this.activity = this.getActivity();
+ }
+
+ public void testIntentTriggerViaOnClick() {
+ final int buttonweather = de.example.exampletdd.R.id.buttonweather;
+ final Button view = (Button) this.activity.findViewById(buttonweather);
+ assertNotNull("Button Weather not allowed to be null", view);
+
+ view.performClick();
+
+ // TouchUtils cannot be used, only allowed in
+ // InstrumentationTestCase or ActivityInstrumentationTestCase2
+
+ // Check the intent which was started
+ final Intent triggeredIntent = this.getStartedActivityIntent();
+ assertNotNull("Intent was null", triggeredIntent);
+ final String data = triggeredIntent.getDataString();
+
+ assertEquals("Incorrect data passed via the intent",
+ "http://gumartinm.name", data);
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">Weather Information Test</string>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="de.example.exampletdd"
+ android:installLocation="auto"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:maxSdkVersion="18"
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18" />
+
+ <uses-feature
+ android:glEsVersion="0x00020000"
+ android:required="true" />
+
+ <!-- TODO: http://developer.android.com/guide/topics/manifest/supports-screens-element.html -->
+ <!-- TODO: supporting multiple layouts/languages http://developer.android.com/guide/practices/screens_support.html -->
+ <compatible-screens>
+ <screen android:screenSize="normal" android:screenDensity="xhdpi" />
+ </compatible-screens>
+ <supports-screens android:smallScreens="false" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!--
+ The following two permissions are not required to use
+ Google Maps Android API v2, but are recommended.
+ -->
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
+
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:logo="@drawable/ic_launcher"
+ android:theme="@style/AppTheme"
+ android:supportsRtl="false">
+
+ <activity android:name="de.example.exampletdd.WeatherTabsActivity"
+ android:hardwareAccelerated="false"
+ android:uiOptions="splitActionBarWhenNarrow"
+ android:launchMode="singleTop" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="de.example.exampletdd.WeatherInformationPreferencesActivity"
+ android:parentActivityName="de.example.exampletdd.WeatherTabsActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.WEATHERINFORMATIONSETTINGS" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <activity android:name="de.example.exampletdd.MapActivity"
+ android:parentActivityName="de.example.exampletdd.WeatherTabsActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.WEATHERINFORMATIONMAP" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="de.example.exampletdd.SpecificActivity"
+ android:parentActivityName="de.example.exampletdd.WeatherTabsActivity"
+ android:exported="false" >
+ <intent-filter>
+ <action android:name="android.intent.action.WEATHERINFORMATIONSPECIFICDATA" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="de.example.exampletdd.widget.WidgetConfigure">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
+ </intent-filter>
+ </activity>
+
+ <receiver android:name="de.example.exampletdd.WeatherInformationBootReceiver"
+ android:enabled="true">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED"></action>
+ </intent-filter>
+ </receiver>
+ <receiver android:name="de.example.exampletdd.widget.WidgetProvider" >
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_provider" />
+ </receiver>
+
+ <!-- Service to update Notification -->
+ <service android:name="de.example.exampletdd.NotificationIntentService"
+ android:exported="false"
+ android:enabled="true" />
+
+ <!-- Service to update Widget -->
+ <service android:name="de.example.exampletdd.WidgetIntentService"
+ android:exported="false"
+ android:enabled="true" />
+
+
+ <meta-data
+ android:name="com.google.android.maps.v2.API_KEY"
+ android:value="" />
+ <meta-data
+ android:name="com.google.android.gms.version"
+ android:value="@integer/google_play_services_version" />
+
+ </application>
+
+</manifest>
--- /dev/null
+package de.example.exampletdd;
+
+import android.app.ActionBar;
+import android.content.Context;
+import android.location.Criteria;
+import android.location.Geocoder;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+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.map.MapButtonsFragment;
+import de.example.exampletdd.fragment.map.MapProgressFragment;
+import de.example.exampletdd.model.DatabaseQueries;
+import de.example.exampletdd.model.WeatherLocation;
+
+public class MapActivity extends FragmentActivity implements
+ LocationListener,
+ MapProgressFragment.TaskCallbacks {
+ private static final String PROGRESS_FRAGMENT_TAG = "PROGRESS_FRAGMENT";
+ private static final String BUTTONS_FRAGMENT_TAG = "BUTTONS_FRAGMENT";
+ private WeatherLocation mRestoreUI;
+
+ // Google Play Services Map
+ private GoogleMap mMap;
+ // TODO: read and store from different threads? Hopefully always from UI thread.
+ private Marker mMarker;
+
+ private LocationManager mLocationManager;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.setContentView(R.layout.weather_map);
+
+ // Acquire a reference to the system Location Manager
+ this.mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+
+ // Google Play Services Map
+ final MapFragment mapFragment = (MapFragment) this.getFragmentManager()
+ .findFragmentById(R.id.weather_map_fragment_map);
+ this.mMap = mapFragment.getMap();
+ this.mMap.setMyLocationEnabled(false);
+ this.mMap.getUiSettings().setMyLocationButtonEnabled(false);
+ this.mMap.getUiSettings().setZoomControlsEnabled(true);
+ this.mMap.getUiSettings().setCompassEnabled(true);
+ this.mMap.setOnMapLongClickListener(new MapActivityOnMapLongClickListener(this));
+ }
+
+ @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 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;
+
+ weatherLocation = new WeatherLocation()
+ .setCity(cityString)
+ .setCountry(countryString)
+ .setLatitude(latitude)
+ .setLongitude(longitude);
+ } else {
+ final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
+ weatherLocation = query.queryDataBase();
+ }
+
+ if (weatherLocation != null) {
+ this.updateUI(weatherLocation);
+ }
+ }
+
+ /**
+ * I am not using fragment transactions in the right way. But I do not know other way for doing what I am doing.
+ *
+ * {@link http://stackoverflow.com/questions/16265733/failure-delivering-result-onactivityforresult}
+ */
+ @Override
+ public void onPostResume() {
+ super.onPostResume();
+
+ final FragmentManager fm = getSupportFragmentManager();
+ final Fragment progressFragment = fm.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
+ if (progressFragment == null) {
+ this.addButtonsFragment();
+ } else {
+ this.removeProgressFragment();
+ final Bundle bundle = progressFragment.getArguments();
+ double latitude = bundle.getDouble("latitude");
+ double longitude = bundle.getDouble("longitude");
+ this.addProgressFragment(latitude, longitude);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
+ // Save UI state
+ // Save Google Maps Marker
+ 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()
+ .setCity(cityString)
+ .setCountry(countryString)
+ .setLatitude(latitude)
+ .setLongitude(longitude);
+ savedInstanceState.putSerializable("WeatherLocation", location);
+ }
+
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ this.mLocationManager.removeUpdates(this);
+ }
+
+ public void onClickSaveLocation(final View v) {
+ if (this.mMarker != null) {
+ final LatLng position = this.mMarker.getPosition();
+
+ 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 DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+ if (weatherLocation != null) {
+ weatherLocation
+ .setCity(cityString)
+ .setCountry(countryString)
+ .setLatitude(position.latitude)
+ .setLongitude(position.longitude)
+ .setLastCurrentUIUpdate(null)
+ .setLastForecastUIUpdate(null);
+ query.updateDataBase(weatherLocation);
+ } else {
+ final WeatherLocation location = new WeatherLocation()
+ .setCity(cityString)
+ .setCountry(countryString)
+ .setIsSelected(true)
+ .setLatitude(position.latitude)
+ .setLongitude(position.longitude);
+ query.insertIntoDataBase(location);
+ }
+ }
+ }
+
+ public void onClickGetLocation(final View v) {
+ // TODO: Somehow I should show a progress dialog.
+ // If Google Play Services is available
+ if (this.mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+ // TODO: Hopefully there will be results even if location did not change...
+ final Criteria criteria = new Criteria();
+ criteria.setAccuracy(Criteria.ACCURACY_FINE);
+ criteria.setAltitudeRequired(false);
+ criteria.setBearingAccuracy(Criteria.NO_REQUIREMENT);
+ criteria.setBearingRequired(false);
+ criteria.setCostAllowed(false);
+ criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
+ criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
+ criteria.setSpeedAccuracy(Criteria.NO_REQUIREMENT);
+ criteria.setSpeedRequired(false);
+ criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH);
+
+ this.mLocationManager.requestSingleUpdate(criteria, this, null);
+ } else {
+ // TODO: string resource
+ Toast.makeText(this, "You do not have enabled location.", Toast.LENGTH_LONG).show();
+ }
+ // Trying to use the synchronous calls. Problems: mGoogleApiClient read/store from different threads.
+ // new GetLocationTask(this).execute();
+ }
+
+ private void updateUI(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());
+ if (this.mMarker != null) {
+ // Just one marker on map
+ this.mMarker.remove();
+ }
+ 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);
+ }
+
+ private class MapActivityOnMapLongClickListener implements OnMapLongClickListener {
+ // Store the context passed to the AsyncTask when the system instantiates it.
+ private final Context localContext;
+
+ private MapActivityOnMapLongClickListener(final Context context) {
+ this.localContext = context;
+ }
+
+ @Override
+ public void onMapLongClick(final LatLng point) {
+ final MapActivity activity = (MapActivity) this.localContext;
+ activity.getAddressAndUpdateUI(point.latitude, point.longitude);
+ }
+
+ }
+
+ /**
+ * Getting the address of the current location, using reverse geocoding only works if
+ * a geocoding service is available.
+ *
+ */
+ private void getAddressAndUpdateUI(final double latitude, final double longitude) {
+ // In Gingerbread and later, use Geocoder.isPresent() to see if a geocoder is available.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && Geocoder.isPresent()) {
+ this.removeButtonsFragment();
+ this.removeProgressFragment();
+ this.addProgressFragment(latitude, longitude);
+ } else {
+ this.removeProgressFragment();
+ this.addButtonsFragment();
+ // No geocoder is present. Issue an error message.
+ // TODO: string resource
+ Toast.makeText(this, "Cannot get address. No geocoder available.", Toast.LENGTH_LONG).show();
+
+ // Default values
+ final String city = this.getString(R.string.city_not_found);
+ final String country = this.getString(R.string.country_not_found);
+ final WeatherLocation weatherLocation = new WeatherLocation()
+ .setLatitude(latitude)
+ .setLongitude(longitude)
+ .setCity(city)
+ .setCountry(country);
+
+ updateUI(weatherLocation);
+ }
+ }
+
+ /*****************************************************************************************************
+ *
+ * MapProgressFragment.TaskCallbacks
+ *
+ *****************************************************************************************************/
+ @Override
+ public void onPostExecute(WeatherLocation weatherLocation) {
+
+ this.updateUI(weatherLocation);
+ this.removeProgressFragment();
+
+ this.addButtonsFragment();
+ }
+
+ /*****************************************************************************************************
+ *
+ * MapProgressFragment
+ * I am not using fragment transactions in the right way. But I do not know other way for doing what I am doing.
+ * Android sucks.
+ *
+ * "Avoid performing transactions inside asynchronous callback methods." :(
+ * see: http://stackoverflow.com/questions/16265733/failure-delivering-result-onactivityforresult
+ * see: http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
+ * How do you do what I am doing in a different way without using fragments?
+ *****************************************************************************************************/
+
+ private void addProgressFragment(final double latitude, final double longitude) {
+ final Fragment progressFragment = new MapProgressFragment();
+ progressFragment.setRetainInstance(true);
+ final Bundle args = new Bundle();
+ args.putDouble("latitude", latitude);
+ args.putDouble("longitude", longitude);
+ progressFragment.setArguments(args);
+
+ final FragmentManager fm = this.getSupportFragmentManager();
+ final FragmentTransaction fragmentTransaction = fm.beginTransaction();
+ fragmentTransaction.setCustomAnimations(R.anim.weather_map_enter_progress, R.anim.weather_map_exit_progress);
+ fragmentTransaction.add(R.id.weather_map_buttons_container, progressFragment, PROGRESS_FRAGMENT_TAG).commit();
+ fm.executePendingTransactions();
+ }
+
+ private void removeProgressFragment() {
+ final FragmentManager fm = this.getSupportFragmentManager();
+ final Fragment progressFragment = fm.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
+ if (progressFragment != null) {
+ final FragmentTransaction fragmentTransaction = fm.beginTransaction();
+ fragmentTransaction.remove(progressFragment).commit();
+ fm.executePendingTransactions();
+ }
+ }
+
+ private void addButtonsFragment() {
+ final FragmentManager fm = this.getSupportFragmentManager();
+ Fragment buttonsFragment = fm.findFragmentByTag(BUTTONS_FRAGMENT_TAG);
+ if (buttonsFragment == null) {
+ buttonsFragment = new MapButtonsFragment();
+ buttonsFragment.setRetainInstance(true);
+ final FragmentTransaction fragmentTransaction = fm.beginTransaction();
+ fragmentTransaction.setCustomAnimations(R.anim.weather_map_enter_progress, R.anim.weather_map_exit_progress);
+ fragmentTransaction.add(R.id.weather_map_buttons_container, buttonsFragment, BUTTONS_FRAGMENT_TAG).commit();
+ fm.executePendingTransactions();
+ }
+
+ if (this.mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+ final Button getLocationButton = (Button) this.findViewById(R.id.weather_map_button_getlocation);
+ getLocationButton.setEnabled(true);
+ }
+ }
+
+ private void removeButtonsFragment() {
+ final FragmentManager fm = this.getSupportFragmentManager();
+ final Fragment buttonsFragment = fm.findFragmentByTag(BUTTONS_FRAGMENT_TAG);
+ if (buttonsFragment != null) {
+ final FragmentTransaction fragmentTransaction = fm.beginTransaction();
+ fragmentTransaction.remove(buttonsFragment).commit();
+ fm.executePendingTransactions();
+ }
+ }
+
+ /*****************************************************************************************************
+ *
+ * android.location.LocationListener
+ *
+ *****************************************************************************************************/
+
+ @Override
+ public void onLocationChanged(final Location location) {
+ // It was called from onClickGetLocation (UI thread) This method will run in the same thread (the UI thread)
+ // so, I do no think there should be any problem.
+
+ // Display the current location in the UI
+ // TODO: May location not be null?
+ this.getAddressAndUpdateUI(location.getLatitude(), location.getLongitude());
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ // TODO Auto-generated method stub
+
+ }
+}
--- /dev/null
+package de.example.exampletdd;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+import org.apache.http.client.ClientProtocolException;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.http.AndroidHttpClient;
+import android.preference.PreferenceManager;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.TaskStackBuilder;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import com.fasterxml.jackson.core.JsonParseException;
+
+import de.example.exampletdd.httpclient.CustomHTTPClient;
+import de.example.exampletdd.model.DatabaseQueries;
+import de.example.exampletdd.model.WeatherLocation;
+import de.example.exampletdd.model.currentweather.Current;
+import de.example.exampletdd.parser.JPOSWeatherParser;
+import de.example.exampletdd.service.IconsList;
+import de.example.exampletdd.service.ServiceParser;
+
+public class NotificationIntentService extends IntentService {
+ private static final String TAG = "NotificationIntentService";
+
+
+ public NotificationIntentService() {
+ super("NIS-Thread");
+ }
+
+ @Override
+ protected void onHandleIntent(final Intent intent) {
+ final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+
+ if (weatherLocation != null) {
+ final ServiceParser weatherService = new ServiceParser(new JPOSWeatherParser());
+ final CustomHTTPClient HTTPClient = new CustomHTTPClient(
+ AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent"));
+
+ Current current = null;
+ try {
+ current = this.doInBackgroundThrowable(weatherLocation, HTTPClient, weatherService);
+
+ } catch (final JsonParseException e) {
+ Log.e(TAG, "doInBackground exception: ", e);
+ } 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);
+ } finally {
+ HTTPClient.close();
+ }
+
+ if (current != null) {
+ this.showNotification(current, weatherLocation);
+ }
+ }
+ }
+
+ private Current doInBackgroundThrowable(final WeatherLocation weatherLocation,
+ final CustomHTTPClient HTTPClient, final ServiceParser weatherService)
+ throws ClientProtocolException, MalformedURLException, URISyntaxException,
+ JsonParseException, IOException {
+
+ final String APIVersion = this.getResources().getString(R.string.api_version);
+
+ final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today);
+ final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion,
+ weatherLocation.getLatitude(), weatherLocation.getLongitude());
+ final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
+ final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
+ final Current current = weatherService.retrieveCurrentFromJPOS(jsonData);
+ // TODO: what is this for? I guess I could skip it :/
+ final Calendar now = Calendar.getInstance();
+ current.setDate(now.getTime());
+
+ return current;
+ }
+
+ private interface UnitsConversor {
+
+ public double doConversion(final double value);
+ }
+
+ private void showNotification(final Current current, final WeatherLocation weatherLocation) {
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this.getApplicationContext());
+
+ // TODO: repeating the same code in Overview, Specific and Current!!!
+ // 1. Update units of measurement.
+ // 1.1 Temperature
+ String tempSymbol;
+ UnitsConversor tempUnitsConversor;
+ String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
+ String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ if (unitsPreferenceValue.equals(values[0])) {
+ tempSymbol = values[0];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value - 273.15;
+ }
+
+ };
+ } else if (unitsPreferenceValue.equals(values[1])) {
+ tempSymbol = values[1];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return (value * 1.8) - 459.67;
+ }
+
+ };
+ } else {
+ tempSymbol = values[2];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value;
+ }
+
+ };
+ }
+
+
+ // 2. Formatters
+ final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
+ tempFormatter.applyPattern("#####.#####");
+
+
+ // 3. Prepare data for RemoteViews.
+ String tempMax = "";
+ if (current.getMain().getTemp_max() != null) {
+ double conversion = (Double) current.getMain().getTemp_max();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMax = tempFormatter.format(conversion) + tempSymbol;
+ }
+ String tempMin = "";
+ if (current.getMain().getTemp_min() != null) {
+ double conversion = (Double) current.getMain().getTemp_min();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMin = tempFormatter.format(conversion) + tempSymbol;
+ }
+ Bitmap picture;
+ if ((current.getWeather().size() > 0)
+ && (current.getWeather().get(0).getIcon() != null)
+ && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
+ final String icon = current.getWeather().get(0).getIcon();
+ picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
+ .getResourceDrawable());
+ } else {
+ picture = BitmapFactory.decodeResource(this.getResources(),
+ R.drawable.weather_severe_alert);
+ }
+ final String city = weatherLocation.getCity();
+ final String country = weatherLocation.getCountry();
+
+ // 4. Insert data in RemoteViews.
+ final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.notification);
+ remoteView.setImageViewBitmap(R.id.weather_notification_image, picture);
+ remoteView.setTextViewText(R.id.weather_notification_temperature_max, tempMax);
+ remoteView.setTextViewText(R.id.weather_notification_temperature_min, tempMin);
+ remoteView.setTextViewText(R.id.weather_notification_city, city);
+ remoteView.setTextViewText(R.id.weather_notification_country, country);
+
+ // 5. Activity launcher.
+ final Intent resultIntent = new Intent(this.getApplicationContext(), WeatherTabsActivity.class);
+ // The PendingIntent to launch our activity if the user selects this notification
+// final PendingIntent contentIntent = PendingIntent.getActivity(
+// this.getApplicationContext(), 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ // The stack builder object will contain an artificial back stack for the started Activity.
+ // This ensures that navigating backward from the Activity leads out of
+ // your application to the Home screen.
+ final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
+ // Adds the back stack for the Intent (but not the Intent itself)
+ stackBuilder.addParentStack(WeatherTabsActivity.class);
+ // Adds the Intent that starts the Activity to the top of the stack
+ stackBuilder.addNextIntent(resultIntent);
+ final PendingIntent resultPendingIntent =
+ stackBuilder.getPendingIntent(
+ 0,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+
+ final NotificationManagerCompat notificationManager =
+ NotificationManagerCompat.from(this.getApplicationContext());
+
+
+ // 6. Create notification.
+ final NotificationCompat.Builder notificationBuilder =
+ new NotificationCompat.Builder(this.getApplicationContext())
+ .setContent(remoteView)
+ .setSmallIcon(R.drawable.ic_launcher)
+ .setAutoCancel(true)
+ .setLocalOnly(true)
+ .setWhen(System.currentTimeMillis())
+ .setContentIntent(resultPendingIntent)
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT);
+
+ final Notification notification = notificationBuilder.build();
+ notification.flags |= Notification.FLAG_AUTO_CANCEL;
+
+ // Send the notification.
+ // Sets an ID for the notification, so it can be updated (just in case)
+ int notifyID = 1;
+ notificationManager.notify(notifyID, notification);
+ }
+}
--- /dev/null
+package de.example.exampletdd;
+
+import android.app.ActionBar;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import de.example.exampletdd.model.DatabaseQueries;
+import de.example.exampletdd.model.WeatherLocation;
+
+public class SpecificActivity extends FragmentActivity {
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.setContentView(R.layout.weather_specific);
+
+ final ActionBar actionBar = this.getActionBar();
+
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ // 1. Update title.
+ final DatabaseQueries query = new DatabaseQueries(this);
+ final WeatherLocation weatherLocation = query.queryDataBase();
+ if (weatherLocation != null) {
+ final ActionBar actionBar = this.getActionBar();
+ // TODO: I18N and comma :/
+ actionBar.setTitle(weatherLocation.getCity() + "," + weatherLocation.getCountry());
+ }
+ }
+}
--- /dev/null
+package de.example.exampletdd;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
+
+public class WeatherInformationBootReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+
+ if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
+
+ // Update Time Rate
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(context);
+ final String keyPreference = context
+ .getString(R.string.weather_preferences_update_time_rate_key);
+ final String updateTimeRate = sharedPreferences.getString(keyPreference, "");
+ long chosenInterval = 0;
+ if (updateTimeRate.equals("900")) {
+ chosenInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
+ } else if (updateTimeRate.equals("1800")) {
+ chosenInterval = AlarmManager.INTERVAL_HALF_HOUR;
+ } else if (updateTimeRate.equals("3600")) {
+ chosenInterval = AlarmManager.INTERVAL_HOUR;
+ } else if (updateTimeRate.equals("43200")) {
+ chosenInterval = AlarmManager.INTERVAL_HALF_DAY;
+ } else if (updateTimeRate.equals("86400")) {
+ chosenInterval = AlarmManager.INTERVAL_DAY;
+ }
+
+ if (chosenInterval != 0) {
+ final AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ // TODO: better use some string instead of .class? In case I change the service class
+ // this could be a problem (I guess)
+ final Intent serviceIntent = new Intent(context, NotificationIntentService.class);
+ final PendingIntent alarmIntent = PendingIntent.getService(
+ context,
+ 0,
+ serviceIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ alarmMgr.setInexactRepeating(
+ AlarmManager.ELAPSED_REALTIME,
+ SystemClock.elapsedRealtime() + chosenInterval,
+ chosenInterval,
+ alarmIntent);
+ }
+ }
+ }
+
+}
--- /dev/null
+package de.example.exampletdd;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.os.Bundle;
+import de.example.exampletdd.fragment.preferences.WeatherInformationPreferencesFragment;
+
+public class WeatherInformationPreferencesActivity extends Activity {
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ this.getFragmentManager()
+ .beginTransaction()
+ .replace(android.R.id.content,
+ new WeatherInformationPreferencesFragment()).commit();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final ActionBar actionBar = this.getActionBar();
+ actionBar.setTitle(this.getString(R.string.weather_preferences_action_settings));
+ }
+}
--- /dev/null
+package de.example.exampletdd;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.FragmentTransaction;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.Menu;
+import android.view.MenuItem;
+import de.example.exampletdd.fragment.current.CurrentFragment;
+import de.example.exampletdd.fragment.overview.OverviewFragment;
+import de.example.exampletdd.model.DatabaseQueries;
+import de.example.exampletdd.model.WeatherLocation;
+
+public class WeatherTabsActivity extends FragmentActivity {
+ private static final int NUM_ITEMS = 2;
+ private ViewPager mPager;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.setContentView(R.layout.fragment_pager);
+
+ this.mPager = (ViewPager)this.findViewById(R.id.pager);
+ this.mPager.setAdapter(new TabsAdapter(this.getSupportFragmentManager()));
+
+
+ this.mPager.setOnPageChangeListener(
+ new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(final int position) {
+ WeatherTabsActivity.this.getActionBar().setSelectedNavigationItem(position);
+ }
+ });
+
+
+ final ActionBar actionBar = this.getActionBar();
+
+ PreferenceManager.setDefaultValues(this, R.xml.weather_preferences, false);
+
+ // Specify that tabs should be displayed in the action bar.
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+
+ // Create a tab listener that is called when the user changes tabs.
+ final ActionBar.TabListener tabListener = new ActionBar.TabListener() {
+
+ @Override
+ public void onTabSelected(final Tab tab, final FragmentTransaction ft) {
+ WeatherTabsActivity.this.mPager.setCurrentItem(tab.getPosition());
+
+ }
+
+ @Override
+ public void onTabUnselected(final Tab tab, final FragmentTransaction ft) {
+
+ }
+
+ @Override
+ public void onTabReselected(final Tab tab, final FragmentTransaction ft) {
+
+ }
+
+ };
+
+ actionBar.addTab(actionBar.newTab().setText("CURRENTLY").setTabListener(tabListener));
+ actionBar.addTab(actionBar.newTab().setText("FORECAST").setTabListener(tabListener));
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+
+ this.getMenuInflater().inflate(R.menu.weather_main_menu, menu);
+
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ super.onOptionsItemSelected(item);
+
+ Intent intent;
+ final int itemId = item.getItemId();
+ if (itemId == R.id.weather_menu_settings) {
+ intent = new Intent("de.example.exampletdd.WEATHERINFO")
+ .setComponent(new ComponentName("de.example.exampletdd",
+ "de.example.exampletdd.WeatherInformationPreferencesActivity"));
+ 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.MapActivity"));
+ this.startActivity(intent);
+ return true;
+ } else {
+ }
+
+ // TODO: calling again super method?
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(final Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ }
+
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final ActionBar actionBar = this.getActionBar();
+
+ // 1. Update title.
+ final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+ if (weatherLocation != null) {
+ // TODO: I18N and comma :/
+ actionBar.setTitle(weatherLocation.getCity() + "," + weatherLocation.getCountry());
+ } else {
+ // TODO: static resource
+ actionBar.setTitle("no chosen location");
+ }
+
+ // 2. Update forecast tab text.
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this);
+ final String keyPreference = this.getString(R.string.weather_preferences_day_forecast_key);
+ final String value = sharedPreferences.getString(keyPreference, "");
+ String humanValue = "";
+ if (value.equals("5")) {
+ humanValue = "5 DAY FORECAST";
+ } else if (value.equals("10")) {
+ humanValue = "10 DAY FORECAST";
+ } else if (value.equals("14")) {
+ humanValue = "14 DAY FORECAST";
+ }
+ actionBar.getTabAt(1).setText(humanValue);
+ }
+
+ @Override
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ private class TabsAdapter extends FragmentPagerAdapter {
+ public TabsAdapter(final FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public int getCount() {
+ return NUM_ITEMS;
+ }
+
+ @Override
+ public Fragment getItem(final int position) {
+ if (position == 0) {
+ // TODO: new instance every time I click on tab?
+ return new CurrentFragment();
+ } else {
+ // TODO: new instance every time I click on tab?
+ final Fragment fragment = new OverviewFragment();
+ return fragment;
+ }
+
+ }
+ }
+}
--- /dev/null
+package de.example.exampletdd;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+import org.apache.http.client.ClientProtocolException;
+
+import android.app.IntentService;
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.net.http.AndroidHttpClient;
+import android.preference.PreferenceManager;
+import android.support.v4.app.TaskStackBuilder;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import com.fasterxml.jackson.core.JsonParseException;
+
+import de.example.exampletdd.httpclient.CustomHTTPClient;
+import de.example.exampletdd.model.DatabaseQueries;
+import de.example.exampletdd.model.WeatherLocation;
+import de.example.exampletdd.model.currentweather.Current;
+import de.example.exampletdd.parser.JPOSWeatherParser;
+import de.example.exampletdd.service.IconsList;
+import de.example.exampletdd.service.PermanentStorage;
+import de.example.exampletdd.service.ServiceParser;
+import de.example.exampletdd.widget.WidgetConfigure;
+
+public class WidgetIntentService extends IntentService {
+ private static final String TAG = "WidgetIntentService";
+
+
+ public WidgetIntentService() {
+ super("WIS-Thread");
+ }
+
+ @Override
+ protected void onHandleIntent(final Intent intent) {
+ Log.i(TAG, "onHandleIntent");
+ final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
+ final boolean isUpdateByApp = intent.getBooleanExtra("updateByApp", false);
+
+ if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ // Nothing to do. Something went wrong. Show error.
+ return;
+ }
+
+
+ final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+
+ if (weatherLocation == null) {
+ // Nothing to do. Show error.
+ final RemoteViews view = this.makeErrorView(appWidgetId);
+ this.updateWidget(view, appWidgetId);
+ return;
+ }
+
+ if (isUpdateByApp) {
+ this.updateByApp(weatherLocation, appWidgetId);
+ } else {
+ this.updateByTimeout(weatherLocation, appWidgetId);
+ }
+
+ }
+
+ private void updateByApp(final WeatherLocation weatherLocation, final int appWidgetId) {
+ final PermanentStorage store = new PermanentStorage(this.getApplicationContext());
+ final Current current = store.getCurrent();
+
+ this.updateWidget(current, weatherLocation, appWidgetId);
+ }
+
+ private void updateByTimeout(final WeatherLocation weatherLocation, final int appWidgetId) {
+
+ final Current current = this.getRemoteCurrent(weatherLocation);
+
+ this.updateWidget(current, weatherLocation, appWidgetId);
+ }
+
+ private void updateWidget(final Current current, final WeatherLocation weatherLocation, final int appWidgetId) {
+
+ if (current != null) {
+ final RemoteViews view = this.makeView(current, weatherLocation, appWidgetId);
+ this.updateWidget(view, appWidgetId);
+ } else {
+ // Show error.
+ final RemoteViews view = this.makeErrorView(appWidgetId);
+ this.updateWidget(view, appWidgetId);
+ }
+ }
+
+
+
+ private Current getRemoteCurrent(final WeatherLocation weatherLocation) {
+
+ final ServiceParser weatherService = new ServiceParser(new JPOSWeatherParser());
+ final CustomHTTPClient HTTPClient = new CustomHTTPClient(
+ AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent"));
+
+ try {
+ return this.getRemoteCurrentThrowable(weatherLocation, HTTPClient, weatherService);
+
+ } catch (final JsonParseException e) {
+ Log.e(TAG, "doInBackground exception: ", e);
+ } 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);
+ } finally {
+ HTTPClient.close();
+ }
+
+ return null;
+ }
+
+ private Current getRemoteCurrentThrowable(final WeatherLocation weatherLocation,
+ final CustomHTTPClient HTTPClient, final ServiceParser weatherService)
+ throws ClientProtocolException, MalformedURLException, URISyntaxException,
+ JsonParseException, IOException {
+
+ final String APIVersion = this.getResources().getString(R.string.api_version);
+
+ final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today);
+ final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion,
+ weatherLocation.getLatitude(), weatherLocation.getLongitude());
+ final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
+ final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
+ final Current current = weatherService.retrieveCurrentFromJPOS(jsonData);
+ // TODO: what is this for? I guess I could skip it :/
+ final Calendar now = Calendar.getInstance();
+ current.setDate(now.getTime());
+
+ return current;
+ }
+
+ private interface UnitsConversor {
+
+ public double doConversion(final double value);
+ }
+
+ private RemoteViews makeView(final Current current, final WeatherLocation weatherLocation, final int appWidgetId) {
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this.getApplicationContext());
+
+ // TODO: repeating the same code in Overview, Specific and Current!!!
+ // 1. Update units of measurement.
+ // 1.1 Temperature
+ String tempSymbol;
+ UnitsConversor tempUnitsConversor;
+ String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
+ String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ if (unitsPreferenceValue.equals(values[0])) {
+ tempSymbol = values[0];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value - 273.15;
+ }
+
+ };
+ } else if (unitsPreferenceValue.equals(values[1])) {
+ tempSymbol = values[1];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return (value * 1.8) - 459.67;
+ }
+
+ };
+ } else {
+ tempSymbol = values[2];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value;
+ }
+
+ };
+ }
+
+
+ // 2. Formatters
+ final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
+ tempFormatter.applyPattern("#####.#####");
+
+
+ // 3. Prepare data for RemoteViews.
+ String tempMax = "";
+ if (current.getMain().getTemp_max() != null) {
+ double conversion = (Double) current.getMain().getTemp_max();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMax = tempFormatter.format(conversion) + tempSymbol;
+ }
+ String tempMin = "";
+ if (current.getMain().getTemp_min() != null) {
+ double conversion = (Double) current.getMain().getTemp_min();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMin = tempFormatter.format(conversion) + tempSymbol;
+ }
+ Bitmap picture;
+ if ((current.getWeather().size() > 0)
+ && (current.getWeather().get(0).getIcon() != null)
+ && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
+ final String icon = current.getWeather().get(0).getIcon();
+ picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
+ .getResourceDrawable());
+ } else {
+ picture = BitmapFactory.decodeResource(this.getResources(),
+ R.drawable.weather_severe_alert);
+ }
+ final String city = weatherLocation.getCity();
+ final String country = weatherLocation.getCountry();
+
+ // 4. Insert data in RemoteViews.
+ final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget);
+ remoteView.setImageViewBitmap(R.id.weather_appwidget_image, picture);
+ remoteView.setTextViewText(R.id.weather_appwidget_temperature_max, tempMax);
+ remoteView.setTextViewText(R.id.weather_appwidget_temperature_min, tempMin);
+ remoteView.setTextViewText(R.id.weather_appwidget_city, city);
+ remoteView.setTextViewText(R.id.weather_appwidget_country, country);
+
+ // 5. Activity launcher.
+ final Intent resultIntent = new Intent(this.getApplicationContext(), WidgetConfigure.class);
+ resultIntent.putExtra("actionFromUser", true);
+ resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ // From: http://stackoverflow.com/questions/4011178/multiple-instances-of-widget-only-updating-last-widget
+ final Uri data = Uri.withAppendedPath(Uri.parse("PAIN" + "://widget/id/") ,String.valueOf(appWidgetId));
+ resultIntent.setData(data);
+
+ final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
+ // Adds the back stack for the Intent (but not the Intent itself)
+ stackBuilder.addParentStack(WidgetConfigure.class);
+ // Adds the Intent that starts the Activity to the top of the stack
+ stackBuilder.addNextIntent(resultIntent);
+ final PendingIntent resultPendingIntent =
+ stackBuilder.getPendingIntent(
+ 0,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ remoteView.setOnClickPendingIntent(R.id.weather_appwidget, resultPendingIntent);
+
+ return remoteView;
+ }
+
+ private RemoteViews makeErrorView(final int appWidgetId) {
+ final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget_error);
+
+ // 5. Activity launcher.
+ final Intent resultIntent = new Intent(this.getApplicationContext(), WidgetConfigure.class);
+ resultIntent.putExtra("actionFromUser", true);
+ resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ // From: http://stackoverflow.com/questions/4011178/multiple-instances-of-widget-only-updating-last-widget
+ final Uri data = Uri.withAppendedPath(Uri.parse("PAIN" + "://widget/id/") ,String.valueOf(appWidgetId));
+ resultIntent.setData(data);
+
+ final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
+ // Adds the back stack for the Intent (but not the Intent itself)
+ stackBuilder.addParentStack(WidgetConfigure.class);
+ // Adds the Intent that starts the Activity to the top of the stack
+ stackBuilder.addNextIntent(resultIntent);
+ final PendingIntent resultPendingIntent =
+ stackBuilder.getPendingIntent(
+ 0,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ remoteView.setOnClickPendingIntent(R.id.weather_appwidget_error, resultPendingIntent);
+
+ return remoteView;
+ }
+
+ private void updateWidget(final RemoteViews remoteView, final int appWidgetId) {
+
+ final AppWidgetManager manager = AppWidgetManager.getInstance(this.getApplicationContext());
+ manager.updateAppWidget(appWidgetId, remoteView);
+ }
+
+// private void updateWidgets(final RemoteViews remoteView) {
+//
+// final ComponentName widgets = new ComponentName(this.getApplicationContext(), WidgetProvider.class);
+// final AppWidgetManager manager = AppWidgetManager.getInstance(this.getApplicationContext());
+// manager.updateAppWidget(widgets, remoteView);
+// }
+}
--- /dev/null
+package de.example.exampletdd.dummy;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class for providing sample content for user interfaces created by
+ * Android template wizards.
+ * <p>
+ * TODO: Replace all uses of this class before publishing your app.
+ */
+public class DummyContent {
+
+ /**
+ * An array of sample (dummy) items.
+ */
+ public static List<DummyItem> ITEMS = new ArrayList<DummyItem>();
+
+ /**
+ * A map of sample (dummy) items, by ID.
+ */
+ public static Map<String, DummyItem> ITEM_MAP = new HashMap<String, DummyItem>();
+
+ static {
+ // Add 3 sample items.
+ addItem(new DummyItem("1", "Item 1"));
+ addItem(new DummyItem("2", "Item 2"));
+ addItem(new DummyItem("3", "Item 3"));
+ }
+
+ private static void addItem(DummyItem item) {
+ ITEMS.add(item);
+ ITEM_MAP.put(item.id, item);
+ }
+
+ /**
+ * A dummy item representing a piece of content.
+ */
+ public static class DummyItem {
+ public String id;
+ public String content;
+
+ public DummyItem(String id, String content) {
+ this.id = id;
+ this.content = content;
+ }
+
+ @Override
+ public String toString() {
+ return content;
+ }
+ }
+}
--- /dev/null
+package de.example.exampletdd.fragment;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+public class ErrorDialogFragment extends DialogFragment {
+
+ public static ErrorDialogFragment newInstance(final int title) {
+ final ErrorDialogFragment frag = new ErrorDialogFragment();
+ final Bundle args = new Bundle();
+
+ args.putInt("title", title);
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ @Override
+ public Dialog onCreateDialog(final Bundle savedInstanceState) {
+ final int title = this.getArguments().getInt("title");
+
+ return new AlertDialog.Builder(this.getActivity())
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(title)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog,
+ final int whichButton) {
+
+ }
+ }).create();
+ }
+
+ @Override
+ public void onDestroyView() {
+ if (getDialog() != null && getRetainInstance()) {
+ getDialog().setDismissMessage(null);
+ }
+ super.onDestroyView();
+ }
+}
\ No newline at end of file
--- /dev/null
+package de.example.exampletdd.fragment;
+
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.KeyEvent;
+
+public class ProgressDialogFragment extends DialogFragment {
+
+ public static ProgressDialogFragment newInstance(final int title) {
+ return newInstance(title, null);
+ }
+
+ public static ProgressDialogFragment newInstance(final int title,
+ final String message) {
+ final ProgressDialogFragment frag = new ProgressDialogFragment();
+ final Bundle args = new Bundle();
+
+ args.putInt("title", title);
+ args.putString("message", message);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @Override
+ public Dialog onCreateDialog(final Bundle savedInstanceState) {
+ final int title = this.getArguments().getInt("title");
+ final String message = this.getArguments().getString("message");
+
+ final ProgressDialog dialog = new ProgressDialog(this.getActivity());
+ dialog.setIcon(android.R.drawable.ic_dialog_info);
+ if (title != 0) {
+ dialog.setTitle(title);
+ }
+ if (message != null) {
+ dialog.setMessage(message);
+ }
+ dialog.setCancelable(false);
+ this.setCancelable(false);
+ dialog.setIndeterminate(true);
+ dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
+
+ @Override
+ public final boolean onKey(final DialogInterface dialog,
+ final int keyCode, final KeyEvent event) {
+ return false;
+ }
+ });
+
+ return dialog;
+ }
+}
--- /dev/null
+package de.example.exampletdd.fragment.current;
+
+import java.io.IOException;
+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.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import org.apache.http.client.ClientProtocolException;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+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.support.v4.app.Fragment;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.fasterxml.jackson.core.JsonParseException;
+
+import de.example.exampletdd.R;
+import de.example.exampletdd.WidgetIntentService;
+import de.example.exampletdd.httpclient.CustomHTTPClient;
+import de.example.exampletdd.model.DatabaseQueries;
+import de.example.exampletdd.model.WeatherLocation;
+import de.example.exampletdd.model.currentweather.Current;
+import de.example.exampletdd.parser.JPOSWeatherParser;
+import de.example.exampletdd.service.IconsList;
+import de.example.exampletdd.service.PermanentStorage;
+import de.example.exampletdd.service.ServiceParser;
+
+public class CurrentFragment extends Fragment {
+ private static final String TAG = "CurrentFragment";
+ private BroadcastReceiver mReceiver;
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.weather_current_fragment, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(final Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ // Restore UI state
+ final Current current = (Current) savedInstanceState.getSerializable("Current");
+
+ // TODO: Could it be better to store in global forecast data even if it is null value?
+ // So, perhaps do not check for null value and always store in global variable.
+ if (current != null) {
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ store.saveCurrent(current);
+ }
+ }
+
+ this.setHasOptionsMenu(false);
+
+ this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
+ this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
+ this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+
+ this.mReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals("de.example.exampletdd.UPDATECURRENT")) {
+ final Current currentRemote = (Current) intent.getSerializableExtra("current");
+
+ if (currentRemote != null) {
+
+ // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask.
+ final DatabaseQueries query = new DatabaseQueries(context.getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+ final PermanentStorage store = new PermanentStorage(context.getApplicationContext());
+ final Current current = store.getCurrent();
+
+ if (current == null || !CurrentFragment.this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
+ // 2. Update UI.
+ CurrentFragment.this.updateUI(currentRemote);
+
+ // 3. Update Data.
+ store.saveCurrent(currentRemote);
+ weatherLocation.setLastCurrentUIUpdate(new Date());
+ query.updateDataBase(weatherLocation);
+ }
+
+ } else {
+ // Empty UI and show error message
+ CurrentFragment.this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
+ CurrentFragment.this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
+ CurrentFragment.this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.VISIBLE);
+ }
+ }
+ }
+ };
+
+ // Register receiver
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction("de.example.exampletdd.UPDATECURRENT");
+ LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext())
+ .registerReceiver(this.mReceiver, filter);
+
+ // Empty UI
+ this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
+
+ final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+ if (weatherLocation == null) {
+ // Nothing to do.
+ // Show error message
+ final ProgressBar progress = (ProgressBar) getActivity().findViewById(R.id.weather_current_progressbar);
+ progress.setVisibility(View.GONE);
+ final TextView errorMessage = (TextView) getActivity().findViewById(R.id.weather_current_error_message);
+ errorMessage.setVisibility(View.VISIBLE);
+ return;
+ }
+
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ final Current current = store.getCurrent();
+
+ if (current != null && this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
+ this.updateUI(current);
+ } else {
+ // Load remote data (aynchronous)
+ // Gets the data from the web.
+ this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
+ this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
+ final CurrentTask task = new CurrentTask(
+ this.getActivity().getApplicationContext(),
+ new CustomHTTPClient(AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")),
+ new ServiceParser(new JPOSWeatherParser()));
+
+ task.execute(weatherLocation.getLatitude(), weatherLocation.getLongitude());
+ // TODO: make sure UI thread keeps running in parallel after that. I guess.
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
+
+ // Save UI state
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ final Current current = store.getCurrent();
+
+ // TODO: Could it be better to save current data even if it is null value?
+ // So, perhaps do not check for null value.
+ if (current != null) {
+ savedInstanceState.putSerializable("Current", current);
+ }
+
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
+ public void onPause() {
+ LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver);
+
+ super.onPause();
+ }
+
+ private interface UnitsConversor {
+
+ public double doConversion(final double value);
+ }
+
+ private void updateUI(final Current current) {
+
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this.getActivity().getApplicationContext());
+
+ // TODO: repeating the same code in Overview, Specific and Current!!!
+ // 1. Update units of measurement.
+ // 1.1 Temperature
+ String tempSymbol;
+ UnitsConversor tempUnitsConversor;
+ String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
+ String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ if (unitsPreferenceValue.equals(values[0])) {
+ tempSymbol = values[0];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value - 273.15;
+ }
+
+ };
+ } else if (unitsPreferenceValue.equals(values[1])) {
+ tempSymbol = values[1];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return (value * 1.8) - 459.67;
+ }
+
+ };
+ } else {
+ tempSymbol = values[2];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value;
+ }
+
+ };
+ }
+
+ // 1.2 Wind
+ String windSymbol;
+ UnitsConversor windUnitsConversor;
+ keyPreference = this.getResources().getString(R.string.weather_preferences_wind_key);
+ unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ values = this.getResources().getStringArray(R.array.weather_preferences_wind);
+ if (unitsPreferenceValue.equals(values[0])) {
+ windSymbol = values[0];
+ windUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value;
+ }
+ };
+ } else {
+ windSymbol = values[1];
+ windUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value * 2.237;
+ }
+ };
+ }
+
+ // 1.3 Pressure
+ String pressureSymbol;
+ UnitsConversor pressureUnitsConversor;
+ keyPreference = this.getResources().getString(R.string.weather_preferences_pressure_key);
+ unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
+ if (unitsPreferenceValue.equals(values[0])) {
+ pressureSymbol = values[0];
+ pressureUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value;
+ }
+ };
+ } else {
+ pressureSymbol = values[1];
+ pressureUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value / 113.25d;
+ }
+ };
+ }
+
+
+ // 2. Formatters
+ final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
+ tempFormatter.applyPattern("#####.#####");
+ final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.US);
+
+
+ // 3. Prepare data for UI.
+ String tempMax = "";
+ if (current.getMain().getTemp_max() != null) {
+ double conversion = (Double) current.getMain().getTemp_max();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMax = tempFormatter.format(conversion) + tempSymbol;
+ }
+ String tempMin = "";
+ if (current.getMain().getTemp_min() != null) {
+ double conversion = (Double) current.getMain().getTemp_min();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMin = tempFormatter.format(conversion) + tempSymbol;
+ }
+ Bitmap picture;
+ if ((current.getWeather().size() > 0)
+ && (current.getWeather().get(0).getIcon() != null)
+ && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
+ final String icon = current.getWeather().get(0).getIcon();
+ picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
+ .getResourceDrawable());
+ } else {
+ picture = BitmapFactory.decodeResource(this.getResources(),
+ R.drawable.weather_severe_alert);
+ }
+
+ // TODO: static resource
+ String description = "no description available";
+ if (current.getWeather().size() > 0) {
+ description = current.getWeather().get(0).getDescription();
+ }
+
+ // TODO: units!!!!
+ String humidityValue = "";
+ if ((current.getMain() != null)
+ && (current.getMain().getHumidity() != null)) {
+ final double conversion = (Double) current.getMain().getHumidity();
+ humidityValue = tempFormatter.format(conversion);
+ }
+ String pressureValue = "";
+ if ((current.getMain() != null)
+ && (current.getMain().getPressure() != null)) {
+ double conversion = (Double) current.getMain().getPressure();
+ conversion = pressureUnitsConversor.doConversion(conversion);
+ pressureValue = tempFormatter.format(conversion);
+ }
+ String windValue = "";
+ if ((current.getWind() != null)
+ && (current.getWind().getSpeed() != null)) {
+ double conversion = (Double) current.getWind().getSpeed();
+ conversion = windUnitsConversor.doConversion(conversion);
+ windValue = tempFormatter.format(conversion);
+ }
+ String rainValue = "";
+ if ((current.getRain() != null)
+ && (current.getRain().get3h() != null)) {
+ final double conversion = (Double) current.getRain().get3h();
+ rainValue = tempFormatter.format(conversion);
+ }
+ String cloudsValue = "";
+ if ((current.getClouds() != null)
+ && (current.getClouds().getAll() != null)) {
+ final double conversion = (Double) current.getClouds().getAll();
+ cloudsValue = tempFormatter.format(conversion);
+ }
+ String snowValue = "";
+ if ((current.getSnow() != null)
+ && (current.getSnow().get3h() != null)) {
+ final double conversion = (Double) current.getSnow().get3h();
+ snowValue = tempFormatter.format(conversion);
+ }
+ String feelsLike = "";
+ if (current.getMain().getTemp() != null) {
+ double conversion = (Double) current.getMain().getTemp();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ feelsLike = tempFormatter.format(conversion);
+ }
+ String sunRiseTime = "";
+ if (current.getSys().getSunrise() != null) {
+ final long unixTime = (Long) current.getSys().getSunrise();
+ final Date unixDate = new Date(unixTime * 1000L);
+ sunRiseTime = dateFormat.format(unixDate);
+ }
+ String sunSetTime = "";
+ if (current.getSys().getSunset() != null) {
+ final long unixTime = (Long) current.getSys().getSunset();
+ final Date unixDate = new Date(unixTime * 1000L);
+ sunSetTime = dateFormat.format(unixDate);
+ }
+
+
+ // 4. Update UI.
+ final TextView tempMaxView = (TextView) getActivity().findViewById(R.id.weather_current_temp_max);
+ tempMaxView.setText(tempMax);
+ final TextView tempMinView = (TextView) getActivity().findViewById(R.id.weather_current_temp_min);
+ tempMinView.setText(tempMin);
+ final ImageView pictureView = (ImageView) getActivity().findViewById(R.id.weather_current_picture);
+ pictureView.setImageBitmap(picture);
+
+ final TextView descriptionView = (TextView) getActivity().findViewById(R.id.weather_current_description);
+ descriptionView.setText(description);
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_humidity_value)).setText(humidityValue);
+ ((TextView) getActivity().findViewById(R.id.weather_current_humidity_units)).setText(
+ this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_pressure_value)).setText(pressureValue);
+ ((TextView) getActivity().findViewById(R.id.weather_current_pressure_units)).setText(pressureSymbol);
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_wind_value)).setText(windValue);
+ ((TextView) getActivity().findViewById(R.id.weather_current_wind_units)).setText(windSymbol);
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_rain_value)).setText(rainValue);
+ ((TextView) getActivity().findViewById(R.id.weather_current_rain_units)).setText(
+ this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_clouds_value)).setText(cloudsValue);
+ ((TextView) getActivity().findViewById(R.id.weather_current_clouds_units)).setText(
+ this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_snow_value)).setText(snowValue);
+ ((TextView) getActivity().findViewById(R.id.weather_current_snow_units)).setText(
+ this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_value)).setText(feelsLike);
+ ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_units)).setText(tempSymbol);
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_sunrise_value)).setText(sunRiseTime);
+
+ ((TextView) getActivity().findViewById(R.id.weather_current_sunset_value)).setText(sunSetTime);
+
+ this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.VISIBLE);
+ this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
+ this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
+ }
+
+ private boolean isDataFresh(final Date lastUpdate) {
+ if (lastUpdate == null) {
+ return false;
+ }
+
+ final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
+ this.getActivity().getApplicationContext());
+ final String keyPreference = this.getString(R.string.weather_preferences_refresh_interval_key);
+ final String refresh = sharedPreferences.getString(
+ keyPreference,
+ this.getResources().getStringArray(R.array.weather_preferences_refresh_interval)[0]);
+ final Date currentTime = new Date();
+ if (((currentTime.getTime() - lastUpdate.getTime())) < Long.valueOf(refresh)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // TODO: How could I show just one progress dialog when I have two fragments in tabs
+ // activity doing the same in background?
+ // I mean, if OverviewTask shows one progress dialog and CurrentTask does the same I will have
+ // have two progress dialogs... How may I solve this problem? I HATE ANDROID.
+ private class CurrentTask extends AsyncTask<Object, Void, Current> {
+ // Store the context passed to the AsyncTask when the system instantiates it.
+ private final Context localContext;
+ final CustomHTTPClient HTTPClient;
+ final ServiceParser weatherService;
+
+ public CurrentTask(final Context context, final CustomHTTPClient HTTPClient,
+ final ServiceParser weatherService) {
+ this.localContext = context;
+ this.HTTPClient = HTTPClient;
+ this.weatherService = weatherService;
+ }
+
+ @Override
+ protected Current doInBackground(final Object... params) {
+ final double latitude = (Double) params[0];
+ final double longitude = (Double) params[1];
+
+ Current current = null;
+ try {
+ current = this.doInBackgroundThrowable(latitude, longitude);
+ } catch (final JsonParseException e) {
+ Log.e(TAG, "CurrentTask doInBackground exception: ", e);
+ } catch (final ClientProtocolException e) {
+ Log.e(TAG, "CurrentTask doInBackground exception: ", e);
+ } catch (final MalformedURLException e) {
+ Log.e(TAG, "CurrentTask doInBackground exception: ", e);
+ } catch (final URISyntaxException e) {
+ Log.e(TAG, "CurrentTask doInBackground exception: ", e);
+ } catch (final IOException e) {
+ // logger infrastructure swallows UnknownHostException :/
+ Log.e(TAG, "CurrentTask doInBackground exception: " + e.getMessage(), e);
+ } finally {
+ HTTPClient.close();
+ }
+
+ return current;
+ }
+
+ private Current doInBackgroundThrowable(final double latitude, final double longitude)
+ throws URISyntaxException, ClientProtocolException, JsonParseException, IOException {
+
+ final String APIVersion = localContext.getResources().getString(R.string.api_version);
+ final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_today);
+ final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, latitude, longitude);
+ final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
+ final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
+ final Current current = weatherService.retrieveCurrentFromJPOS(jsonData);
+ // TODO: what is this for? I guess I could skip it :/
+ final Calendar now = Calendar.getInstance();
+ current.setDate(now.getTime());
+
+ return current;
+ }
+
+ @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 :(
+
+ // Call updateUI on the UI thread.
+ final Intent currentData = new Intent("de.example.exampletdd.UPDATECURRENT");
+ currentData.putExtra("current", current);
+ LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(currentData);
+ }
+ }
+}
--- /dev/null
+package de.example.exampletdd.fragment.map;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import de.example.exampletdd.R;
+
+public class MapButtonsFragment extends Fragment {
+
+ @Override
+ public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
+ final Bundle savedInstanceState) {
+
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.weather_map_buttons, container, false);
+ }
+
+ /**
+ * This method will only be called once when the retained
+ * Fragment is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Retain this fragment across configuration changes.
+ this.setRetainInstance(true);
+ }
+}
--- /dev/null
+package de.example.exampletdd.fragment.map;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+import android.app.Activity;
+import android.content.Context;
+import android.location.Address;
+import android.location.Geocoder;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import de.example.exampletdd.R;
+import de.example.exampletdd.model.WeatherLocation;
+
+/**
+ * {@link http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html}
+ *
+ */
+public class MapProgressFragment extends Fragment {
+
+ /**
+ *
+ * Callback interface through which the fragment will report the
+ * task's progress and results back to the Activity.
+ */
+ public static interface TaskCallbacks {
+ void onPostExecute(final WeatherLocation weatherLocation);
+ }
+
+ private TaskCallbacks mCallbacks;
+
+ @Override
+ public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
+ final Bundle savedInstanceState) {
+
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.weather_map_progress, container, false);
+ }
+
+ /**
+ * This method will only be called once when the retained
+ * Fragment is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Retain this fragment across configuration changes.
+ this.setRetainInstance(true);
+
+ final Bundle bundle = this.getArguments();
+ double latitude = bundle.getDouble("latitude");
+ double longitude = bundle.getDouble("longitude");
+
+ // Create and execute the background task.
+ new GetAddressTask(this.getActivity().getApplicationContext()).execute(latitude, longitude);
+ }
+
+ /**
+ * Hold a reference to the parent Activity so we can report the
+ * task's current progress and results. The Android framework
+ * will pass us a reference to the newly created Activity after
+ * each configuration change.
+ */
+ @Override
+ public void onAttach(final Activity activity) {
+ super.onAttach(activity);
+ mCallbacks = (TaskCallbacks) activity;
+ }
+
+ /**
+ * Set the callback to null so we don't accidentally leak the
+ * Activity instance.
+ */
+// @Override
+// public void onDetach() {
+// super.onDetach();
+// mCallbacks = null;
+// }
+
+ /**
+ * I am not using onDetach because there are problems when my activity goes to background.
+ *
+ * {@link http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html}
+ */
+ @Override
+ public void onPause() {
+ super.onPause();
+ mCallbacks = null;
+ }
+
+ private class GetAddressTask extends AsyncTask<Object, Void, WeatherLocation> {
+ private static final String TAG = "GetAddressTask";
+ // Store the context passed to the AsyncTask when the system instantiates it.
+ private final Context localContext;
+
+ private GetAddressTask(final Context context) {
+ this.localContext = context;
+ }
+
+ @Override
+ protected WeatherLocation doInBackground(final Object... params) {
+ final double latitude = (Double) params[0];
+ final double longitude = (Double) params[1];
+
+ WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
+ try {
+ weatherLocation = this.getLocation(latitude, longitude);
+ } catch (final Throwable e) { // Hopefully nothing goes wrong because of catching Throwable.
+ Log.e(TAG, "GetAddressTask 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 :(
+
+ // Call updateUI on the UI thread.
+ if (mCallbacks != null) {
+ mCallbacks.onPostExecute(weatherLocation);
+ }
+ }
+
+ private WeatherLocation getLocation(final double latitude, final double longitude) throws IOException {
+ // TODO: i18n Locale.getDefault()
+ final Geocoder geocoder = new Geocoder(this.localContext, Locale.US);
+ final List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
+
+ // Default values
+ WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
+
+ if (addresses != null && addresses.size() > 0) {
+ if (addresses.get(0).getLocality() != null) {
+ weatherLocation.setCity(addresses.get(0).getLocality());
+ }
+ if(addresses.get(0).getCountryName() != null) {
+ weatherLocation.setCountry(addresses.get(0).getCountryName());
+ }
+ }
+
+ return weatherLocation;
+ }
+
+ private WeatherLocation doDefaultLocation(final double latitude, final double longitude) {
+ // Default values
+ String city = this.localContext.getString(R.string.city_not_found);
+ String country = this.localContext.getString(R.string.country_not_found);
+
+ return new WeatherLocation()
+ .setLatitude(latitude)
+ .setLongitude(longitude)
+ .setCity(city)
+ .setCountry(country);
+ }
+ }
+}
--- /dev/null
+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 OverviewAdapter extends ArrayAdapter<OverviewEntry> {
+ private final int resource;
+
+ public OverviewAdapter(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 OverviewEntry entry = this.getItem(position);
+
+
+ // Setting date
+ viewHolder.dateNameView.setText(entry.getDateName());
+ viewHolder.dateNumberView.setText(entry.getDateNumber());
+
+ // Setting temperature max/min
+ viewHolder.temperatureMaxView.setText(entry.getMaxTemp());
+ viewHolder.temperatureMinView.setText(entry.getMinTemp());
+
+ // 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.dateNameView = (TextView) workingView
+ .findViewById(R.id.weather_main_entry_date_name);
+ viewHolder.dateNumberView = (TextView) workingView
+ .findViewById(R.id.weather_main_entry_date_number);
+ viewHolder.temperatureMaxView = (TextView) workingView
+ .findViewById(R.id.weather_main_entry_temperature_max);
+ viewHolder.temperatureMinView = (TextView) workingView
+ .findViewById(R.id.weather_main_entry_temperature_min);
+ 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 dateNameView;
+ public TextView dateNumberView;
+ public TextView temperatureMaxView;
+ public TextView temperatureMinView;
+ public ImageView pictureView;
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.fragment.overview;
+
+import android.graphics.Bitmap;
+
+public class OverviewEntry {
+ private final String dateName;
+ private final String dateNumber;
+ private final String maxTemp;
+ private final String minTemp;
+ private final Bitmap picture;
+
+ public OverviewEntry(final String dateName, final String dateNumber,
+ final String maxTemp, final String minTemp,
+ final Bitmap picture) {
+ this.dateName = dateName;
+ this.dateNumber = dateNumber;
+ this.maxTemp = maxTemp;
+ this.minTemp = minTemp;
+ this.picture = picture;
+ }
+
+ public String getDateName() {
+ return this.dateName;
+ }
+
+ public String getDateNumber() {
+ return this.dateNumber;
+ }
+
+ public String getMaxTemp() {
+ return this.maxTemp;
+ }
+
+ public String getMinTemp() {
+ return this.minTemp;
+ }
+
+ public Bitmap getPicture() {
+ return this.picture;
+ }
+}
--- /dev/null
+package de.example.exampletdd.fragment.overview;
+
+import java.io.IOException;
+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.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.http.client.ClientProtocolException;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+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.support.v4.app.ListFragment;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.ListView;
+
+import com.fasterxml.jackson.core.JsonParseException;
+
+import de.example.exampletdd.R;
+import de.example.exampletdd.fragment.specific.SpecificFragment;
+import de.example.exampletdd.httpclient.CustomHTTPClient;
+import de.example.exampletdd.model.DatabaseQueries;
+import de.example.exampletdd.model.WeatherLocation;
+import de.example.exampletdd.model.forecastweather.Forecast;
+import de.example.exampletdd.parser.JPOSWeatherParser;
+import de.example.exampletdd.service.IconsList;
+import de.example.exampletdd.service.PermanentStorage;
+import de.example.exampletdd.service.ServiceParser;
+
+public class OverviewFragment extends ListFragment {
+ private static final String TAG = "OverviewFragment";
+ private BroadcastReceiver mReceiver;
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onActivityCreated(final Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ final ListView listWeatherView = this.getListView();
+ listWeatherView.setChoiceMode(ListView.CHOICE_MODE_NONE);
+
+ if (savedInstanceState != null) {
+ // Restore UI state
+ final Forecast forecast = (Forecast) savedInstanceState.getSerializable("Forecast");
+
+ // TODO: Could it be better to store in global forecast data even if it is null value?
+ // So, perhaps do not check for null value and always store in global variable.
+ if (forecast != null) {
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ store.saveForecast(forecast);
+ }
+ }
+
+ this.setHasOptionsMenu(false);
+
+ this.setEmptyText(this.getString(R.string.text_field_remote_error));
+ this.setListShownNoAnimation(false);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ this.mReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals("de.example.exampletdd.UPDATEFORECAST")) {
+ final Forecast forecastRemote = (Forecast) intent.getSerializableExtra("forecast");
+
+ if (forecastRemote != null) {
+
+ // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask.
+ final DatabaseQueries query = new DatabaseQueries(context.getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+ final PermanentStorage store = new PermanentStorage(context.getApplicationContext());
+ final Forecast forecast = store.getForecast();
+
+ if (forecast == null || !OverviewFragment.this.isDataFresh(weatherLocation.getLastForecastUIUpdate())) {
+ // 2. Update UI.
+ OverviewFragment.this.updateUI(forecastRemote);
+
+ // 3. Update Data.
+ store.saveForecast(forecastRemote);
+ weatherLocation.setLastForecastUIUpdate(new Date());
+ query.updateDataBase(weatherLocation);
+
+ // 4. Show list.
+ OverviewFragment.this.setListShownNoAnimation(true);
+ }
+
+ } else {
+ // Empty list and show error message (see setEmptyText in onCreate)
+ OverviewFragment.this.setListAdapter(null);
+ OverviewFragment.this.setListShownNoAnimation(true);
+ }
+ }
+ }
+ };
+
+ // Register receiver
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction("de.example.exampletdd.UPDATEFORECAST");
+ LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext())
+ .registerReceiver(this.mReceiver, filter);
+
+ final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext());
+ final WeatherLocation weatherLocation = query.queryDataBase();
+ if (weatherLocation == null) {
+ // Nothing to do.
+ // Empty list and show error message (see setEmptyText in onCreate)
+ this.setListAdapter(null);
+ this.setListShownNoAnimation(true);
+ return;
+ }
+
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ final Forecast forecast = store.getForecast();
+
+ // TODO: store forecast data in permanent storage and check here if there is data in permanent storage
+ if (forecast != null && this.isDataFresh(weatherLocation.getLastForecastUIUpdate())) {
+ this.updateUI(forecast);
+ } else {
+ // Load remote data (aynchronous)
+ // Gets the data from the web.
+ this.setListShownNoAnimation(false);
+ final OverviewTask task = new OverviewTask(
+ this.getActivity().getApplicationContext(),
+ new CustomHTTPClient(AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")),
+ new ServiceParser(new JPOSWeatherParser()));
+
+ task.execute(weatherLocation.getLatitude(), weatherLocation.getLongitude());
+ // TODO: make sure thread UI keeps running in parallel after that. I guess.
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
+
+ // Save UI state
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ final Forecast forecast = store.getForecast();
+
+ // TODO: Could it be better to save forecast data even if it is null value?
+ // So, perhaps do not check for null value.
+ if (forecast != null) {
+ savedInstanceState.putSerializable("Forecast", forecast);
+ }
+
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
+ public void onPause() {
+ LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver);
+
+ super.onPause();
+ }
+
+ @Override
+ public void onListItemClick(final ListView l, final View v, final int position, final long id) {
+ final SpecificFragment fragment = (SpecificFragment) this
+ .getFragmentManager().findFragmentById(R.id.weather_specific_fragment);
+ if (fragment == null) {
+ // handset layout
+ final Intent intent = new Intent("de.example.exampletdd.WEATHERINFO")
+ .setComponent(new ComponentName("de.example.exampletdd",
+ "de.example.exampletdd.SpecificActivity"));
+ intent.putExtra("CHOSEN_DAY", (int) id);
+ OverviewFragment.this.getActivity().startActivity(intent);
+ } else {
+ // tablet layout
+ fragment.updateUIByChosenDay((int) id);
+ }
+ }
+
+ private interface UnitsConversor {
+
+ public double doConversion(final double value);
+ }
+
+ private void updateUI(final Forecast forecastWeatherData) {
+
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this.getActivity().getApplicationContext());
+
+ // TODO: repeating the same code in Overview, Specific and Current!!!
+ // 1. Update units of measurement.
+ String symbol;
+ UnitsConversor unitsConversor;
+ String keyPreference = this.getResources().getString(
+ R.string.weather_preferences_temperature_key);
+ final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ if (unitsPreferenceValue.equals(values[0])) {
+ symbol = values[0];
+ unitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value - 273.15;
+ }
+
+ };
+ } else if (unitsPreferenceValue.equals(values[1])) {
+ symbol = values[1];
+ unitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return (value * 1.8) - 459.67;
+ }
+
+ };
+ } else {
+ symbol = values[2];
+ unitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value;
+ }
+
+ };
+ }
+
+
+ // 2. Update number day forecast.
+ keyPreference = this.getResources().getString(R.string.weather_preferences_day_forecast_key);
+ final String dayForecast = sharedPreferences.getString(keyPreference, "5");
+ final int mDayForecast = Integer.valueOf(dayForecast);
+
+
+ // 3. Formatters
+ final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
+ tempFormatter.applyPattern("#####.##");
+ final SimpleDateFormat dayNameFormatter = new SimpleDateFormat("EEE", Locale.US);
+ final SimpleDateFormat monthAndDayNumberormatter = new SimpleDateFormat("MMM d", Locale.US);
+
+
+ // 4. Prepare data for UI.
+ final List<OverviewEntry> entries = new ArrayList<OverviewEntry>();
+ final OverviewAdapter adapter = new OverviewAdapter(this.getActivity(),
+ R.layout.weather_main_entry_list);
+ final Calendar calendar = Calendar.getInstance();
+ int count = mDayForecast;
+ for (final de.example.exampletdd.model.forecastweather.List forecast : forecastWeatherData
+ .getList()) {
+
+ Bitmap picture;
+
+ if ((forecast.getWeather().size() > 0) &&
+ (forecast.getWeather().get(0).getIcon() != null) &&
+ (IconsList.getIcon(forecast.getWeather().get(0).getIcon()) != null)) {
+ final String icon = forecast.getWeather().get(0).getIcon();
+ picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
+ .getResourceDrawable());
+ } else {
+ picture = BitmapFactory.decodeResource(this.getResources(),
+ R.drawable.weather_severe_alert);
+ }
+
+ final Long forecastUNIXDate = (Long) forecast.getDt();
+ calendar.setTimeInMillis(forecastUNIXDate * 1000L);
+ final Date dayTime = calendar.getTime();
+ final String dayTextName = dayNameFormatter.format(dayTime);
+ final String monthAndDayNumberText = monthAndDayNumberormatter.format(dayTime);
+
+ Double maxTemp = null;
+ if (forecast.getTemp().getMax() != null) {
+ maxTemp = (Double) forecast.getTemp().getMax();
+ maxTemp = unitsConversor.doConversion(maxTemp);
+ }
+
+ Double minTemp = null;
+ if (forecast.getTemp().getMin() != null) {
+ minTemp = (Double) forecast.getTemp().getMin();
+ minTemp = unitsConversor.doConversion(minTemp);
+ }
+
+ if ((maxTemp != null) && (minTemp != null)) {
+ entries.add(new OverviewEntry(dayTextName, monthAndDayNumberText,
+ tempFormatter.format(maxTemp) + symbol, tempFormatter.format(minTemp) + symbol,
+ picture));
+ }
+
+ count = count - 1;
+ if (count == 0) {
+ break;
+ }
+ }
+
+
+ // 5. Update UI.
+ adapter.addAll(entries);
+ this.setListAdapter(adapter);
+ }
+
+ private boolean isDataFresh(final Date lastUpdate) {
+ if (lastUpdate == null) {
+ return false;
+ }
+
+ final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
+ this.getActivity().getApplicationContext());
+ final String keyPreference = this.getString(R.string.weather_preferences_refresh_interval_key);
+ final String refresh = sharedPreferences.getString(
+ keyPreference,
+ this.getResources().getStringArray(R.array.weather_preferences_refresh_interval)[0]);
+ final Date currentTime = new Date();
+ if (((currentTime.getTime() - lastUpdate.getTime())) < Long.valueOf(refresh)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // TODO: How could I show just one progress dialog when I have two fragments in tabs
+ // activity doing the same in background?
+ // I mean, if OverviewTask shows one progress dialog and CurrentTask does the same I will have
+ // have two progress dialogs... How may I solve this problem? I HATE ANDROID.
+ private class OverviewTask extends AsyncTask<Object, Void, Forecast> {
+ // Store the context passed to the AsyncTask when the system instantiates it.
+ private final Context localContext;
+ private final CustomHTTPClient HTTPClient;
+ private final ServiceParser weatherService;
+
+ public OverviewTask(final Context context, final CustomHTTPClient HTTPClient,
+ final ServiceParser weatherService) {
+ this.localContext = context;
+ this.HTTPClient = HTTPClient;
+ this.weatherService = weatherService;
+ }
+
+ @Override
+ protected Forecast doInBackground(final Object... params) {
+ final double latitude = (Double) params[0];
+ final double longitude = (Double) params[1];
+
+ Forecast forecast = null;
+
+ try {
+ forecast = this.doInBackgroundThrowable(latitude, longitude);
+ } catch (final JsonParseException e) {
+ Log.e(TAG, "OverviewTask doInBackground exception: ", e);
+ } catch (final ClientProtocolException e) {
+ Log.e(TAG, "OverviewTask doInBackground exception: ", e);
+ } catch (final MalformedURLException e) {
+ Log.e(TAG, "OverviewTask doInBackground exception: ", e);
+ } catch (final URISyntaxException e) {
+ Log.e(TAG, "OverviewTask doInBackground exception: ", e);
+ } catch (final IOException e) {
+ // logger infrastructure swallows UnknownHostException :/
+ Log.e(TAG, "OverviewTask doInBackground exception: " + e.getMessage(), e);
+ } finally {
+ HTTPClient.close();
+ }
+
+ return forecast;
+ }
+
+ private Forecast doInBackgroundThrowable(final double latitude, final double longitude)
+ throws URISyntaxException, ClientProtocolException, JsonParseException, IOException {
+
+ final String APIVersion = localContext.getResources().getString(R.string.api_version);
+ final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_forecast);
+ // TODO: number as resource
+ final String url = weatherService.createURIAPIForecast(urlAPI, APIVersion, latitude, longitude, "14");
+ final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
+ final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
+
+ return weatherService.retrieveForecastFromJPOS(jsonData);
+ }
+
+ @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 :(
+
+ // Call updateUI on the UI thread.
+ final Intent forecastData = new Intent("de.example.exampletdd.UPDATEFORECAST");
+ forecastData.putExtra("forecast", forecast);
+ LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(forecastData);
+ }
+ }
+}
--- /dev/null
+package de.example.exampletdd.fragment.preferences;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.preference.SwitchPreference;
+import de.example.exampletdd.R;
+import de.example.exampletdd.NotificationIntentService;
+
+public class WeatherInformationPreferencesFragment extends PreferenceFragment
+ implements OnSharedPreferenceChangeListener {
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Load the preferences from an XML resource
+ this.addPreferencesFromResource(R.xml.weather_preferences);
+
+
+ // Temperature units
+ String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ String[] humanValues = this.getResources().getStringArray(R.array.weather_preferences_temperature_human_value);
+ String keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_temperature_key);
+ Preference connectionPref = this.findPreference(keyPreference);
+ String value = this.getPreferenceManager().getSharedPreferences()
+ .getString(keyPreference, "");
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ }
+ connectionPref.setSummary(humanValue);
+
+ // Wind
+ values = this.getResources().getStringArray(R.array.weather_preferences_wind);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_wind_human_value);
+ keyPreference = this.getString(R.string.weather_preferences_wind_key);
+ connectionPref = this.findPreference(keyPreference);
+ value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
+ humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ }
+ connectionPref.setSummary(humanValue);
+
+ // Pressure
+ values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_pressure_human_value);
+ keyPreference = this.getString(R.string.weather_preferences_pressure_key);
+ connectionPref = this.findPreference(keyPreference);
+ value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
+ humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ }
+ connectionPref.setSummary(humanValue);
+
+ // Forecast days number
+ values = this.getResources().getStringArray(R.array.weather_preferences_day_forecast);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_day_forecast_human_value);
+ keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_day_forecast_key);
+ connectionPref = this.findPreference(keyPreference);
+ value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
+ humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ }
+ connectionPref.setSummary(humanValue);
+
+ // Refresh interval
+ values = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval_human_value);
+ keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_refresh_interval_key);
+ connectionPref = this.findPreference(keyPreference);
+ value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
+ humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ } else if (value.equals(values[3])) {
+ humanValue = humanValues[3];
+ } else if (value.equals(values[4])) {
+ humanValue = humanValues[4];
+ } else if (value.equals(values[5])) {
+ humanValue = humanValues[5];
+ } else if (value.equals(values[6])) {
+ humanValue = humanValues[6];
+ }
+ connectionPref.setSummary(humanValue);
+
+ // Update Time Rate
+ values = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate_human_value);
+ keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_update_time_rate_key);
+ connectionPref = this.findPreference(keyPreference);
+ value = this.getPreferenceManager().getSharedPreferences()
+ .getString(keyPreference, "");
+ humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ } else if (value.equals(values[3])) {
+ humanValue = humanValues[3];
+ } else if (value.equals(values[4])) {
+ humanValue = humanValues[4];
+ }
+ connectionPref.setSummary(humanValue);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ this.getPreferenceManager().getSharedPreferences()
+ .registerOnSharedPreferenceChangeListener(this);
+
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ this.getPreferenceManager().getSharedPreferences()
+ .unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(
+ final SharedPreferences sharedPreferences, final String key) {
+
+ // Temperature units
+ String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ String[] humanValues = this.getResources().getStringArray(R.array.weather_preferences_temperature_human_value);
+ String keyValue = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_temperature_key);
+ if (key.equals(keyValue)) {
+ final Preference connectionPref = this.findPreference(key);
+ final String value = sharedPreferences.getString(key, "");
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ }
+
+ connectionPref.setSummary(humanValue);
+ return;
+ }
+
+ // Wind
+ values = this.getResources().getStringArray(R.array.weather_preferences_wind);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_wind_human_value);
+ keyValue = this.getString(R.string.weather_preferences_wind_key);
+ if (key.equals(keyValue)) {
+ final Preference connectionPref = this.findPreference(key);
+ final String value = sharedPreferences.getString(key, "");
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ }
+
+ connectionPref.setSummary(humanValue);
+ return;
+ }
+
+ // Pressure
+ values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_pressure_human_value);
+ keyValue = this.getString(R.string.weather_preferences_pressure_key);
+ if (key.equals(keyValue)) {
+ final Preference connectionPref = this.findPreference(key);
+ final String value = sharedPreferences.getString(key, "");
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ }
+
+ connectionPref.setSummary(humanValue);
+ return;
+ }
+
+ // Forecast days number
+ values = this.getResources().getStringArray(R.array.weather_preferences_day_forecast);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_day_forecast_human_value);
+ keyValue = this.getActivity().getString(
+ R.string.weather_preferences_day_forecast_key);
+ if (key.equals(keyValue)) {
+ final Preference connectionPref = this.findPreference(key);
+ final String value = sharedPreferences.getString(key, "");
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ }
+ connectionPref.setSummary(humanValue);
+ return;
+ }
+
+ // Refresh interval
+ values = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval_human_value);
+ keyValue = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_refresh_interval_key);
+ if (key.equals(keyValue)) {
+ final Preference connectionPref = this.findPreference(key);
+ final String value = sharedPreferences.getString(key, "");
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ } else if (value.equals(values[3])) {
+ humanValue = humanValues[3];
+ } else if (value.equals(values[4])) {
+ humanValue = humanValues[4];
+ } else if (value.equals(values[5])) {
+ humanValue = humanValues[5];
+ } else if (value.equals(values[6])) {
+ humanValue = humanValues[6];
+ }
+ connectionPref.setSummary(humanValue);
+ return;
+ }
+
+ // Notification switch
+ keyValue = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_notifications_switch_key);
+ if (key.equals(keyValue)) {
+ final SwitchPreference preference = (SwitchPreference)this.findPreference(key);
+ if (preference.isChecked())
+ {
+ keyValue = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_update_time_rate_key);
+ final String value = sharedPreferences.getString(keyValue, "");
+ this.updateNotification(value);
+ } else {
+ this.cancelNotification();
+ }
+ }
+ // Update Time Rate
+ values = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate);
+ humanValues = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate_human_value);
+ keyValue = this.getActivity().getApplicationContext().getString(
+ R.string.weather_preferences_update_time_rate_key);
+ if (key.equals(keyValue)) {
+ final Preference connectionPref = this.findPreference(key);
+ final String value = sharedPreferences.getString(key, "");
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ } else if (value.equals(values[3])) {
+ humanValue = humanValues[3];
+ } else if (value.equals(values[4])) {
+ humanValue = humanValues[4];
+ }
+
+ this.updateNotification(value);
+ connectionPref.setSummary(humanValue);
+ return;
+ }
+ }
+
+ private void updateNotification(final String updateTimeRate) {
+ final String[] values = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate);
+ long chosenInterval = 0;
+ if (updateTimeRate.equals(values[0])) {
+ chosenInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
+ } else if (updateTimeRate.equals(values[1])) {
+ chosenInterval = AlarmManager.INTERVAL_HALF_HOUR;
+ } else if (updateTimeRate.equals(values[2])) {
+ chosenInterval = AlarmManager.INTERVAL_HOUR;
+ } else if (updateTimeRate.equals(values[3])) {
+ chosenInterval = AlarmManager.INTERVAL_HALF_DAY;
+ } else if (updateTimeRate.equals(values[4])) {
+ chosenInterval = AlarmManager.INTERVAL_DAY;
+ }
+
+ final AlarmManager alarmMgr =
+ (AlarmManager) this.getActivity().getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ // TODO: better use some string instead of .class? In case I change the service class
+ // this could be a problem (I guess)
+ final Intent serviceIntent =
+ new Intent(this.getActivity().getApplicationContext(), NotificationIntentService.class);
+ final PendingIntent alarmIntent =
+ PendingIntent.getService(
+ this.getActivity().getApplicationContext(),
+ 0,
+ serviceIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ if (chosenInterval != 0) {
+ alarmMgr.setInexactRepeating(
+ AlarmManager.ELAPSED_REALTIME,
+ SystemClock.elapsedRealtime(),
+ chosenInterval,
+ alarmIntent);
+ }
+ }
+
+ private void cancelNotification() {
+ final AlarmManager alarmMgr =
+ (AlarmManager) this.getActivity().getApplicationContext().getSystemService(Context.ALARM_SERVICE);
+ final Intent serviceIntent =
+ new Intent(this.getActivity().getApplicationContext(), NotificationIntentService.class);
+ final PendingIntent alarmIntent =
+ PendingIntent.getService(
+ this.getActivity().getApplicationContext(),
+ 0,
+ serviceIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ alarmMgr.cancel(alarmIntent);
+ }
+}
--- /dev/null
+package de.example.exampletdd.fragment.specific;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.example.exampletdd.R;
+import de.example.exampletdd.model.forecastweather.Forecast;
+import de.example.exampletdd.service.IconsList;
+import de.example.exampletdd.service.PermanentStorage;
+
+
+public class SpecificFragment extends Fragment {
+ private int mChosenDay;
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Bundle extras = this.getActivity().getIntent().getExtras();
+
+ if (extras != null) {
+ // handset layout
+ this.mChosenDay = extras.getInt("CHOSEN_DAY", 0);
+ } else {
+ // tablet layout
+ // Always 0 when tablet layout (by default shows the first day)
+ this.mChosenDay = 0;
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.weather_specific_fragment, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(final Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ // Restore UI state
+ final Forecast forecast = (Forecast) savedInstanceState.getSerializable("Forecast");
+
+ // TODO: Could it be better to store in global data forecast even if it is null value?
+ // So, perhaps do not check for null value and always store in global variable.
+ if (forecast != null) {
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ store.saveForecast(forecast);
+ }
+
+ this.mChosenDay = savedInstanceState.getInt("mChosenDay");
+ }
+
+ this.setHasOptionsMenu(false);
+ }
+
+ @Override
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
+
+ // Save UI state
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ final Forecast forecast = store.getForecast();
+
+ // TODO: Could it be better to save forecast data even if it is null value?
+ // So, perhaps do not check for null value.
+ if (forecast != null) {
+ savedInstanceState.putSerializable("Forecast", forecast);
+ }
+
+ savedInstanceState.putInt("mChosenDay", this.mChosenDay);
+
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ /**
+ * This method is used by tablet layout.
+ *
+ * @param chosenDay
+ */
+ public void updateUIByChosenDay(final int chosenDay) {
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ final Forecast forecast = store.getForecast();
+
+ if (forecast != null) {
+ this.updateUI(forecast, chosenDay);
+ }
+ }
+
+ private interface UnitsConversor {
+
+ public double doConversion(final double value);
+ }
+
+ private void updateUI(final Forecast forecastWeatherData, final int chosenDay) {
+
+ final SharedPreferences sharedPreferences = PreferenceManager
+ .getDefaultSharedPreferences(this.getActivity());
+
+ // TODO: repeating the same code in Overview, Specific and Current!!!
+ // 1. Update units of measurement.
+ // 1.1 Temperature
+ String tempSymbol;
+ UnitsConversor tempUnitsConversor;
+ String keyPreference = this.getResources().getString(
+ R.string.weather_preferences_temperature_key);
+ String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ if (unitsPreferenceValue.equals(values[0])) {
+ tempSymbol = values[0];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value - 273.15;
+ }
+
+ };
+ } else if (unitsPreferenceValue.equals(values[1])) {
+ tempSymbol = values[1];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return (value * 1.8) - 459.67;
+ }
+
+ };
+ } else {
+ tempSymbol = values[2];
+ tempUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(final double value) {
+ return value;
+ }
+
+ };
+ }
+
+ // 1.2 Wind
+ String windSymbol;
+ UnitsConversor windUnitsConversor;
+ keyPreference = this.getResources().getString(R.string.weather_preferences_wind_key);
+ unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ values = this.getResources().getStringArray(R.array.weather_preferences_wind);
+ if (unitsPreferenceValue.equals(values[0])) {
+ windSymbol = values[0];
+ windUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value;
+ }
+ };
+ } else {
+ windSymbol = values[1];
+ windUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value * 2.237;
+ }
+ };
+ }
+
+ // 1.3 Pressure
+ String pressureSymbol;
+ UnitsConversor pressureUnitsConversor;
+ keyPreference = this.getResources().getString(R.string.weather_preferences_pressure_key);
+ unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
+ values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
+ if (unitsPreferenceValue.equals(values[0])) {
+ pressureSymbol = values[0];
+ pressureUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value;
+ }
+ };
+ } else {
+ pressureSymbol = values[1];
+ pressureUnitsConversor = new UnitsConversor(){
+
+ @Override
+ public double doConversion(double value) {
+ return value / 113.25d;
+ }
+ };
+ }
+
+
+ // 2. Formatters
+ final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
+ tempFormatter.applyPattern("#####.#####");
+
+
+ // 3. Prepare data for UI.
+ final de.example.exampletdd.model.forecastweather.List forecast = forecastWeatherData
+ .getList().get((chosenDay));
+
+ final SimpleDateFormat dayFormatter = new SimpleDateFormat("EEEE - MMM d", Locale.US);
+ final Calendar calendar = Calendar.getInstance();
+ final Long forecastUNIXDate = (Long) forecast.getDt();
+ calendar.setTimeInMillis(forecastUNIXDate * 1000L);
+ final Date date = calendar.getTime();
+
+ String tempMax = "";
+ if (forecast.getTemp().getMax() != null) {
+ double conversion = (Double) forecast.getTemp().getMax();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMax = tempFormatter.format(conversion) + tempSymbol;
+ }
+ String tempMin = "";
+ if (forecast.getTemp().getMin() != null) {
+ double conversion = (Double) forecast.getTemp().getMin();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMin = tempFormatter.format(conversion) + tempSymbol;
+ }
+ Bitmap picture;
+ if ((forecast.getWeather().size() > 0) && (forecast.getWeather().get(0).getIcon() != null)
+ && (IconsList.getIcon(forecast.getWeather().get(0).getIcon()) != null)) {
+ final String icon = forecast.getWeather().get(0).getIcon();
+ picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
+ .getResourceDrawable());
+ } else {
+ picture = BitmapFactory.decodeResource(this.getResources(),
+ R.drawable.weather_severe_alert);
+ }
+
+ // TODO: string resource
+ String description = "no description available";
+ if (forecast.getWeather().size() > 0) {
+ description = forecast.getWeather().get(0).getDescription();
+ }
+
+ // TODO: units!!!!
+ String humidityValue = "";
+ if (forecast.getHumidity() != null) {
+ final double conversion = (Double) forecast.getHumidity();
+ humidityValue = tempFormatter.format(conversion);
+ }
+ String pressureValue = "";
+ if (forecast.getPressure() != null) {
+ double conversion = (Double) forecast.getPressure();
+ conversion = pressureUnitsConversor.doConversion(conversion);
+ pressureValue = tempFormatter.format(conversion);
+ }
+ String windValue = "";
+ if (forecast.getSpeed() != null) {
+ double conversion = (Double) forecast.getSpeed();
+ conversion = windUnitsConversor.doConversion(conversion);
+ windValue = tempFormatter.format(conversion);
+ }
+ String rainValue = "";
+ if (forecast.getRain() != null) {
+ final double conversion = (Double) forecast.getRain();
+ rainValue = tempFormatter.format(conversion);
+ }
+ String cloudsValue = "";
+ if (forecast.getRain() != null) {
+ final double conversion = (Double) forecast.getClouds();
+ cloudsValue = tempFormatter.format(conversion);
+ }
+
+ String tempDay = "";
+ if (forecast.getTemp().getDay() != null) {
+ double conversion = (Double) forecast.getTemp().getDay();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempDay = tempFormatter.format(conversion) + tempSymbol;
+ }
+ String tempMorn = "";
+ if (forecast.getTemp().getMorn() != null) {
+ double conversion = (Double) forecast.getTemp().getMorn();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempMorn = tempFormatter.format(conversion) + tempSymbol;
+ }
+ String tempEve = "";
+ if (forecast.getTemp().getEve() != null) {
+ double conversion = (Double) forecast.getTemp().getEve();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempEve = tempFormatter.format(conversion) + tempSymbol;
+ }
+ String tempNight = "";
+ if (forecast.getTemp().getNight() != null) {
+ double conversion = (Double) forecast.getTemp().getNight();
+ conversion = tempUnitsConversor.doConversion(conversion);
+ tempNight = tempFormatter.format(conversion) + tempSymbol;
+ }
+
+
+ // 4. Update UI.
+ this.getActivity().getActionBar().setSubtitle(dayFormatter.format(date).toUpperCase());
+
+ final TextView tempMaxView = (TextView) getActivity().findViewById(R.id.weather_specific_temp_max);
+ tempMaxView.setText(tempMax);
+ final TextView tempMinView = (TextView) getActivity().findViewById(R.id.weather_specific_temp_min);
+ tempMinView.setText(tempMin);
+ final ImageView pictureView = (ImageView) getActivity().findViewById(R.id.weather_specific_picture);
+ pictureView.setImageBitmap(picture);
+
+ final TextView descriptionView = (TextView) getActivity().findViewById(R.id.weather_specific_description);
+ descriptionView.setText(description);
+
+ final TextView humidityValueView = (TextView) getActivity().findViewById(R.id.weather_specific_humidity_value);
+ humidityValueView.setText(humidityValue);
+ ((TextView) getActivity().findViewById(R.id.weather_specific_pressure_value)).setText(pressureValue);
+ ((TextView) getActivity().findViewById(R.id.weather_specific_pressure_units)).setText(pressureSymbol);
+ ((TextView) getActivity().findViewById(R.id.weather_specific_wind_value)).setText(windValue);;
+ ((TextView) getActivity().findViewById(R.id.weather_specific_wind_units)).setText(windSymbol);
+ final TextView rainValueView = (TextView) getActivity().findViewById(R.id.weather_specific_rain_value);
+ rainValueView.setText(rainValue);
+ final TextView cloudsValueView = (TextView) getActivity().findViewById(R.id.weather_specific_clouds_value);
+ cloudsValueView.setText(cloudsValue);
+
+ final TextView tempDayView = (TextView) getActivity().findViewById(R.id.weather_specific_day_temperature);
+ tempDayView.setText(tempDay);
+ final TextView tempMornView = (TextView) getActivity().findViewById(R.id.weather_specific_morn_temperature);
+ tempMornView.setText(tempMorn);
+ final TextView tempEveView = (TextView) getActivity().findViewById(R.id.weather_specific_eve_temperature);
+ tempEveView.setText(tempEve);
+ final TextView tempNightView = (TextView) getActivity().findViewById(R.id.weather_specific_night_temperature);
+ tempNightView.setText(tempNight);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
+ final Forecast forecast = store.getForecast();
+
+ if (forecast != null) {
+ this.updateUI(forecast, this.mChosenDay);
+ }
+
+ // TODO: Overview is doing things with mListState... Why not here?
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package de.example.exampletdd.httpclient;
+
+import java.nio.charset.Charset;
+
+/**
+ * Commons constants.
+ *
+ * @since 4.2
+ */
+public final class Consts {
+
+ public static final int CR = 13; // <US-ASCII CR, carriage return (13)>
+ public static final int LF = 10; // <US-ASCII LF, linefeed (10)>
+ public static final int SP = 32; // <US-ASCII SP, space (32)>
+ public static final int HT = 9; // <US-ASCII HT, horizontal-tab (9)>
+
+ public static final Charset UTF_8 = Charset.forName("UTF-8");
+ public static final Charset ASCII = Charset.forName("US-ASCII");
+ public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+
+ private Consts() {
+ }
+
+}
--- /dev/null
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package de.example.exampletdd.httpclient;
+
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Locale;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.ParseException;
+import org.apache.http.message.BasicHeaderValueParser;
+
+/**
+ * Content type information consisting of a MIME type and an optional charset.
+ * <p/>
+ * This class makes no attempts to verify validity of the MIME type.
+ * The input parameters of the {@link #create(String, String)} method, however, may not
+ * contain characters <">, <;>, <,> reserved by the HTTP specification.
+ *
+ * @since 4.2
+ */
+
+public final class ContentType {
+
+ // constants
+ public static final ContentType APPLICATION_ATOM_XML = create(
+ "application/atom+xml", Consts.ISO_8859_1);
+ public static final ContentType APPLICATION_FORM_URLENCODED = create(
+ "application/x-www-form-urlencoded", Consts.ISO_8859_1);
+ public static final ContentType APPLICATION_JSON = create(
+ "application/json", Consts.UTF_8);
+ public static final ContentType APPLICATION_OCTET_STREAM = create(
+ "application/octet-stream", (Charset) null);
+ public static final ContentType APPLICATION_SVG_XML = create(
+ "application/svg+xml", Consts.ISO_8859_1);
+ public static final ContentType APPLICATION_XHTML_XML = create(
+ "application/xhtml+xml", Consts.ISO_8859_1);
+ public static final ContentType APPLICATION_XML = create(
+ "application/xml", Consts.ISO_8859_1);
+ public static final ContentType MULTIPART_FORM_DATA = create(
+ "multipart/form-data", Consts.ISO_8859_1);
+ public static final ContentType TEXT_HTML = create(
+ "text/html", Consts.ISO_8859_1);
+ public static final ContentType TEXT_PLAIN = create(
+ "text/plain", Consts.ISO_8859_1);
+ public static final ContentType TEXT_XML = create(
+ "text/xml", Consts.ISO_8859_1);
+ public static final ContentType WILDCARD = create(
+ "*/*", (Charset) null);
+
+ // defaults
+ public static final ContentType DEFAULT_TEXT = TEXT_PLAIN;
+ public static final ContentType DEFAULT_BINARY = APPLICATION_OCTET_STREAM;
+
+ private final String mimeType;
+ private final Charset charset;
+
+ /**
+ * Given a MIME type and a character set, constructs a ContentType.
+ * @param mimeType The MIME type to use for the ContentType header.
+ * @param charset The optional character set to use with the ContentType header.
+ * @throws UnsupportedCharsetException
+ * If no support for the named charset is available in this Java virtual machine
+ */
+ ContentType(final String mimeType, final Charset charset) {
+ this.mimeType = mimeType;
+ this.charset = charset;
+ }
+
+ public String getMimeType() {
+ return this.mimeType;
+ }
+
+ public Charset getCharset() {
+ return this.charset;
+ }
+
+ /**
+ * Converts a ContentType to a string which can be used as a ContentType header.
+ * If a charset is provided by the ContentType, it will be included in the string.
+ */
+ @Override
+ public String toString() {
+ final StringBuilder buf = new StringBuilder();
+ buf.append(this.mimeType);
+ if (this.charset != null) {
+ buf.append("; charset=");
+ buf.append(this.charset);
+ }
+ return buf.toString();
+ }
+
+ private static boolean valid(final String s) {
+ for (int i = 0; i < s.length(); i++) {
+ final char ch = s.charAt(i);
+ if ((ch == '"') || (ch == ',') || (ch == ';')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Creates a new instance of {@link ContentType}.
+ *
+ * @param mimeType MIME type. It may not be <code>null</code> or empty. It may not contain
+ * characters <">, <;>, <,> reserved by the HTTP specification.
+ * @param charset charset.
+ * @return content type
+ */
+ public static ContentType create(final String mimeType, final Charset charset) {
+ if (mimeType == null) {
+ throw new IllegalArgumentException("MIME type may not be null");
+ }
+ final String type = mimeType.trim().toLowerCase(Locale.US);
+ if (type.length() == 0) {
+ throw new IllegalArgumentException("MIME type may not be empty");
+ }
+ if (!valid(type)) {
+ throw new IllegalArgumentException("MIME type may not contain reserved characters");
+ }
+ return new ContentType(type, charset);
+ }
+
+ /**
+ * Creates a new instance of {@link ContentType} without a charset.
+ *
+ * @param mimeType MIME type. It may not be <code>null</code> or empty. It may not contain
+ * characters <">, <;>, <,> reserved by the HTTP specification.
+ * @return content type
+ */
+ public static ContentType create(final String mimeType) {
+ return new ContentType(mimeType, (Charset) null);
+ }
+
+ /**
+ * Creates a new instance of {@link ContentType}.
+ *
+ * @param mimeType MIME type. It may not be <code>null</code> or empty. It may not contain
+ * characters <">, <;>, <,> reserved by the HTTP specification.
+ * @param charset charset. It may not contain characters <">, <;>, <,> reserved by the HTTP
+ * specification. This parameter is optional.
+ * @return content type
+ */
+ public static ContentType create(
+ final String mimeType, final String charset) throws UnsupportedCharsetException {
+ return create(mimeType, charset != null ? Charset.forName(charset) : null);
+ }
+
+ private static ContentType create(final HeaderElement helem) {
+ final String mimeType = helem.getName();
+ String charset = null;
+ final NameValuePair param = helem.getParameterByName("charset");
+ if (param != null) {
+ charset = param.getValue();
+ }
+ return create(mimeType, charset);
+ }
+
+ /**
+ * Parses textual representation of <code>Content-Type</code> value.
+ *
+ * @param s text
+ * @return content type
+ * @throws ParseException if the given text does not represent a valid
+ * <code>Content-Type</code> value.
+ */
+ public static ContentType parse(
+ final String s) throws ParseException, UnsupportedCharsetException {
+ if (s == null) {
+ throw new IllegalArgumentException("Content type may not be null");
+ }
+ final HeaderElement[] elements = BasicHeaderValueParser.parseElements(s, null);
+ if (elements.length > 0) {
+ return create(elements[0]);
+ } else {
+ throw new ParseException("Invalid content type: " + s);
+ }
+ }
+
+ /**
+ * Extracts <code>Content-Type</code> value from {@link HttpEntity} exactly as
+ * specified by the <code>Content-Type</code> header of the entity. Returns <code>null</code>
+ * if not specified.
+ *
+ * @param entity HTTP entity
+ * @return content type
+ * @throws ParseException if the given text does not represent a valid
+ * <code>Content-Type</code> value.
+ */
+ public static ContentType get(
+ final HttpEntity entity) throws ParseException, UnsupportedCharsetException {
+ if (entity == null) {
+ return null;
+ }
+ final Header header = entity.getContentType();
+ if (header != null) {
+ final HeaderElement[] elements = header.getElements();
+ if (elements.length > 0) {
+ return create(elements[0]);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Extracts <code>Content-Type</code> value from {@link HttpEntity} or returns default value
+ * if not explicitly specified.
+ *
+ * @param entity HTTP entity
+ * @return content type
+ * @throws ParseException if the given text does not represent a valid
+ * <code>Content-Type</code> value.
+ */
+ public static ContentType getOrDefault(final HttpEntity entity) throws ParseException {
+ final ContentType contentType = get(entity);
+ return contentType != null ? contentType : DEFAULT_TEXT;
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.httpclient;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
+
+import android.net.http.AndroidHttpClient;
+
+public class CustomHTTPClient {
+ private final AndroidHttpClient httpClient;
+
+ public CustomHTTPClient(final AndroidHttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
+
+ public String retrieveDataAsString(final URL url)
+ throws URISyntaxException, ClientProtocolException, IOException {
+
+ final ResponseHandler<String> handler = new ResponseHandler<String>() {
+ @Override
+ public String handleResponse(
+ final HttpResponse response)
+ throws UnsupportedEncodingException, IOException {
+
+ if (response != null) {
+ final HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ try {
+ final ContentType contentType = ContentType.getOrDefault(entity);
+ final ByteArrayOutputStream buffer = CustomHTTPClient.this
+ .sortResponse(response);
+ return new String(buffer.toByteArray(), contentType.getCharset());
+ } finally {
+ entity.consumeContent();
+ }
+ }
+
+ throw new IOException("There is no entity");
+ }
+
+ throw new IOException("There is no response");
+ }
+ };
+
+ final HttpGet httpGet = new HttpGet();
+ httpGet.setURI(url.toURI());
+
+ return this.httpClient.execute(httpGet, handler);
+ }
+
+ public ByteArrayOutputStream retrieveRawData(final URL url)
+ throws URISyntaxException, ClientProtocolException, IOException {
+ final ResponseHandler<ByteArrayOutputStream> handler = new ResponseHandler<ByteArrayOutputStream>() {
+
+ @Override
+ public ByteArrayOutputStream handleResponse(
+ final HttpResponse response)
+ throws UnsupportedEncodingException, IOException {
+
+ if (response != null) {
+ final HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ try {
+ return CustomHTTPClient.this.sortResponse(response);
+ } finally {
+ entity.consumeContent();
+ }
+ }
+
+ throw new IOException("There is no entity");
+ }
+
+ throw new IOException("There is no response");
+ }
+ };
+
+ final HttpGet httpGet = new HttpGet();
+ httpGet.setURI(url.toURI());
+
+ return this.httpClient.execute(httpGet, handler);
+ }
+
+ public void close() {
+ this.httpClient.close();
+ }
+
+ private ByteArrayOutputStream sortResponse(final HttpResponse httpResponse) throws IOException {
+
+ if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ throw new IOException("Unexpected response code: "
+ + httpResponse.getStatusLine().getStatusCode());
+ }
+
+ final HttpEntity entity = httpResponse.getEntity();
+ final InputStream inputStream = entity.getContent();
+ try {
+ return this.readInputStream(inputStream);
+ } finally {
+ inputStream.close();
+ }
+
+ }
+
+ private ByteArrayOutputStream readInputStream (final InputStream inputStream) throws IOException {
+ final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
+ final int bufferSize = 1024;
+ final byte[] buffer = new byte[bufferSize];
+
+ int len = 0;
+ while ((len = inputStream.read(buffer)) != -1) {
+ byteBuffer.write(buffer, 0, len);
+ }
+
+ return byteBuffer;
+ }
+}
--- /dev/null
+package de.example.exampletdd.model;
+
+import android.content.Context;
+
+public class DatabaseQueries {
+ private final Context localContext;
+
+ public DatabaseQueries(final Context context) {
+ this.localContext = context;
+ }
+
+ public WeatherLocation queryDataBase() {
+
+ final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this.localContext);
+ try {
+ final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper);
+ return queryDb.queryDataBase();
+ } finally {
+ dbHelper.close();
+ }
+ }
+
+ public long insertIntoDataBase(final WeatherLocation weatherLocation) {
+
+ final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this.localContext);
+ try {
+ final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper);
+ return queryDb.insertIntoDataBase(weatherLocation);
+ } finally {
+ dbHelper.close();
+ }
+ }
+
+ public void updateDataBase(final WeatherLocation weatherLocation) {
+
+ final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this.localContext);
+ try {
+ final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper);
+ queryDb.updateDataBase(weatherLocation);
+ } finally {
+ dbHelper.close();
+ }
+ }
+}
--- /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 = -1469725417020355109L;
+ private int id;
+ private String city;
+ private String country;
+ private boolean isSelected;
+ private double latitude;
+ private double longitude;
+ private Date lastCurrentUIUpdate;
+ private Date lastForecastUIUpdate;
+
+ public WeatherLocation setId(int id) {
+ this.id = id;
+ return this;
+ }
+
+ public WeatherLocation setCity(String city) {
+ this.city = city;
+ return this;
+ }
+
+ public WeatherLocation setCountry(String country) {
+ this.country = country;
+ return this;
+ }
+
+ public WeatherLocation setIsSelected(boolean isSelected) {
+ this.isSelected = isSelected;
+ return this;
+ }
+
+ public WeatherLocation setLatitude(double latitude) {
+ this.latitude = latitude;
+ return this;
+ }
+
+ public WeatherLocation setLongitude(double longitude) {
+ this.longitude = longitude;
+ return this;
+ }
+
+ public WeatherLocation setLastCurrentUIUpdate(Date lastCurrentUIUpdate) {
+ this.lastCurrentUIUpdate = lastCurrentUIUpdate;
+ return this;
+ }
+
+ public WeatherLocation setLastForecastUIUpdate(Date lastForecastUIUpdate) {
+ this.lastForecastUIUpdate = lastForecastUIUpdate;
+ return this;
+ }
+
+ public int getId() {
+ return this.id;
+ }
+
+ public String getCity() {
+ return this.city;
+ }
+
+ public String getCountry() {
+ return this.country;
+ }
+
+ public boolean getIsSelected() {
+ return this.isSelected;
+ }
+
+ 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 java.util.Calendar;
+import java.util.Date;
+
+import android.content.ContentValues;
+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;
+ }
+
+ public 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 WeatherLocationDbQueries.DoQuery doQuery = new WeatherLocationDbQueries.DoQuery() {
+
+ @Override
+ public WeatherLocation doQuery(final Cursor cursor) {
+ final int id = cursor.getInt(cursor.getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation._ID));
+ final String city = cursor.getString(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY));
+ final String country = cursor.getString(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY));
+ final boolean isSelected = (cursor.getInt(cursor
+ .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED)) == 0) ? false : true;
+ Date lastCurrentUIUpdate = null;
+ if (!cursor.isNull(cursor
+ .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE))) {
+ final long javaTime = cursor.getLong(cursor
+ .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE));
+ lastCurrentUIUpdate = new Date(javaTime);
+ }
+ Date lasForecastUIUpdate = null;
+ if (!cursor.isNull(cursor
+ .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE))) {
+ final long javaTime = cursor.getLong(cursor
+ .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE));
+ lasForecastUIUpdate = new Date(javaTime);
+ }
+ final double latitude = cursor.getDouble(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE));
+ final double longitude = cursor.getDouble(cursor.
+ getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE));
+
+
+ return new WeatherLocation()
+ .setId(id)
+ .setCity(city)
+ .setCountry(country)
+ .setIsSelected(isSelected)
+ .setLastCurrentUIUpdate(lastCurrentUIUpdate)
+ .setLastForecastUIUpdate(lasForecastUIUpdate)
+ .setLatitude(latitude)
+ .setLongitude(longitude);
+ }
+ };
+
+ return this.queryDataBase(
+ WeatherLocationContract.WeatherLocation.TABLE_NAME, projection,
+ selectionArgs, selection, doQuery);
+ }
+
+ public long insertIntoDataBase(final WeatherLocation weatherLocation) {
+ // Create a new map of values, where column names are the keys
+ final ContentValues values = new ContentValues();
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY, weatherLocation.getCity());
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY, weatherLocation.getCountry());
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED, weatherLocation.getIsSelected());
+ Date javaTime = weatherLocation.getLastCurrentUIUpdate();
+ if (javaTime != null) {
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE, javaTime.getTime());
+ }
+ javaTime = weatherLocation.getLastForecastUIUpdate();
+ if (javaTime != null) {
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE, javaTime.getTime());
+ }
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE, weatherLocation.getLatitude());
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE, weatherLocation.getLongitude());
+
+ return this.insertIntoDataBase(WeatherLocationContract.WeatherLocation.TABLE_NAME, values);
+ }
+
+ public void updateDataBase(final WeatherLocation weatherLocation) {
+ final String selection = WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED + " = ?";
+ final String[] selectionArgs = { "1" };
+ // Create a new map of values, where column names are the keys
+ final ContentValues values = new ContentValues();
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY, weatherLocation.getCity());
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY, weatherLocation.getCountry());
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED, weatherLocation.getIsSelected());
+ Date javaTime = weatherLocation.getLastCurrentUIUpdate();
+ if (javaTime != null) {
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE, javaTime.getTime());
+ } else {
+ values.putNull(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE);
+ }
+ javaTime = weatherLocation.getLastForecastUIUpdate();
+ if (javaTime != null) {
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE, javaTime.getTime());
+ } else {
+ values.putNull(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE);
+ }
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE, weatherLocation.getLatitude());
+ values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE, weatherLocation.getLongitude());
+
+ this.updateDataBase(WeatherLocationContract.WeatherLocation.TABLE_NAME, selectionArgs, selection, values);
+ }
+
+ // TODO: May I perform another query after this method (after closing almost everything but mDbHelper)
+ private WeatherLocation queryDataBase(final 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();
+ }
+ }
+
+ // TODO: May I perform another query after this method (after closing almost everything but mDbHelper)
+ private long insertIntoDataBase(final String table, final ContentValues values) {
+ final SQLiteDatabase db = this.mDbHelper.getWritableDatabase();
+ try {
+ return db.insert(table, null, values);
+ } finally {
+ db.close();
+ }
+ }
+
+ // TODO: May I perform another query after this method (after closing almost everything but mDbHelper)
+ private long updateDataBase(final String table, final String[] selectionArgs,
+ final String selection, final ContentValues values) {
+ final SQLiteDatabase db = this.mDbHelper.getWritableDatabase();
+ try {
+ return db.update(table, values, selection, selectionArgs);
+ } finally {
+ db.close();
+ }
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+public class Clouds implements Serializable {
+ private static final long serialVersionUID = 3034435739326030899L;
+ private Number all;
+
+ public Number getAll(){
+ return this.all;
+ }
+ public void setAll(final Number all){
+ this.all = all;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Clouds [all=").append(this.all).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+public class Coord implements Serializable {
+ private static final long serialVersionUID = 7151637605146377486L;
+ private Number lat;
+ private Number lon;
+
+ public Number getLat(){
+ return this.lat;
+ }
+ public void setLat(final Number lat){
+ this.lat = lat;
+ }
+ public Number getLon(){
+ return this.lon;
+ }
+ public void setLon(final Number lon){
+ this.lon = lon;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Coord [lat=").append(this.lat).append(", lon=").append(this.lon)
+ .append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Auto generated by: http://jsongen.byingtondesign.com/
+ * (with my own modifications)
+ *
+ */
+public class Current implements Serializable {
+ private static final long serialVersionUID = -730690341739860818L;
+ private String base;
+ private Clouds clouds;
+ private Number cod;
+ private Coord coord;
+ private Number dt;
+ private Number id;
+ private Main main;
+ private String name;
+ private Rain rain;
+ private Snow snow;
+ private Sys sys;
+ private List<Weather> weather;
+ private Wind wind;
+ private byte[] iconData;
+ private Date date;
+
+ public String getBase(){
+ return this.base;
+ }
+ public void setBase(final String base){
+ this.base = base;
+ }
+ public Clouds getClouds(){
+ return this.clouds;
+ }
+ public void setClouds(final Clouds clouds){
+ this.clouds = clouds;
+ }
+
+ public Number getCod() {
+ return this.cod;
+ }
+
+ public void setCod(final Number cod) {
+ this.cod = cod;
+ }
+ public Coord getCoord(){
+ return this.coord;
+ }
+ public void setCoord(final Coord coord){
+ this.coord = coord;
+ }
+ public Number getDt(){
+ return this.dt;
+ }
+ public void setDt(final Number dt){
+ this.dt = dt;
+ }
+ public Number getId(){
+ return this.id;
+ }
+ public void setId(final Number id){
+ this.id = id;
+ }
+ public Main getMain(){
+ return this.main;
+ }
+ public void setMain(final Main main){
+ this.main = main;
+ }
+ public String getName(){
+ return this.name;
+ }
+ public void setName(final String name){
+ this.name = name;
+ }
+ public Rain getRain(){
+ return this.rain;
+ }
+ public void setRain(final Rain rain){
+ this.rain = rain;
+ }
+ public Snow getSnow() {
+ return this.snow;
+ }
+ public void setSnow(final Snow snow) {
+ this.snow = snow;
+ }
+ public Sys getSys(){
+ return this.sys;
+ }
+ public void setSys(final Sys sys){
+ this.sys = sys;
+ }
+ public List<Weather> getWeather(){
+ return this.weather;
+ }
+ public void setWeather(final List<Weather> weather){
+ this.weather = weather;
+ }
+ public Wind getWind(){
+ return this.wind;
+ }
+ public void setWind(final Wind wind){
+ this.wind = wind;
+ }
+
+ public byte[] getIconData() {
+ return this.iconData;
+ }
+
+ public void setIconData(final byte[] iconData) {
+ this.iconData = iconData;
+ }
+
+ public Date getDate() {
+ return this.date;
+ }
+
+ public void setDate(final Date date) {
+ this.date = date;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Current [base=").append(this.base).append(", clouds=")
+ .append(this.clouds).append(", cod=").append(this.cod).append(", coord=")
+ .append(this.coord).append(", dt=").append(this.dt).append(", id=").append(this.id)
+ .append(", main=").append(this.main).append(", name=").append(this.name)
+ .append(", rain=").append(this.rain).append(", snow=").append(this.snow)
+ .append(", sys=").append(this.sys).append(", weather=").append(this.weather)
+ .append(", wind=").append(this.wind).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+public class Main implements Serializable {
+ private static final long serialVersionUID = -6000879164436289447L;
+ private Number grnd_level;
+ private Number humidity;
+ private Number pressure;
+ private Number sea_level;
+ private Number temp;
+ private Number temp_max;
+ private Number temp_min;
+
+ public Number getGrnd_level() {
+ return this.grnd_level;
+ }
+
+ public void setGrnd_level(final Number grnd_level) {
+ this.grnd_level = grnd_level;
+ }
+
+ public Number getHumidity(){
+ return this.humidity;
+ }
+ public void setHumidity(final Number humidity){
+ this.humidity = humidity;
+ }
+ public Number getPressure(){
+ return this.pressure;
+ }
+ public void setPressure(final Number pressure){
+ this.pressure = pressure;
+ }
+
+ public Number getSea_level() {
+ return this.sea_level;
+ }
+
+ public void setSea_level(final Number sea_level) {
+ this.sea_level = sea_level;
+ }
+
+ public Number getTemp(){
+ return this.temp;
+ }
+ public void setTemp(final Number temp){
+ this.temp = temp;
+ }
+ public Number getTemp_max(){
+ return this.temp_max;
+ }
+ public void setTemp_max(final Number temp_max){
+ this.temp_max = temp_max;
+ }
+ public Number getTemp_min(){
+ return this.temp_min;
+ }
+ public void setTemp_min(final Number temp_min){
+ this.temp_min = temp_min;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Main [grnd_level=").append(this.grnd_level).append(", humidity=")
+ .append(this.humidity).append(", pressure=").append(this.pressure)
+ .append(", sea_level=").append(this.sea_level).append(", temp=").append(this.temp)
+ .append(", temp_max=").append(this.temp_max).append(", temp_min=")
+ .append(this.temp_min).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+public class Rain implements Serializable {
+ private static final long serialVersionUID = 1318464783605029435L;
+ private Number three;
+
+ public Number get3h(){
+ return this.three;
+ }
+
+ public void set3h(final Number threeh) {
+ this.three = threeh;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Rain [three=").append(this.three).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+public class Snow implements Serializable {
+ private static final long serialVersionUID = 6769716772818311879L;
+ private Number three;
+
+ public Number get3h() {
+ return this.three;
+ }
+
+ public void set3h(final Number threeh) {
+ this.three = threeh;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Snow [three=").append(this.three).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+
+public class Sys implements Serializable {
+ private static final long serialVersionUID = 5333083785731053139L;
+ private String country;
+ private Number message;
+ private Number sunrise;
+ private Number sunset;
+
+ public String getCountry(){
+ return this.country;
+ }
+ public void setCountry(final String country){
+ this.country = country;
+ }
+ public Number getMessage(){
+ return this.message;
+ }
+ public void setMessage(final Number message){
+ this.message = message;
+ }
+ public Number getSunrise(){
+ return this.sunrise;
+ }
+ public void setSunrise(final Number sunrise){
+ this.sunrise = sunrise;
+ }
+ public Number getSunset(){
+ return this.sunset;
+ }
+ public void setSunset(final Number sunset){
+ this.sunset = sunset;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Sys [country=").append(this.country).append(", message=")
+ .append(this.message).append(", sunrise=").append(this.sunrise).append(", sunset=")
+ .append(this.sunset).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+public class Weather implements Serializable {
+ private static final long serialVersionUID = -34336548786316655L;
+ private String description;
+ private String icon;
+ private Number id;
+ private String main;
+
+ public String getDescription(){
+ return this.description;
+ }
+ public void setDescription(final String description){
+ this.description = description;
+ }
+ public String getIcon(){
+ return this.icon;
+ }
+ public void setIcon(final String icon){
+ this.icon = icon;
+ }
+ public Number getId(){
+ return this.id;
+ }
+ public void setId(final Number id){
+ this.id = id;
+ }
+ public String getMain(){
+ return this.main;
+ }
+ public void setMain(final String main){
+ this.main = main;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Weather [description=").append(this.description).append(", icon=")
+ .append(this.icon).append(", id=").append(this.id).append(", main=")
+ .append(this.main).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.currentweather;
+
+import java.io.Serializable;
+
+public class Wind implements Serializable {
+ private static final long serialVersionUID = 5495842422633674631L;
+ private Number deg;
+ private Number speed;
+
+ public Number getDeg(){
+ return this.deg;
+ }
+ public void setDeg(final Number deg){
+ this.deg = deg;
+ }
+ public Number getSpeed(){
+ return this.speed;
+ }
+ public void setSpeed(final Number speed){
+ this.speed = speed;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Wind [deg=").append(this.deg).append(", speed=").append(this.speed)
+ .append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.forecastweather;
+
+import java.io.Serializable;
+
+
+public class City implements Serializable {
+ private static final long serialVersionUID = 3079687975077030704L;
+ private Coord coord;
+ private String country;
+ private Number id;
+ private String name;
+ private Number population;
+
+ public Coord getCoord(){
+ return this.coord;
+ }
+ public void setCoord(final Coord coord){
+ this.coord = coord;
+ }
+ public String getCountry(){
+ return this.country;
+ }
+ public void setCountry(final String country){
+ this.country = country;
+ }
+ public Number getId(){
+ return this.id;
+ }
+ public void setId(final Number id){
+ this.id = id;
+ }
+ public String getName(){
+ return this.name;
+ }
+ public void setName(final String name){
+ this.name = name;
+ }
+ public Number getPopulation(){
+ return this.population;
+ }
+ public void setPopulation(final Number population){
+ this.population = population;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("City [coord=").append(this.coord).append(", country=").append(this.country)
+ .append(", id=").append(this.id).append(", name=").append(this.name)
+ .append(", population=").append(this.population).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.forecastweather;
+
+import java.io.Serializable;
+
+public class Coord implements Serializable {
+ private static final long serialVersionUID = 8069257976701986700L;
+ private Number lat;
+ private Number lon;
+
+ public Number getLat(){
+ return this.lat;
+ }
+ public void setLat(final Number lat){
+ this.lat = lat;
+ }
+ public Number getLon(){
+ return this.lon;
+ }
+ public void setLon(final Number lon){
+ this.lon = lon;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Coord [lat=").append(this.lat).append(", lon=").append(this.lon)
+ .append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.forecastweather;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Auto generated by: http://jsongen.byingtondesign.com/
+ * (with my own modifications)
+ *
+ */
+public class Forecast implements Serializable {
+ private static final long serialVersionUID = 5095443678019686190L;
+ private City city;
+ private Number cnt;
+ private Number cod;
+ private List<de.example.exampletdd.model.forecastweather.List> list;
+ private Number message;
+
+ public City getCity(){
+ return this.city;
+ }
+ public void setCity(final City city){
+ this.city = city;
+ }
+ public Number getCnt(){
+ return this.cnt;
+ }
+ public void setCnt(final Number cnt){
+ this.cnt = cnt;
+ }
+
+ public Number getCod() {
+ return this.cod;
+ }
+
+ public void setCod(final Number cod) {
+ this.cod = cod;
+ }
+
+ public List<de.example.exampletdd.model.forecastweather.List> getList() {
+ return this.list;
+ }
+
+ public void setList(final List<de.example.exampletdd.model.forecastweather.List> list) {
+ this.list = list;
+ }
+ public Number getMessage(){
+ return this.message;
+ }
+ public void setMessage(final Number message){
+ this.message = message;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Forecast [city=").append(this.city).append(", cnt=")
+ .append(this.cnt).append(", cod=").append(this.cod).append(", list=")
+ .append(this.list).append(", message=").append(this.message).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.forecastweather;
+
+import java.io.Serializable;
+
+
+public class List implements Serializable {
+ private static final long serialVersionUID = 838468273188666785L;
+ private Number clouds;
+ private Number deg;
+ private Number dt;
+ private Number humidity;
+ private Number pressure;
+ private Number rain;
+ private Number snow;
+ private Number speed;
+ private Temp temp;
+ private java.util.List<Weather> weather;
+
+ public Number getClouds(){
+ return this.clouds;
+ }
+ public void setClouds(final Number clouds){
+ this.clouds = clouds;
+ }
+ public Number getDeg(){
+ return this.deg;
+ }
+ public void setDeg(final Number deg){
+ this.deg = deg;
+ }
+ public Number getDt(){
+ return this.dt;
+ }
+ public void setDt(final Number dt){
+ this.dt = dt;
+ }
+ public Number getHumidity(){
+ return this.humidity;
+ }
+ public void setHumidity(final Number humidity){
+ this.humidity = humidity;
+ }
+ public Number getPressure(){
+ return this.pressure;
+ }
+ public void setPressure(final Number pressure){
+ this.pressure = pressure;
+ }
+ public Number getRain(){
+ return this.rain;
+ }
+ public void setRain(final Number rain){
+ this.rain = rain;
+ }
+ public Number getSnow() {
+ return this.snow;
+ }
+ public void setSnow(final Number snow) {
+ this.snow = snow;
+ }
+ public Number getSpeed(){
+ return this.speed;
+ }
+ public void setSpeed(final Number speed){
+ this.speed = speed;
+ }
+ public Temp getTemp(){
+ return this.temp;
+ }
+ public void setTemp(final Temp temp){
+ this.temp = temp;
+ }
+
+ public java.util.List<Weather> getWeather() {
+ return this.weather;
+ }
+
+ public void setWeather(final java.util.List<Weather> weather) {
+ this.weather = weather;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("List [clouds=").append(this.clouds).append(", deg=").append(this.deg)
+ .append(", dt=").append(this.dt).append(", humidity=").append(this.humidity)
+ .append(", pressure=").append(this.pressure).append(", rain=").append(this.rain)
+ .append(", snow=").append(this.snow).append(", speed=").append(this.speed)
+ .append(", temp=").append(this.temp).append(", weather=").append(this.weather)
+ .append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.forecastweather;
+
+import java.io.Serializable;
+
+public class Temp implements Serializable {
+ private static final long serialVersionUID = -7614799035018271127L;
+ private Number day;
+ private Number eve;
+ private Number max;
+ private Number min;
+ private Number morn;
+ private Number night;
+
+ public Number getDay(){
+ return this.day;
+ }
+ public void setDay(final Number day){
+ this.day = day;
+ }
+ public Number getEve(){
+ return this.eve;
+ }
+ public void setEve(final Number eve){
+ this.eve = eve;
+ }
+ public Number getMax(){
+ return this.max;
+ }
+ public void setMax(final Number max){
+ this.max = max;
+ }
+ public Number getMin(){
+ return this.min;
+ }
+ public void setMin(final Number min){
+ this.min = min;
+ }
+ public Number getMorn(){
+ return this.morn;
+ }
+ public void setMorn(final Number morn){
+ this.morn = morn;
+ }
+ public Number getNight(){
+ return this.night;
+ }
+ public void setNight(final Number night){
+ this.night = night;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Temp [day=").append(this.day).append(", eve=").append(this.eve)
+ .append(", max=").append(this.max).append(", min=").append(this.min)
+ .append(", morn=").append(this.morn).append(", night=").append(this.night)
+ .append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.model.forecastweather;
+
+import java.io.Serializable;
+
+public class Weather implements Serializable {
+ private static final long serialVersionUID = -5066357704517363241L;
+ private String description;
+ private String icon;
+ private Number id;
+ private String main;
+
+ public String getDescription(){
+ return this.description;
+ }
+ public void setDescription(final String description){
+ this.description = description;
+ }
+ public String getIcon(){
+ return this.icon;
+ }
+ public void setIcon(final String icon){
+ this.icon = icon;
+ }
+ public Number getId(){
+ return this.id;
+ }
+ public void setId(final Number id){
+ this.id = id;
+ }
+ public String getMain(){
+ return this.main;
+ }
+ public void setMain(final String main){
+ this.main = main;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Weather [description=").append(this.description).append(", icon=")
+ .append(this.icon).append(", id=").append(this.id).append(", main=")
+ .append(this.main).append("]");
+ return builder.toString();
+ }
+}
--- /dev/null
+package de.example.exampletdd.parser;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParseException;
+
+import de.example.exampletdd.model.currentweather.Current;
+import de.example.exampletdd.model.forecastweather.Forecast;
+
+public interface IJPOSParser {
+
+ public Current retrieveCurrenFromJPOS(final String jsonData)
+ throws JsonParseException, IOException;
+
+ public Forecast retrieveForecastFromJPOS(final String jsonData)
+ throws JsonParseException, IOException;
+}
--- /dev/null
+package de.example.exampletdd.parser;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+
+import de.example.exampletdd.model.currentweather.Clouds;
+import de.example.exampletdd.model.currentweather.Coord;
+import de.example.exampletdd.model.currentweather.Current;
+import de.example.exampletdd.model.currentweather.Main;
+import de.example.exampletdd.model.currentweather.Rain;
+import de.example.exampletdd.model.currentweather.Sys;
+import de.example.exampletdd.model.currentweather.Wind;
+import de.example.exampletdd.model.forecastweather.City;
+import de.example.exampletdd.model.forecastweather.Forecast;
+import de.example.exampletdd.model.forecastweather.Temp;
+
+public class JPOSWeatherParser implements IJPOSParser {
+
+ @Override
+ public Current retrieveCurrenFromJPOS(final String jsonData)
+ throws JsonParseException, IOException {
+ final JsonFactory f = new JsonFactory();
+
+ final Current currentWeatherData = new Current();
+ currentWeatherData.setClouds(new Clouds());
+ currentWeatherData.setCoord(new Coord());
+ currentWeatherData.setMain(new Main());
+ currentWeatherData.setRain(new Rain());
+ currentWeatherData.setSys(new Sys());
+ currentWeatherData
+ .setWeather(new ArrayList<de.example.exampletdd.model.currentweather.Weather>());
+ currentWeatherData.setWind(new Wind());
+ final JsonParser jParser = f.createParser(jsonData);
+
+ this.getCurrentWeatherData(currentWeatherData, jParser);
+
+ return currentWeatherData;
+ }
+
+ @Override
+ public Forecast retrieveForecastFromJPOS(final String jsonData)
+ throws JsonParseException, IOException {
+ final JsonFactory f = new JsonFactory();
+
+ final Forecast forecastWeatherData = new Forecast();
+ forecastWeatherData
+ .setList(new ArrayList<de.example.exampletdd.model.forecastweather.List>(15));
+ final City city = new City();
+ city.setCoord(new de.example.exampletdd.model.forecastweather.Coord());
+ forecastWeatherData.setCity(city);
+ final JsonParser jParser = f.createParser(jsonData);
+
+ this.getForecastWeatherData(forecastWeatherData, jParser);
+
+ return forecastWeatherData;
+ }
+
+ private void getCurrentWeatherData(final Current currentWeatherData,
+ final JsonParser jParser) throws JsonParseException, IOException {
+ if (jParser.nextToken() == JsonToken.START_OBJECT) {
+
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String fieldname = jParser.getCurrentName();
+ final JsonToken nextToken = jParser.nextToken();
+ if (nextToken == JsonToken.START_OBJECT) {
+ this.getCurrentWeatherDataObjects(currentWeatherData, jParser, fieldname);
+ }
+ if (nextToken == JsonToken.START_ARRAY) {
+ JsonToken tokenNext = jParser.nextToken();
+ while (tokenNext != JsonToken.END_ARRAY) {
+ if (tokenNext == JsonToken.START_OBJECT) {
+ this.getCurrentWeatherDataObjects(currentWeatherData, jParser, fieldname);
+ }
+ tokenNext = jParser.nextToken();
+ }
+ }
+ if ((nextToken == JsonToken.VALUE_NUMBER_INT)
+ || (nextToken == JsonToken.VALUE_STRING)) {
+ this.getCurrentWeatherDataObjects(currentWeatherData, jParser, fieldname);
+ }
+ }
+ }
+ }
+
+ private void getCurrentWeatherDataObjects(final Current currentWeatherData,
+ final JsonParser jParser, final String fieldname) throws JsonParseException,
+ IOException {
+ if (fieldname == "coord") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("lon".equals(namefield)) {
+ currentWeatherData.getCoord().setLon(jParser.getDoubleValue());
+ }
+ if ("lat".equals(namefield)) {
+ currentWeatherData.getCoord().setLat(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "sys") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("message".equals(namefield)) {
+ currentWeatherData.getSys().setMessage(jParser.getDoubleValue());
+ }
+ if ("country".equals(namefield)) {
+ currentWeatherData.getSys().setCountry(jParser.getValueAsString());
+ }
+ if ("sunrise".equals(namefield)) {
+ currentWeatherData.getSys().setSunrise(jParser.getValueAsLong());
+ }
+ if ("sunset".equals(namefield)) {
+ currentWeatherData.getSys().setSunset(jParser.getValueAsLong());
+ }
+ }
+ }
+ if (fieldname == "weather") {
+ final de.example.exampletdd.model.currentweather.Weather weather = new de.example.exampletdd.model.currentweather.Weather();
+ currentWeatherData.getWeather().add(weather);
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("id".equals(namefield)) {
+ weather.setId(jParser.getIntValue());
+ }
+ if ("main".equals(namefield)) {
+ weather.setMain(jParser.getText());
+ }
+ if ("description".equals(namefield)) {
+ weather.setDescription(jParser.getText());
+ }
+ if ("icon".equals(namefield)) {
+ weather.setIcon(jParser.getText());
+ }
+
+ }
+ }
+ if (fieldname == "base") {
+ currentWeatherData.setBase(jParser.getText());
+ }
+ if (fieldname == "main") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("temp".equals(namefield)) {
+ currentWeatherData.getMain().setTemp(jParser.getDoubleValue());
+ }
+ if ("temp_min".equals(namefield)) {
+ currentWeatherData.getMain().setTemp_min(jParser.getDoubleValue());
+ }
+ if ("temp_max".equals(namefield)) {
+ currentWeatherData.getMain().setTemp_max(jParser.getDoubleValue());
+ }
+ if ("pressure".equals(namefield)) {
+ currentWeatherData.getMain().setPressure(jParser.getDoubleValue());
+ }
+ if ("sea_level".equals(namefield)) {
+ currentWeatherData.getMain().setSea_level(jParser.getDoubleValue());
+ }
+ if ("grnd_level".equals(namefield)) {
+ currentWeatherData.getMain().setGrnd_level(jParser.getDoubleValue());
+ }
+ if ("humidity".equals(namefield)) {
+ currentWeatherData.getMain().setHumidity(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "wind") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("speed".equals(namefield)) {
+ currentWeatherData.getWind().setSpeed(jParser.getDoubleValue());
+ }
+ if ("deg".equals(namefield)) {
+ currentWeatherData.getWind().setDeg(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "clouds") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("all".equals(namefield)) {
+ currentWeatherData.getClouds().setAll(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "dt") {
+ currentWeatherData.setDt(jParser.getLongValue());
+ }
+ if (fieldname == "rain") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("3h".equals(namefield)) {
+ currentWeatherData.getRain().set3h(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "snow") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("3h".equals(namefield)) {
+ currentWeatherData.getSnow().set3h(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "id") {
+ currentWeatherData.setId(jParser.getLongValue());
+ }
+ if (fieldname == "name") {
+ currentWeatherData.setName(jParser.getText());
+ }
+ if (fieldname == "cod") {
+ currentWeatherData.setCod(jParser.getIntValue());
+ }
+ }
+
+ private void getForecastWeatherData(final Forecast forecastWeatherData,
+ final JsonParser jParser) throws JsonParseException, IOException {
+ if (jParser.nextToken() == JsonToken.START_OBJECT) {
+
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String fieldname = jParser.getCurrentName();
+ final JsonToken nextToken = jParser.nextToken();
+ if (nextToken == JsonToken.START_OBJECT) {
+ this.getForecastWeatherDataObjects(forecastWeatherData, jParser, fieldname);
+ }
+ if (nextToken == JsonToken.START_ARRAY) {
+ JsonToken tokenNext = jParser.nextToken();
+ while (tokenNext != JsonToken.END_ARRAY) {
+ if (tokenNext == JsonToken.START_OBJECT) {
+ this.getForecastWeatherDataObjects(forecastWeatherData, jParser, fieldname);
+ }
+ tokenNext = jParser.nextToken();
+ }
+ }
+ if ((nextToken == JsonToken.VALUE_NUMBER_INT)
+ || (nextToken == JsonToken.VALUE_STRING)) {
+ this.getForecastWeatherDataObjects(forecastWeatherData, jParser, fieldname);
+ }
+ }
+ }
+ }
+
+ private void getForecastWeatherDataObjects(final Forecast forecastWeatherData,
+ final JsonParser jParser, final String fieldname) throws JsonParseException,
+ IOException {
+
+ if (fieldname == "cod") {
+ final String stringCod = jParser.getText();
+ forecastWeatherData.setCod(Long.valueOf(stringCod));
+ }
+ if (fieldname == "message") {
+ forecastWeatherData.setMessage(jParser.getDoubleValue());
+ }
+ if (fieldname == "city") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ final JsonToken nextToken = jParser.nextToken(); // move to
+ // value
+ if ("id".equals(namefield)) {
+ forecastWeatherData.getCity().setId(jParser.getLongValue());
+ }
+ if ("name".equals(namefield)) {
+ forecastWeatherData.getCity().setName(jParser.getText());
+ }
+ if ("coord".equals(namefield)) {
+ if (nextToken == JsonToken.START_OBJECT) {
+ this.getForecastWeatherDataObjects(forecastWeatherData, jParser, namefield);
+ }
+ }
+ if ("country".equals(namefield)) {
+ forecastWeatherData.getCity().setCountry(jParser.getText());
+ }
+ if ("population".equals(namefield)) {
+ forecastWeatherData.getCity().setPopulation(jParser.getLongValue());
+ }
+ }
+ }
+ if (fieldname == "cnt") {
+ forecastWeatherData.setCnt(jParser.getIntValue());
+ }
+ if (fieldname == "coord") {
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("lon".equals(namefield)) {
+ forecastWeatherData.getCity().getCoord().setLon(jParser.getDoubleValue());
+ }
+ if ("lat".equals(namefield)) {
+ forecastWeatherData.getCity().getCoord().setLat(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "list") {
+ final de.example.exampletdd.model.forecastweather.List list = new de.example.exampletdd.model.forecastweather.List();
+ list.setTemp(new Temp());
+ list.setWeather(new ArrayList<de.example.exampletdd.model.forecastweather.Weather>());
+ forecastWeatherData.getList().add(list);
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ final JsonToken nextToken = jParser.nextToken(); // move to
+ // value
+ if ("dt".equals(namefield)) {
+ list.setDt(jParser.getLongValue());
+ }
+ if ("temp".equals(namefield)) {
+ if (nextToken == JsonToken.START_OBJECT) {
+ this.getForecastWeatherDataObjects(forecastWeatherData, jParser, namefield);
+ }
+ }
+ if ("pressure".equals(namefield)) {
+ list.setPressure(jParser.getDoubleValue());
+ }
+ if ("humidity".equals(namefield)) {
+ list.setHumidity(jParser.getDoubleValue());
+ }
+ if ("weather".equals(namefield)) {
+ if (nextToken == JsonToken.START_ARRAY) {
+ JsonToken tokenNext = jParser.nextToken();
+ while (tokenNext != JsonToken.END_ARRAY) {
+ if (tokenNext == JsonToken.START_OBJECT) {
+ this.getForecastWeatherDataObjects(forecastWeatherData, jParser,
+ namefield);
+ }
+ tokenNext = jParser.nextToken();
+ }
+ }
+ }
+ if ("speed".equals(namefield)) {
+ list.setSpeed(jParser.getDoubleValue());
+ }
+ if ("deg".equals(namefield)) {
+ list.setDeg(jParser.getDoubleValue());
+ }
+ if ("clouds".equals(namefield)) {
+ list.setClouds(jParser.getDoubleValue());
+ }
+ if ("rain".equals(namefield)) {
+ list.setRain(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "temp") {
+ final de.example.exampletdd.model.forecastweather.List list = forecastWeatherData
+ .getList().get(
+ (forecastWeatherData.getList().size() - 1));
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+ if ("day".equals(namefield)) {
+ list.getTemp().setDay(jParser.getDoubleValue());
+ }
+ if ("min".equals(namefield)) {
+ list.getTemp().setMin(jParser.getDoubleValue());
+ }
+ if ("max".equals(namefield)) {
+ list.getTemp().setMax(jParser.getDoubleValue());
+ }
+ if ("night".equals(namefield)) {
+ list.getTemp().setNight(jParser.getDoubleValue());
+ }
+ if ("eve".equals(namefield)) {
+ list.getTemp().setEve(jParser.getDoubleValue());
+ }
+ if ("morn".equals(namefield)) {
+ list.getTemp().setMorn(jParser.getDoubleValue());
+ }
+ }
+ }
+ if (fieldname == "weather") {
+ final de.example.exampletdd.model.forecastweather.List list = forecastWeatherData
+ .getList().get(
+ (forecastWeatherData.getList().size() - 1));
+ final de.example.exampletdd.model.forecastweather.Weather weather = new de.example.exampletdd.model.forecastweather.Weather();
+ while (jParser.nextToken() != JsonToken.END_OBJECT) {
+ final String namefield = jParser.getCurrentName();
+ jParser.nextToken(); // move to value
+
+ if ("id".equals(namefield)) {
+ weather.setId(jParser.getIntValue());
+ }
+ if ("main".equals(namefield)) {
+ weather.setMain(jParser.getText());
+ }
+ if ("description".equals(namefield)) {
+ weather.setDescription(jParser.getText());
+ }
+ if ("icon".equals(namefield)) {
+ weather.setIcon(jParser.getText());
+ }
+ }
+ list.getWeather().add(weather);
+ }
+ }
+}
--- /dev/null
+package de.example.exampletdd.service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import de.example.exampletdd.R;
+
+public enum IconsList {
+ ICON_01d("01d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_clear;
+ }
+ },
+ ICON_01n("01n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_clear_night;
+ }
+ },
+ ICON_02d("02d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_few_clouds;
+ }
+ },
+ ICON_02n("02n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_few_clouds_night;
+ }
+ },
+ ICON_03d("03d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_few_clouds;
+ }
+ },
+ ICON_03n("03n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_few_clouds;
+ }
+ },
+ ICON_04d("04d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_overcast;
+ }
+ },
+ ICON_04n("04n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_overcast;
+ }
+ },
+ ICON_09d("09d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_showers;
+ }
+ },
+ ICON_09n("09n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_showers;
+ }
+ },
+ ICON_10d("10d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_showers_scattered;
+ }
+ },
+ ICON_10n("10n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_showers_scattered;
+ }
+ },
+ ICON_11d("11d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_storm;
+ }
+ },
+ ICON_11n("11n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_storm;
+ }
+ },
+ ICON_13d("13d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_snow;
+ }
+ },
+ ICON_13n("13n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_snow;
+ }
+ },
+ ICON_50d("50d") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_fog;
+ }
+ },
+ ICON_50n("50n") {
+ @Override
+ public int getResourceDrawable() {
+ return R.drawable.weather_fog;
+ }
+ };
+
+ private final String icon;
+ // Map with every enum constant. Class variable initializer. JLS§12.4.2
+ // Executed in textual order.
+ private static final Map<String, IconsList> codeMap = new HashMap<String, IconsList>();
+
+ // Static initializer. JLS§12.4.2 Executed in textual order.
+ static {
+ for (final IconsList code : IconsList.values()) {
+ codeMap.put(code.getIcon(), code);
+ }
+ }
+
+ private IconsList(final String icon) {
+ this.icon = icon;
+ }
+
+ public static final IconsList getIcon(final String icon) {
+ return codeMap.get(icon);
+ }
+
+ private String getIcon() {
+ return this.icon;
+ }
+
+ public abstract int getResourceDrawable();
+}
--- /dev/null
+package de.example.exampletdd.service;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.StreamCorruptedException;
+
+import android.content.Context;
+import android.util.Log;
+import de.example.exampletdd.model.currentweather.Current;
+import de.example.exampletdd.model.forecastweather.Forecast;
+
+
+/**
+ * TODO: show some error message when there is no enough space for saving files. :/
+ *
+ */
+public class PermanentStorage {
+ private static final String TAG = "PermanentStorage";
+ private static final String CURRENT_DATA_FILE = "current.file";
+ private static final String FORECAST_DATA_FILE = "forecast.file";
+ private final Context context;
+
+ public PermanentStorage(final Context context) {
+ this.context = context;
+ }
+
+ public void saveCurrent(final Current current) {
+
+ try {
+ this.saveObject(CURRENT_DATA_FILE, current);
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "saveCurrent exception: ", e);
+ } catch (IOException e) {
+ Log.e(TAG, "saveCurrent exception: ", e);
+ }
+ }
+
+ public Current getCurrent() {
+
+ try {
+ return (Current) this.getObject(CURRENT_DATA_FILE);
+ } catch (final StreamCorruptedException e) {
+ Log.e(TAG, "getCurrent exception: ", e);
+ } catch (final FileNotFoundException e) {
+ Log.e(TAG, "getCurrent exception: ", e);
+ } catch (final IOException e) {
+ Log.e(TAG, "getCurrent exception: ", e);
+ } catch (final ClassNotFoundException e) {
+ Log.e(TAG, "getCurrent exception: ", e);
+ }
+
+ return null;
+ }
+
+ public void saveForecast(final Forecast forecast) {
+
+ try {
+ this.saveObject(FORECAST_DATA_FILE, forecast);
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "saveForecast exception: ", e);
+ } catch (IOException e) {
+ Log.e(TAG, "saveForecast exception: ", e);
+ }
+ }
+
+ public Forecast getForecast() {
+
+ try {
+ return (Forecast) this.getObject(FORECAST_DATA_FILE);
+ } catch (final StreamCorruptedException e) {
+ Log.e(TAG, "getForecast exception: ", e);
+ } catch (final FileNotFoundException e) {
+ Log.e(TAG, "getForecast exception: ", e);
+ } catch (final IOException e) {
+ Log.e(TAG, "getForecast exception: ", e);
+ } catch (final ClassNotFoundException e) {
+ Log.e(TAG, "getForecast exception: ", e);
+ }
+
+ return null;
+ }
+
+ private void saveObject(final String fileName, final Object objectToStore)
+ throws FileNotFoundException, IOException {
+ final String temporaryFileName = fileName.concat(".tmp");
+
+ final FileOutputStream tmpPersistFile = this.context.openFileOutput(
+ temporaryFileName, Context.MODE_PRIVATE);
+ try {
+ final ObjectOutputStream oos = new ObjectOutputStream(tmpPersistFile);
+ try {
+ oos.writeObject(objectToStore);
+
+ // Don't fear the fsync!
+ // http://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/
+ tmpPersistFile.flush();
+ tmpPersistFile.getFD().sync();
+ } finally {
+ oos.close();
+ }
+ } finally {
+ tmpPersistFile.close();
+ }
+
+ this.renameFile(temporaryFileName, fileName);
+ }
+
+ private Object getObject(final String fileName) throws StreamCorruptedException, FileNotFoundException,
+ IOException, ClassNotFoundException {
+ final InputStream persistFile = this.context.openFileInput(fileName);
+ try {
+ final ObjectInputStream ois = new ObjectInputStream(persistFile);
+ try {
+ return ois.readObject();
+ } finally {
+ ois.close();
+ }
+ } finally {
+ persistFile.close();
+ }
+ }
+
+ private void renameFile(final String fromFileName, final String toFileName) throws IOException {
+ final File filesDir = this.context.getFilesDir();
+ final File fromFile = new File(filesDir, fromFileName);
+ final File toFile = new File(filesDir, toFileName);
+ if (!fromFile.renameTo(toFile)) {
+ if (!fromFile.delete()) {
+ throw new IOException("PermanentStorage, delete file error");
+ }
+ throw new IOException("PermanentStorage, rename file error");
+ }
+ }
+}
+
--- /dev/null
+package de.example.exampletdd.service;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Locale;
+
+import com.fasterxml.jackson.core.JsonParseException;
+
+import de.example.exampletdd.model.currentweather.Current;
+import de.example.exampletdd.model.forecastweather.Forecast;
+import de.example.exampletdd.parser.IJPOSParser;
+
+public class ServiceParser {
+ private final IJPOSParser JPOSParser;
+
+ public ServiceParser(final IJPOSParser JPOSWeatherParser) {
+ this.JPOSParser = JPOSWeatherParser;
+ }
+
+ public Current retrieveCurrentFromJPOS(final String jsonData)
+ throws JsonParseException, IOException {
+ return this.JPOSParser.retrieveCurrenFromJPOS(jsonData);
+ }
+
+ public Forecast retrieveForecastFromJPOS(final String jsonData)
+ throws JsonParseException, IOException {
+ return this.JPOSParser.retrieveForecastFromJPOS(jsonData);
+ }
+
+ public String createURIAPIForecast(final String urlAPI, final String APIVersion,
+ final double latitude, final double longitude, final String resultsNumber) {
+
+ final MessageFormat formatURIAPI = new MessageFormat(urlAPI, Locale.US);
+ final Object[] values = new Object[4];
+ values[0] = APIVersion;
+ values[1] = latitude;
+ values[2] = longitude;
+ values[3] = resultsNumber;
+
+ return formatURIAPI.format(values);
+ }
+
+ public String createURIAPICurrent(final String urlAPI, final String APIVersion,
+ final double latitude, final double longitude) {
+
+ final MessageFormat formatURIAPI = new MessageFormat(urlAPI, Locale.US);
+ final Object[] values = new Object[3];
+ values[0] = APIVersion;
+ values[1] = latitude;
+ values[2] = longitude;
+
+ return formatURIAPI.format(values);
+ }
+
+ public String createURIAPIicon(final String icon, final String urlAPI) {
+
+ final MessageFormat formatURIAPI = new MessageFormat(urlAPI, Locale.US);
+ final Object[] values = new Object[1];
+ values[0] = icon;
+
+ return formatURIAPI.format(values);
+ }
+
+}
--- /dev/null
+package de.example.exampletdd.widget;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.Fragment;
+import android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import de.example.exampletdd.R;
+
+public class WidgetConfigure extends Activity {
+ private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
+
+ final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+
+
+ // When the button is clicked, save the string in our prefs and return that they
+ // clicked OK.
+ // Push widget update to surface with newly set prefix
+ final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(
+ WidgetConfigure.this.getApplicationContext());
+ WidgetProvider.updateAppWidget(
+ WidgetConfigure.this.getApplicationContext(),
+ appWidgetManager,
+ mAppWidgetId);
+
+ // Make sure we pass back the original appWidgetId
+ final Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
+ WidgetConfigure.this.setResult(RESULT_OK, resultValue);
+ finish();
+ }
+ };
+
+ @Override
+ public void onCreate(final Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Find the widget id from the intent.
+ final Intent intent = getIntent();
+ final Bundle extras = intent.getExtras();
+ boolean isActionFromUser = false;
+
+ if (extras != null) {
+ mAppWidgetId = extras.getInt(
+ AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
+
+ isActionFromUser = extras.getBoolean("actionFromUser", false);
+ }
+
+ // If they gave us an intent without the widget id, just bail.
+ if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ this.finish();
+ }
+
+ if (!isActionFromUser) {
+ // Set the result to CANCELED. This will cause the widget host to cancel
+ // out of the widget placement if they press the back button.
+ this.setResult(RESULT_CANCELED);
+ }
+
+ // Set the view layout resource to use.
+ this.setContentView(R.layout.appwidget_configure);
+
+ final Bundle args = new Bundle();
+ args.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
+ final Fragment preferences = new WidgetPreferences();
+ preferences.setRetainInstance(true);
+ preferences.setArguments(args);
+ this.getFragmentManager()
+ .beginTransaction()
+ .replace(R.id.weather_appwidget_configure_preferences, preferences)
+ .commit();
+
+ // Bind the action for the save button.
+ this.findViewById(R.id.weather_appwidget_configure_save_button).setOnClickListener(mOnClickListener);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final ActionBar actionBar = this.getActionBar();
+ actionBar.setTitle(this.getString(R.string.widget_preferences_action_settings));
+ }
+}
--- /dev/null
+package de.example.exampletdd.widget;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.PreferenceFragment;
+import android.preference.SwitchPreference;
+import de.example.exampletdd.R;
+
+/**
+ * TODO:
+ * IT DOES NOT WORK IF USER IS WORKING WITH TWO OR MORE WIDGET PREFERENCE WINDOWS AT THE SAME TIME
+ * (hopefully nobody will realize...)
+ * How to implement custom preference activities (no extending from PreferenceActivity or PreferenceFragment)
+ * without pain?
+ */
+public class WidgetPreferences extends PreferenceFragment implements OnSharedPreferenceChangeListener {
+ private int appWidgetId;
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Retain this fragment across configuration changes.
+ this.setRetainInstance(true);
+
+ final Bundle bundle = this.getArguments();
+ appWidgetId = bundle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
+
+ // Load the preferences from an XML resource
+ this.addPreferencesFromResource(R.xml.appwidget_preferences);
+
+
+ /******************* Show/hide country field *******************/
+ String keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.widget_preferences_country_switch_key);
+ String realKeyPreference = keyPreference + "_" + appWidgetId;
+
+ // What was saved to permanent storage (or default values if it is the first time)
+ boolean countryValue = this.getActivity().getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE)
+ .getBoolean(realKeyPreference, false);
+
+ // What is shown on the screen
+ final SwitchPreference countryPref = (SwitchPreference) this.findPreference(keyPreference);
+ countryPref.setChecked(countryValue);
+
+ /********************* Temperature units **********************/
+ final String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
+ final String[] humanValues = this.getResources().getStringArray(R.array.weather_preferences_temperature_human_value);
+
+ keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.widget_preferences_temperature_key);
+ realKeyPreference = keyPreference + "_" + appWidgetId;
+
+
+ // What was saved to permanent storage (or default values if it is the first time)
+ final String tempValue = this.getActivity().getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE)
+ .getString(realKeyPreference, this.getString(R.string.weather_preferences_temperature_celsius));
+ String humanValue = this.getString(R.string.weather_preferences_temperature_celsius_human_value);
+ int index = 0;
+ if (tempValue.equals(values[0])) {
+ index = 0;
+ humanValue = humanValues[0];
+ } else if (tempValue.equals(values[1])) {
+ index = 1;
+ humanValue = humanValues[1];
+ } else if (tempValue.equals(values[2])) {
+ index = 2;
+ humanValue = humanValues[2];
+ }
+
+
+ // What is shown on the screen
+ final ListPreference listPref = (ListPreference) this.findPreference(keyPreference);
+ listPref.setSummary(humanValue);
+ listPref.setValueIndex(index);
+ listPref.setValue(tempValue);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
+
+ /******************* Show/hide country field *******************/
+ String keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.widget_preferences_country_switch_key);
+ if (key.equals(keyPreference)) {
+ final String realKeyPreference = keyPreference + "_" + appWidgetId;
+ // Saving to permanent storage.
+ final SharedPreferences.Editor prefs =
+ this.getActivity().getSharedPreferences(
+ "WIDGET_PREFERENCES",
+ Context.MODE_PRIVATE).edit();
+ // What is shown on the screen
+ final SwitchPreference preference = (SwitchPreference) this.findPreference(key);
+ if (preference.isChecked())
+ {
+ // Saving to permanent storage.
+ prefs.putBoolean(realKeyPreference, true);
+ } else {
+ // Saving to permanent storage.
+ prefs.putBoolean(realKeyPreference, false);
+ }
+ prefs.commit();
+ }
+
+ /********************* Temperature units **********************/
+ keyPreference = this.getActivity().getApplicationContext().getString(
+ R.string.widget_preferences_temperature_key);
+ if (key.equals(keyPreference)) {
+ final String[] values = this.getResources().getStringArray(
+ R.array.weather_preferences_temperature);
+ final String[] humanValues = this.getResources().getStringArray(
+ R.array.weather_preferences_temperature_human_value);
+
+ // What is shown on the screen
+ final ListPreference listPref = (ListPreference) this.findPreference(key);
+ final String value = listPref.getValue();
+ String humanValue = "";
+ if (value.equals(values[0])) {
+ humanValue = humanValues[0];
+ } else if (value.equals(values[1])) {
+ humanValue = humanValues[1];
+ } else if (value.equals(values[2])) {
+ humanValue = humanValues[2];
+ }
+ // Update data on screen
+ listPref.setSummary(humanValue);
+
+
+ // Saving to permanent storage.
+ final String realKeyPreference = keyPreference + "_" + appWidgetId;
+
+ final SharedPreferences.Editor prefs =
+ this.getActivity().getSharedPreferences(
+ "WIDGET_PREFERENCES",
+ Context.MODE_PRIVATE).edit();
+ prefs.putString(realKeyPreference, value);
+ prefs.commit();
+ return;
+ }
+
+
+
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ this.getPreferenceManager().getSharedPreferences()
+ .registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ this.getPreferenceManager().getSharedPreferences()
+ .unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ public static void deletePreference(final Context context, final int appWidgetId) {
+ final String keyPreference = context.getApplicationContext().getString(
+ R.string.widget_preferences_temperature_key);
+ final String realKeyPreference = keyPreference + "_" + appWidgetId;
+
+ final SharedPreferences.Editor prefs = context.getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE).edit();
+ prefs.remove(realKeyPreference);
+ prefs.commit();
+ }
+}
--- /dev/null
+package de.example.exampletdd.widget;
+
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import de.example.exampletdd.WidgetIntentService;
+
+public class WidgetProvider extends AppWidgetProvider {
+
+ @Override
+ public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
+ // For each widget that needs an update, get the text that we should display:
+ // - Create a RemoteViews object for it
+ // - Set the text in the RemoteViews object
+ // - Tell the AppWidgetManager to show that views object for the widget.
+ final int N = appWidgetIds.length;
+ for (int i=0; i<N; i++) {
+ int appWidgetId = appWidgetIds[i];
+ // To prevent any ANR timeouts, we perform the update in a service
+ final Intent intent = new Intent(context.getApplicationContext(), WidgetIntentService.class);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ intent.putExtra("updateByApp", false);
+ context.startService(intent);
+ }
+ }
+
+ @Override
+ public void onDeleted(final Context context, final int[] appWidgetIds) {
+ // When the user deletes the widget, delete the preference associated with it.
+ final int N = appWidgetIds.length;
+ for (int i=0; i<N; i++) {
+ WidgetPreferences.deletePreference(context, appWidgetIds[i]);
+ }
+ }
+
+ static void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId) {
+
+ int widgetId;
+ Bundle myOptions = appWidgetManager.getAppWidgetOptions(appWidgetId);
+
+ // Get the value of OPTION_APPWIDGET_HOST_CATEGORY
+ int category = myOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
+
+ // If the value is WIDGET_CATEGORY_KEYGUARD, it's a lockscreen widget
+ boolean isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+
+ // Once you know the widget's category, you can optionally load a different base layout, set different
+ // properties, and so on. For example:
+ //int baseLayout = isKeyguard ? R.layout.keyguard_widget_layout : R.layout.widget_layout;
+
+ // Construct the RemoteViews object. It takes the package name (in our case, it's our
+ // package, but it needs this because on the other side it's the widget host inflating
+ // the layout from our package).
+ //final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget);
+
+ final Intent intent = new Intent(context.getApplicationContext(), WidgetIntentService.class);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ context.startService(intent);
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<set>
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromYDelta="100%"
+ android:toYDelta="0%"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<set>
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromYDelta="0%"
+ android:toYDelta="-100%"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
--- /dev/null
+<?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.OverviewFragment" />
+
+ <fragment
+ android:id="@+id/weather_specific_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ class="de.example.exampletdd.fragment.specific.SpecificFragment" />
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/weather_appwidget"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="fill"
+ android:orientation="horizontal"
+ android:baselineAligned="false"
+ android:background="@color/widget_background_holo_dark"
+ android:padding="@dimen/widget_margin" >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:padding="4dp"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:id="@+id/weather_appwidget_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:contentDescription="@string/icon_weather_description"
+ android:orientation="vertical"
+ android:src="@drawable/weather_showers" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:padding="4dp"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_appwidget_temperature_max"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="12ºC"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_appwidget_temperature_min"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="5ºC"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="normal" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:padding="4dp" >
+
+ <TextView
+ android:id="@+id/weather_appwidget_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="Morata de Tajuña"
+ android:textAlignment="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_appwidget_country"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="Spain"
+ android:textAlignment="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+ </LinearLayout>
+
+
+
+
+
+</LinearLayout>
--- /dev/null
+<?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:layout_gravity="fill_vertical|fill_horizontal" >
+
+ <LinearLayout android:id="@+id/weather_appwidget_configure_preferences"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_gravity="center"
+ android:orientation="horizontal" >
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/weather_appwidget_configure_preferences"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:baselineAligned="false"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/weather_appwidget_configure_refresh_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAlignment="center"
+ android:text="@string/widget_preferences_button_refresh" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:baselineAligned="false"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/weather_appwidget_configure_save_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAlignment="center"
+ android:text="@android:string/ok" />
+ </LinearLayout>
+
+</RelativeLayout>
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/weather_appwidget_error"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="fill"
+ android:orientation="horizontal"
+ android:baselineAligned="false"
+ android:background="@color/widget_background_holo_dark"
+ android:padding="@dimen/widget_margin" >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:padding="4dp"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:contentDescription="@string/icon_weather_description"
+ android:orientation="vertical"
+ android:src="@drawable/ic_launcher" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:padding="4dp" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/text_field_remote_error"
+ android:textAlignment="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+
+
+
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:padding="4dip"
+ android:gravity="center_horizontal"
+ android:layout_width="match_parent" android:layout_height="match_parent">
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+ </android.support.v4.view.ViewPager>
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="fill"
+ android:baselineAligned="false"
+ android:orientation="horizontal" >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:contentDescription="@string/icon_weather_description"
+ android:orientation="vertical"
+ android:src="@drawable/ic_launcher" />
+ </LinearLayout>
+
+
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_weight="2"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_notification_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="Morata de Tajuña"
+ android:textAlignment="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_notification_country"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="Spain"
+ android:textAlignment="center"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_notification_temperature_max"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="12ºC"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_notification_temperature_min"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="5ºC"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="normal" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:id="@+id/weather_notification_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:contentDescription="@string/icon_weather_description"
+ android:orientation="vertical"
+ android:src="@drawable/ic_launcher" />
+
+ </LinearLayout>
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/weather_current_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center">
+
+ <!-- TODO: align start/end feels like-snow humidity-rain wind-clouds -->
+ <LinearLayout android:id="@+id/weather_current_data_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="fill_vertical|center_horizontal"
+ android:orientation="vertical" >
+
+ <!-- TODO: http://developer.android.com/guide/topics/manifest/supports-screens-element.html -->
+ <!-- TODO: supporting multiple layouts/languages http://developer.android.com/guide/practices/screens_support.html -->
+ <!-- TODO: Should I use RelativeLayout for long texts (I18N) and RTL/LTR UI?
+ With long texts, many times, text will not fit... The same for WP8 :/ -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:layout_gravity="top|center"
+ android:padding="50dp"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/weather_current_picture"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/icon_weather_description"
+ android:scaleType="fitCenter"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:src="@drawable/weather_showers" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_current_temp_max"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="10dp"
+ android:paddingStart="20dp"
+ android:singleLine="true"
+ android:text="55ºC"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_current_temp_min"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="textStart"
+ android:paddingEnd="10dp"
+ android:paddingStart="20dp"
+ android:singleLine="true"
+ android:text="25ºC"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="normal" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:padding="25dp"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/weather_current_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="Light rain"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:baselineAligned="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|fill_horizontal"
+ android:orientation="horizontal" >
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="horizontal" >
+ <!-- Feels like -->
+ <TextView
+ android:id="@+id/weather_current_feelslike"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:layout_margin="5dp"
+ android:gravity="start"
+ android:text="@string/text_field_feels_like"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textStyle="bold" />
+
+ <!-- Feels like Value-->
+ <TextView
+ android:id="@+id/weather_current_feelslike_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="83"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Feels like Units-->
+ <TextView
+ android:id="@+id/weather_current_feelslike_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="ºC"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:orientation="horizontal" >
+ <!-- Snow -->
+ <TextView
+ android:id="@+id/weather_current_snow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_snow"
+ android:gravity="end"
+ android:layout_gravity="end"
+ android:textAlignment="textEnd"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Snow Value-->
+ <TextView
+ android:id="@+id/weather_current_snow_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="1.22"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Snow Units -->
+ <TextView
+ android:id="@+id/weather_current_snow_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" mm 3h"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:baselineAligned="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|fill_horizontal"
+ android:orientation="horizontal" >
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="horizontal" >
+ <!-- Humidity -->
+ <TextView
+ android:id="@+id/weather_current_humidity"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:layout_margin="5dp"
+ android:gravity="start"
+ android:text="@string/text_field_humidity"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textStyle="bold" />
+
+ <!-- Humidity Value-->
+ <TextView
+ android:id="@+id/weather_current_humidity_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="83"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Humidity Units-->
+ <TextView
+ android:id="@+id/weather_current_humidity_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="%"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:orientation="horizontal" >
+ <!-- Rain -->
+ <TextView
+ android:id="@+id/weather_current_rain"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_rain"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Rain Value-->
+ <TextView
+ android:id="@+id/weather_current_rain_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="1.24"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Rain Units -->
+ <TextView
+ android:id="@+id/weather_current_rain_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" mm 3h"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:baselineAligned="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|fill_horizontal"
+ android:orientation="horizontal" >
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="horizontal" >
+ <!-- Wind -->
+ <TextView
+ android:id="@+id/weather_current_wind"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_wind"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Wind Value-->
+ <TextView
+ android:id="@+id/weather_current_wind_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="6.36"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Wind Units -->
+ <TextView
+ android:id="@+id/weather_current_wind_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" m/s"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:orientation="horizontal" >
+ <!-- Clouds -->
+ <TextView
+ android:id="@+id/weather_current_clouds"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_clouds"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Clouds Value-->
+ <TextView
+ android:id="@+id/weather_current_clouds_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="6.36"
+ android:layout_gravity="end"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Clouds Units -->
+ <TextView
+ android:id="@+id/weather_current_clouds_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="%"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <!-- Pressure -->
+ <TextView
+ android:id="@+id/weather_current_pressure"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_pressure"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Pressure Value-->
+ <TextView
+ android:id="@+id/weather_current_pressure_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="1036.05"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Pressure Units-->
+ <TextView
+ android:id="@+id/weather_current_pressure_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" hpa"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <!-- Sun rise -->
+ <TextView
+ android:id="@+id/weather_current_sunrise"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_sun_rise"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Sun rise Value-->
+ <TextView
+ android:id="@+id/weather_current_sunrise_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="2014.04.20 10:29:33"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <!-- Sun rise -->
+ <TextView
+ android:id="@+id/weather_current_sunset"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_sun_set"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Sun rise Value-->
+ <TextView
+ android:id="@+id/weather_current_sunset_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="2014.04.20 10:29:33"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <ProgressBar
+ android:id="@+id/weather_current_progressbar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone"
+ style="?android:attr/progressBarStyleLarge" />
+
+ <TextView
+ android:id="@+id/weather_current_error_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/text_field_remote_error"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:visibility="gone" />
+
+ </FrameLayout>
+</ScrollView>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:baselineAligned="false"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:padding="5dp" >
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_main_entry_date_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="SUN"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_main_entry_date_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="APR 23"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ </LinearLayout>
+
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_main_entry_temperature_max"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="12ºC"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_main_entry_temperature_min"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="5ºC"
+ android:textAlignment="center"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textStyle="normal" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:id="@+id/weather_main_entry_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:contentDescription="@string/icon_weather_description"
+ android:orientation="vertical"
+ android:src="@drawable/ic_launcher" />
+
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?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="center"
+ tools:context="de.example.exampletdd.MapActivity" >
+
+ <LinearLayout
+ android:id="@+id/weather_map_citycountry_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true" >
+ <LinearLayout
+ android:id="@+id/weather_map_city_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/weather_map_city"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="City"
+ android:layout_gravity="center"
+ android:textAlignment="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textIsSelectable="false"
+ android:textStyle="bold|normal" />
+ </LinearLayout>
+
+ <ProgressBar
+ android:id="@+id/weather_map_progress"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:indeterminateBehavior="repeat"
+ android:indeterminateDuration="3500"
+ android:indeterminateOnly="true"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:id="@+id/weather_map_country_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:layout_height="wrap_content" >
+ <TextView
+ android:id="@+id/weather_map_country"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Country"
+ android:layout_gravity="center"
+ android:textAlignment="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textIsSelectable="false"
+ android:textStyle="bold|normal" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <fragment
+ android:id="@+id/weather_map_fragment_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_citycountry_container"
+ android:layout_above="@+id/weather_map_buttons_container" />
+
+ <LinearLayout
+ android:id="@+id/weather_map_buttons_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:orientation="horizontal"
+ android:baselineAligned="false" >
+ </LinearLayout>
+
+</RelativeLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:baselineAligned="false" >
+
+ <LinearLayout
+ android:id="@+id/weather_map_button_savelocation_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:layout_height="wrap_content">
+ <Button
+ android:id="@+id/weather_map_button_savelocation"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:onClick="onClickSaveLocation"
+ android:textAlignment="center"
+ android:text="@string/weather_map_button_savelocation" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/weather_map_button_getlocation_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:layout_height="wrap_content" >
+ <Button
+ android:id="@+id/weather_map_button_getlocation"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:onClick="onClickGetLocation"
+ android:textAlignment="center"
+ android:enabled="false"
+ android:text="@string/weather_map_button_getlocation" />
+ </LinearLayout>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
+
+ <ProgressBar
+ android:id="@+id/weather_map_progressbar"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:indeterminateBehavior="repeat"
+ android:indeterminateDuration="3500"
+ android:indeterminateOnly="true"
+ android:visibility="visible" />
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/weather_specific"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ tools:context="de.example.exampletdd.SpecificActivity"
+ tools:ignore="MergeRootFrame" >
+
+
+ <fragment
+ android:id="@+id/specific_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ class="de.example.exampletdd.fragment.specific.SpecificFragment" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/weather_specific_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <!-- TODO: align start/end humidity-rain wind-clouds -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="fill_vertical|center_horizontal"
+ android:orientation="vertical" >
+
+ <!-- TODO: http://developer.android.com/guide/topics/manifest/supports-screens-element.html -->
+ <!-- TODO: supporting multiple layouts/languages http://developer.android.com/guide/practices/screens_support.html -->
+ <!-- TODO: Should I use RelativeLayout for long texts (I18N) and RTL/LTR UI?
+ With long texts, many times, text will not fit... The same for WP8 :/ -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:layout_gravity="top|center"
+ android:padding="50dp"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/weather_specific_picture"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/icon_weather_description"
+ android:scaleType="fitCenter"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:src="@drawable/weather_showers" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/weather_specific_temp_max"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="10dp"
+ android:paddingStart="20dp"
+ android:singleLine="true"
+ android:text="55ºC"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/weather_specific_temp_min"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="textStart"
+ android:paddingEnd="10dp"
+ android:paddingStart="20dp"
+ android:singleLine="true"
+ android:text="25ºC"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="normal" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:padding="25dp"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/weather_specific_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="Light rain"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:baselineAligned="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="horizontal" >
+ <!-- Humidity -->
+ <TextView
+ android:id="@+id/weather_specific_humidity"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:layout_margin="5dp"
+ android:gravity="start"
+ android:text="@string/text_field_humidity"
+ android:textAlignment="textStart"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textStyle="bold" />
+
+ <!-- Humidity Value-->
+ <TextView
+ android:id="@+id/weather_specific_humidity_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="83"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Humidity Units-->
+ <TextView
+ android:id="@+id/weather_specific_humidity_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="%"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:orientation="horizontal" >
+ <!-- Rain -->
+ <TextView
+ android:id="@+id/weather_specific_rain"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_rain"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Rain Value-->
+ <TextView
+ android:id="@+id/weather_specific_rain_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="1.24"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Rain Units -->
+ <TextView
+ android:id="@+id/weather_specific_rain_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" mm 3h"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+ </LinearLayout>
+
+
+ <LinearLayout
+ android:baselineAligned="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="horizontal" >
+
+ <!-- Wind -->
+ <TextView
+ android:id="@+id/weather_specific_wind"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_wind"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Wind Value-->
+ <TextView
+ android:id="@+id/weather_specific_wind_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="6.36"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Wind Units -->
+ <TextView
+ android:id="@+id/weather_specific_wind_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" m/s"
+ android:layout_gravity="start"
+ android:gravity="start"
+ android:textAlignment="textStart"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:orientation="horizontal" >
+ <!-- Clouds -->
+ <TextView
+ android:id="@+id/weather_specific_clouds"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_clouds"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Clouds Value-->
+ <TextView
+ android:id="@+id/weather_specific_clouds_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="6.36"
+ android:layout_gravity="end"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Clouds Units -->
+ <TextView
+ android:id="@+id/weather_specific_clouds_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="%"
+ android:layout_gravity="end"
+ android:gravity="end"
+ android:textAlignment="textEnd"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center"
+ android:orientation="horizontal" >
+
+ <!-- Pressure -->
+ <TextView
+ android:id="@+id/weather_specific_pressure"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_field_pressure"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:layout_margin="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+
+ <!-- Pressure Value-->
+ <TextView
+ android:id="@+id/weather_specific_pressure_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="1036.05"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="normal" />
+
+ <!-- Pressure Units-->
+ <TextView
+ android:id="@+id/weather_specific_pressure_units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" hpa"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:textAlignment="center"
+ android:layout_marginTop="5dp"
+ android:layout_marginBottom="5dp"
+ android:layout_marginEnd="5dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <HorizontalScrollView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|start"
+ android:layout_margin="10dp"
+ android:fadingEdge="none"
+ android:scrollbars="horizontal|none" >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:fadingEdge="none"
+ android:orientation="horizontal"
+ android:scrollbarAlwaysDrawVerticalTrack="false"
+ android:scrollbars="none" >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp"
+ android:orientation="vertical" >
+
+ <!-- Time of day -->
+ <TextView
+ android:id="@+id/weather_specific_morn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="MORNING"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textAlignment="center"
+ android:layout_gravity="top|center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <!-- Temperature -->
+ <TextView
+ android:id="@+id/weather_specific_morn_temperature"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="55ºC"
+ android:textAlignment="center"
+ android:layout_gravity="bottom|center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <!-- Time of day -->
+ <TextView
+ android:id="@+id/weather_specific_day"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="DAY"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textAlignment="center"
+ android:layout_gravity="top|center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <!-- Temperature -->
+ <TextView
+ android:id="@+id/weather_specific_day_temperature"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="55ºC"
+ android:textAlignment="center"
+ android:layout_gravity="bottom|center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp"
+ android:orientation="vertical" >
+
+ <!-- Time of day -->
+ <TextView
+ android:id="@+id/weather_specific_eve"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="EVENING"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textAlignment="center"
+ android:layout_gravity="top|center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <!-- Temperature -->
+ <TextView
+ android:id="@+id/weather_specific_eve_temperature"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="55ºC"
+ android:textAlignment="center"
+ android:layout_gravity="bottom|center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp"
+ android:orientation="vertical" >
+
+ <!-- Time of day -->
+ <TextView
+ android:id="@+id/weather_specific_night"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="NIGHT"
+ android:textColor="@color/weather_time_of_day_color_title"
+ android:textAlignment="center"
+ android:layout_gravity="top|center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <!-- Temperature -->
+ <TextView
+ android:id="@+id/weather_specific_night_temperature"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="55ºC"
+ android:textAlignment="center"
+ android:layout_gravity="bottom|center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold" />
+ </LinearLayout>
+ </LinearLayout>
+ </HorizontalScrollView>
+ </LinearLayout>
+</ScrollView>
--- /dev/null
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="de.example.exampletdd.MainActivity" >
+
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never"
+ android:title="@string/weather_preferences_action_settings"/>
+
+</menu>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+
+ <item
+ android:id="@+id/weather_menu_settings"
+ android:menuCategory="system"
+ android:title="@string/weather_preferences_action_settings"
+ android:titleCondensed="@string/weather_preferences_action_settings"
+ android:checked="false"
+ android:visible="true"
+ android:checkable="false"
+ android:enabled="true"
+ android:icon="@drawable/ic_action_settings"
+ android:showAsAction="ifRoom">
+ </item>
+ <item
+ android:id="@+id/weather_menu_map"
+ android:icon="@drawable/ic_action_map"
+ android:showAsAction="ifRoom"
+ android:visible="true"
+ android:checkable="false"
+ android:enabled="true"
+ android:checked="false"
+ android:title="@string/weather_map_action_map"
+ android:titleCondensed="@string/weather_map_action_map">
+ </item>
+
+
+</menu>
--- /dev/null
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
--- /dev/null
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="widget_margin">0dp</dimen>
+</resources>
--- /dev/null
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
--- /dev/null
+<resources>
+
+ <!--
+ Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
+ -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string-array name="weather_preferences_day_forecast">
+ <item>5</item>
+ <item>10</item>
+ <item>14</item>
+ </string-array>
+ <string-array name="weather_preferences_day_forecast_human_value">
+ <item>5 day forecast</item>
+ <item>10 day forecast</item>
+ <item>14 day forecast</item>
+ </string-array>
+ <string-array name="weather_preferences_update_time_rate">
+ <item>900</item>
+ <item>1800</item>
+ <item>3600</item>
+ <item>43200</item>
+ <item>86400</item>
+ </string-array>
+ <string-array name="weather_preferences_update_time_rate_human_value">
+ <item>fifteen minutes</item>
+ <item>half hour</item>
+ <item>one hour</item>
+ <item>half day</item>
+ <item>one day</item>
+ </string-array>
+ <string-array name="weather_preferences_refresh_interval">
+ <item>300000</item>
+ <item>900000</item>
+ <item>1800000</item>
+ <item>3600000</item>
+ <item>7200000</item>
+ <item>43200000</item>
+ <item>86400000</item>
+ </string-array>
+ <string-array name="weather_preferences_refresh_interval_human_value">
+ <item>five minutes</item>
+ <item>fifteen minutes</item>
+ <item>half hour</item>
+ <item>one hour</item>
+ <item>two hours</item>
+ <item>half day</item>
+ <item>one day</item>
+ </string-array>
+ <string-array name="weather_preferences_temperature">
+ <item>@string/weather_preferences_temperature_celsius</item>
+ <item>@string/weather_preferences_temperature_fahrenheit</item>
+ <item>@string/weather_preferences_temperature_kelvin</item>
+ </string-array>
+ <string-array name="weather_preferences_temperature_human_value">
+ <item>@string/weather_preferences_temperature_celsius_human_value</item>
+ <item>@string/weather_preferences_temperature_fahrenheit_human_value</item>
+ <item>@string/weather_preferences_temperature_kelvin_human_value</item>
+ </string-array>
+ <string-array name="weather_preferences_wind">
+ <item>@string/weather_preferences_wind_meters</item>
+ <item>@string/weather_preferences_wind_miles</item>
+ </string-array>
+ <string-array name="weather_preferences_wind_human_value">
+ <item>@string/weather_preferences_wind_human_value_meters</item>
+ <item>@string/weather_preferences_wind_human_value_miles</item>
+ </string-array>
+ <string-array name="weather_preferences_pressure">
+ <item>@string/weather_preferences_pressure_pascal</item>
+ <item>@string/weather_preferences_pressure_standard_atm</item>
+ </string-array>
+ <string-array name="weather_preferences_pressure_human_value">
+ <item>@string/weather_preferences_pressure_human_value_pascal</item>
+ <item>@string/weather_preferences_pressure_human_value_standard_atm</item>
+ </string-array>
+</resources>
--- /dev/null
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="widget_margin">8dp</dimen>
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <string name="app_name">Weather Information</string>
+ <string name="icon_weather_description">Icon weather</string>
+
+
+ <!-- Activities Current, Overview and Specific -->
+ <string name="text_field_sun_rise">SUN RISE</string>
+ <string name="text_field_sun_set">SUN SET</string>
+ <string name="text_field_feels_like">FEELS LIKE</string>
+ <string name="text_field_clouds">CLOUDS</string>
+ <string name="text_field_rain">RAIN</string>
+ <string name="text_field_wind">WIND</string>
+ <string name="text_field_snow">SNOW</string>
+ <string name="text_field_pressure">PRESSURE</string>
+ <string name="text_field_humidity">HUMIDITY</string>
+ <string name="text_units_mm3h">mm 3h</string>
+ <string name="text_units_percent">%</string>
+ <string name="text_field_remote_error">No data available</string>
+
+
+ <!-- Preferences Acitivity -->
+ <string name="weather_preferences_action_settings">Settings</string>
+ <string name="weather_preferences_units">Units</string>
+ <string name="weather_preferences_temperature_key">weather_preferences_temperature</string>
+ <string name="weather_preferences_temperature">Temperature</string>
+ <string name="weather_preferences_temperature_celsius">ºC</string>
+ <string name="weather_preferences_temperature_fahrenheit">ºF</string>
+ <string name="weather_preferences_temperature_kelvin">K</string>
+ <string name="weather_preferences_temperature_celsius_human_value">celsius</string>
+ <string name="weather_preferences_temperature_fahrenheit_human_value">fahrenheit</string>
+ <string name="weather_preferences_temperature_kelvin_human_value">kelvin</string>
+ <string name="weather_preferences_notifications">Notifications</string>
+ <string name="weather_preferences_notifications_switch_off_summary">Disabled</string>
+ <string name="weather_preferences_notifications_switch_on_summary">Enabled</string>
+ <string name="weather_preferences_notifications_switch_off">OFF</string>
+ <string name="weather_preferences_notifications_switch_on">ON</string>
+ <string name="weather_preferences_notifications_switch_key">weather_preferences_notifications_switch</string>
+ <string name="weather_preferences_update_time_rate_key">weather_preferences_update_time_rate</string>
+ <string name="weather_preferences_update_time_rate">Update time rate</string>
+ <string name="weather_preferences_day_forecast_key">weather_preferences_day_forecast</string>
+ <string name="weather_preferences_day_forecast">Forecast days number</string>
+ <string name="weather_preferences_refresh_interval_key">weather_preferences_refresh_interval</string>
+ <string name="weather_preferences_refresh_interval">Refresh interval</string>
+ <string name="weather_preferences_wind_key">weather_preferences_wind</string>
+ <string name="weather_preferences_wind">Wind</string>
+ <string name="weather_preferences_wind_meters">m/s</string>
+ <string name="weather_preferences_wind_miles">mph</string>
+ <string name="weather_preferences_wind_human_value_meters">meter per second</string>
+ <string name="weather_preferences_wind_human_value_miles">miles per hour</string>
+ <string name="weather_preferences_pressure_key">weather_preferences_pressure</string>
+ <string name="weather_preferences_pressure">Pressure</string>
+ <string name="weather_preferences_pressure_pascal">hpa</string>
+ <string name="weather_preferences_pressure_standard_atm">atm</string>
+ <string name="weather_preferences_pressure_human_value_pascal">pascal</string>
+ <string name="weather_preferences_pressure_human_value_standard_atm">standard atmosphere</string>
+
+
+ <!-- Widget Preferences Activity -->
+ <string name="widget_preferences_action_settings">Settings</string>
+ <string name="widget_preferences_button_refresh">Refresh</string>
+ <string name="widget_preferences_country">Country</string>
+ <string name="widget_preferences_units">Units</string>
+ <string name="widget_preferences_temperature_key">widget_preferences_temperature</string>
+ <string name="widget_preferences_country_switch_key">widget_preferences_countries_switch</string>
+ <string name="widget_preferences_country_switch_off_summary">Hide</string>
+ <string name="widget_preferences_country_switch_on_summary">Show</string>
+ <string name="widget_preferences_country_switch_off">OFF</string>
+ <string name="widget_preferences_country_switch_on">ON</string>
+
+
+ <!-- Map Activity -->
+ <string name="weather_map_action_map">Select Location</string>
+ <string name="city_not_found">city not found</string>
+ <string name="country_not_found">country not found</string>
+ <string name="progress_dialog_generic_message">Please wait…</string>
+ <string name="weather_map_button_savelocation">Save Location</string>
+ <string name="weather_map_button_getlocation">Get Location</string>
+
+
+ <!-- DO NOT TRANSLATE -->
+ <string name="uri_api_weather_today">http://api.openweathermap.org/data/{0}/weather?lat={1}&lon={2}&cnt=1</string>
+ <string name="uri_api_weather_forecast">http://api.openweathermap.org/data/{0}/forecast/daily?lat={1}&lon={2}&cnt={3}&mode=json</string>
+ <string name="api_version">2.5</string>
+</resources>
--- /dev/null
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="android:Theme.Holo">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+
+ <color name="weather_time_of_day_color_title">#48aed4</color>
+ <color name="widget_background_holo_dark">#ff000000</color>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
+ <PreferenceCategory android:title="@string/widget_preferences_country">
+ <SwitchPreference android:key="@string/widget_preferences_country_switch_key"
+ android:summaryOn="@string/widget_preferences_country_switch_on_summary"
+ android:summaryOff="@string/widget_preferences_country_switch_off_summary"
+ android:switchTextOff="@string/widget_preferences_country_switch_off"
+ android:switchTextOn="@string/widget_preferences_country_switch_on"
+ android:selectable="true"
+ android:enabled="true"
+ android:defaultValue="@string/widget_preferences_country_switch_off"
+ android:disableDependentsState="false"
+ android:persistent="true"/>
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/widget_preferences_units">
+ <ListPreference android:key="@string/widget_preferences_temperature_key"
+ android:title="@string/weather_preferences_temperature"
+ android:summary="@string/weather_preferences_temperature_celsius_human_value"
+ android:entries="@array/weather_preferences_temperature_human_value"
+ android:entryValues="@array/weather_preferences_temperature"
+ android:selectable="true"
+ android:persistent="true"
+ android:defaultValue="@string/weather_preferences_temperature_celsius" />
+ </PreferenceCategory>
+
+</PreferenceScreen>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="180dp"
+ android:minHeight="40dp"
+ android:minResizeWidth="180dp"
+ android:minResizeHeight="40dp"
+ android:resizeMode="none"
+ android:previewImage="@drawable/ic_launcher"
+ android:initialLayout="@layout/appwidget_error"
+ android:configure="de.example.exampletdd.widget.WidgetConfigure"
+ android:widgetCategory="home_screen|keyguard"
+ android:updatePeriodMillis="3600000">
+</appwidget-provider>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
+ <ListPreference android:key="@string/weather_preferences_day_forecast_key"
+ android:title="@string/weather_preferences_day_forecast"
+ android:entries="@array/weather_preferences_day_forecast_human_value"
+ android:entryValues="@array/weather_preferences_day_forecast"
+ android:selectable="true"
+ android:persistent="true"
+ android:defaultValue="14"
+ android:summary="14 day forecast" />
+ <ListPreference android:key="@string/weather_preferences_refresh_interval_key"
+ android:title="@string/weather_preferences_refresh_interval"
+ android:entries="@array/weather_preferences_refresh_interval_human_value"
+ android:entryValues="@array/weather_preferences_refresh_interval"
+ android:selectable="true"
+ android:persistent="true"
+ android:defaultValue="300000"
+ android:summary="five minutes" />
+ <PreferenceCategory android:title="@string/weather_preferences_units">
+ <ListPreference android:key="@string/weather_preferences_temperature_key"
+ android:title="@string/weather_preferences_temperature"
+ android:summary="@string/weather_preferences_temperature_celsius_human_value"
+ android:entries="@array/weather_preferences_temperature_human_value"
+ android:entryValues="@array/weather_preferences_temperature"
+ android:selectable="true"
+ android:persistent="true"
+ android:defaultValue="@string/weather_preferences_temperature_celsius" />
+ <ListPreference android:key="@string/weather_preferences_wind_key"
+ android:entryValues="@array/weather_preferences_wind"
+ android:entries="@array/weather_preferences_wind_human_value"
+ android:summary="@string/weather_preferences_wind_human_value_meters"
+ android:selectable="true"
+ android:persistent="true"
+ android:defaultValue="@string/weather_preferences_wind_meters"
+ android:title="@string/weather_preferences_wind"/>
+ <ListPreference android:key="@string/weather_preferences_pressure_key"
+ android:entryValues="@array/weather_preferences_pressure"
+ android:entries="@array/weather_preferences_pressure_human_value"
+ android:summary="@string/weather_preferences_pressure_human_value_pascal"
+ android:selectable="true"
+ android:persistent="true"
+ android:defaultValue="@string/weather_preferences_pressure_pascal"
+ android:title="@string/weather_preferences_pressure"/>
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/weather_preferences_notifications">
+ <SwitchPreference android:key="@string/weather_preferences_notifications_switch_key"
+ android:summaryOn="@string/weather_preferences_notifications_switch_on_summary"
+ android:summaryOff="@string/weather_preferences_notifications_switch_off_summary"
+ android:switchTextOff="@string/weather_preferences_notifications_switch_off"
+ android:switchTextOn="@string/weather_preferences_notifications_switch_on"
+ android:selectable="true"
+ android:enabled="true"
+ android:defaultValue="@string/weather_preferences_notifications_switch_off"
+ android:disableDependentsState="false"
+ android:persistent="true"/>
+ <ListPreference android:key="@string/weather_preferences_update_time_rate_key"
+ android:entries="@array/weather_preferences_update_time_rate_human_value"
+ android:entryValues="@array/weather_preferences_update_time_rate"
+ android:title="@string/weather_preferences_update_time_rate"
+ android:defaultValue="900"
+ android:persistent="true"
+ android:selectable="true"
+ android:summary="fifteen minutes"
+ android:dependency="@string/weather_preferences_notifications_switch_key"/>
+ </PreferenceCategory>
+</PreferenceScreen>
--- /dev/null
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.12.2'
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+++ /dev/null
-/com
-/de
-/.gitignore
--- /dev/null
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
--- /dev/null
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
--- /dev/null
+@if "%DEBUG%" == "" @echo off\r
+@rem ##########################################################################\r
+@rem\r
+@rem Gradle startup script for Windows\r
+@rem\r
+@rem ##########################################################################\r
+\r
+@rem Set local scope for the variables with windows NT shell\r
+if "%OS%"=="Windows_NT" setlocal\r
+\r
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
+set DEFAULT_JVM_OPTS=\r
+\r
+set DIRNAME=%~dp0\r
+if "%DIRNAME%" == "" set DIRNAME=.\r
+set APP_BASE_NAME=%~n0\r
+set APP_HOME=%DIRNAME%\r
+\r
+@rem Find java.exe\r
+if defined JAVA_HOME goto findJavaFromJavaHome\r
+\r
+set JAVA_EXE=java.exe\r
+%JAVA_EXE% -version >NUL 2>&1\r
+if "%ERRORLEVEL%" == "0" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:findJavaFromJavaHome\r
+set JAVA_HOME=%JAVA_HOME:"=%\r
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
+\r
+if exist "%JAVA_EXE%" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:init\r
+@rem Get command-line arguments, handling Windowz variants\r
+\r
+if not "%OS%" == "Windows_NT" goto win9xME_args\r
+if "%@eval[2+2]" == "4" goto 4NT_args\r
+\r
+:win9xME_args\r
+@rem Slurp the command line arguments.\r
+set CMD_LINE_ARGS=\r
+set _SKIP=2\r
+\r
+:win9xME_args_slurp\r
+if "x%~1" == "x" goto execute\r
+\r
+set CMD_LINE_ARGS=%*\r
+goto execute\r
+\r
+:4NT_args\r
+@rem Get arguments from the 4NT Shell from JP Software\r
+set CMD_LINE_ARGS=%$\r
+\r
+:execute\r
+@rem Setup the command line\r
+\r
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
+\r
+@rem Execute Gradle\r
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r
+\r
+:end\r
+@rem End local scope for the variables with windows NT shell\r
+if "%ERRORLEVEL%"=="0" goto mainEnd\r
+\r
+:fail\r
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
+rem the _cmd.exe /c_ return code!\r
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
+exit /b 1\r
+\r
+:mainEnd\r
+if "%OS%"=="Windows_NT" endlocal\r
+\r
+:omega\r
--- /dev/null
+ECLIPSE ANDROID PROJECT IMPORT SUMMARY
+======================================
+
+Manifest Merging:
+-----------------
+Your project uses libraries that provide manifests, and your Eclipse
+project did not explicitly turn on manifest merging. In Android Gradle
+projects, manifests are always merged (meaning that contents from your
+libraries' manifests will be merged into the app manifest. If you had
+manually copied contents from library manifests into your app manifest
+you may need to remove these for the app to build correctly.
+
+Ignored Files:
+--------------
+The following files were *not* copied into the new Gradle project; you
+should evaluate whether these are still needed in your project and if
+so manually move them:
+
+* ic_launcher-web.png
+* proguard-project.txt
+* tests/
+* tests/gen/
+* tests/gen/de/
+* tests/gen/de/example/
+* tests/gen/de/example/exampletdd/
+* tests/gen/de/example/exampletdd/test/
+* tests/gen/de/example/exampletdd/test/BuildConfig.java
+* tests/gen/de/example/exampletdd/test/R.java
+* tests/proguard-project.txt
+* tests/project.properties
+
+Replaced Jars with Dependencies:
+--------------------------------
+The importer recognized the following .jar files as third party
+libraries and replaced them with Gradle dependencies instead. This has
+the advantage that more explicit version information is known, and the
+libraries can be updated automatically. However, it is possible that
+the .jar file in your project was of an older version than the
+dependency we picked, which could render the project not compileable.
+You can disable the jar replacement in the import wizard and try again:
+
+android-support-v4.jar => com.android.support:support-v4:+
+
+Replaced Libraries with Dependencies:
+-------------------------------------
+The importer recognized the following library projects as third party
+libraries and replaced them with Gradle dependencies instead. This has
+the advantage that more explicit version information is known, and the
+libraries can be updated automatically. However, it is possible that
+the source files in your project were of an older version than the
+dependency we picked, which could render the project not compileable.
+You can disable the library replacement in the import wizard and try
+again:
+
+google-play-services_lib => [com.google.android.gms:play-services:+]
+
+Moved Files:
+------------
+Android Gradle projects use a different directory structure than ADT
+Eclipse projects. Here's how the projects were restructured:
+
+* AndroidManifest.xml => app/src/main/AndroidManifest.xml
+* libs/jackson-core-2.3.3.jar => app/libs/jackson-core-2.3.3.jar
+* lint.xml => app/lint.xml
+* res/ => app/src/main/res/
+* src/ => app/src/main/java/
+* tests/res/ => app/src/androidTest/res/
+* tests/src/ => app/src/androidTest/java/
+
+Next Steps:
+-----------
+You can now build the project. The Gradle project needs network
+connectivity to download dependencies.
+
+Bugs:
+-----
+If for some reason your project does not build, and you determine that
+it is due to a bug or limitation of the Eclipse to Gradle importer,
+please file a bug at http://b.android.com with category
+Component-Tools.
+
+(This import summary is for your information only, and can be deleted
+after import once you are satisfied with the results.)
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
-</lint>
\ No newline at end of file
+++ /dev/null
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
--keep class * extends java.util.ListResourceBundle {
- protected Object[][] getContents();
-}
-
--keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
- public static final *** NULL;
-}
-
--keepnames @com.google.android.gms.common.annotation.KeepName class *
--keepclassmembernames class * {
- @com.google.android.gms.common.annotation.KeepName *;
-}
-
--keepnames class * implements android.os.Parcelable {
- public static final ** CREATOR;
-}
+++ /dev/null
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-18
-android.library.reference.1=../google-play-services_lib
-android.library=false
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<set>
- <translate xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromYDelta="100%"
- android:toYDelta="0%"
- android:interpolator="@android:anim/decelerate_interpolator"
- android:duration="@android:integer/config_mediumAnimTime"/>
-</set>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<set>
- <translate xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromYDelta="0%"
- android:toYDelta="-100%"
- android:interpolator="@android:anim/accelerate_interpolator"
- android:duration="@android:integer/config_mediumAnimTime"/>
-</set>
+++ /dev/null
-<?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.OverviewFragment" />
-
- <fragment
- android:id="@+id/weather_specific_fragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- class="de.example.exampletdd.fragment.specific.SpecificFragment" />
-
-</FrameLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/weather_appwidget"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="fill"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:background="@color/widget_background_holo_dark"
- android:padding="@dimen/widget_margin" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:padding="4dp"
- android:orientation="vertical" >
-
- <ImageView
- android:id="@+id/weather_appwidget_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:contentDescription="@string/icon_weather_description"
- android:orientation="vertical"
- android:src="@drawable/weather_showers" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:padding="4dp"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/weather_appwidget_temperature_max"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="12ºC"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_appwidget_temperature_min"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="5ºC"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="normal" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:orientation="vertical"
- android:padding="4dp" >
-
- <TextView
- android:id="@+id/weather_appwidget_city"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="Morata de Tajuña"
- android:textAlignment="center"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_appwidget_country"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="Spain"
- android:textAlignment="center"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
- </LinearLayout>
-
-
-
-
-
-</LinearLayout>
+++ /dev/null
-<?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:layout_gravity="fill_vertical|fill_horizontal" >
-
- <LinearLayout android:id="@+id/weather_appwidget_configure_preferences"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_gravity="center"
- android:orientation="horizontal" >
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/weather_appwidget_configure_preferences"
- android:layout_centerHorizontal="true"
- android:layout_gravity="center"
- android:gravity="center"
- android:baselineAligned="false"
- android:orientation="horizontal" >
-
- <Button
- android:id="@+id/weather_appwidget_configure_refresh_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:textAlignment="center"
- android:text="@string/widget_preferences_button_refresh" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:layout_gravity="center"
- android:gravity="center"
- android:baselineAligned="false"
- android:orientation="horizontal" >
-
- <Button
- android:id="@+id/weather_appwidget_configure_save_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:textAlignment="center"
- android:text="@android:string/ok" />
- </LinearLayout>
-
-</RelativeLayout>
-
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/weather_appwidget_error"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="fill"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:background="@color/widget_background_holo_dark"
- android:padding="@dimen/widget_margin" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:padding="4dp"
- android:orientation="vertical" >
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:contentDescription="@string/icon_weather_description"
- android:orientation="vertical"
- android:src="@drawable/ic_launcher" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:orientation="vertical"
- android:padding="4dp" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/text_field_remote_error"
- android:textAlignment="center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
- </LinearLayout>
-
-
-
-
-
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:padding="4dip"
- android:gravity="center_horizontal"
- android:layout_width="match_parent" android:layout_height="match_parent">
-
- <android.support.v4.view.ViewPager
- android:id="@+id/pager"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_weight="1">
- </android.support.v4.view.ViewPager>
-
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="fill"
- android:baselineAligned="false"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:orientation="vertical" >
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:contentDescription="@string/icon_weather_description"
- android:orientation="vertical"
- android:src="@drawable/ic_launcher" />
- </LinearLayout>
-
-
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:layout_weight="2"
- android:gravity="center"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/weather_notification_city"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="Morata de Tajuña"
- android:textAlignment="center"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_notification_country"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="Spain"
- android:textAlignment="center"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:gravity="center"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/weather_notification_temperature_max"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="12ºC"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_notification_temperature_min"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="5ºC"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="normal" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:orientation="vertical" >
-
- <ImageView
- android:id="@+id/weather_notification_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:contentDescription="@string/icon_weather_description"
- android:orientation="vertical"
- android:src="@drawable/ic_launcher" />
-
- </LinearLayout>
-
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/weather_current_fragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center">
-
- <!-- TODO: align start/end feels like-snow humidity-rain wind-clouds -->
- <LinearLayout android:id="@+id/weather_current_data_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="fill_vertical|center_horizontal"
- android:orientation="vertical" >
-
- <!-- TODO: http://developer.android.com/guide/topics/manifest/supports-screens-element.html -->
- <!-- TODO: supporting multiple layouts/languages http://developer.android.com/guide/practices/screens_support.html -->
- <!-- TODO: Should I use RelativeLayout for long texts (I18N) and RTL/LTR UI?
- With long texts, many times, text will not fit... The same for WP8 :/ -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:layout_gravity="top|center"
- android:padding="50dp"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@+id/weather_current_picture"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:contentDescription="@string/icon_weather_description"
- android:scaleType="fitCenter"
- android:gravity="center"
- android:layout_gravity="center"
- android:src="@drawable/weather_showers" />
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/weather_current_temp_max"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="10dp"
- android:paddingStart="20dp"
- android:singleLine="true"
- android:text="55ºC"
- android:textAlignment="textStart"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_current_temp_min"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAlignment="textStart"
- android:paddingEnd="10dp"
- android:paddingStart="20dp"
- android:singleLine="true"
- android:text="25ºC"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="normal" />
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:padding="25dp"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <TextView
- android:id="@+id/weather_current_description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="Light rain"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textStyle="bold" />
- </LinearLayout>
-
- <LinearLayout
- android:baselineAligned="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|fill_horizontal"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="horizontal" >
- <!-- Feels like -->
- <TextView
- android:id="@+id/weather_current_feelslike"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:layout_margin="5dp"
- android:gravity="start"
- android:text="@string/text_field_feels_like"
- android:textAlignment="textStart"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textStyle="bold" />
-
- <!-- Feels like Value-->
- <TextView
- android:id="@+id/weather_current_feelslike_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="83"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Feels like Units-->
- <TextView
- android:id="@+id/weather_current_feelslike_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="ºC"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:orientation="horizontal" >
- <!-- Snow -->
- <TextView
- android:id="@+id/weather_current_snow"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_snow"
- android:gravity="end"
- android:layout_gravity="end"
- android:textAlignment="textEnd"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Snow Value-->
- <TextView
- android:id="@+id/weather_current_snow_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="1.22"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Snow Units -->
- <TextView
- android:id="@+id/weather_current_snow_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=" mm 3h"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:baselineAligned="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|fill_horizontal"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="horizontal" >
- <!-- Humidity -->
- <TextView
- android:id="@+id/weather_current_humidity"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:layout_margin="5dp"
- android:gravity="start"
- android:text="@string/text_field_humidity"
- android:textAlignment="textStart"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textStyle="bold" />
-
- <!-- Humidity Value-->
- <TextView
- android:id="@+id/weather_current_humidity_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="83"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Humidity Units-->
- <TextView
- android:id="@+id/weather_current_humidity_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="%"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:orientation="horizontal" >
- <!-- Rain -->
- <TextView
- android:id="@+id/weather_current_rain"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_rain"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Rain Value-->
- <TextView
- android:id="@+id/weather_current_rain_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="1.24"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Rain Units -->
- <TextView
- android:id="@+id/weather_current_rain_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=" mm 3h"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:baselineAligned="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|fill_horizontal"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="horizontal" >
- <!-- Wind -->
- <TextView
- android:id="@+id/weather_current_wind"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_wind"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Wind Value-->
- <TextView
- android:id="@+id/weather_current_wind_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="6.36"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Wind Units -->
- <TextView
- android:id="@+id/weather_current_wind_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=" m/s"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:orientation="horizontal" >
- <!-- Clouds -->
- <TextView
- android:id="@+id/weather_current_clouds"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_clouds"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Clouds Value-->
- <TextView
- android:id="@+id/weather_current_clouds_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="6.36"
- android:layout_gravity="end"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Clouds Units -->
- <TextView
- android:id="@+id/weather_current_clouds_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="%"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <!-- Pressure -->
- <TextView
- android:id="@+id/weather_current_pressure"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_pressure"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Pressure Value-->
- <TextView
- android:id="@+id/weather_current_pressure_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="1036.05"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Pressure Units-->
- <TextView
- android:id="@+id/weather_current_pressure_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=" hpa"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <!-- Sun rise -->
- <TextView
- android:id="@+id/weather_current_sunrise"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_sun_rise"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Sun rise Value-->
- <TextView
- android:id="@+id/weather_current_sunrise_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="2014.04.20 10:29:33"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <!-- Sun rise -->
- <TextView
- android:id="@+id/weather_current_sunset"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_sun_set"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Sun rise Value-->
- <TextView
- android:id="@+id/weather_current_sunset_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="2014.04.20 10:29:33"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
- </LinearLayout>
- </LinearLayout>
-
- <ProgressBar
- android:id="@+id/weather_current_progressbar"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:visibility="gone"
- style="?android:attr/progressBarStyleLarge" />
-
- <TextView
- android:id="@+id/weather_current_error_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/text_field_remote_error"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:visibility="gone" />
-
- </FrameLayout>
-</ScrollView>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:baselineAligned="false"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_horizontal"
- android:orientation="horizontal"
- android:padding="5dp" >
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/weather_main_entry_date_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="SUN"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_main_entry_date_number"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="APR 23"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- </LinearLayout>
-
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/weather_main_entry_temperature_max"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="12ºC"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_main_entry_temperature_min"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="5ºC"
- android:textAlignment="center"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textStyle="normal" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:gravity="center"
- android:orientation="vertical" >
-
- <ImageView
- android:id="@+id/weather_main_entry_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:contentDescription="@string/icon_weather_description"
- android:orientation="vertical"
- android:src="@drawable/ic_launcher" />
-
- </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
+++ /dev/null
-<?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="center"
- tools:context="de.example.exampletdd.MapActivity" >
-
- <LinearLayout
- android:id="@+id/weather_map_citycountry_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_alignParentStart="true" >
- <LinearLayout
- android:id="@+id/weather_map_city_container"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:gravity="center"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/weather_map_city"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="City"
- android:layout_gravity="center"
- android:textAlignment="center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textIsSelectable="false"
- android:textStyle="bold|normal" />
- </LinearLayout>
-
- <ProgressBar
- android:id="@+id/weather_map_progress"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:indeterminateBehavior="repeat"
- android:indeterminateDuration="3500"
- android:indeterminateOnly="true"
- android:visibility="gone" />
-
- <LinearLayout
- android:id="@+id/weather_map_country_container"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:gravity="center"
- android:layout_height="wrap_content" >
- <TextView
- android:id="@+id/weather_map_country"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Country"
- android:layout_gravity="center"
- android:textAlignment="center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textIsSelectable="false"
- android:textStyle="bold|normal" />
- </LinearLayout>
- </LinearLayout>
-
- <fragment
- android:id="@+id/weather_map_fragment_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_citycountry_container"
- android:layout_above="@+id/weather_map_buttons_container" />
-
- <LinearLayout
- android:id="@+id/weather_map_buttons_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentStart="true"
- android:orientation="horizontal"
- android:baselineAligned="false" >
- </LinearLayout>
-
-</RelativeLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:baselineAligned="false" >
-
- <LinearLayout
- android:id="@+id/weather_map_button_savelocation_container"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:gravity="center"
- android:layout_height="wrap_content">
- <Button
- android:id="@+id/weather_map_button_savelocation"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:onClick="onClickSaveLocation"
- android:textAlignment="center"
- android:text="@string/weather_map_button_savelocation" />
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/weather_map_button_getlocation_container"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:gravity="center"
- android:layout_height="wrap_content" >
- <Button
- android:id="@+id/weather_map_button_getlocation"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:onClick="onClickGetLocation"
- android:textAlignment="center"
- android:enabled="false"
- android:text="@string/weather_map_button_getlocation" />
- </LinearLayout>
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
-
- <ProgressBar
- android:id="@+id/weather_map_progressbar"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:indeterminateBehavior="repeat"
- android:indeterminateDuration="3500"
- android:indeterminateOnly="true"
- android:visibility="visible" />
-
-</LinearLayout>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/weather_specific"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical"
- tools:context="de.example.exampletdd.SpecificActivity"
- tools:ignore="MergeRootFrame" >
-
-
- <fragment
- android:id="@+id/specific_fragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- class="de.example.exampletdd.fragment.specific.SpecificFragment" />
-
-</LinearLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/weather_specific_fragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <!-- TODO: align start/end humidity-rain wind-clouds -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="fill_vertical|center_horizontal"
- android:orientation="vertical" >
-
- <!-- TODO: http://developer.android.com/guide/topics/manifest/supports-screens-element.html -->
- <!-- TODO: supporting multiple layouts/languages http://developer.android.com/guide/practices/screens_support.html -->
- <!-- TODO: Should I use RelativeLayout for long texts (I18N) and RTL/LTR UI?
- With long texts, many times, text will not fit... The same for WP8 :/ -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:layout_gravity="top|center"
- android:padding="50dp"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@+id/weather_specific_picture"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:contentDescription="@string/icon_weather_description"
- android:scaleType="fitCenter"
- android:gravity="center"
- android:layout_gravity="center"
- android:src="@drawable/weather_showers" />
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/weather_specific_temp_max"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="10dp"
- android:paddingStart="20dp"
- android:singleLine="true"
- android:text="55ºC"
- android:textAlignment="textStart"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/weather_specific_temp_min"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAlignment="textStart"
- android:paddingEnd="10dp"
- android:paddingStart="20dp"
- android:singleLine="true"
- android:text="25ºC"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="normal" />
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:padding="25dp"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <TextView
- android:id="@+id/weather_specific_description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="Light rain"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textStyle="bold" />
- </LinearLayout>
-
- <LinearLayout
- android:baselineAligned="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="horizontal" >
- <!-- Humidity -->
- <TextView
- android:id="@+id/weather_specific_humidity"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:layout_margin="5dp"
- android:gravity="start"
- android:text="@string/text_field_humidity"
- android:textAlignment="textStart"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textStyle="bold" />
-
- <!-- Humidity Value-->
- <TextView
- android:id="@+id/weather_specific_humidity_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="83"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Humidity Units-->
- <TextView
- android:id="@+id/weather_specific_humidity_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="%"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:orientation="horizontal" >
- <!-- Rain -->
- <TextView
- android:id="@+id/weather_specific_rain"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_rain"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Rain Value-->
- <TextView
- android:id="@+id/weather_specific_rain_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="1.24"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Rain Units -->
- <TextView
- android:id="@+id/weather_specific_rain_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=" mm 3h"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
- </LinearLayout>
-
-
- <LinearLayout
- android:baselineAligned="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:orientation="horizontal" >
-
- <!-- Wind -->
- <TextView
- android:id="@+id/weather_specific_wind"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_wind"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Wind Value-->
- <TextView
- android:id="@+id/weather_specific_wind_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="6.36"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Wind Units -->
- <TextView
- android:id="@+id/weather_specific_wind_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=" m/s"
- android:layout_gravity="start"
- android:gravity="start"
- android:textAlignment="textStart"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_gravity="center"
- android:layout_weight="1"
- android:orientation="horizontal" >
- <!-- Clouds -->
- <TextView
- android:id="@+id/weather_specific_clouds"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_clouds"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Clouds Value-->
- <TextView
- android:id="@+id/weather_specific_clouds_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="6.36"
- android:layout_gravity="end"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Clouds Units -->
- <TextView
- android:id="@+id/weather_specific_clouds_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="%"
- android:layout_gravity="end"
- android:gravity="end"
- android:textAlignment="textEnd"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center"
- android:orientation="horizontal" >
-
- <!-- Pressure -->
- <TextView
- android:id="@+id/weather_specific_pressure"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text_field_pressure"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:textColor="@color/weather_time_of_day_color_title"
- android:layout_margin="5dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
-
- <!-- Pressure Value-->
- <TextView
- android:id="@+id/weather_specific_pressure_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="1036.05"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="normal" />
-
- <!-- Pressure Units-->
- <TextView
- android:id="@+id/weather_specific_pressure_units"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text=" hpa"
- android:layout_gravity="center"
- android:gravity="center"
- android:textAlignment="center"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="5dp"
- android:layout_marginEnd="5dp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold" />
- </LinearLayout>
-
- <HorizontalScrollView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|start"
- android:layout_margin="10dp"
- android:fadingEdge="none"
- android:scrollbars="horizontal|none" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:fadingEdge="none"
- android:orientation="horizontal"
- android:scrollbarAlwaysDrawVerticalTrack="false"
- android:scrollbars="none" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:orientation="vertical" >
-
- <!-- Time of day -->
- <TextView
- android:id="@+id/weather_specific_morn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="MORNING"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textAlignment="center"
- android:layout_gravity="top|center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <!-- Temperature -->
- <TextView
- android:id="@+id/weather_specific_morn_temperature"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="55ºC"
- android:textAlignment="center"
- android:layout_gravity="bottom|center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <!-- Time of day -->
- <TextView
- android:id="@+id/weather_specific_day"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="DAY"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textAlignment="center"
- android:layout_gravity="top|center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <!-- Temperature -->
- <TextView
- android:id="@+id/weather_specific_day_temperature"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="55ºC"
- android:textAlignment="center"
- android:layout_gravity="bottom|center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:orientation="vertical" >
-
- <!-- Time of day -->
- <TextView
- android:id="@+id/weather_specific_eve"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="EVENING"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textAlignment="center"
- android:layout_gravity="top|center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <!-- Temperature -->
- <TextView
- android:id="@+id/weather_specific_eve_temperature"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="55ºC"
- android:textAlignment="center"
- android:layout_gravity="bottom|center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:orientation="vertical" >
-
- <!-- Time of day -->
- <TextView
- android:id="@+id/weather_specific_night"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="NIGHT"
- android:textColor="@color/weather_time_of_day_color_title"
- android:textAlignment="center"
- android:layout_gravity="top|center"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <!-- Temperature -->
- <TextView
- android:id="@+id/weather_specific_night_temperature"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="55ºC"
- android:textAlignment="center"
- android:layout_gravity="bottom|center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold" />
- </LinearLayout>
- </LinearLayout>
- </HorizontalScrollView>
- </LinearLayout>
-</ScrollView>
+++ /dev/null
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- tools:context="de.example.exampletdd.MainActivity" >
-
- <item
- android:id="@+id/action_settings"
- android:orderInCategory="100"
- android:showAsAction="never"
- android:title="@string/weather_preferences_action_settings"/>
-
-</menu>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
-
-
- <item
- android:id="@+id/weather_menu_settings"
- android:menuCategory="system"
- android:title="@string/weather_preferences_action_settings"
- android:titleCondensed="@string/weather_preferences_action_settings"
- android:checked="false"
- android:visible="true"
- android:checkable="false"
- android:enabled="true"
- android:icon="@drawable/ic_action_settings"
- android:showAsAction="ifRoom">
- </item>
- <item
- android:id="@+id/weather_menu_map"
- android:icon="@drawable/ic_action_map"
- android:showAsAction="ifRoom"
- android:visible="true"
- android:checkable="false"
- android:enabled="true"
- android:checked="false"
- android:title="@string/weather_map_action_map"
- android:titleCondensed="@string/weather_map_action_map">
- </item>
-
-
-</menu>
+++ /dev/null
-<resources>
-
- <!--
- Base application theme for API 11+. This theme completely replaces
- AppBaseTheme from res/values/styles.xml on API 11+ devices.
- -->
- <style name="AppBaseTheme" parent="android:Theme.Holo">
- <!-- API 11 theme customizations can go here. -->
- </style>
-
-</resources>
+++ /dev/null
-<resources>
-
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
- <dimen name="widget_margin">0dp</dimen>
-</resources>
+++ /dev/null
-<resources>
-
- <!--
- Base application theme for API 14+. This theme completely replaces
- AppBaseTheme from BOTH res/values/styles.xml and
- res/values-v11/styles.xml on API 14+ devices.
- -->
- <style name="AppBaseTheme" parent="android:Theme.Holo">
- <!-- API 14 theme customizations can go here. -->
- </style>
-
-</resources>
+++ /dev/null
-<resources>
-
- <!--
- Example customization of dimensions originally defined in res/values/dimens.xml
- (such as screen margins) for screens with more than 820dp of available width. This
- would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
- -->
- <dimen name="activity_horizontal_margin">64dp</dimen>
-
-</resources>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string-array name="weather_preferences_day_forecast">
- <item>5</item>
- <item>10</item>
- <item>14</item>
- </string-array>
- <string-array name="weather_preferences_day_forecast_human_value">
- <item>5 day forecast</item>
- <item>10 day forecast</item>
- <item>14 day forecast</item>
- </string-array>
- <string-array name="weather_preferences_update_time_rate">
- <item>900</item>
- <item>1800</item>
- <item>3600</item>
- <item>43200</item>
- <item>86400</item>
- </string-array>
- <string-array name="weather_preferences_update_time_rate_human_value">
- <item>fifteen minutes</item>
- <item>half hour</item>
- <item>one hour</item>
- <item>half day</item>
- <item>one day</item>
- </string-array>
- <string-array name="weather_preferences_refresh_interval">
- <item>300000</item>
- <item>900000</item>
- <item>1800000</item>
- <item>3600000</item>
- <item>7200000</item>
- <item>43200000</item>
- <item>86400000</item>
- </string-array>
- <string-array name="weather_preferences_refresh_interval_human_value">
- <item>five minutes</item>
- <item>fifteen minutes</item>
- <item>half hour</item>
- <item>one hour</item>
- <item>two hours</item>
- <item>half day</item>
- <item>one day</item>
- </string-array>
- <string-array name="weather_preferences_temperature">
- <item>@string/weather_preferences_temperature_celsius</item>
- <item>@string/weather_preferences_temperature_fahrenheit</item>
- <item>@string/weather_preferences_temperature_kelvin</item>
- </string-array>
- <string-array name="weather_preferences_temperature_human_value">
- <item>@string/weather_preferences_temperature_celsius_human_value</item>
- <item>@string/weather_preferences_temperature_fahrenheit_human_value</item>
- <item>@string/weather_preferences_temperature_kelvin_human_value</item>
- </string-array>
- <string-array name="weather_preferences_wind">
- <item>@string/weather_preferences_wind_meters</item>
- <item>@string/weather_preferences_wind_miles</item>
- </string-array>
- <string-array name="weather_preferences_wind_human_value">
- <item>@string/weather_preferences_wind_human_value_meters</item>
- <item>@string/weather_preferences_wind_human_value_miles</item>
- </string-array>
- <string-array name="weather_preferences_pressure">
- <item>@string/weather_preferences_pressure_pascal</item>
- <item>@string/weather_preferences_pressure_standard_atm</item>
- </string-array>
- <string-array name="weather_preferences_pressure_human_value">
- <item>@string/weather_preferences_pressure_human_value_pascal</item>
- <item>@string/weather_preferences_pressure_human_value_standard_atm</item>
- </string-array>
-</resources>
+++ /dev/null
-<resources>
-
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
- <dimen name="widget_margin">8dp</dimen>
-</resources>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
- <string name="app_name">Weather Information</string>
- <string name="icon_weather_description">Icon weather</string>
-
-
- <!-- Activities Current, Overview and Specific -->
- <string name="text_field_sun_rise">SUN RISE</string>
- <string name="text_field_sun_set">SUN SET</string>
- <string name="text_field_feels_like">FEELS LIKE</string>
- <string name="text_field_clouds">CLOUDS</string>
- <string name="text_field_rain">RAIN</string>
- <string name="text_field_wind">WIND</string>
- <string name="text_field_snow">SNOW</string>
- <string name="text_field_pressure">PRESSURE</string>
- <string name="text_field_humidity">HUMIDITY</string>
- <string name="text_units_mm3h">mm 3h</string>
- <string name="text_units_percent">%</string>
- <string name="text_field_remote_error">No data available</string>
-
-
- <!-- Preferences Acitivity -->
- <string name="weather_preferences_action_settings">Settings</string>
- <string name="weather_preferences_units">Units</string>
- <string name="weather_preferences_temperature_key">weather_preferences_temperature</string>
- <string name="weather_preferences_temperature">Temperature</string>
- <string name="weather_preferences_temperature_celsius">ºC</string>
- <string name="weather_preferences_temperature_fahrenheit">ºF</string>
- <string name="weather_preferences_temperature_kelvin">K</string>
- <string name="weather_preferences_temperature_celsius_human_value">celsius</string>
- <string name="weather_preferences_temperature_fahrenheit_human_value">fahrenheit</string>
- <string name="weather_preferences_temperature_kelvin_human_value">kelvin</string>
- <string name="weather_preferences_notifications">Notifications</string>
- <string name="weather_preferences_notifications_switch_off_summary">Disabled</string>
- <string name="weather_preferences_notifications_switch_on_summary">Enabled</string>
- <string name="weather_preferences_notifications_switch_off">OFF</string>
- <string name="weather_preferences_notifications_switch_on">ON</string>
- <string name="weather_preferences_notifications_switch_key">weather_preferences_notifications_switch</string>
- <string name="weather_preferences_update_time_rate_key">weather_preferences_update_time_rate</string>
- <string name="weather_preferences_update_time_rate">Update time rate</string>
- <string name="weather_preferences_day_forecast_key">weather_preferences_day_forecast</string>
- <string name="weather_preferences_day_forecast">Forecast days number</string>
- <string name="weather_preferences_refresh_interval_key">weather_preferences_refresh_interval</string>
- <string name="weather_preferences_refresh_interval">Refresh interval</string>
- <string name="weather_preferences_wind_key">weather_preferences_wind</string>
- <string name="weather_preferences_wind">Wind</string>
- <string name="weather_preferences_wind_meters">m/s</string>
- <string name="weather_preferences_wind_miles">mph</string>
- <string name="weather_preferences_wind_human_value_meters">meter per second</string>
- <string name="weather_preferences_wind_human_value_miles">miles per hour</string>
- <string name="weather_preferences_pressure_key">weather_preferences_pressure</string>
- <string name="weather_preferences_pressure">Pressure</string>
- <string name="weather_preferences_pressure_pascal">hpa</string>
- <string name="weather_preferences_pressure_standard_atm">atm</string>
- <string name="weather_preferences_pressure_human_value_pascal">pascal</string>
- <string name="weather_preferences_pressure_human_value_standard_atm">standard atmosphere</string>
-
-
- <!-- Widget Preferences Activity -->
- <string name="widget_preferences_action_settings">Settings</string>
- <string name="widget_preferences_button_refresh">Refresh</string>
- <string name="widget_preferences_country">Country</string>
- <string name="widget_preferences_units">Units</string>
- <string name="widget_preferences_temperature_key">widget_preferences_temperature</string>
- <string name="widget_preferences_country_switch_key">widget_preferences_countries_switch</string>
- <string name="widget_preferences_country_switch_off_summary">Hide</string>
- <string name="widget_preferences_country_switch_on_summary">Show</string>
- <string name="widget_preferences_country_switch_off">OFF</string>
- <string name="widget_preferences_country_switch_on">ON</string>
-
-
- <!-- Map Activity -->
- <string name="weather_map_action_map">Select Location</string>
- <string name="city_not_found">city not found</string>
- <string name="country_not_found">country not found</string>
- <string name="progress_dialog_generic_message">Please wait…</string>
- <string name="weather_map_button_savelocation">Save Location</string>
- <string name="weather_map_button_getlocation">Get Location</string>
-
-
- <!-- DO NOT TRANSLATE -->
- <string name="uri_api_weather_today">http://api.openweathermap.org/data/{0}/weather?lat={1}&lon={2}&cnt=1</string>
- <string name="uri_api_weather_forecast">http://api.openweathermap.org/data/{0}/forecast/daily?lat={1}&lon={2}&cnt={3}&mode=json</string>
- <string name="api_version">2.5</string>
-</resources>
+++ /dev/null
-<resources>
-
- <!--
- Base application theme, dependent on API level. This theme is replaced
- by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
- -->
- <style name="AppBaseTheme" parent="android:Theme.Holo">
- <!--
- Theme customizations available in newer API levels can go in
- res/values-vXX/styles.xml, while customizations related to
- backward-compatibility can go here.
- -->
- </style>
-
- <!-- Application theme. -->
- <style name="AppTheme" parent="android:Theme.Holo">
- <!-- All customizations that are NOT specific to a particular API-level can go here. -->
- </style>
-
-
- <color name="weather_time_of_day_color_title">#48aed4</color>
- <color name="widget_background_holo_dark">#ff000000</color>
-
-</resources>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
- <PreferenceCategory android:title="@string/widget_preferences_country">
- <SwitchPreference android:key="@string/widget_preferences_country_switch_key"
- android:summaryOn="@string/widget_preferences_country_switch_on_summary"
- android:summaryOff="@string/widget_preferences_country_switch_off_summary"
- android:switchTextOff="@string/widget_preferences_country_switch_off"
- android:switchTextOn="@string/widget_preferences_country_switch_on"
- android:selectable="true"
- android:enabled="true"
- android:defaultValue="@string/widget_preferences_country_switch_off"
- android:disableDependentsState="false"
- android:persistent="true"/>
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/widget_preferences_units">
- <ListPreference android:key="@string/widget_preferences_temperature_key"
- android:title="@string/weather_preferences_temperature"
- android:summary="@string/weather_preferences_temperature_celsius_human_value"
- android:entries="@array/weather_preferences_temperature_human_value"
- android:entryValues="@array/weather_preferences_temperature"
- android:selectable="true"
- android:persistent="true"
- android:defaultValue="@string/weather_preferences_temperature_celsius" />
- </PreferenceCategory>
-
-</PreferenceScreen>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="180dp"
- android:minHeight="40dp"
- android:minResizeWidth="180dp"
- android:minResizeHeight="40dp"
- android:resizeMode="none"
- android:previewImage="@drawable/ic_launcher"
- android:initialLayout="@layout/appwidget_error"
- android:configure="de.example.exampletdd.widget.WidgetConfigure"
- android:widgetCategory="home_screen|keyguard"
- android:updatePeriodMillis="3600000">
-</appwidget-provider>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
- <ListPreference android:key="@string/weather_preferences_day_forecast_key"
- android:title="@string/weather_preferences_day_forecast"
- android:entries="@array/weather_preferences_day_forecast_human_value"
- android:entryValues="@array/weather_preferences_day_forecast"
- android:selectable="true"
- android:persistent="true"
- android:defaultValue="14"
- android:summary="14 day forecast" />
- <ListPreference android:key="@string/weather_preferences_refresh_interval_key"
- android:title="@string/weather_preferences_refresh_interval"
- android:entries="@array/weather_preferences_refresh_interval_human_value"
- android:entryValues="@array/weather_preferences_refresh_interval"
- android:selectable="true"
- android:persistent="true"
- android:defaultValue="300000"
- android:summary="five minutes" />
- <PreferenceCategory android:title="@string/weather_preferences_units">
- <ListPreference android:key="@string/weather_preferences_temperature_key"
- android:title="@string/weather_preferences_temperature"
- android:summary="@string/weather_preferences_temperature_celsius_human_value"
- android:entries="@array/weather_preferences_temperature_human_value"
- android:entryValues="@array/weather_preferences_temperature"
- android:selectable="true"
- android:persistent="true"
- android:defaultValue="@string/weather_preferences_temperature_celsius" />
- <ListPreference android:key="@string/weather_preferences_wind_key"
- android:entryValues="@array/weather_preferences_wind"
- android:entries="@array/weather_preferences_wind_human_value"
- android:summary="@string/weather_preferences_wind_human_value_meters"
- android:selectable="true"
- android:persistent="true"
- android:defaultValue="@string/weather_preferences_wind_meters"
- android:title="@string/weather_preferences_wind"/>
- <ListPreference android:key="@string/weather_preferences_pressure_key"
- android:entryValues="@array/weather_preferences_pressure"
- android:entries="@array/weather_preferences_pressure_human_value"
- android:summary="@string/weather_preferences_pressure_human_value_pascal"
- android:selectable="true"
- android:persistent="true"
- android:defaultValue="@string/weather_preferences_pressure_pascal"
- android:title="@string/weather_preferences_pressure"/>
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/weather_preferences_notifications">
- <SwitchPreference android:key="@string/weather_preferences_notifications_switch_key"
- android:summaryOn="@string/weather_preferences_notifications_switch_on_summary"
- android:summaryOff="@string/weather_preferences_notifications_switch_off_summary"
- android:switchTextOff="@string/weather_preferences_notifications_switch_off"
- android:switchTextOn="@string/weather_preferences_notifications_switch_on"
- android:selectable="true"
- android:enabled="true"
- android:defaultValue="@string/weather_preferences_notifications_switch_off"
- android:disableDependentsState="false"
- android:persistent="true"/>
- <ListPreference android:key="@string/weather_preferences_update_time_rate_key"
- android:entries="@array/weather_preferences_update_time_rate_human_value"
- android:entryValues="@array/weather_preferences_update_time_rate"
- android:title="@string/weather_preferences_update_time_rate"
- android:defaultValue="900"
- android:persistent="true"
- android:selectable="true"
- android:summary="fifteen minutes"
- android:dependency="@string/weather_preferences_notifications_switch_key"/>
- </PreferenceCategory>
-</PreferenceScreen>
--- /dev/null
+include ':app'
+++ /dev/null
-package de.example.exampletdd;
-
-import android.app.ActionBar;
-import android.content.Context;
-import android.location.Criteria;
-import android.location.Geocoder;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.Toast;
-
-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.map.MapButtonsFragment;
-import de.example.exampletdd.fragment.map.MapProgressFragment;
-import de.example.exampletdd.model.DatabaseQueries;
-import de.example.exampletdd.model.WeatherLocation;
-
-public class MapActivity extends FragmentActivity implements
- LocationListener,
- MapProgressFragment.TaskCallbacks {
- private static final String PROGRESS_FRAGMENT_TAG = "PROGRESS_FRAGMENT";
- private static final String BUTTONS_FRAGMENT_TAG = "BUTTONS_FRAGMENT";
- private WeatherLocation mRestoreUI;
-
- // Google Play Services Map
- private GoogleMap mMap;
- // TODO: read and store from different threads? Hopefully always from UI thread.
- private Marker mMarker;
-
- private LocationManager mLocationManager;
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- this.setContentView(R.layout.weather_map);
-
- // Acquire a reference to the system Location Manager
- this.mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
-
- // Google Play Services Map
- final MapFragment mapFragment = (MapFragment) this.getFragmentManager()
- .findFragmentById(R.id.weather_map_fragment_map);
- this.mMap = mapFragment.getMap();
- this.mMap.setMyLocationEnabled(false);
- this.mMap.getUiSettings().setMyLocationButtonEnabled(false);
- this.mMap.getUiSettings().setZoomControlsEnabled(true);
- this.mMap.getUiSettings().setCompassEnabled(true);
- this.mMap.setOnMapLongClickListener(new MapActivityOnMapLongClickListener(this));
- }
-
- @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 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;
-
- weatherLocation = new WeatherLocation()
- .setCity(cityString)
- .setCountry(countryString)
- .setLatitude(latitude)
- .setLongitude(longitude);
- } else {
- final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
- weatherLocation = query.queryDataBase();
- }
-
- if (weatherLocation != null) {
- this.updateUI(weatherLocation);
- }
- }
-
- /**
- * I am not using fragment transactions in the right way. But I do not know other way for doing what I am doing.
- *
- * {@link http://stackoverflow.com/questions/16265733/failure-delivering-result-onactivityforresult}
- */
- @Override
- public void onPostResume() {
- super.onPostResume();
-
- final FragmentManager fm = getSupportFragmentManager();
- final Fragment progressFragment = fm.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
- if (progressFragment == null) {
- this.addButtonsFragment();
- } else {
- this.removeProgressFragment();
- final Bundle bundle = progressFragment.getArguments();
- double latitude = bundle.getDouble("latitude");
- double longitude = bundle.getDouble("longitude");
- this.addProgressFragment(latitude, longitude);
- }
- }
-
- @Override
- public void onSaveInstanceState(final Bundle savedInstanceState) {
- // Save UI state
- // Save Google Maps Marker
- 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()
- .setCity(cityString)
- .setCountry(countryString)
- .setLatitude(latitude)
- .setLongitude(longitude);
- savedInstanceState.putSerializable("WeatherLocation", location);
- }
-
- super.onSaveInstanceState(savedInstanceState);
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- this.mLocationManager.removeUpdates(this);
- }
-
- public void onClickSaveLocation(final View v) {
- if (this.mMarker != null) {
- final LatLng position = this.mMarker.getPosition();
-
- 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 DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
- if (weatherLocation != null) {
- weatherLocation
- .setCity(cityString)
- .setCountry(countryString)
- .setLatitude(position.latitude)
- .setLongitude(position.longitude)
- .setLastCurrentUIUpdate(null)
- .setLastForecastUIUpdate(null);
- query.updateDataBase(weatherLocation);
- } else {
- final WeatherLocation location = new WeatherLocation()
- .setCity(cityString)
- .setCountry(countryString)
- .setIsSelected(true)
- .setLatitude(position.latitude)
- .setLongitude(position.longitude);
- query.insertIntoDataBase(location);
- }
- }
- }
-
- public void onClickGetLocation(final View v) {
- // TODO: Somehow I should show a progress dialog.
- // If Google Play Services is available
- if (this.mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
- // TODO: Hopefully there will be results even if location did not change...
- final Criteria criteria = new Criteria();
- criteria.setAccuracy(Criteria.ACCURACY_FINE);
- criteria.setAltitudeRequired(false);
- criteria.setBearingAccuracy(Criteria.NO_REQUIREMENT);
- criteria.setBearingRequired(false);
- criteria.setCostAllowed(false);
- criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
- criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
- criteria.setSpeedAccuracy(Criteria.NO_REQUIREMENT);
- criteria.setSpeedRequired(false);
- criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH);
-
- this.mLocationManager.requestSingleUpdate(criteria, this, null);
- } else {
- // TODO: string resource
- Toast.makeText(this, "You do not have enabled location.", Toast.LENGTH_LONG).show();
- }
- // Trying to use the synchronous calls. Problems: mGoogleApiClient read/store from different threads.
- // new GetLocationTask(this).execute();
- }
-
- private void updateUI(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());
- if (this.mMarker != null) {
- // Just one marker on map
- this.mMarker.remove();
- }
- 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);
- }
-
- private class MapActivityOnMapLongClickListener implements OnMapLongClickListener {
- // Store the context passed to the AsyncTask when the system instantiates it.
- private final Context localContext;
-
- private MapActivityOnMapLongClickListener(final Context context) {
- this.localContext = context;
- }
-
- @Override
- public void onMapLongClick(final LatLng point) {
- final MapActivity activity = (MapActivity) this.localContext;
- activity.getAddressAndUpdateUI(point.latitude, point.longitude);
- }
-
- }
-
- /**
- * Getting the address of the current location, using reverse geocoding only works if
- * a geocoding service is available.
- *
- */
- private void getAddressAndUpdateUI(final double latitude, final double longitude) {
- // In Gingerbread and later, use Geocoder.isPresent() to see if a geocoder is available.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && Geocoder.isPresent()) {
- this.removeButtonsFragment();
- this.removeProgressFragment();
- this.addProgressFragment(latitude, longitude);
- } else {
- this.removeProgressFragment();
- this.addButtonsFragment();
- // No geocoder is present. Issue an error message.
- // TODO: string resource
- Toast.makeText(this, "Cannot get address. No geocoder available.", Toast.LENGTH_LONG).show();
-
- // Default values
- final String city = this.getString(R.string.city_not_found);
- final String country = this.getString(R.string.country_not_found);
- final WeatherLocation weatherLocation = new WeatherLocation()
- .setLatitude(latitude)
- .setLongitude(longitude)
- .setCity(city)
- .setCountry(country);
-
- updateUI(weatherLocation);
- }
- }
-
- /*****************************************************************************************************
- *
- * MapProgressFragment.TaskCallbacks
- *
- *****************************************************************************************************/
- @Override
- public void onPostExecute(WeatherLocation weatherLocation) {
-
- this.updateUI(weatherLocation);
- this.removeProgressFragment();
-
- this.addButtonsFragment();
- }
-
- /*****************************************************************************************************
- *
- * MapProgressFragment
- * I am not using fragment transactions in the right way. But I do not know other way for doing what I am doing.
- * Android sucks.
- *
- * "Avoid performing transactions inside asynchronous callback methods." :(
- * see: http://stackoverflow.com/questions/16265733/failure-delivering-result-onactivityforresult
- * see: http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
- * How do you do what I am doing in a different way without using fragments?
- *****************************************************************************************************/
-
- private void addProgressFragment(final double latitude, final double longitude) {
- final Fragment progressFragment = new MapProgressFragment();
- progressFragment.setRetainInstance(true);
- final Bundle args = new Bundle();
- args.putDouble("latitude", latitude);
- args.putDouble("longitude", longitude);
- progressFragment.setArguments(args);
-
- final FragmentManager fm = this.getSupportFragmentManager();
- final FragmentTransaction fragmentTransaction = fm.beginTransaction();
- fragmentTransaction.setCustomAnimations(R.anim.weather_map_enter_progress, R.anim.weather_map_exit_progress);
- fragmentTransaction.add(R.id.weather_map_buttons_container, progressFragment, PROGRESS_FRAGMENT_TAG).commit();
- fm.executePendingTransactions();
- }
-
- private void removeProgressFragment() {
- final FragmentManager fm = this.getSupportFragmentManager();
- final Fragment progressFragment = fm.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
- if (progressFragment != null) {
- final FragmentTransaction fragmentTransaction = fm.beginTransaction();
- fragmentTransaction.remove(progressFragment).commit();
- fm.executePendingTransactions();
- }
- }
-
- private void addButtonsFragment() {
- final FragmentManager fm = this.getSupportFragmentManager();
- Fragment buttonsFragment = fm.findFragmentByTag(BUTTONS_FRAGMENT_TAG);
- if (buttonsFragment == null) {
- buttonsFragment = new MapButtonsFragment();
- buttonsFragment.setRetainInstance(true);
- final FragmentTransaction fragmentTransaction = fm.beginTransaction();
- fragmentTransaction.setCustomAnimations(R.anim.weather_map_enter_progress, R.anim.weather_map_exit_progress);
- fragmentTransaction.add(R.id.weather_map_buttons_container, buttonsFragment, BUTTONS_FRAGMENT_TAG).commit();
- fm.executePendingTransactions();
- }
-
- if (this.mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
- final Button getLocationButton = (Button) this.findViewById(R.id.weather_map_button_getlocation);
- getLocationButton.setEnabled(true);
- }
- }
-
- private void removeButtonsFragment() {
- final FragmentManager fm = this.getSupportFragmentManager();
- final Fragment buttonsFragment = fm.findFragmentByTag(BUTTONS_FRAGMENT_TAG);
- if (buttonsFragment != null) {
- final FragmentTransaction fragmentTransaction = fm.beginTransaction();
- fragmentTransaction.remove(buttonsFragment).commit();
- fm.executePendingTransactions();
- }
- }
-
- /*****************************************************************************************************
- *
- * android.location.LocationListener
- *
- *****************************************************************************************************/
-
- @Override
- public void onLocationChanged(final Location location) {
- // It was called from onClickGetLocation (UI thread) This method will run in the same thread (the UI thread)
- // so, I do no think there should be any problem.
-
- // Display the current location in the UI
- // TODO: May location not be null?
- this.getAddressAndUpdateUI(location.getLatitude(), location.getLongitude());
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void onProviderDisabled(String provider) {
- // TODO Auto-generated method stub
-
- }
-}
+++ /dev/null
-package de.example.exampletdd;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.Calendar;
-import java.util.Locale;
-
-import org.apache.http.client.ClientProtocolException;
-
-import android.app.IntentService;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.http.AndroidHttpClient;
-import android.preference.PreferenceManager;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
-import android.support.v4.app.TaskStackBuilder;
-import android.util.Log;
-import android.widget.RemoteViews;
-
-import com.fasterxml.jackson.core.JsonParseException;
-
-import de.example.exampletdd.httpclient.CustomHTTPClient;
-import de.example.exampletdd.model.DatabaseQueries;
-import de.example.exampletdd.model.WeatherLocation;
-import de.example.exampletdd.model.currentweather.Current;
-import de.example.exampletdd.parser.JPOSWeatherParser;
-import de.example.exampletdd.service.IconsList;
-import de.example.exampletdd.service.ServiceParser;
-
-public class NotificationIntentService extends IntentService {
- private static final String TAG = "NotificationIntentService";
-
-
- public NotificationIntentService() {
- super("NIS-Thread");
- }
-
- @Override
- protected void onHandleIntent(final Intent intent) {
- final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
-
- if (weatherLocation != null) {
- final ServiceParser weatherService = new ServiceParser(new JPOSWeatherParser());
- final CustomHTTPClient HTTPClient = new CustomHTTPClient(
- AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent"));
-
- Current current = null;
- try {
- current = this.doInBackgroundThrowable(weatherLocation, HTTPClient, weatherService);
-
- } catch (final JsonParseException e) {
- Log.e(TAG, "doInBackground exception: ", e);
- } 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);
- } finally {
- HTTPClient.close();
- }
-
- if (current != null) {
- this.showNotification(current, weatherLocation);
- }
- }
- }
-
- private Current doInBackgroundThrowable(final WeatherLocation weatherLocation,
- final CustomHTTPClient HTTPClient, final ServiceParser weatherService)
- throws ClientProtocolException, MalformedURLException, URISyntaxException,
- JsonParseException, IOException {
-
- final String APIVersion = this.getResources().getString(R.string.api_version);
-
- final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today);
- final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion,
- weatherLocation.getLatitude(), weatherLocation.getLongitude());
- final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
- final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
- final Current current = weatherService.retrieveCurrentFromJPOS(jsonData);
- // TODO: what is this for? I guess I could skip it :/
- final Calendar now = Calendar.getInstance();
- current.setDate(now.getTime());
-
- return current;
- }
-
- private interface UnitsConversor {
-
- public double doConversion(final double value);
- }
-
- private void showNotification(final Current current, final WeatherLocation weatherLocation) {
- final SharedPreferences sharedPreferences = PreferenceManager
- .getDefaultSharedPreferences(this.getApplicationContext());
-
- // TODO: repeating the same code in Overview, Specific and Current!!!
- // 1. Update units of measurement.
- // 1.1 Temperature
- String tempSymbol;
- UnitsConversor tempUnitsConversor;
- String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
- String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- if (unitsPreferenceValue.equals(values[0])) {
- tempSymbol = values[0];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value - 273.15;
- }
-
- };
- } else if (unitsPreferenceValue.equals(values[1])) {
- tempSymbol = values[1];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return (value * 1.8) - 459.67;
- }
-
- };
- } else {
- tempSymbol = values[2];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value;
- }
-
- };
- }
-
-
- // 2. Formatters
- final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
- tempFormatter.applyPattern("#####.#####");
-
-
- // 3. Prepare data for RemoteViews.
- String tempMax = "";
- if (current.getMain().getTemp_max() != null) {
- double conversion = (Double) current.getMain().getTemp_max();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMax = tempFormatter.format(conversion) + tempSymbol;
- }
- String tempMin = "";
- if (current.getMain().getTemp_min() != null) {
- double conversion = (Double) current.getMain().getTemp_min();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMin = tempFormatter.format(conversion) + tempSymbol;
- }
- Bitmap picture;
- if ((current.getWeather().size() > 0)
- && (current.getWeather().get(0).getIcon() != null)
- && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
- final String icon = current.getWeather().get(0).getIcon();
- picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
- .getResourceDrawable());
- } else {
- picture = BitmapFactory.decodeResource(this.getResources(),
- R.drawable.weather_severe_alert);
- }
- final String city = weatherLocation.getCity();
- final String country = weatherLocation.getCountry();
-
- // 4. Insert data in RemoteViews.
- final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.notification);
- remoteView.setImageViewBitmap(R.id.weather_notification_image, picture);
- remoteView.setTextViewText(R.id.weather_notification_temperature_max, tempMax);
- remoteView.setTextViewText(R.id.weather_notification_temperature_min, tempMin);
- remoteView.setTextViewText(R.id.weather_notification_city, city);
- remoteView.setTextViewText(R.id.weather_notification_country, country);
-
- // 5. Activity launcher.
- final Intent resultIntent = new Intent(this.getApplicationContext(), WeatherTabsActivity.class);
- // The PendingIntent to launch our activity if the user selects this notification
-// final PendingIntent contentIntent = PendingIntent.getActivity(
-// this.getApplicationContext(), 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- // The stack builder object will contain an artificial back stack for the started Activity.
- // This ensures that navigating backward from the Activity leads out of
- // your application to the Home screen.
- final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
- // Adds the back stack for the Intent (but not the Intent itself)
- stackBuilder.addParentStack(WeatherTabsActivity.class);
- // Adds the Intent that starts the Activity to the top of the stack
- stackBuilder.addNextIntent(resultIntent);
- final PendingIntent resultPendingIntent =
- stackBuilder.getPendingIntent(
- 0,
- PendingIntent.FLAG_UPDATE_CURRENT
- );
-
- final NotificationManagerCompat notificationManager =
- NotificationManagerCompat.from(this.getApplicationContext());
-
-
- // 6. Create notification.
- final NotificationCompat.Builder notificationBuilder =
- new NotificationCompat.Builder(this.getApplicationContext())
- .setContent(remoteView)
- .setSmallIcon(R.drawable.ic_launcher)
- .setAutoCancel(true)
- .setLocalOnly(true)
- .setWhen(System.currentTimeMillis())
- .setContentIntent(resultPendingIntent)
- .setPriority(NotificationCompat.PRIORITY_DEFAULT);
-
- final Notification notification = notificationBuilder.build();
- notification.flags |= Notification.FLAG_AUTO_CANCEL;
-
- // Send the notification.
- // Sets an ID for the notification, so it can be updated (just in case)
- int notifyID = 1;
- notificationManager.notify(notifyID, notification);
- }
-}
+++ /dev/null
-package de.example.exampletdd;
-
-import android.app.ActionBar;
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import de.example.exampletdd.model.DatabaseQueries;
-import de.example.exampletdd.model.WeatherLocation;
-
-public class SpecificActivity extends FragmentActivity {
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- this.setContentView(R.layout.weather_specific);
-
- final ActionBar actionBar = this.getActionBar();
-
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
- actionBar.setDisplayHomeAsUpEnabled(true);
-
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- // 1. Update title.
- final DatabaseQueries query = new DatabaseQueries(this);
- final WeatherLocation weatherLocation = query.queryDataBase();
- if (weatherLocation != null) {
- final ActionBar actionBar = this.getActionBar();
- // TODO: I18N and comma :/
- actionBar.setTitle(weatherLocation.getCity() + "," + weatherLocation.getCountry());
- }
- }
-}
+++ /dev/null
-package de.example.exampletdd;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.SystemClock;
-import android.preference.PreferenceManager;
-
-public class WeatherInformationBootReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(final Context context, final Intent intent) {
-
- if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
-
- // Update Time Rate
- final SharedPreferences sharedPreferences = PreferenceManager
- .getDefaultSharedPreferences(context);
- final String keyPreference = context
- .getString(R.string.weather_preferences_update_time_rate_key);
- final String updateTimeRate = sharedPreferences.getString(keyPreference, "");
- long chosenInterval = 0;
- if (updateTimeRate.equals("900")) {
- chosenInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
- } else if (updateTimeRate.equals("1800")) {
- chosenInterval = AlarmManager.INTERVAL_HALF_HOUR;
- } else if (updateTimeRate.equals("3600")) {
- chosenInterval = AlarmManager.INTERVAL_HOUR;
- } else if (updateTimeRate.equals("43200")) {
- chosenInterval = AlarmManager.INTERVAL_HALF_DAY;
- } else if (updateTimeRate.equals("86400")) {
- chosenInterval = AlarmManager.INTERVAL_DAY;
- }
-
- if (chosenInterval != 0) {
- final AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- // TODO: better use some string instead of .class? In case I change the service class
- // this could be a problem (I guess)
- final Intent serviceIntent = new Intent(context, NotificationIntentService.class);
- final PendingIntent alarmIntent = PendingIntent.getService(
- context,
- 0,
- serviceIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- alarmMgr.setInexactRepeating(
- AlarmManager.ELAPSED_REALTIME,
- SystemClock.elapsedRealtime() + chosenInterval,
- chosenInterval,
- alarmIntent);
- }
- }
- }
-
-}
+++ /dev/null
-package de.example.exampletdd;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.os.Bundle;
-import de.example.exampletdd.fragment.preferences.WeatherInformationPreferencesFragment;
-
-public class WeatherInformationPreferencesActivity extends Activity {
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- this.getFragmentManager()
- .beginTransaction()
- .replace(android.R.id.content,
- new WeatherInformationPreferencesFragment()).commit();
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- final ActionBar actionBar = this.getActionBar();
- actionBar.setTitle(this.getString(R.string.weather_preferences_action_settings));
- }
-}
+++ /dev/null
-package de.example.exampletdd;
-
-import android.app.ActionBar;
-import android.app.ActionBar.Tab;
-import android.app.FragmentTransaction;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.view.Menu;
-import android.view.MenuItem;
-import de.example.exampletdd.fragment.current.CurrentFragment;
-import de.example.exampletdd.fragment.overview.OverviewFragment;
-import de.example.exampletdd.model.DatabaseQueries;
-import de.example.exampletdd.model.WeatherLocation;
-
-public class WeatherTabsActivity extends FragmentActivity {
- private static final int NUM_ITEMS = 2;
- private ViewPager mPager;
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- this.setContentView(R.layout.fragment_pager);
-
- this.mPager = (ViewPager)this.findViewById(R.id.pager);
- this.mPager.setAdapter(new TabsAdapter(this.getSupportFragmentManager()));
-
-
- this.mPager.setOnPageChangeListener(
- new ViewPager.SimpleOnPageChangeListener() {
- @Override
- public void onPageSelected(final int position) {
- WeatherTabsActivity.this.getActionBar().setSelectedNavigationItem(position);
- }
- });
-
-
- final ActionBar actionBar = this.getActionBar();
-
- PreferenceManager.setDefaultValues(this, R.xml.weather_preferences, false);
-
- // Specify that tabs should be displayed in the action bar.
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
- actionBar.setDisplayHomeAsUpEnabled(true);
-
- // Create a tab listener that is called when the user changes tabs.
- final ActionBar.TabListener tabListener = new ActionBar.TabListener() {
-
- @Override
- public void onTabSelected(final Tab tab, final FragmentTransaction ft) {
- WeatherTabsActivity.this.mPager.setCurrentItem(tab.getPosition());
-
- }
-
- @Override
- public void onTabUnselected(final Tab tab, final FragmentTransaction ft) {
-
- }
-
- @Override
- public void onTabReselected(final Tab tab, final FragmentTransaction ft) {
-
- }
-
- };
-
- actionBar.addTab(actionBar.newTab().setText("CURRENTLY").setTabListener(tabListener));
- actionBar.addTab(actionBar.newTab().setText("FORECAST").setTabListener(tabListener));
- }
-
- @Override
- public boolean onCreateOptionsMenu(final Menu menu) {
-
- this.getMenuInflater().inflate(R.menu.weather_main_menu, menu);
-
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(final MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- super.onOptionsItemSelected(item);
-
- Intent intent;
- final int itemId = item.getItemId();
- if (itemId == R.id.weather_menu_settings) {
- intent = new Intent("de.example.exampletdd.WEATHERINFO")
- .setComponent(new ComponentName("de.example.exampletdd",
- "de.example.exampletdd.WeatherInformationPreferencesActivity"));
- 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.MapActivity"));
- this.startActivity(intent);
- return true;
- } else {
- }
-
- // TODO: calling again super method?
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- protected void onRestoreInstanceState(final Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- }
-
-
- @Override
- public void onResume() {
- super.onResume();
-
- final ActionBar actionBar = this.getActionBar();
-
- // 1. Update title.
- final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
- if (weatherLocation != null) {
- // TODO: I18N and comma :/
- actionBar.setTitle(weatherLocation.getCity() + "," + weatherLocation.getCountry());
- } else {
- // TODO: static resource
- actionBar.setTitle("no chosen location");
- }
-
- // 2. Update forecast tab text.
- final SharedPreferences sharedPreferences = PreferenceManager
- .getDefaultSharedPreferences(this);
- final String keyPreference = this.getString(R.string.weather_preferences_day_forecast_key);
- final String value = sharedPreferences.getString(keyPreference, "");
- String humanValue = "";
- if (value.equals("5")) {
- humanValue = "5 DAY FORECAST";
- } else if (value.equals("10")) {
- humanValue = "10 DAY FORECAST";
- } else if (value.equals("14")) {
- humanValue = "14 DAY FORECAST";
- }
- actionBar.getTabAt(1).setText(humanValue);
- }
-
- @Override
- public void onSaveInstanceState(final Bundle savedInstanceState) {
- super.onSaveInstanceState(savedInstanceState);
- }
-
- private class TabsAdapter extends FragmentPagerAdapter {
- public TabsAdapter(final FragmentManager fm) {
- super(fm);
- }
-
- @Override
- public int getCount() {
- return NUM_ITEMS;
- }
-
- @Override
- public Fragment getItem(final int position) {
- if (position == 0) {
- // TODO: new instance every time I click on tab?
- return new CurrentFragment();
- } else {
- // TODO: new instance every time I click on tab?
- final Fragment fragment = new OverviewFragment();
- return fragment;
- }
-
- }
- }
-}
+++ /dev/null
-package de.example.exampletdd;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.Calendar;
-import java.util.Locale;
-
-import org.apache.http.client.ClientProtocolException;
-
-import android.app.IntentService;
-import android.app.PendingIntent;
-import android.appwidget.AppWidgetManager;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.net.http.AndroidHttpClient;
-import android.preference.PreferenceManager;
-import android.support.v4.app.TaskStackBuilder;
-import android.util.Log;
-import android.widget.RemoteViews;
-
-import com.fasterxml.jackson.core.JsonParseException;
-
-import de.example.exampletdd.httpclient.CustomHTTPClient;
-import de.example.exampletdd.model.DatabaseQueries;
-import de.example.exampletdd.model.WeatherLocation;
-import de.example.exampletdd.model.currentweather.Current;
-import de.example.exampletdd.parser.JPOSWeatherParser;
-import de.example.exampletdd.service.IconsList;
-import de.example.exampletdd.service.PermanentStorage;
-import de.example.exampletdd.service.ServiceParser;
-import de.example.exampletdd.widget.WidgetConfigure;
-
-public class WidgetIntentService extends IntentService {
- private static final String TAG = "WidgetIntentService";
-
-
- public WidgetIntentService() {
- super("WIS-Thread");
- }
-
- @Override
- protected void onHandleIntent(final Intent intent) {
- Log.i(TAG, "onHandleIntent");
- final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
- final boolean isUpdateByApp = intent.getBooleanExtra("updateByApp", false);
-
- if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
- // Nothing to do. Something went wrong. Show error.
- return;
- }
-
-
- final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
-
- if (weatherLocation == null) {
- // Nothing to do. Show error.
- final RemoteViews view = this.makeErrorView(appWidgetId);
- this.updateWidget(view, appWidgetId);
- return;
- }
-
- if (isUpdateByApp) {
- this.updateByApp(weatherLocation, appWidgetId);
- } else {
- this.updateByTimeout(weatherLocation, appWidgetId);
- }
-
- }
-
- private void updateByApp(final WeatherLocation weatherLocation, final int appWidgetId) {
- final PermanentStorage store = new PermanentStorage(this.getApplicationContext());
- final Current current = store.getCurrent();
-
- this.updateWidget(current, weatherLocation, appWidgetId);
- }
-
- private void updateByTimeout(final WeatherLocation weatherLocation, final int appWidgetId) {
-
- final Current current = this.getRemoteCurrent(weatherLocation);
-
- this.updateWidget(current, weatherLocation, appWidgetId);
- }
-
- private void updateWidget(final Current current, final WeatherLocation weatherLocation, final int appWidgetId) {
-
- if (current != null) {
- final RemoteViews view = this.makeView(current, weatherLocation, appWidgetId);
- this.updateWidget(view, appWidgetId);
- } else {
- // Show error.
- final RemoteViews view = this.makeErrorView(appWidgetId);
- this.updateWidget(view, appWidgetId);
- }
- }
-
-
-
- private Current getRemoteCurrent(final WeatherLocation weatherLocation) {
-
- final ServiceParser weatherService = new ServiceParser(new JPOSWeatherParser());
- final CustomHTTPClient HTTPClient = new CustomHTTPClient(
- AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent"));
-
- try {
- return this.getRemoteCurrentThrowable(weatherLocation, HTTPClient, weatherService);
-
- } catch (final JsonParseException e) {
- Log.e(TAG, "doInBackground exception: ", e);
- } 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);
- } finally {
- HTTPClient.close();
- }
-
- return null;
- }
-
- private Current getRemoteCurrentThrowable(final WeatherLocation weatherLocation,
- final CustomHTTPClient HTTPClient, final ServiceParser weatherService)
- throws ClientProtocolException, MalformedURLException, URISyntaxException,
- JsonParseException, IOException {
-
- final String APIVersion = this.getResources().getString(R.string.api_version);
-
- final String urlAPI = this.getResources().getString(R.string.uri_api_weather_today);
- final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion,
- weatherLocation.getLatitude(), weatherLocation.getLongitude());
- final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
- final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
- final Current current = weatherService.retrieveCurrentFromJPOS(jsonData);
- // TODO: what is this for? I guess I could skip it :/
- final Calendar now = Calendar.getInstance();
- current.setDate(now.getTime());
-
- return current;
- }
-
- private interface UnitsConversor {
-
- public double doConversion(final double value);
- }
-
- private RemoteViews makeView(final Current current, final WeatherLocation weatherLocation, final int appWidgetId) {
- final SharedPreferences sharedPreferences = PreferenceManager
- .getDefaultSharedPreferences(this.getApplicationContext());
-
- // TODO: repeating the same code in Overview, Specific and Current!!!
- // 1. Update units of measurement.
- // 1.1 Temperature
- String tempSymbol;
- UnitsConversor tempUnitsConversor;
- String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
- String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- if (unitsPreferenceValue.equals(values[0])) {
- tempSymbol = values[0];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value - 273.15;
- }
-
- };
- } else if (unitsPreferenceValue.equals(values[1])) {
- tempSymbol = values[1];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return (value * 1.8) - 459.67;
- }
-
- };
- } else {
- tempSymbol = values[2];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value;
- }
-
- };
- }
-
-
- // 2. Formatters
- final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
- tempFormatter.applyPattern("#####.#####");
-
-
- // 3. Prepare data for RemoteViews.
- String tempMax = "";
- if (current.getMain().getTemp_max() != null) {
- double conversion = (Double) current.getMain().getTemp_max();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMax = tempFormatter.format(conversion) + tempSymbol;
- }
- String tempMin = "";
- if (current.getMain().getTemp_min() != null) {
- double conversion = (Double) current.getMain().getTemp_min();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMin = tempFormatter.format(conversion) + tempSymbol;
- }
- Bitmap picture;
- if ((current.getWeather().size() > 0)
- && (current.getWeather().get(0).getIcon() != null)
- && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
- final String icon = current.getWeather().get(0).getIcon();
- picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
- .getResourceDrawable());
- } else {
- picture = BitmapFactory.decodeResource(this.getResources(),
- R.drawable.weather_severe_alert);
- }
- final String city = weatherLocation.getCity();
- final String country = weatherLocation.getCountry();
-
- // 4. Insert data in RemoteViews.
- final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget);
- remoteView.setImageViewBitmap(R.id.weather_appwidget_image, picture);
- remoteView.setTextViewText(R.id.weather_appwidget_temperature_max, tempMax);
- remoteView.setTextViewText(R.id.weather_appwidget_temperature_min, tempMin);
- remoteView.setTextViewText(R.id.weather_appwidget_city, city);
- remoteView.setTextViewText(R.id.weather_appwidget_country, country);
-
- // 5. Activity launcher.
- final Intent resultIntent = new Intent(this.getApplicationContext(), WidgetConfigure.class);
- resultIntent.putExtra("actionFromUser", true);
- resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- // From: http://stackoverflow.com/questions/4011178/multiple-instances-of-widget-only-updating-last-widget
- final Uri data = Uri.withAppendedPath(Uri.parse("PAIN" + "://widget/id/") ,String.valueOf(appWidgetId));
- resultIntent.setData(data);
-
- final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
- // Adds the back stack for the Intent (but not the Intent itself)
- stackBuilder.addParentStack(WidgetConfigure.class);
- // Adds the Intent that starts the Activity to the top of the stack
- stackBuilder.addNextIntent(resultIntent);
- final PendingIntent resultPendingIntent =
- stackBuilder.getPendingIntent(
- 0,
- PendingIntent.FLAG_UPDATE_CURRENT
- );
- remoteView.setOnClickPendingIntent(R.id.weather_appwidget, resultPendingIntent);
-
- return remoteView;
- }
-
- private RemoteViews makeErrorView(final int appWidgetId) {
- final RemoteViews remoteView = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.appwidget_error);
-
- // 5. Activity launcher.
- final Intent resultIntent = new Intent(this.getApplicationContext(), WidgetConfigure.class);
- resultIntent.putExtra("actionFromUser", true);
- resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- // From: http://stackoverflow.com/questions/4011178/multiple-instances-of-widget-only-updating-last-widget
- final Uri data = Uri.withAppendedPath(Uri.parse("PAIN" + "://widget/id/") ,String.valueOf(appWidgetId));
- resultIntent.setData(data);
-
- final TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.getApplicationContext());
- // Adds the back stack for the Intent (but not the Intent itself)
- stackBuilder.addParentStack(WidgetConfigure.class);
- // Adds the Intent that starts the Activity to the top of the stack
- stackBuilder.addNextIntent(resultIntent);
- final PendingIntent resultPendingIntent =
- stackBuilder.getPendingIntent(
- 0,
- PendingIntent.FLAG_UPDATE_CURRENT
- );
- remoteView.setOnClickPendingIntent(R.id.weather_appwidget_error, resultPendingIntent);
-
- return remoteView;
- }
-
- private void updateWidget(final RemoteViews remoteView, final int appWidgetId) {
-
- final AppWidgetManager manager = AppWidgetManager.getInstance(this.getApplicationContext());
- manager.updateAppWidget(appWidgetId, remoteView);
- }
-
-// private void updateWidgets(final RemoteViews remoteView) {
-//
-// final ComponentName widgets = new ComponentName(this.getApplicationContext(), WidgetProvider.class);
-// final AppWidgetManager manager = AppWidgetManager.getInstance(this.getApplicationContext());
-// manager.updateAppWidget(widgets, remoteView);
-// }
-}
+++ /dev/null
-package de.example.exampletdd.dummy;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Helper class for providing sample content for user interfaces created by
- * Android template wizards.
- * <p>
- * TODO: Replace all uses of this class before publishing your app.
- */
-public class DummyContent {
-
- /**
- * An array of sample (dummy) items.
- */
- public static List<DummyItem> ITEMS = new ArrayList<DummyItem>();
-
- /**
- * A map of sample (dummy) items, by ID.
- */
- public static Map<String, DummyItem> ITEM_MAP = new HashMap<String, DummyItem>();
-
- static {
- // Add 3 sample items.
- addItem(new DummyItem("1", "Item 1"));
- addItem(new DummyItem("2", "Item 2"));
- addItem(new DummyItem("3", "Item 3"));
- }
-
- private static void addItem(DummyItem item) {
- ITEMS.add(item);
- ITEM_MAP.put(item.id, item);
- }
-
- /**
- * A dummy item representing a piece of content.
- */
- public static class DummyItem {
- public String id;
- public String content;
-
- public DummyItem(String id, String content) {
- this.id = id;
- this.content = content;
- }
-
- @Override
- public String toString() {
- return content;
- }
- }
-}
+++ /dev/null
-package de.example.exampletdd.fragment;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-
-public class ErrorDialogFragment extends DialogFragment {
-
- public static ErrorDialogFragment newInstance(final int title) {
- final ErrorDialogFragment frag = new ErrorDialogFragment();
- final Bundle args = new Bundle();
-
- args.putInt("title", title);
- frag.setArguments(args);
-
- return frag;
- }
-
- @Override
- public Dialog onCreateDialog(final Bundle savedInstanceState) {
- final int title = this.getArguments().getInt("title");
-
- return new AlertDialog.Builder(this.getActivity())
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(title)
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(final DialogInterface dialog,
- final int whichButton) {
-
- }
- }).create();
- }
-
- @Override
- public void onDestroyView() {
- if (getDialog() != null && getRetainInstance()) {
- getDialog().setDismissMessage(null);
- }
- super.onDestroyView();
- }
-}
\ No newline at end of file
+++ /dev/null
-package de.example.exampletdd.fragment;
-
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.view.KeyEvent;
-
-public class ProgressDialogFragment extends DialogFragment {
-
- public static ProgressDialogFragment newInstance(final int title) {
- return newInstance(title, null);
- }
-
- public static ProgressDialogFragment newInstance(final int title,
- final String message) {
- final ProgressDialogFragment frag = new ProgressDialogFragment();
- final Bundle args = new Bundle();
-
- args.putInt("title", title);
- args.putString("message", message);
- frag.setArguments(args);
- return frag;
- }
-
- @Override
- public Dialog onCreateDialog(final Bundle savedInstanceState) {
- final int title = this.getArguments().getInt("title");
- final String message = this.getArguments().getString("message");
-
- final ProgressDialog dialog = new ProgressDialog(this.getActivity());
- dialog.setIcon(android.R.drawable.ic_dialog_info);
- if (title != 0) {
- dialog.setTitle(title);
- }
- if (message != null) {
- dialog.setMessage(message);
- }
- dialog.setCancelable(false);
- this.setCancelable(false);
- dialog.setIndeterminate(true);
- dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
-
- @Override
- public final boolean onKey(final DialogInterface dialog,
- final int keyCode, final KeyEvent event) {
- return false;
- }
- });
-
- return dialog;
- }
-}
+++ /dev/null
-package de.example.exampletdd.fragment.current;
-
-import java.io.IOException;
-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.Calendar;
-import java.util.Date;
-import java.util.Locale;
-
-import org.apache.http.client.ClientProtocolException;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-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.support.v4.app.Fragment;
-import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import com.fasterxml.jackson.core.JsonParseException;
-
-import de.example.exampletdd.R;
-import de.example.exampletdd.WidgetIntentService;
-import de.example.exampletdd.httpclient.CustomHTTPClient;
-import de.example.exampletdd.model.DatabaseQueries;
-import de.example.exampletdd.model.WeatherLocation;
-import de.example.exampletdd.model.currentweather.Current;
-import de.example.exampletdd.parser.JPOSWeatherParser;
-import de.example.exampletdd.service.IconsList;
-import de.example.exampletdd.service.PermanentStorage;
-import de.example.exampletdd.service.ServiceParser;
-
-public class CurrentFragment extends Fragment {
- private static final String TAG = "CurrentFragment";
- private BroadcastReceiver mReceiver;
-
- @Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.weather_current_fragment, container, false);
- }
-
- @Override
- public void onActivityCreated(final Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- if (savedInstanceState != null) {
- // Restore UI state
- final Current current = (Current) savedInstanceState.getSerializable("Current");
-
- // TODO: Could it be better to store in global forecast data even if it is null value?
- // So, perhaps do not check for null value and always store in global variable.
- if (current != null) {
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- store.saveCurrent(current);
- }
- }
-
- this.setHasOptionsMenu(false);
-
- this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
- this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
- this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
-
- this.mReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(final Context context, final Intent intent) {
- final String action = intent.getAction();
- if (action.equals("de.example.exampletdd.UPDATECURRENT")) {
- final Current currentRemote = (Current) intent.getSerializableExtra("current");
-
- if (currentRemote != null) {
-
- // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask.
- final DatabaseQueries query = new DatabaseQueries(context.getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
- final PermanentStorage store = new PermanentStorage(context.getApplicationContext());
- final Current current = store.getCurrent();
-
- if (current == null || !CurrentFragment.this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
- // 2. Update UI.
- CurrentFragment.this.updateUI(currentRemote);
-
- // 3. Update Data.
- store.saveCurrent(currentRemote);
- weatherLocation.setLastCurrentUIUpdate(new Date());
- query.updateDataBase(weatherLocation);
- }
-
- } else {
- // Empty UI and show error message
- CurrentFragment.this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
- CurrentFragment.this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
- CurrentFragment.this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.VISIBLE);
- }
- }
- }
- };
-
- // Register receiver
- final IntentFilter filter = new IntentFilter();
- filter.addAction("de.example.exampletdd.UPDATECURRENT");
- LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext())
- .registerReceiver(this.mReceiver, filter);
-
- // Empty UI
- this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.GONE);
-
- final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
- if (weatherLocation == null) {
- // Nothing to do.
- // Show error message
- final ProgressBar progress = (ProgressBar) getActivity().findViewById(R.id.weather_current_progressbar);
- progress.setVisibility(View.GONE);
- final TextView errorMessage = (TextView) getActivity().findViewById(R.id.weather_current_error_message);
- errorMessage.setVisibility(View.VISIBLE);
- return;
- }
-
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- final Current current = store.getCurrent();
-
- if (current != null && this.isDataFresh(weatherLocation.getLastCurrentUIUpdate())) {
- this.updateUI(current);
- } else {
- // Load remote data (aynchronous)
- // Gets the data from the web.
- this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.VISIBLE);
- this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
- final CurrentTask task = new CurrentTask(
- this.getActivity().getApplicationContext(),
- new CustomHTTPClient(AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")),
- new ServiceParser(new JPOSWeatherParser()));
-
- task.execute(weatherLocation.getLatitude(), weatherLocation.getLongitude());
- // TODO: make sure UI thread keeps running in parallel after that. I guess.
- }
- }
-
- @Override
- public void onSaveInstanceState(final Bundle savedInstanceState) {
-
- // Save UI state
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- final Current current = store.getCurrent();
-
- // TODO: Could it be better to save current data even if it is null value?
- // So, perhaps do not check for null value.
- if (current != null) {
- savedInstanceState.putSerializable("Current", current);
- }
-
- super.onSaveInstanceState(savedInstanceState);
- }
-
- @Override
- public void onPause() {
- LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver);
-
- super.onPause();
- }
-
- private interface UnitsConversor {
-
- public double doConversion(final double value);
- }
-
- private void updateUI(final Current current) {
-
- final SharedPreferences sharedPreferences = PreferenceManager
- .getDefaultSharedPreferences(this.getActivity().getApplicationContext());
-
- // TODO: repeating the same code in Overview, Specific and Current!!!
- // 1. Update units of measurement.
- // 1.1 Temperature
- String tempSymbol;
- UnitsConversor tempUnitsConversor;
- String keyPreference = this.getResources().getString(R.string.weather_preferences_temperature_key);
- String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- if (unitsPreferenceValue.equals(values[0])) {
- tempSymbol = values[0];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value - 273.15;
- }
-
- };
- } else if (unitsPreferenceValue.equals(values[1])) {
- tempSymbol = values[1];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return (value * 1.8) - 459.67;
- }
-
- };
- } else {
- tempSymbol = values[2];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value;
- }
-
- };
- }
-
- // 1.2 Wind
- String windSymbol;
- UnitsConversor windUnitsConversor;
- keyPreference = this.getResources().getString(R.string.weather_preferences_wind_key);
- unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- values = this.getResources().getStringArray(R.array.weather_preferences_wind);
- if (unitsPreferenceValue.equals(values[0])) {
- windSymbol = values[0];
- windUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value;
- }
- };
- } else {
- windSymbol = values[1];
- windUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value * 2.237;
- }
- };
- }
-
- // 1.3 Pressure
- String pressureSymbol;
- UnitsConversor pressureUnitsConversor;
- keyPreference = this.getResources().getString(R.string.weather_preferences_pressure_key);
- unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
- if (unitsPreferenceValue.equals(values[0])) {
- pressureSymbol = values[0];
- pressureUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value;
- }
- };
- } else {
- pressureSymbol = values[1];
- pressureUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value / 113.25d;
- }
- };
- }
-
-
- // 2. Formatters
- final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
- tempFormatter.applyPattern("#####.#####");
- final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.US);
-
-
- // 3. Prepare data for UI.
- String tempMax = "";
- if (current.getMain().getTemp_max() != null) {
- double conversion = (Double) current.getMain().getTemp_max();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMax = tempFormatter.format(conversion) + tempSymbol;
- }
- String tempMin = "";
- if (current.getMain().getTemp_min() != null) {
- double conversion = (Double) current.getMain().getTemp_min();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMin = tempFormatter.format(conversion) + tempSymbol;
- }
- Bitmap picture;
- if ((current.getWeather().size() > 0)
- && (current.getWeather().get(0).getIcon() != null)
- && (IconsList.getIcon(current.getWeather().get(0).getIcon()) != null)) {
- final String icon = current.getWeather().get(0).getIcon();
- picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
- .getResourceDrawable());
- } else {
- picture = BitmapFactory.decodeResource(this.getResources(),
- R.drawable.weather_severe_alert);
- }
-
- // TODO: static resource
- String description = "no description available";
- if (current.getWeather().size() > 0) {
- description = current.getWeather().get(0).getDescription();
- }
-
- // TODO: units!!!!
- String humidityValue = "";
- if ((current.getMain() != null)
- && (current.getMain().getHumidity() != null)) {
- final double conversion = (Double) current.getMain().getHumidity();
- humidityValue = tempFormatter.format(conversion);
- }
- String pressureValue = "";
- if ((current.getMain() != null)
- && (current.getMain().getPressure() != null)) {
- double conversion = (Double) current.getMain().getPressure();
- conversion = pressureUnitsConversor.doConversion(conversion);
- pressureValue = tempFormatter.format(conversion);
- }
- String windValue = "";
- if ((current.getWind() != null)
- && (current.getWind().getSpeed() != null)) {
- double conversion = (Double) current.getWind().getSpeed();
- conversion = windUnitsConversor.doConversion(conversion);
- windValue = tempFormatter.format(conversion);
- }
- String rainValue = "";
- if ((current.getRain() != null)
- && (current.getRain().get3h() != null)) {
- final double conversion = (Double) current.getRain().get3h();
- rainValue = tempFormatter.format(conversion);
- }
- String cloudsValue = "";
- if ((current.getClouds() != null)
- && (current.getClouds().getAll() != null)) {
- final double conversion = (Double) current.getClouds().getAll();
- cloudsValue = tempFormatter.format(conversion);
- }
- String snowValue = "";
- if ((current.getSnow() != null)
- && (current.getSnow().get3h() != null)) {
- final double conversion = (Double) current.getSnow().get3h();
- snowValue = tempFormatter.format(conversion);
- }
- String feelsLike = "";
- if (current.getMain().getTemp() != null) {
- double conversion = (Double) current.getMain().getTemp();
- conversion = tempUnitsConversor.doConversion(conversion);
- feelsLike = tempFormatter.format(conversion);
- }
- String sunRiseTime = "";
- if (current.getSys().getSunrise() != null) {
- final long unixTime = (Long) current.getSys().getSunrise();
- final Date unixDate = new Date(unixTime * 1000L);
- sunRiseTime = dateFormat.format(unixDate);
- }
- String sunSetTime = "";
- if (current.getSys().getSunset() != null) {
- final long unixTime = (Long) current.getSys().getSunset();
- final Date unixDate = new Date(unixTime * 1000L);
- sunSetTime = dateFormat.format(unixDate);
- }
-
-
- // 4. Update UI.
- final TextView tempMaxView = (TextView) getActivity().findViewById(R.id.weather_current_temp_max);
- tempMaxView.setText(tempMax);
- final TextView tempMinView = (TextView) getActivity().findViewById(R.id.weather_current_temp_min);
- tempMinView.setText(tempMin);
- final ImageView pictureView = (ImageView) getActivity().findViewById(R.id.weather_current_picture);
- pictureView.setImageBitmap(picture);
-
- final TextView descriptionView = (TextView) getActivity().findViewById(R.id.weather_current_description);
- descriptionView.setText(description);
-
- ((TextView) getActivity().findViewById(R.id.weather_current_humidity_value)).setText(humidityValue);
- ((TextView) getActivity().findViewById(R.id.weather_current_humidity_units)).setText(
- this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
-
- ((TextView) getActivity().findViewById(R.id.weather_current_pressure_value)).setText(pressureValue);
- ((TextView) getActivity().findViewById(R.id.weather_current_pressure_units)).setText(pressureSymbol);
-
- ((TextView) getActivity().findViewById(R.id.weather_current_wind_value)).setText(windValue);
- ((TextView) getActivity().findViewById(R.id.weather_current_wind_units)).setText(windSymbol);
-
- ((TextView) getActivity().findViewById(R.id.weather_current_rain_value)).setText(rainValue);
- ((TextView) getActivity().findViewById(R.id.weather_current_rain_units)).setText(
- this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
-
- ((TextView) getActivity().findViewById(R.id.weather_current_clouds_value)).setText(cloudsValue);
- ((TextView) getActivity().findViewById(R.id.weather_current_clouds_units)).setText(
- this.getActivity().getApplicationContext().getString(R.string.text_units_percent));
-
- ((TextView) getActivity().findViewById(R.id.weather_current_snow_value)).setText(snowValue);
- ((TextView) getActivity().findViewById(R.id.weather_current_snow_units)).setText(
- this.getActivity().getApplicationContext().getString(R.string.text_units_mm3h));
-
- ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_value)).setText(feelsLike);
- ((TextView) getActivity().findViewById(R.id.weather_current_feelslike_units)).setText(tempSymbol);
-
- ((TextView) getActivity().findViewById(R.id.weather_current_sunrise_value)).setText(sunRiseTime);
-
- ((TextView) getActivity().findViewById(R.id.weather_current_sunset_value)).setText(sunSetTime);
-
- this.getActivity().findViewById(R.id.weather_current_data_container).setVisibility(View.VISIBLE);
- this.getActivity().findViewById(R.id.weather_current_progressbar).setVisibility(View.GONE);
- this.getActivity().findViewById(R.id.weather_current_error_message).setVisibility(View.GONE);
- }
-
- private boolean isDataFresh(final Date lastUpdate) {
- if (lastUpdate == null) {
- return false;
- }
-
- final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
- this.getActivity().getApplicationContext());
- final String keyPreference = this.getString(R.string.weather_preferences_refresh_interval_key);
- final String refresh = sharedPreferences.getString(
- keyPreference,
- this.getResources().getStringArray(R.array.weather_preferences_refresh_interval)[0]);
- final Date currentTime = new Date();
- if (((currentTime.getTime() - lastUpdate.getTime())) < Long.valueOf(refresh)) {
- return true;
- }
-
- return false;
- }
-
- // TODO: How could I show just one progress dialog when I have two fragments in tabs
- // activity doing the same in background?
- // I mean, if OverviewTask shows one progress dialog and CurrentTask does the same I will have
- // have two progress dialogs... How may I solve this problem? I HATE ANDROID.
- private class CurrentTask extends AsyncTask<Object, Void, Current> {
- // Store the context passed to the AsyncTask when the system instantiates it.
- private final Context localContext;
- final CustomHTTPClient HTTPClient;
- final ServiceParser weatherService;
-
- public CurrentTask(final Context context, final CustomHTTPClient HTTPClient,
- final ServiceParser weatherService) {
- this.localContext = context;
- this.HTTPClient = HTTPClient;
- this.weatherService = weatherService;
- }
-
- @Override
- protected Current doInBackground(final Object... params) {
- final double latitude = (Double) params[0];
- final double longitude = (Double) params[1];
-
- Current current = null;
- try {
- current = this.doInBackgroundThrowable(latitude, longitude);
- } catch (final JsonParseException e) {
- Log.e(TAG, "CurrentTask doInBackground exception: ", e);
- } catch (final ClientProtocolException e) {
- Log.e(TAG, "CurrentTask doInBackground exception: ", e);
- } catch (final MalformedURLException e) {
- Log.e(TAG, "CurrentTask doInBackground exception: ", e);
- } catch (final URISyntaxException e) {
- Log.e(TAG, "CurrentTask doInBackground exception: ", e);
- } catch (final IOException e) {
- // logger infrastructure swallows UnknownHostException :/
- Log.e(TAG, "CurrentTask doInBackground exception: " + e.getMessage(), e);
- } finally {
- HTTPClient.close();
- }
-
- return current;
- }
-
- private Current doInBackgroundThrowable(final double latitude, final double longitude)
- throws URISyntaxException, ClientProtocolException, JsonParseException, IOException {
-
- final String APIVersion = localContext.getResources().getString(R.string.api_version);
- final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_today);
- final String url = weatherService.createURIAPICurrent(urlAPI, APIVersion, latitude, longitude);
- final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
- final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
- final Current current = weatherService.retrieveCurrentFromJPOS(jsonData);
- // TODO: what is this for? I guess I could skip it :/
- final Calendar now = Calendar.getInstance();
- current.setDate(now.getTime());
-
- return current;
- }
-
- @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 :(
-
- // Call updateUI on the UI thread.
- final Intent currentData = new Intent("de.example.exampletdd.UPDATECURRENT");
- currentData.putExtra("current", current);
- LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(currentData);
- }
- }
-}
+++ /dev/null
-package de.example.exampletdd.fragment.map;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import de.example.exampletdd.R;
-
-public class MapButtonsFragment extends Fragment {
-
- @Override
- public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
- final Bundle savedInstanceState) {
-
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.weather_map_buttons, container, false);
- }
-
- /**
- * This method will only be called once when the retained
- * Fragment is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Retain this fragment across configuration changes.
- this.setRetainInstance(true);
- }
-}
+++ /dev/null
-package de.example.exampletdd.fragment.map;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-import android.app.Activity;
-import android.content.Context;
-import android.location.Address;
-import android.location.Geocoder;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import de.example.exampletdd.R;
-import de.example.exampletdd.model.WeatherLocation;
-
-/**
- * {@link http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html}
- *
- */
-public class MapProgressFragment extends Fragment {
-
- /**
- *
- * Callback interface through which the fragment will report the
- * task's progress and results back to the Activity.
- */
- public static interface TaskCallbacks {
- void onPostExecute(final WeatherLocation weatherLocation);
- }
-
- private TaskCallbacks mCallbacks;
-
- @Override
- public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
- final Bundle savedInstanceState) {
-
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.weather_map_progress, container, false);
- }
-
- /**
- * This method will only be called once when the retained
- * Fragment is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Retain this fragment across configuration changes.
- this.setRetainInstance(true);
-
- final Bundle bundle = this.getArguments();
- double latitude = bundle.getDouble("latitude");
- double longitude = bundle.getDouble("longitude");
-
- // Create and execute the background task.
- new GetAddressTask(this.getActivity().getApplicationContext()).execute(latitude, longitude);
- }
-
- /**
- * Hold a reference to the parent Activity so we can report the
- * task's current progress and results. The Android framework
- * will pass us a reference to the newly created Activity after
- * each configuration change.
- */
- @Override
- public void onAttach(final Activity activity) {
- super.onAttach(activity);
- mCallbacks = (TaskCallbacks) activity;
- }
-
- /**
- * Set the callback to null so we don't accidentally leak the
- * Activity instance.
- */
-// @Override
-// public void onDetach() {
-// super.onDetach();
-// mCallbacks = null;
-// }
-
- /**
- * I am not using onDetach because there are problems when my activity goes to background.
- *
- * {@link http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html}
- */
- @Override
- public void onPause() {
- super.onPause();
- mCallbacks = null;
- }
-
- private class GetAddressTask extends AsyncTask<Object, Void, WeatherLocation> {
- private static final String TAG = "GetAddressTask";
- // Store the context passed to the AsyncTask when the system instantiates it.
- private final Context localContext;
-
- private GetAddressTask(final Context context) {
- this.localContext = context;
- }
-
- @Override
- protected WeatherLocation doInBackground(final Object... params) {
- final double latitude = (Double) params[0];
- final double longitude = (Double) params[1];
-
- WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
- try {
- weatherLocation = this.getLocation(latitude, longitude);
- } catch (final Throwable e) { // Hopefully nothing goes wrong because of catching Throwable.
- Log.e(TAG, "GetAddressTask 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 :(
-
- // Call updateUI on the UI thread.
- if (mCallbacks != null) {
- mCallbacks.onPostExecute(weatherLocation);
- }
- }
-
- private WeatherLocation getLocation(final double latitude, final double longitude) throws IOException {
- // TODO: i18n Locale.getDefault()
- final Geocoder geocoder = new Geocoder(this.localContext, Locale.US);
- final List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
-
- // Default values
- WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
-
- if (addresses != null && addresses.size() > 0) {
- if (addresses.get(0).getLocality() != null) {
- weatherLocation.setCity(addresses.get(0).getLocality());
- }
- if(addresses.get(0).getCountryName() != null) {
- weatherLocation.setCountry(addresses.get(0).getCountryName());
- }
- }
-
- return weatherLocation;
- }
-
- private WeatherLocation doDefaultLocation(final double latitude, final double longitude) {
- // Default values
- String city = this.localContext.getString(R.string.city_not_found);
- String country = this.localContext.getString(R.string.country_not_found);
-
- return new WeatherLocation()
- .setLatitude(latitude)
- .setLongitude(longitude)
- .setCity(city)
- .setCountry(country);
- }
- }
-}
+++ /dev/null
-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 OverviewAdapter extends ArrayAdapter<OverviewEntry> {
- private final int resource;
-
- public OverviewAdapter(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 OverviewEntry entry = this.getItem(position);
-
-
- // Setting date
- viewHolder.dateNameView.setText(entry.getDateName());
- viewHolder.dateNumberView.setText(entry.getDateNumber());
-
- // Setting temperature max/min
- viewHolder.temperatureMaxView.setText(entry.getMaxTemp());
- viewHolder.temperatureMinView.setText(entry.getMinTemp());
-
- // 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.dateNameView = (TextView) workingView
- .findViewById(R.id.weather_main_entry_date_name);
- viewHolder.dateNumberView = (TextView) workingView
- .findViewById(R.id.weather_main_entry_date_number);
- viewHolder.temperatureMaxView = (TextView) workingView
- .findViewById(R.id.weather_main_entry_temperature_max);
- viewHolder.temperatureMinView = (TextView) workingView
- .findViewById(R.id.weather_main_entry_temperature_min);
- 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 dateNameView;
- public TextView dateNumberView;
- public TextView temperatureMaxView;
- public TextView temperatureMinView;
- public ImageView pictureView;
- }
-
-}
+++ /dev/null
-package de.example.exampletdd.fragment.overview;
-
-import android.graphics.Bitmap;
-
-public class OverviewEntry {
- private final String dateName;
- private final String dateNumber;
- private final String maxTemp;
- private final String minTemp;
- private final Bitmap picture;
-
- public OverviewEntry(final String dateName, final String dateNumber,
- final String maxTemp, final String minTemp,
- final Bitmap picture) {
- this.dateName = dateName;
- this.dateNumber = dateNumber;
- this.maxTemp = maxTemp;
- this.minTemp = minTemp;
- this.picture = picture;
- }
-
- public String getDateName() {
- return this.dateName;
- }
-
- public String getDateNumber() {
- return this.dateNumber;
- }
-
- public String getMaxTemp() {
- return this.maxTemp;
- }
-
- public String getMinTemp() {
- return this.minTemp;
- }
-
- public Bitmap getPicture() {
- return this.picture;
- }
-}
+++ /dev/null
-package de.example.exampletdd.fragment.overview;
-
-import java.io.IOException;
-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.Date;
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.http.client.ClientProtocolException;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-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.support.v4.app.ListFragment;
-import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-import android.view.View;
-import android.widget.ListView;
-
-import com.fasterxml.jackson.core.JsonParseException;
-
-import de.example.exampletdd.R;
-import de.example.exampletdd.fragment.specific.SpecificFragment;
-import de.example.exampletdd.httpclient.CustomHTTPClient;
-import de.example.exampletdd.model.DatabaseQueries;
-import de.example.exampletdd.model.WeatherLocation;
-import de.example.exampletdd.model.forecastweather.Forecast;
-import de.example.exampletdd.parser.JPOSWeatherParser;
-import de.example.exampletdd.service.IconsList;
-import de.example.exampletdd.service.PermanentStorage;
-import de.example.exampletdd.service.ServiceParser;
-
-public class OverviewFragment extends ListFragment {
- private static final String TAG = "OverviewFragment";
- private BroadcastReceiver mReceiver;
-
- @Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public void onActivityCreated(final Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- final ListView listWeatherView = this.getListView();
- listWeatherView.setChoiceMode(ListView.CHOICE_MODE_NONE);
-
- if (savedInstanceState != null) {
- // Restore UI state
- final Forecast forecast = (Forecast) savedInstanceState.getSerializable("Forecast");
-
- // TODO: Could it be better to store in global forecast data even if it is null value?
- // So, perhaps do not check for null value and always store in global variable.
- if (forecast != null) {
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- store.saveForecast(forecast);
- }
- }
-
- this.setHasOptionsMenu(false);
-
- this.setEmptyText(this.getString(R.string.text_field_remote_error));
- this.setListShownNoAnimation(false);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- this.mReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(final Context context, final Intent intent) {
- final String action = intent.getAction();
- if (action.equals("de.example.exampletdd.UPDATEFORECAST")) {
- final Forecast forecastRemote = (Forecast) intent.getSerializableExtra("forecast");
-
- if (forecastRemote != null) {
-
- // 1. Check conditions. They must be the same as the ones that triggered the AsyncTask.
- final DatabaseQueries query = new DatabaseQueries(context.getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
- final PermanentStorage store = new PermanentStorage(context.getApplicationContext());
- final Forecast forecast = store.getForecast();
-
- if (forecast == null || !OverviewFragment.this.isDataFresh(weatherLocation.getLastForecastUIUpdate())) {
- // 2. Update UI.
- OverviewFragment.this.updateUI(forecastRemote);
-
- // 3. Update Data.
- store.saveForecast(forecastRemote);
- weatherLocation.setLastForecastUIUpdate(new Date());
- query.updateDataBase(weatherLocation);
-
- // 4. Show list.
- OverviewFragment.this.setListShownNoAnimation(true);
- }
-
- } else {
- // Empty list and show error message (see setEmptyText in onCreate)
- OverviewFragment.this.setListAdapter(null);
- OverviewFragment.this.setListShownNoAnimation(true);
- }
- }
- }
- };
-
- // Register receiver
- final IntentFilter filter = new IntentFilter();
- filter.addAction("de.example.exampletdd.UPDATEFORECAST");
- LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext())
- .registerReceiver(this.mReceiver, filter);
-
- final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext());
- final WeatherLocation weatherLocation = query.queryDataBase();
- if (weatherLocation == null) {
- // Nothing to do.
- // Empty list and show error message (see setEmptyText in onCreate)
- this.setListAdapter(null);
- this.setListShownNoAnimation(true);
- return;
- }
-
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- final Forecast forecast = store.getForecast();
-
- // TODO: store forecast data in permanent storage and check here if there is data in permanent storage
- if (forecast != null && this.isDataFresh(weatherLocation.getLastForecastUIUpdate())) {
- this.updateUI(forecast);
- } else {
- // Load remote data (aynchronous)
- // Gets the data from the web.
- this.setListShownNoAnimation(false);
- final OverviewTask task = new OverviewTask(
- this.getActivity().getApplicationContext(),
- new CustomHTTPClient(AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")),
- new ServiceParser(new JPOSWeatherParser()));
-
- task.execute(weatherLocation.getLatitude(), weatherLocation.getLongitude());
- // TODO: make sure thread UI keeps running in parallel after that. I guess.
- }
- }
-
- @Override
- public void onSaveInstanceState(final Bundle savedInstanceState) {
-
- // Save UI state
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- final Forecast forecast = store.getForecast();
-
- // TODO: Could it be better to save forecast data even if it is null value?
- // So, perhaps do not check for null value.
- if (forecast != null) {
- savedInstanceState.putSerializable("Forecast", forecast);
- }
-
- super.onSaveInstanceState(savedInstanceState);
- }
-
- @Override
- public void onPause() {
- LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver);
-
- super.onPause();
- }
-
- @Override
- public void onListItemClick(final ListView l, final View v, final int position, final long id) {
- final SpecificFragment fragment = (SpecificFragment) this
- .getFragmentManager().findFragmentById(R.id.weather_specific_fragment);
- if (fragment == null) {
- // handset layout
- final Intent intent = new Intent("de.example.exampletdd.WEATHERINFO")
- .setComponent(new ComponentName("de.example.exampletdd",
- "de.example.exampletdd.SpecificActivity"));
- intent.putExtra("CHOSEN_DAY", (int) id);
- OverviewFragment.this.getActivity().startActivity(intent);
- } else {
- // tablet layout
- fragment.updateUIByChosenDay((int) id);
- }
- }
-
- private interface UnitsConversor {
-
- public double doConversion(final double value);
- }
-
- private void updateUI(final Forecast forecastWeatherData) {
-
- final SharedPreferences sharedPreferences = PreferenceManager
- .getDefaultSharedPreferences(this.getActivity().getApplicationContext());
-
- // TODO: repeating the same code in Overview, Specific and Current!!!
- // 1. Update units of measurement.
- String symbol;
- UnitsConversor unitsConversor;
- String keyPreference = this.getResources().getString(
- R.string.weather_preferences_temperature_key);
- final String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- if (unitsPreferenceValue.equals(values[0])) {
- symbol = values[0];
- unitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value - 273.15;
- }
-
- };
- } else if (unitsPreferenceValue.equals(values[1])) {
- symbol = values[1];
- unitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return (value * 1.8) - 459.67;
- }
-
- };
- } else {
- symbol = values[2];
- unitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value;
- }
-
- };
- }
-
-
- // 2. Update number day forecast.
- keyPreference = this.getResources().getString(R.string.weather_preferences_day_forecast_key);
- final String dayForecast = sharedPreferences.getString(keyPreference, "5");
- final int mDayForecast = Integer.valueOf(dayForecast);
-
-
- // 3. Formatters
- final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
- tempFormatter.applyPattern("#####.##");
- final SimpleDateFormat dayNameFormatter = new SimpleDateFormat("EEE", Locale.US);
- final SimpleDateFormat monthAndDayNumberormatter = new SimpleDateFormat("MMM d", Locale.US);
-
-
- // 4. Prepare data for UI.
- final List<OverviewEntry> entries = new ArrayList<OverviewEntry>();
- final OverviewAdapter adapter = new OverviewAdapter(this.getActivity(),
- R.layout.weather_main_entry_list);
- final Calendar calendar = Calendar.getInstance();
- int count = mDayForecast;
- for (final de.example.exampletdd.model.forecastweather.List forecast : forecastWeatherData
- .getList()) {
-
- Bitmap picture;
-
- if ((forecast.getWeather().size() > 0) &&
- (forecast.getWeather().get(0).getIcon() != null) &&
- (IconsList.getIcon(forecast.getWeather().get(0).getIcon()) != null)) {
- final String icon = forecast.getWeather().get(0).getIcon();
- picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
- .getResourceDrawable());
- } else {
- picture = BitmapFactory.decodeResource(this.getResources(),
- R.drawable.weather_severe_alert);
- }
-
- final Long forecastUNIXDate = (Long) forecast.getDt();
- calendar.setTimeInMillis(forecastUNIXDate * 1000L);
- final Date dayTime = calendar.getTime();
- final String dayTextName = dayNameFormatter.format(dayTime);
- final String monthAndDayNumberText = monthAndDayNumberormatter.format(dayTime);
-
- Double maxTemp = null;
- if (forecast.getTemp().getMax() != null) {
- maxTemp = (Double) forecast.getTemp().getMax();
- maxTemp = unitsConversor.doConversion(maxTemp);
- }
-
- Double minTemp = null;
- if (forecast.getTemp().getMin() != null) {
- minTemp = (Double) forecast.getTemp().getMin();
- minTemp = unitsConversor.doConversion(minTemp);
- }
-
- if ((maxTemp != null) && (minTemp != null)) {
- entries.add(new OverviewEntry(dayTextName, monthAndDayNumberText,
- tempFormatter.format(maxTemp) + symbol, tempFormatter.format(minTemp) + symbol,
- picture));
- }
-
- count = count - 1;
- if (count == 0) {
- break;
- }
- }
-
-
- // 5. Update UI.
- adapter.addAll(entries);
- this.setListAdapter(adapter);
- }
-
- private boolean isDataFresh(final Date lastUpdate) {
- if (lastUpdate == null) {
- return false;
- }
-
- final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
- this.getActivity().getApplicationContext());
- final String keyPreference = this.getString(R.string.weather_preferences_refresh_interval_key);
- final String refresh = sharedPreferences.getString(
- keyPreference,
- this.getResources().getStringArray(R.array.weather_preferences_refresh_interval)[0]);
- final Date currentTime = new Date();
- if (((currentTime.getTime() - lastUpdate.getTime())) < Long.valueOf(refresh)) {
- return true;
- }
-
- return false;
- }
-
- // TODO: How could I show just one progress dialog when I have two fragments in tabs
- // activity doing the same in background?
- // I mean, if OverviewTask shows one progress dialog and CurrentTask does the same I will have
- // have two progress dialogs... How may I solve this problem? I HATE ANDROID.
- private class OverviewTask extends AsyncTask<Object, Void, Forecast> {
- // Store the context passed to the AsyncTask when the system instantiates it.
- private final Context localContext;
- private final CustomHTTPClient HTTPClient;
- private final ServiceParser weatherService;
-
- public OverviewTask(final Context context, final CustomHTTPClient HTTPClient,
- final ServiceParser weatherService) {
- this.localContext = context;
- this.HTTPClient = HTTPClient;
- this.weatherService = weatherService;
- }
-
- @Override
- protected Forecast doInBackground(final Object... params) {
- final double latitude = (Double) params[0];
- final double longitude = (Double) params[1];
-
- Forecast forecast = null;
-
- try {
- forecast = this.doInBackgroundThrowable(latitude, longitude);
- } catch (final JsonParseException e) {
- Log.e(TAG, "OverviewTask doInBackground exception: ", e);
- } catch (final ClientProtocolException e) {
- Log.e(TAG, "OverviewTask doInBackground exception: ", e);
- } catch (final MalformedURLException e) {
- Log.e(TAG, "OverviewTask doInBackground exception: ", e);
- } catch (final URISyntaxException e) {
- Log.e(TAG, "OverviewTask doInBackground exception: ", e);
- } catch (final IOException e) {
- // logger infrastructure swallows UnknownHostException :/
- Log.e(TAG, "OverviewTask doInBackground exception: " + e.getMessage(), e);
- } finally {
- HTTPClient.close();
- }
-
- return forecast;
- }
-
- private Forecast doInBackgroundThrowable(final double latitude, final double longitude)
- throws URISyntaxException, ClientProtocolException, JsonParseException, IOException {
-
- final String APIVersion = localContext.getResources().getString(R.string.api_version);
- final String urlAPI = localContext.getResources().getString(R.string.uri_api_weather_forecast);
- // TODO: number as resource
- final String url = weatherService.createURIAPIForecast(urlAPI, APIVersion, latitude, longitude, "14");
- final String urlWithoutCache = url.concat("&time=" + System.currentTimeMillis());
- final String jsonData = HTTPClient.retrieveDataAsString(new URL(urlWithoutCache));
-
- return weatherService.retrieveForecastFromJPOS(jsonData);
- }
-
- @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 :(
-
- // Call updateUI on the UI thread.
- final Intent forecastData = new Intent("de.example.exampletdd.UPDATEFORECAST");
- forecastData.putExtra("forecast", forecast);
- LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(forecastData);
- }
- }
-}
+++ /dev/null
-package de.example.exampletdd.fragment.preferences;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.preference.SwitchPreference;
-import de.example.exampletdd.R;
-import de.example.exampletdd.NotificationIntentService;
-
-public class WeatherInformationPreferencesFragment extends PreferenceFragment
- implements OnSharedPreferenceChangeListener {
-
- @Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Load the preferences from an XML resource
- this.addPreferencesFromResource(R.xml.weather_preferences);
-
-
- // Temperature units
- String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- String[] humanValues = this.getResources().getStringArray(R.array.weather_preferences_temperature_human_value);
- String keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_temperature_key);
- Preference connectionPref = this.findPreference(keyPreference);
- String value = this.getPreferenceManager().getSharedPreferences()
- .getString(keyPreference, "");
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- }
- connectionPref.setSummary(humanValue);
-
- // Wind
- values = this.getResources().getStringArray(R.array.weather_preferences_wind);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_wind_human_value);
- keyPreference = this.getString(R.string.weather_preferences_wind_key);
- connectionPref = this.findPreference(keyPreference);
- value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
- humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- }
- connectionPref.setSummary(humanValue);
-
- // Pressure
- values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_pressure_human_value);
- keyPreference = this.getString(R.string.weather_preferences_pressure_key);
- connectionPref = this.findPreference(keyPreference);
- value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
- humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- }
- connectionPref.setSummary(humanValue);
-
- // Forecast days number
- values = this.getResources().getStringArray(R.array.weather_preferences_day_forecast);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_day_forecast_human_value);
- keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_day_forecast_key);
- connectionPref = this.findPreference(keyPreference);
- value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
- humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- }
- connectionPref.setSummary(humanValue);
-
- // Refresh interval
- values = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval_human_value);
- keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_refresh_interval_key);
- connectionPref = this.findPreference(keyPreference);
- value = this.getPreferenceManager().getSharedPreferences().getString(keyPreference, "");
- humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- } else if (value.equals(values[3])) {
- humanValue = humanValues[3];
- } else if (value.equals(values[4])) {
- humanValue = humanValues[4];
- } else if (value.equals(values[5])) {
- humanValue = humanValues[5];
- } else if (value.equals(values[6])) {
- humanValue = humanValues[6];
- }
- connectionPref.setSummary(humanValue);
-
- // Update Time Rate
- values = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate_human_value);
- keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_update_time_rate_key);
- connectionPref = this.findPreference(keyPreference);
- value = this.getPreferenceManager().getSharedPreferences()
- .getString(keyPreference, "");
- humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- } else if (value.equals(values[3])) {
- humanValue = humanValues[3];
- } else if (value.equals(values[4])) {
- humanValue = humanValues[4];
- }
- connectionPref.setSummary(humanValue);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- this.getPreferenceManager().getSharedPreferences()
- .registerOnSharedPreferenceChangeListener(this);
-
- }
-
- @Override
- public void onPause() {
- super.onPause();
- this.getPreferenceManager().getSharedPreferences()
- .unregisterOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public void onSharedPreferenceChanged(
- final SharedPreferences sharedPreferences, final String key) {
-
- // Temperature units
- String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- String[] humanValues = this.getResources().getStringArray(R.array.weather_preferences_temperature_human_value);
- String keyValue = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_temperature_key);
- if (key.equals(keyValue)) {
- final Preference connectionPref = this.findPreference(key);
- final String value = sharedPreferences.getString(key, "");
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- }
-
- connectionPref.setSummary(humanValue);
- return;
- }
-
- // Wind
- values = this.getResources().getStringArray(R.array.weather_preferences_wind);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_wind_human_value);
- keyValue = this.getString(R.string.weather_preferences_wind_key);
- if (key.equals(keyValue)) {
- final Preference connectionPref = this.findPreference(key);
- final String value = sharedPreferences.getString(key, "");
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- }
-
- connectionPref.setSummary(humanValue);
- return;
- }
-
- // Pressure
- values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_pressure_human_value);
- keyValue = this.getString(R.string.weather_preferences_pressure_key);
- if (key.equals(keyValue)) {
- final Preference connectionPref = this.findPreference(key);
- final String value = sharedPreferences.getString(key, "");
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- }
-
- connectionPref.setSummary(humanValue);
- return;
- }
-
- // Forecast days number
- values = this.getResources().getStringArray(R.array.weather_preferences_day_forecast);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_day_forecast_human_value);
- keyValue = this.getActivity().getString(
- R.string.weather_preferences_day_forecast_key);
- if (key.equals(keyValue)) {
- final Preference connectionPref = this.findPreference(key);
- final String value = sharedPreferences.getString(key, "");
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- }
- connectionPref.setSummary(humanValue);
- return;
- }
-
- // Refresh interval
- values = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_refresh_interval_human_value);
- keyValue = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_refresh_interval_key);
- if (key.equals(keyValue)) {
- final Preference connectionPref = this.findPreference(key);
- final String value = sharedPreferences.getString(key, "");
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- } else if (value.equals(values[3])) {
- humanValue = humanValues[3];
- } else if (value.equals(values[4])) {
- humanValue = humanValues[4];
- } else if (value.equals(values[5])) {
- humanValue = humanValues[5];
- } else if (value.equals(values[6])) {
- humanValue = humanValues[6];
- }
- connectionPref.setSummary(humanValue);
- return;
- }
-
- // Notification switch
- keyValue = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_notifications_switch_key);
- if (key.equals(keyValue)) {
- final SwitchPreference preference = (SwitchPreference)this.findPreference(key);
- if (preference.isChecked())
- {
- keyValue = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_update_time_rate_key);
- final String value = sharedPreferences.getString(keyValue, "");
- this.updateNotification(value);
- } else {
- this.cancelNotification();
- }
- }
- // Update Time Rate
- values = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate);
- humanValues = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate_human_value);
- keyValue = this.getActivity().getApplicationContext().getString(
- R.string.weather_preferences_update_time_rate_key);
- if (key.equals(keyValue)) {
- final Preference connectionPref = this.findPreference(key);
- final String value = sharedPreferences.getString(key, "");
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- } else if (value.equals(values[3])) {
- humanValue = humanValues[3];
- } else if (value.equals(values[4])) {
- humanValue = humanValues[4];
- }
-
- this.updateNotification(value);
- connectionPref.setSummary(humanValue);
- return;
- }
- }
-
- private void updateNotification(final String updateTimeRate) {
- final String[] values = this.getResources().getStringArray(R.array.weather_preferences_update_time_rate);
- long chosenInterval = 0;
- if (updateTimeRate.equals(values[0])) {
- chosenInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
- } else if (updateTimeRate.equals(values[1])) {
- chosenInterval = AlarmManager.INTERVAL_HALF_HOUR;
- } else if (updateTimeRate.equals(values[2])) {
- chosenInterval = AlarmManager.INTERVAL_HOUR;
- } else if (updateTimeRate.equals(values[3])) {
- chosenInterval = AlarmManager.INTERVAL_HALF_DAY;
- } else if (updateTimeRate.equals(values[4])) {
- chosenInterval = AlarmManager.INTERVAL_DAY;
- }
-
- final AlarmManager alarmMgr =
- (AlarmManager) this.getActivity().getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- // TODO: better use some string instead of .class? In case I change the service class
- // this could be a problem (I guess)
- final Intent serviceIntent =
- new Intent(this.getActivity().getApplicationContext(), NotificationIntentService.class);
- final PendingIntent alarmIntent =
- PendingIntent.getService(
- this.getActivity().getApplicationContext(),
- 0,
- serviceIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- if (chosenInterval != 0) {
- alarmMgr.setInexactRepeating(
- AlarmManager.ELAPSED_REALTIME,
- SystemClock.elapsedRealtime(),
- chosenInterval,
- alarmIntent);
- }
- }
-
- private void cancelNotification() {
- final AlarmManager alarmMgr =
- (AlarmManager) this.getActivity().getApplicationContext().getSystemService(Context.ALARM_SERVICE);
- final Intent serviceIntent =
- new Intent(this.getActivity().getApplicationContext(), NotificationIntentService.class);
- final PendingIntent alarmIntent =
- PendingIntent.getService(
- this.getActivity().getApplicationContext(),
- 0,
- serviceIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- alarmMgr.cancel(alarmIntent);
- }
-}
+++ /dev/null
-package de.example.exampletdd.fragment.specific;
-
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-import de.example.exampletdd.R;
-import de.example.exampletdd.model.forecastweather.Forecast;
-import de.example.exampletdd.service.IconsList;
-import de.example.exampletdd.service.PermanentStorage;
-
-
-public class SpecificFragment extends Fragment {
- private int mChosenDay;
-
- @Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- final Bundle extras = this.getActivity().getIntent().getExtras();
-
- if (extras != null) {
- // handset layout
- this.mChosenDay = extras.getInt("CHOSEN_DAY", 0);
- } else {
- // tablet layout
- // Always 0 when tablet layout (by default shows the first day)
- this.mChosenDay = 0;
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.weather_specific_fragment, container, false);
- }
-
- @Override
- public void onActivityCreated(final Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- if (savedInstanceState != null) {
- // Restore UI state
- final Forecast forecast = (Forecast) savedInstanceState.getSerializable("Forecast");
-
- // TODO: Could it be better to store in global data forecast even if it is null value?
- // So, perhaps do not check for null value and always store in global variable.
- if (forecast != null) {
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- store.saveForecast(forecast);
- }
-
- this.mChosenDay = savedInstanceState.getInt("mChosenDay");
- }
-
- this.setHasOptionsMenu(false);
- }
-
- @Override
- public void onSaveInstanceState(final Bundle savedInstanceState) {
-
- // Save UI state
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- final Forecast forecast = store.getForecast();
-
- // TODO: Could it be better to save forecast data even if it is null value?
- // So, perhaps do not check for null value.
- if (forecast != null) {
- savedInstanceState.putSerializable("Forecast", forecast);
- }
-
- savedInstanceState.putInt("mChosenDay", this.mChosenDay);
-
- super.onSaveInstanceState(savedInstanceState);
- }
-
- /**
- * This method is used by tablet layout.
- *
- * @param chosenDay
- */
- public void updateUIByChosenDay(final int chosenDay) {
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- final Forecast forecast = store.getForecast();
-
- if (forecast != null) {
- this.updateUI(forecast, chosenDay);
- }
- }
-
- private interface UnitsConversor {
-
- public double doConversion(final double value);
- }
-
- private void updateUI(final Forecast forecastWeatherData, final int chosenDay) {
-
- final SharedPreferences sharedPreferences = PreferenceManager
- .getDefaultSharedPreferences(this.getActivity());
-
- // TODO: repeating the same code in Overview, Specific and Current!!!
- // 1. Update units of measurement.
- // 1.1 Temperature
- String tempSymbol;
- UnitsConversor tempUnitsConversor;
- String keyPreference = this.getResources().getString(
- R.string.weather_preferences_temperature_key);
- String unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- if (unitsPreferenceValue.equals(values[0])) {
- tempSymbol = values[0];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value - 273.15;
- }
-
- };
- } else if (unitsPreferenceValue.equals(values[1])) {
- tempSymbol = values[1];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return (value * 1.8) - 459.67;
- }
-
- };
- } else {
- tempSymbol = values[2];
- tempUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(final double value) {
- return value;
- }
-
- };
- }
-
- // 1.2 Wind
- String windSymbol;
- UnitsConversor windUnitsConversor;
- keyPreference = this.getResources().getString(R.string.weather_preferences_wind_key);
- unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- values = this.getResources().getStringArray(R.array.weather_preferences_wind);
- if (unitsPreferenceValue.equals(values[0])) {
- windSymbol = values[0];
- windUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value;
- }
- };
- } else {
- windSymbol = values[1];
- windUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value * 2.237;
- }
- };
- }
-
- // 1.3 Pressure
- String pressureSymbol;
- UnitsConversor pressureUnitsConversor;
- keyPreference = this.getResources().getString(R.string.weather_preferences_pressure_key);
- unitsPreferenceValue = sharedPreferences.getString(keyPreference, "");
- values = this.getResources().getStringArray(R.array.weather_preferences_pressure);
- if (unitsPreferenceValue.equals(values[0])) {
- pressureSymbol = values[0];
- pressureUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value;
- }
- };
- } else {
- pressureSymbol = values[1];
- pressureUnitsConversor = new UnitsConversor(){
-
- @Override
- public double doConversion(double value) {
- return value / 113.25d;
- }
- };
- }
-
-
- // 2. Formatters
- final DecimalFormat tempFormatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
- tempFormatter.applyPattern("#####.#####");
-
-
- // 3. Prepare data for UI.
- final de.example.exampletdd.model.forecastweather.List forecast = forecastWeatherData
- .getList().get((chosenDay));
-
- final SimpleDateFormat dayFormatter = new SimpleDateFormat("EEEE - MMM d", Locale.US);
- final Calendar calendar = Calendar.getInstance();
- final Long forecastUNIXDate = (Long) forecast.getDt();
- calendar.setTimeInMillis(forecastUNIXDate * 1000L);
- final Date date = calendar.getTime();
-
- String tempMax = "";
- if (forecast.getTemp().getMax() != null) {
- double conversion = (Double) forecast.getTemp().getMax();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMax = tempFormatter.format(conversion) + tempSymbol;
- }
- String tempMin = "";
- if (forecast.getTemp().getMin() != null) {
- double conversion = (Double) forecast.getTemp().getMin();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMin = tempFormatter.format(conversion) + tempSymbol;
- }
- Bitmap picture;
- if ((forecast.getWeather().size() > 0) && (forecast.getWeather().get(0).getIcon() != null)
- && (IconsList.getIcon(forecast.getWeather().get(0).getIcon()) != null)) {
- final String icon = forecast.getWeather().get(0).getIcon();
- picture = BitmapFactory.decodeResource(this.getResources(), IconsList.getIcon(icon)
- .getResourceDrawable());
- } else {
- picture = BitmapFactory.decodeResource(this.getResources(),
- R.drawable.weather_severe_alert);
- }
-
- // TODO: string resource
- String description = "no description available";
- if (forecast.getWeather().size() > 0) {
- description = forecast.getWeather().get(0).getDescription();
- }
-
- // TODO: units!!!!
- String humidityValue = "";
- if (forecast.getHumidity() != null) {
- final double conversion = (Double) forecast.getHumidity();
- humidityValue = tempFormatter.format(conversion);
- }
- String pressureValue = "";
- if (forecast.getPressure() != null) {
- double conversion = (Double) forecast.getPressure();
- conversion = pressureUnitsConversor.doConversion(conversion);
- pressureValue = tempFormatter.format(conversion);
- }
- String windValue = "";
- if (forecast.getSpeed() != null) {
- double conversion = (Double) forecast.getSpeed();
- conversion = windUnitsConversor.doConversion(conversion);
- windValue = tempFormatter.format(conversion);
- }
- String rainValue = "";
- if (forecast.getRain() != null) {
- final double conversion = (Double) forecast.getRain();
- rainValue = tempFormatter.format(conversion);
- }
- String cloudsValue = "";
- if (forecast.getRain() != null) {
- final double conversion = (Double) forecast.getClouds();
- cloudsValue = tempFormatter.format(conversion);
- }
-
- String tempDay = "";
- if (forecast.getTemp().getDay() != null) {
- double conversion = (Double) forecast.getTemp().getDay();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempDay = tempFormatter.format(conversion) + tempSymbol;
- }
- String tempMorn = "";
- if (forecast.getTemp().getMorn() != null) {
- double conversion = (Double) forecast.getTemp().getMorn();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempMorn = tempFormatter.format(conversion) + tempSymbol;
- }
- String tempEve = "";
- if (forecast.getTemp().getEve() != null) {
- double conversion = (Double) forecast.getTemp().getEve();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempEve = tempFormatter.format(conversion) + tempSymbol;
- }
- String tempNight = "";
- if (forecast.getTemp().getNight() != null) {
- double conversion = (Double) forecast.getTemp().getNight();
- conversion = tempUnitsConversor.doConversion(conversion);
- tempNight = tempFormatter.format(conversion) + tempSymbol;
- }
-
-
- // 4. Update UI.
- this.getActivity().getActionBar().setSubtitle(dayFormatter.format(date).toUpperCase());
-
- final TextView tempMaxView = (TextView) getActivity().findViewById(R.id.weather_specific_temp_max);
- tempMaxView.setText(tempMax);
- final TextView tempMinView = (TextView) getActivity().findViewById(R.id.weather_specific_temp_min);
- tempMinView.setText(tempMin);
- final ImageView pictureView = (ImageView) getActivity().findViewById(R.id.weather_specific_picture);
- pictureView.setImageBitmap(picture);
-
- final TextView descriptionView = (TextView) getActivity().findViewById(R.id.weather_specific_description);
- descriptionView.setText(description);
-
- final TextView humidityValueView = (TextView) getActivity().findViewById(R.id.weather_specific_humidity_value);
- humidityValueView.setText(humidityValue);
- ((TextView) getActivity().findViewById(R.id.weather_specific_pressure_value)).setText(pressureValue);
- ((TextView) getActivity().findViewById(R.id.weather_specific_pressure_units)).setText(pressureSymbol);
- ((TextView) getActivity().findViewById(R.id.weather_specific_wind_value)).setText(windValue);;
- ((TextView) getActivity().findViewById(R.id.weather_specific_wind_units)).setText(windSymbol);
- final TextView rainValueView = (TextView) getActivity().findViewById(R.id.weather_specific_rain_value);
- rainValueView.setText(rainValue);
- final TextView cloudsValueView = (TextView) getActivity().findViewById(R.id.weather_specific_clouds_value);
- cloudsValueView.setText(cloudsValue);
-
- final TextView tempDayView = (TextView) getActivity().findViewById(R.id.weather_specific_day_temperature);
- tempDayView.setText(tempDay);
- final TextView tempMornView = (TextView) getActivity().findViewById(R.id.weather_specific_morn_temperature);
- tempMornView.setText(tempMorn);
- final TextView tempEveView = (TextView) getActivity().findViewById(R.id.weather_specific_eve_temperature);
- tempEveView.setText(tempEve);
- final TextView tempNightView = (TextView) getActivity().findViewById(R.id.weather_specific_night_temperature);
- tempNightView.setText(tempNight);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- final PermanentStorage store = new PermanentStorage(this.getActivity().getApplicationContext());
- final Forecast forecast = store.getForecast();
-
- if (forecast != null) {
- this.updateUI(forecast, this.mChosenDay);
- }
-
- // TODO: Overview is doing things with mListState... Why not here?
- }
-}
+++ /dev/null
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package de.example.exampletdd.httpclient;
-
-import java.nio.charset.Charset;
-
-/**
- * Commons constants.
- *
- * @since 4.2
- */
-public final class Consts {
-
- public static final int CR = 13; // <US-ASCII CR, carriage return (13)>
- public static final int LF = 10; // <US-ASCII LF, linefeed (10)>
- public static final int SP = 32; // <US-ASCII SP, space (32)>
- public static final int HT = 9; // <US-ASCII HT, horizontal-tab (9)>
-
- public static final Charset UTF_8 = Charset.forName("UTF-8");
- public static final Charset ASCII = Charset.forName("US-ASCII");
- public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
-
- private Consts() {
- }
-
-}
+++ /dev/null
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package de.example.exampletdd.httpclient;
-
-import java.nio.charset.Charset;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.Locale;
-
-import org.apache.http.Header;
-import org.apache.http.HeaderElement;
-import org.apache.http.HttpEntity;
-import org.apache.http.NameValuePair;
-import org.apache.http.ParseException;
-import org.apache.http.message.BasicHeaderValueParser;
-
-/**
- * Content type information consisting of a MIME type and an optional charset.
- * <p/>
- * This class makes no attempts to verify validity of the MIME type.
- * The input parameters of the {@link #create(String, String)} method, however, may not
- * contain characters <">, <;>, <,> reserved by the HTTP specification.
- *
- * @since 4.2
- */
-
-public final class ContentType {
-
- // constants
- public static final ContentType APPLICATION_ATOM_XML = create(
- "application/atom+xml", Consts.ISO_8859_1);
- public static final ContentType APPLICATION_FORM_URLENCODED = create(
- "application/x-www-form-urlencoded", Consts.ISO_8859_1);
- public static final ContentType APPLICATION_JSON = create(
- "application/json", Consts.UTF_8);
- public static final ContentType APPLICATION_OCTET_STREAM = create(
- "application/octet-stream", (Charset) null);
- public static final ContentType APPLICATION_SVG_XML = create(
- "application/svg+xml", Consts.ISO_8859_1);
- public static final ContentType APPLICATION_XHTML_XML = create(
- "application/xhtml+xml", Consts.ISO_8859_1);
- public static final ContentType APPLICATION_XML = create(
- "application/xml", Consts.ISO_8859_1);
- public static final ContentType MULTIPART_FORM_DATA = create(
- "multipart/form-data", Consts.ISO_8859_1);
- public static final ContentType TEXT_HTML = create(
- "text/html", Consts.ISO_8859_1);
- public static final ContentType TEXT_PLAIN = create(
- "text/plain", Consts.ISO_8859_1);
- public static final ContentType TEXT_XML = create(
- "text/xml", Consts.ISO_8859_1);
- public static final ContentType WILDCARD = create(
- "*/*", (Charset) null);
-
- // defaults
- public static final ContentType DEFAULT_TEXT = TEXT_PLAIN;
- public static final ContentType DEFAULT_BINARY = APPLICATION_OCTET_STREAM;
-
- private final String mimeType;
- private final Charset charset;
-
- /**
- * Given a MIME type and a character set, constructs a ContentType.
- * @param mimeType The MIME type to use for the ContentType header.
- * @param charset The optional character set to use with the ContentType header.
- * @throws UnsupportedCharsetException
- * If no support for the named charset is available in this Java virtual machine
- */
- ContentType(final String mimeType, final Charset charset) {
- this.mimeType = mimeType;
- this.charset = charset;
- }
-
- public String getMimeType() {
- return this.mimeType;
- }
-
- public Charset getCharset() {
- return this.charset;
- }
-
- /**
- * Converts a ContentType to a string which can be used as a ContentType header.
- * If a charset is provided by the ContentType, it will be included in the string.
- */
- @Override
- public String toString() {
- final StringBuilder buf = new StringBuilder();
- buf.append(this.mimeType);
- if (this.charset != null) {
- buf.append("; charset=");
- buf.append(this.charset);
- }
- return buf.toString();
- }
-
- private static boolean valid(final String s) {
- for (int i = 0; i < s.length(); i++) {
- final char ch = s.charAt(i);
- if ((ch == '"') || (ch == ',') || (ch == ';')) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Creates a new instance of {@link ContentType}.
- *
- * @param mimeType MIME type. It may not be <code>null</code> or empty. It may not contain
- * characters <">, <;>, <,> reserved by the HTTP specification.
- * @param charset charset.
- * @return content type
- */
- public static ContentType create(final String mimeType, final Charset charset) {
- if (mimeType == null) {
- throw new IllegalArgumentException("MIME type may not be null");
- }
- final String type = mimeType.trim().toLowerCase(Locale.US);
- if (type.length() == 0) {
- throw new IllegalArgumentException("MIME type may not be empty");
- }
- if (!valid(type)) {
- throw new IllegalArgumentException("MIME type may not contain reserved characters");
- }
- return new ContentType(type, charset);
- }
-
- /**
- * Creates a new instance of {@link ContentType} without a charset.
- *
- * @param mimeType MIME type. It may not be <code>null</code> or empty. It may not contain
- * characters <">, <;>, <,> reserved by the HTTP specification.
- * @return content type
- */
- public static ContentType create(final String mimeType) {
- return new ContentType(mimeType, (Charset) null);
- }
-
- /**
- * Creates a new instance of {@link ContentType}.
- *
- * @param mimeType MIME type. It may not be <code>null</code> or empty. It may not contain
- * characters <">, <;>, <,> reserved by the HTTP specification.
- * @param charset charset. It may not contain characters <">, <;>, <,> reserved by the HTTP
- * specification. This parameter is optional.
- * @return content type
- */
- public static ContentType create(
- final String mimeType, final String charset) throws UnsupportedCharsetException {
- return create(mimeType, charset != null ? Charset.forName(charset) : null);
- }
-
- private static ContentType create(final HeaderElement helem) {
- final String mimeType = helem.getName();
- String charset = null;
- final NameValuePair param = helem.getParameterByName("charset");
- if (param != null) {
- charset = param.getValue();
- }
- return create(mimeType, charset);
- }
-
- /**
- * Parses textual representation of <code>Content-Type</code> value.
- *
- * @param s text
- * @return content type
- * @throws ParseException if the given text does not represent a valid
- * <code>Content-Type</code> value.
- */
- public static ContentType parse(
- final String s) throws ParseException, UnsupportedCharsetException {
- if (s == null) {
- throw new IllegalArgumentException("Content type may not be null");
- }
- final HeaderElement[] elements = BasicHeaderValueParser.parseElements(s, null);
- if (elements.length > 0) {
- return create(elements[0]);
- } else {
- throw new ParseException("Invalid content type: " + s);
- }
- }
-
- /**
- * Extracts <code>Content-Type</code> value from {@link HttpEntity} exactly as
- * specified by the <code>Content-Type</code> header of the entity. Returns <code>null</code>
- * if not specified.
- *
- * @param entity HTTP entity
- * @return content type
- * @throws ParseException if the given text does not represent a valid
- * <code>Content-Type</code> value.
- */
- public static ContentType get(
- final HttpEntity entity) throws ParseException, UnsupportedCharsetException {
- if (entity == null) {
- return null;
- }
- final Header header = entity.getContentType();
- if (header != null) {
- final HeaderElement[] elements = header.getElements();
- if (elements.length > 0) {
- return create(elements[0]);
- }
- }
- return null;
- }
-
- /**
- * Extracts <code>Content-Type</code> value from {@link HttpEntity} or returns default value
- * if not explicitly specified.
- *
- * @param entity HTTP entity
- * @return content type
- * @throws ParseException if the given text does not represent a valid
- * <code>Content-Type</code> value.
- */
- public static ContentType getOrDefault(final HttpEntity entity) throws ParseException {
- final ContentType contentType = get(entity);
- return contentType != null ? contentType : DEFAULT_TEXT;
- }
-
-}
+++ /dev/null
-package de.example.exampletdd.httpclient;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-import java.net.URL;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpGet;
-
-import android.net.http.AndroidHttpClient;
-
-public class CustomHTTPClient {
- private final AndroidHttpClient httpClient;
-
- public CustomHTTPClient(final AndroidHttpClient httpClient) {
- this.httpClient = httpClient;
- }
-
- public String retrieveDataAsString(final URL url)
- throws URISyntaxException, ClientProtocolException, IOException {
-
- final ResponseHandler<String> handler = new ResponseHandler<String>() {
- @Override
- public String handleResponse(
- final HttpResponse response)
- throws UnsupportedEncodingException, IOException {
-
- if (response != null) {
- final HttpEntity entity = response.getEntity();
- if (entity != null) {
- try {
- final ContentType contentType = ContentType.getOrDefault(entity);
- final ByteArrayOutputStream buffer = CustomHTTPClient.this
- .sortResponse(response);
- return new String(buffer.toByteArray(), contentType.getCharset());
- } finally {
- entity.consumeContent();
- }
- }
-
- throw new IOException("There is no entity");
- }
-
- throw new IOException("There is no response");
- }
- };
-
- final HttpGet httpGet = new HttpGet();
- httpGet.setURI(url.toURI());
-
- return this.httpClient.execute(httpGet, handler);
- }
-
- public ByteArrayOutputStream retrieveRawData(final URL url)
- throws URISyntaxException, ClientProtocolException, IOException {
- final ResponseHandler<ByteArrayOutputStream> handler = new ResponseHandler<ByteArrayOutputStream>() {
-
- @Override
- public ByteArrayOutputStream handleResponse(
- final HttpResponse response)
- throws UnsupportedEncodingException, IOException {
-
- if (response != null) {
- final HttpEntity entity = response.getEntity();
- if (entity != null) {
- try {
- return CustomHTTPClient.this.sortResponse(response);
- } finally {
- entity.consumeContent();
- }
- }
-
- throw new IOException("There is no entity");
- }
-
- throw new IOException("There is no response");
- }
- };
-
- final HttpGet httpGet = new HttpGet();
- httpGet.setURI(url.toURI());
-
- return this.httpClient.execute(httpGet, handler);
- }
-
- public void close() {
- this.httpClient.close();
- }
-
- private ByteArrayOutputStream sortResponse(final HttpResponse httpResponse) throws IOException {
-
- if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
- throw new IOException("Unexpected response code: "
- + httpResponse.getStatusLine().getStatusCode());
- }
-
- final HttpEntity entity = httpResponse.getEntity();
- final InputStream inputStream = entity.getContent();
- try {
- return this.readInputStream(inputStream);
- } finally {
- inputStream.close();
- }
-
- }
-
- private ByteArrayOutputStream readInputStream (final InputStream inputStream) throws IOException {
- final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
- final int bufferSize = 1024;
- final byte[] buffer = new byte[bufferSize];
-
- int len = 0;
- while ((len = inputStream.read(buffer)) != -1) {
- byteBuffer.write(buffer, 0, len);
- }
-
- return byteBuffer;
- }
-}
+++ /dev/null
-package de.example.exampletdd.model;
-
-import android.content.Context;
-
-public class DatabaseQueries {
- private final Context localContext;
-
- public DatabaseQueries(final Context context) {
- this.localContext = context;
- }
-
- public WeatherLocation queryDataBase() {
-
- final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this.localContext);
- try {
- final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper);
- return queryDb.queryDataBase();
- } finally {
- dbHelper.close();
- }
- }
-
- public long insertIntoDataBase(final WeatherLocation weatherLocation) {
-
- final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this.localContext);
- try {
- final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper);
- return queryDb.insertIntoDataBase(weatherLocation);
- } finally {
- dbHelper.close();
- }
- }
-
- public void updateDataBase(final WeatherLocation weatherLocation) {
-
- final WeatherLocationDbHelper dbHelper = new WeatherLocationDbHelper(this.localContext);
- try {
- final WeatherLocationDbQueries queryDb = new WeatherLocationDbQueries(dbHelper);
- queryDb.updateDataBase(weatherLocation);
- } finally {
- dbHelper.close();
- }
- }
-}
+++ /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 = -1469725417020355109L;
- private int id;
- private String city;
- private String country;
- private boolean isSelected;
- private double latitude;
- private double longitude;
- private Date lastCurrentUIUpdate;
- private Date lastForecastUIUpdate;
-
- public WeatherLocation setId(int id) {
- this.id = id;
- return this;
- }
-
- public WeatherLocation setCity(String city) {
- this.city = city;
- return this;
- }
-
- public WeatherLocation setCountry(String country) {
- this.country = country;
- return this;
- }
-
- public WeatherLocation setIsSelected(boolean isSelected) {
- this.isSelected = isSelected;
- return this;
- }
-
- public WeatherLocation setLatitude(double latitude) {
- this.latitude = latitude;
- return this;
- }
-
- public WeatherLocation setLongitude(double longitude) {
- this.longitude = longitude;
- return this;
- }
-
- public WeatherLocation setLastCurrentUIUpdate(Date lastCurrentUIUpdate) {
- this.lastCurrentUIUpdate = lastCurrentUIUpdate;
- return this;
- }
-
- public WeatherLocation setLastForecastUIUpdate(Date lastForecastUIUpdate) {
- this.lastForecastUIUpdate = lastForecastUIUpdate;
- return this;
- }
-
- public int getId() {
- return this.id;
- }
-
- public String getCity() {
- return this.city;
- }
-
- public String getCountry() {
- return this.country;
- }
-
- public boolean getIsSelected() {
- return this.isSelected;
- }
-
- 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 java.util.Calendar;
-import java.util.Date;
-
-import android.content.ContentValues;
-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;
- }
-
- public 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 WeatherLocationDbQueries.DoQuery doQuery = new WeatherLocationDbQueries.DoQuery() {
-
- @Override
- public WeatherLocation doQuery(final Cursor cursor) {
- final int id = cursor.getInt(cursor.getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation._ID));
- final String city = cursor.getString(cursor.
- getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY));
- final String country = cursor.getString(cursor.
- getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY));
- final boolean isSelected = (cursor.getInt(cursor
- .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED)) == 0) ? false : true;
- Date lastCurrentUIUpdate = null;
- if (!cursor.isNull(cursor
- .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE))) {
- final long javaTime = cursor.getLong(cursor
- .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE));
- lastCurrentUIUpdate = new Date(javaTime);
- }
- Date lasForecastUIUpdate = null;
- if (!cursor.isNull(cursor
- .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE))) {
- final long javaTime = cursor.getLong(cursor
- .getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE));
- lasForecastUIUpdate = new Date(javaTime);
- }
- final double latitude = cursor.getDouble(cursor.
- getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE));
- final double longitude = cursor.getDouble(cursor.
- getColumnIndexOrThrow(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE));
-
-
- return new WeatherLocation()
- .setId(id)
- .setCity(city)
- .setCountry(country)
- .setIsSelected(isSelected)
- .setLastCurrentUIUpdate(lastCurrentUIUpdate)
- .setLastForecastUIUpdate(lasForecastUIUpdate)
- .setLatitude(latitude)
- .setLongitude(longitude);
- }
- };
-
- return this.queryDataBase(
- WeatherLocationContract.WeatherLocation.TABLE_NAME, projection,
- selectionArgs, selection, doQuery);
- }
-
- public long insertIntoDataBase(final WeatherLocation weatherLocation) {
- // Create a new map of values, where column names are the keys
- final ContentValues values = new ContentValues();
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY, weatherLocation.getCity());
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY, weatherLocation.getCountry());
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED, weatherLocation.getIsSelected());
- Date javaTime = weatherLocation.getLastCurrentUIUpdate();
- if (javaTime != null) {
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE, javaTime.getTime());
- }
- javaTime = weatherLocation.getLastForecastUIUpdate();
- if (javaTime != null) {
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE, javaTime.getTime());
- }
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE, weatherLocation.getLatitude());
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE, weatherLocation.getLongitude());
-
- return this.insertIntoDataBase(WeatherLocationContract.WeatherLocation.TABLE_NAME, values);
- }
-
- public void updateDataBase(final WeatherLocation weatherLocation) {
- final String selection = WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED + " = ?";
- final String[] selectionArgs = { "1" };
- // Create a new map of values, where column names are the keys
- final ContentValues values = new ContentValues();
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_CITY, weatherLocation.getCity());
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_COUNTRY, weatherLocation.getCountry());
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_IS_SELECTED, weatherLocation.getIsSelected());
- Date javaTime = weatherLocation.getLastCurrentUIUpdate();
- if (javaTime != null) {
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE, javaTime.getTime());
- } else {
- values.putNull(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_CURRENT_UI_UPDATE);
- }
- javaTime = weatherLocation.getLastForecastUIUpdate();
- if (javaTime != null) {
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE, javaTime.getTime());
- } else {
- values.putNull(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LAST_FORECAST_UI_UPDATE);
- }
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LATITUDE, weatherLocation.getLatitude());
- values.put(WeatherLocationContract.WeatherLocation.COLUMN_NAME_LONGITUDE, weatherLocation.getLongitude());
-
- this.updateDataBase(WeatherLocationContract.WeatherLocation.TABLE_NAME, selectionArgs, selection, values);
- }
-
- // TODO: May I perform another query after this method (after closing almost everything but mDbHelper)
- private WeatherLocation queryDataBase(final 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();
- }
- }
-
- // TODO: May I perform another query after this method (after closing almost everything but mDbHelper)
- private long insertIntoDataBase(final String table, final ContentValues values) {
- final SQLiteDatabase db = this.mDbHelper.getWritableDatabase();
- try {
- return db.insert(table, null, values);
- } finally {
- db.close();
- }
- }
-
- // TODO: May I perform another query after this method (after closing almost everything but mDbHelper)
- private long updateDataBase(final String table, final String[] selectionArgs,
- final String selection, final ContentValues values) {
- final SQLiteDatabase db = this.mDbHelper.getWritableDatabase();
- try {
- return db.update(table, values, selection, selectionArgs);
- } finally {
- db.close();
- }
- }
-
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-public class Clouds implements Serializable {
- private static final long serialVersionUID = 3034435739326030899L;
- private Number all;
-
- public Number getAll(){
- return this.all;
- }
- public void setAll(final Number all){
- this.all = all;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Clouds [all=").append(this.all).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-public class Coord implements Serializable {
- private static final long serialVersionUID = 7151637605146377486L;
- private Number lat;
- private Number lon;
-
- public Number getLat(){
- return this.lat;
- }
- public void setLat(final Number lat){
- this.lat = lat;
- }
- public Number getLon(){
- return this.lon;
- }
- public void setLon(final Number lon){
- this.lon = lon;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Coord [lat=").append(this.lat).append(", lon=").append(this.lon)
- .append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Auto generated by: http://jsongen.byingtondesign.com/
- * (with my own modifications)
- *
- */
-public class Current implements Serializable {
- private static final long serialVersionUID = -730690341739860818L;
- private String base;
- private Clouds clouds;
- private Number cod;
- private Coord coord;
- private Number dt;
- private Number id;
- private Main main;
- private String name;
- private Rain rain;
- private Snow snow;
- private Sys sys;
- private List<Weather> weather;
- private Wind wind;
- private byte[] iconData;
- private Date date;
-
- public String getBase(){
- return this.base;
- }
- public void setBase(final String base){
- this.base = base;
- }
- public Clouds getClouds(){
- return this.clouds;
- }
- public void setClouds(final Clouds clouds){
- this.clouds = clouds;
- }
-
- public Number getCod() {
- return this.cod;
- }
-
- public void setCod(final Number cod) {
- this.cod = cod;
- }
- public Coord getCoord(){
- return this.coord;
- }
- public void setCoord(final Coord coord){
- this.coord = coord;
- }
- public Number getDt(){
- return this.dt;
- }
- public void setDt(final Number dt){
- this.dt = dt;
- }
- public Number getId(){
- return this.id;
- }
- public void setId(final Number id){
- this.id = id;
- }
- public Main getMain(){
- return this.main;
- }
- public void setMain(final Main main){
- this.main = main;
- }
- public String getName(){
- return this.name;
- }
- public void setName(final String name){
- this.name = name;
- }
- public Rain getRain(){
- return this.rain;
- }
- public void setRain(final Rain rain){
- this.rain = rain;
- }
- public Snow getSnow() {
- return this.snow;
- }
- public void setSnow(final Snow snow) {
- this.snow = snow;
- }
- public Sys getSys(){
- return this.sys;
- }
- public void setSys(final Sys sys){
- this.sys = sys;
- }
- public List<Weather> getWeather(){
- return this.weather;
- }
- public void setWeather(final List<Weather> weather){
- this.weather = weather;
- }
- public Wind getWind(){
- return this.wind;
- }
- public void setWind(final Wind wind){
- this.wind = wind;
- }
-
- public byte[] getIconData() {
- return this.iconData;
- }
-
- public void setIconData(final byte[] iconData) {
- this.iconData = iconData;
- }
-
- public Date getDate() {
- return this.date;
- }
-
- public void setDate(final Date date) {
- this.date = date;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Current [base=").append(this.base).append(", clouds=")
- .append(this.clouds).append(", cod=").append(this.cod).append(", coord=")
- .append(this.coord).append(", dt=").append(this.dt).append(", id=").append(this.id)
- .append(", main=").append(this.main).append(", name=").append(this.name)
- .append(", rain=").append(this.rain).append(", snow=").append(this.snow)
- .append(", sys=").append(this.sys).append(", weather=").append(this.weather)
- .append(", wind=").append(this.wind).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-public class Main implements Serializable {
- private static final long serialVersionUID = -6000879164436289447L;
- private Number grnd_level;
- private Number humidity;
- private Number pressure;
- private Number sea_level;
- private Number temp;
- private Number temp_max;
- private Number temp_min;
-
- public Number getGrnd_level() {
- return this.grnd_level;
- }
-
- public void setGrnd_level(final Number grnd_level) {
- this.grnd_level = grnd_level;
- }
-
- public Number getHumidity(){
- return this.humidity;
- }
- public void setHumidity(final Number humidity){
- this.humidity = humidity;
- }
- public Number getPressure(){
- return this.pressure;
- }
- public void setPressure(final Number pressure){
- this.pressure = pressure;
- }
-
- public Number getSea_level() {
- return this.sea_level;
- }
-
- public void setSea_level(final Number sea_level) {
- this.sea_level = sea_level;
- }
-
- public Number getTemp(){
- return this.temp;
- }
- public void setTemp(final Number temp){
- this.temp = temp;
- }
- public Number getTemp_max(){
- return this.temp_max;
- }
- public void setTemp_max(final Number temp_max){
- this.temp_max = temp_max;
- }
- public Number getTemp_min(){
- return this.temp_min;
- }
- public void setTemp_min(final Number temp_min){
- this.temp_min = temp_min;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Main [grnd_level=").append(this.grnd_level).append(", humidity=")
- .append(this.humidity).append(", pressure=").append(this.pressure)
- .append(", sea_level=").append(this.sea_level).append(", temp=").append(this.temp)
- .append(", temp_max=").append(this.temp_max).append(", temp_min=")
- .append(this.temp_min).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-public class Rain implements Serializable {
- private static final long serialVersionUID = 1318464783605029435L;
- private Number three;
-
- public Number get3h(){
- return this.three;
- }
-
- public void set3h(final Number threeh) {
- this.three = threeh;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Rain [three=").append(this.three).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-public class Snow implements Serializable {
- private static final long serialVersionUID = 6769716772818311879L;
- private Number three;
-
- public Number get3h() {
- return this.three;
- }
-
- public void set3h(final Number threeh) {
- this.three = threeh;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Snow [three=").append(this.three).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-
-public class Sys implements Serializable {
- private static final long serialVersionUID = 5333083785731053139L;
- private String country;
- private Number message;
- private Number sunrise;
- private Number sunset;
-
- public String getCountry(){
- return this.country;
- }
- public void setCountry(final String country){
- this.country = country;
- }
- public Number getMessage(){
- return this.message;
- }
- public void setMessage(final Number message){
- this.message = message;
- }
- public Number getSunrise(){
- return this.sunrise;
- }
- public void setSunrise(final Number sunrise){
- this.sunrise = sunrise;
- }
- public Number getSunset(){
- return this.sunset;
- }
- public void setSunset(final Number sunset){
- this.sunset = sunset;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Sys [country=").append(this.country).append(", message=")
- .append(this.message).append(", sunrise=").append(this.sunrise).append(", sunset=")
- .append(this.sunset).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-public class Weather implements Serializable {
- private static final long serialVersionUID = -34336548786316655L;
- private String description;
- private String icon;
- private Number id;
- private String main;
-
- public String getDescription(){
- return this.description;
- }
- public void setDescription(final String description){
- this.description = description;
- }
- public String getIcon(){
- return this.icon;
- }
- public void setIcon(final String icon){
- this.icon = icon;
- }
- public Number getId(){
- return this.id;
- }
- public void setId(final Number id){
- this.id = id;
- }
- public String getMain(){
- return this.main;
- }
- public void setMain(final String main){
- this.main = main;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Weather [description=").append(this.description).append(", icon=")
- .append(this.icon).append(", id=").append(this.id).append(", main=")
- .append(this.main).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.currentweather;
-
-import java.io.Serializable;
-
-public class Wind implements Serializable {
- private static final long serialVersionUID = 5495842422633674631L;
- private Number deg;
- private Number speed;
-
- public Number getDeg(){
- return this.deg;
- }
- public void setDeg(final Number deg){
- this.deg = deg;
- }
- public Number getSpeed(){
- return this.speed;
- }
- public void setSpeed(final Number speed){
- this.speed = speed;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Wind [deg=").append(this.deg).append(", speed=").append(this.speed)
- .append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.forecastweather;
-
-import java.io.Serializable;
-
-
-public class City implements Serializable {
- private static final long serialVersionUID = 3079687975077030704L;
- private Coord coord;
- private String country;
- private Number id;
- private String name;
- private Number population;
-
- public Coord getCoord(){
- return this.coord;
- }
- public void setCoord(final Coord coord){
- this.coord = coord;
- }
- public String getCountry(){
- return this.country;
- }
- public void setCountry(final String country){
- this.country = country;
- }
- public Number getId(){
- return this.id;
- }
- public void setId(final Number id){
- this.id = id;
- }
- public String getName(){
- return this.name;
- }
- public void setName(final String name){
- this.name = name;
- }
- public Number getPopulation(){
- return this.population;
- }
- public void setPopulation(final Number population){
- this.population = population;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("City [coord=").append(this.coord).append(", country=").append(this.country)
- .append(", id=").append(this.id).append(", name=").append(this.name)
- .append(", population=").append(this.population).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.forecastweather;
-
-import java.io.Serializable;
-
-public class Coord implements Serializable {
- private static final long serialVersionUID = 8069257976701986700L;
- private Number lat;
- private Number lon;
-
- public Number getLat(){
- return this.lat;
- }
- public void setLat(final Number lat){
- this.lat = lat;
- }
- public Number getLon(){
- return this.lon;
- }
- public void setLon(final Number lon){
- this.lon = lon;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Coord [lat=").append(this.lat).append(", lon=").append(this.lon)
- .append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.forecastweather;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * Auto generated by: http://jsongen.byingtondesign.com/
- * (with my own modifications)
- *
- */
-public class Forecast implements Serializable {
- private static final long serialVersionUID = 5095443678019686190L;
- private City city;
- private Number cnt;
- private Number cod;
- private List<de.example.exampletdd.model.forecastweather.List> list;
- private Number message;
-
- public City getCity(){
- return this.city;
- }
- public void setCity(final City city){
- this.city = city;
- }
- public Number getCnt(){
- return this.cnt;
- }
- public void setCnt(final Number cnt){
- this.cnt = cnt;
- }
-
- public Number getCod() {
- return this.cod;
- }
-
- public void setCod(final Number cod) {
- this.cod = cod;
- }
-
- public List<de.example.exampletdd.model.forecastweather.List> getList() {
- return this.list;
- }
-
- public void setList(final List<de.example.exampletdd.model.forecastweather.List> list) {
- this.list = list;
- }
- public Number getMessage(){
- return this.message;
- }
- public void setMessage(final Number message){
- this.message = message;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Forecast [city=").append(this.city).append(", cnt=")
- .append(this.cnt).append(", cod=").append(this.cod).append(", list=")
- .append(this.list).append(", message=").append(this.message).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.forecastweather;
-
-import java.io.Serializable;
-
-
-public class List implements Serializable {
- private static final long serialVersionUID = 838468273188666785L;
- private Number clouds;
- private Number deg;
- private Number dt;
- private Number humidity;
- private Number pressure;
- private Number rain;
- private Number snow;
- private Number speed;
- private Temp temp;
- private java.util.List<Weather> weather;
-
- public Number getClouds(){
- return this.clouds;
- }
- public void setClouds(final Number clouds){
- this.clouds = clouds;
- }
- public Number getDeg(){
- return this.deg;
- }
- public void setDeg(final Number deg){
- this.deg = deg;
- }
- public Number getDt(){
- return this.dt;
- }
- public void setDt(final Number dt){
- this.dt = dt;
- }
- public Number getHumidity(){
- return this.humidity;
- }
- public void setHumidity(final Number humidity){
- this.humidity = humidity;
- }
- public Number getPressure(){
- return this.pressure;
- }
- public void setPressure(final Number pressure){
- this.pressure = pressure;
- }
- public Number getRain(){
- return this.rain;
- }
- public void setRain(final Number rain){
- this.rain = rain;
- }
- public Number getSnow() {
- return this.snow;
- }
- public void setSnow(final Number snow) {
- this.snow = snow;
- }
- public Number getSpeed(){
- return this.speed;
- }
- public void setSpeed(final Number speed){
- this.speed = speed;
- }
- public Temp getTemp(){
- return this.temp;
- }
- public void setTemp(final Temp temp){
- this.temp = temp;
- }
-
- public java.util.List<Weather> getWeather() {
- return this.weather;
- }
-
- public void setWeather(final java.util.List<Weather> weather) {
- this.weather = weather;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("List [clouds=").append(this.clouds).append(", deg=").append(this.deg)
- .append(", dt=").append(this.dt).append(", humidity=").append(this.humidity)
- .append(", pressure=").append(this.pressure).append(", rain=").append(this.rain)
- .append(", snow=").append(this.snow).append(", speed=").append(this.speed)
- .append(", temp=").append(this.temp).append(", weather=").append(this.weather)
- .append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.forecastweather;
-
-import java.io.Serializable;
-
-public class Temp implements Serializable {
- private static final long serialVersionUID = -7614799035018271127L;
- private Number day;
- private Number eve;
- private Number max;
- private Number min;
- private Number morn;
- private Number night;
-
- public Number getDay(){
- return this.day;
- }
- public void setDay(final Number day){
- this.day = day;
- }
- public Number getEve(){
- return this.eve;
- }
- public void setEve(final Number eve){
- this.eve = eve;
- }
- public Number getMax(){
- return this.max;
- }
- public void setMax(final Number max){
- this.max = max;
- }
- public Number getMin(){
- return this.min;
- }
- public void setMin(final Number min){
- this.min = min;
- }
- public Number getMorn(){
- return this.morn;
- }
- public void setMorn(final Number morn){
- this.morn = morn;
- }
- public Number getNight(){
- return this.night;
- }
- public void setNight(final Number night){
- this.night = night;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Temp [day=").append(this.day).append(", eve=").append(this.eve)
- .append(", max=").append(this.max).append(", min=").append(this.min)
- .append(", morn=").append(this.morn).append(", night=").append(this.night)
- .append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.model.forecastweather;
-
-import java.io.Serializable;
-
-public class Weather implements Serializable {
- private static final long serialVersionUID = -5066357704517363241L;
- private String description;
- private String icon;
- private Number id;
- private String main;
-
- public String getDescription(){
- return this.description;
- }
- public void setDescription(final String description){
- this.description = description;
- }
- public String getIcon(){
- return this.icon;
- }
- public void setIcon(final String icon){
- this.icon = icon;
- }
- public Number getId(){
- return this.id;
- }
- public void setId(final Number id){
- this.id = id;
- }
- public String getMain(){
- return this.main;
- }
- public void setMain(final String main){
- this.main = main;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("Weather [description=").append(this.description).append(", icon=")
- .append(this.icon).append(", id=").append(this.id).append(", main=")
- .append(this.main).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-package de.example.exampletdd.parser;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonParseException;
-
-import de.example.exampletdd.model.currentweather.Current;
-import de.example.exampletdd.model.forecastweather.Forecast;
-
-public interface IJPOSParser {
-
- public Current retrieveCurrenFromJPOS(final String jsonData)
- throws JsonParseException, IOException;
-
- public Forecast retrieveForecastFromJPOS(final String jsonData)
- throws JsonParseException, IOException;
-}
+++ /dev/null
-package de.example.exampletdd.parser;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
-
-import de.example.exampletdd.model.currentweather.Clouds;
-import de.example.exampletdd.model.currentweather.Coord;
-import de.example.exampletdd.model.currentweather.Current;
-import de.example.exampletdd.model.currentweather.Main;
-import de.example.exampletdd.model.currentweather.Rain;
-import de.example.exampletdd.model.currentweather.Sys;
-import de.example.exampletdd.model.currentweather.Wind;
-import de.example.exampletdd.model.forecastweather.City;
-import de.example.exampletdd.model.forecastweather.Forecast;
-import de.example.exampletdd.model.forecastweather.Temp;
-
-public class JPOSWeatherParser implements IJPOSParser {
-
- @Override
- public Current retrieveCurrenFromJPOS(final String jsonData)
- throws JsonParseException, IOException {
- final JsonFactory f = new JsonFactory();
-
- final Current currentWeatherData = new Current();
- currentWeatherData.setClouds(new Clouds());
- currentWeatherData.setCoord(new Coord());
- currentWeatherData.setMain(new Main());
- currentWeatherData.setRain(new Rain());
- currentWeatherData.setSys(new Sys());
- currentWeatherData
- .setWeather(new ArrayList<de.example.exampletdd.model.currentweather.Weather>());
- currentWeatherData.setWind(new Wind());
- final JsonParser jParser = f.createParser(jsonData);
-
- this.getCurrentWeatherData(currentWeatherData, jParser);
-
- return currentWeatherData;
- }
-
- @Override
- public Forecast retrieveForecastFromJPOS(final String jsonData)
- throws JsonParseException, IOException {
- final JsonFactory f = new JsonFactory();
-
- final Forecast forecastWeatherData = new Forecast();
- forecastWeatherData
- .setList(new ArrayList<de.example.exampletdd.model.forecastweather.List>(15));
- final City city = new City();
- city.setCoord(new de.example.exampletdd.model.forecastweather.Coord());
- forecastWeatherData.setCity(city);
- final JsonParser jParser = f.createParser(jsonData);
-
- this.getForecastWeatherData(forecastWeatherData, jParser);
-
- return forecastWeatherData;
- }
-
- private void getCurrentWeatherData(final Current currentWeatherData,
- final JsonParser jParser) throws JsonParseException, IOException {
- if (jParser.nextToken() == JsonToken.START_OBJECT) {
-
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String fieldname = jParser.getCurrentName();
- final JsonToken nextToken = jParser.nextToken();
- if (nextToken == JsonToken.START_OBJECT) {
- this.getCurrentWeatherDataObjects(currentWeatherData, jParser, fieldname);
- }
- if (nextToken == JsonToken.START_ARRAY) {
- JsonToken tokenNext = jParser.nextToken();
- while (tokenNext != JsonToken.END_ARRAY) {
- if (tokenNext == JsonToken.START_OBJECT) {
- this.getCurrentWeatherDataObjects(currentWeatherData, jParser, fieldname);
- }
- tokenNext = jParser.nextToken();
- }
- }
- if ((nextToken == JsonToken.VALUE_NUMBER_INT)
- || (nextToken == JsonToken.VALUE_STRING)) {
- this.getCurrentWeatherDataObjects(currentWeatherData, jParser, fieldname);
- }
- }
- }
- }
-
- private void getCurrentWeatherDataObjects(final Current currentWeatherData,
- final JsonParser jParser, final String fieldname) throws JsonParseException,
- IOException {
- if (fieldname == "coord") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("lon".equals(namefield)) {
- currentWeatherData.getCoord().setLon(jParser.getDoubleValue());
- }
- if ("lat".equals(namefield)) {
- currentWeatherData.getCoord().setLat(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "sys") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("message".equals(namefield)) {
- currentWeatherData.getSys().setMessage(jParser.getDoubleValue());
- }
- if ("country".equals(namefield)) {
- currentWeatherData.getSys().setCountry(jParser.getValueAsString());
- }
- if ("sunrise".equals(namefield)) {
- currentWeatherData.getSys().setSunrise(jParser.getValueAsLong());
- }
- if ("sunset".equals(namefield)) {
- currentWeatherData.getSys().setSunset(jParser.getValueAsLong());
- }
- }
- }
- if (fieldname == "weather") {
- final de.example.exampletdd.model.currentweather.Weather weather = new de.example.exampletdd.model.currentweather.Weather();
- currentWeatherData.getWeather().add(weather);
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("id".equals(namefield)) {
- weather.setId(jParser.getIntValue());
- }
- if ("main".equals(namefield)) {
- weather.setMain(jParser.getText());
- }
- if ("description".equals(namefield)) {
- weather.setDescription(jParser.getText());
- }
- if ("icon".equals(namefield)) {
- weather.setIcon(jParser.getText());
- }
-
- }
- }
- if (fieldname == "base") {
- currentWeatherData.setBase(jParser.getText());
- }
- if (fieldname == "main") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("temp".equals(namefield)) {
- currentWeatherData.getMain().setTemp(jParser.getDoubleValue());
- }
- if ("temp_min".equals(namefield)) {
- currentWeatherData.getMain().setTemp_min(jParser.getDoubleValue());
- }
- if ("temp_max".equals(namefield)) {
- currentWeatherData.getMain().setTemp_max(jParser.getDoubleValue());
- }
- if ("pressure".equals(namefield)) {
- currentWeatherData.getMain().setPressure(jParser.getDoubleValue());
- }
- if ("sea_level".equals(namefield)) {
- currentWeatherData.getMain().setSea_level(jParser.getDoubleValue());
- }
- if ("grnd_level".equals(namefield)) {
- currentWeatherData.getMain().setGrnd_level(jParser.getDoubleValue());
- }
- if ("humidity".equals(namefield)) {
- currentWeatherData.getMain().setHumidity(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "wind") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("speed".equals(namefield)) {
- currentWeatherData.getWind().setSpeed(jParser.getDoubleValue());
- }
- if ("deg".equals(namefield)) {
- currentWeatherData.getWind().setDeg(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "clouds") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("all".equals(namefield)) {
- currentWeatherData.getClouds().setAll(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "dt") {
- currentWeatherData.setDt(jParser.getLongValue());
- }
- if (fieldname == "rain") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("3h".equals(namefield)) {
- currentWeatherData.getRain().set3h(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "snow") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("3h".equals(namefield)) {
- currentWeatherData.getSnow().set3h(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "id") {
- currentWeatherData.setId(jParser.getLongValue());
- }
- if (fieldname == "name") {
- currentWeatherData.setName(jParser.getText());
- }
- if (fieldname == "cod") {
- currentWeatherData.setCod(jParser.getIntValue());
- }
- }
-
- private void getForecastWeatherData(final Forecast forecastWeatherData,
- final JsonParser jParser) throws JsonParseException, IOException {
- if (jParser.nextToken() == JsonToken.START_OBJECT) {
-
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String fieldname = jParser.getCurrentName();
- final JsonToken nextToken = jParser.nextToken();
- if (nextToken == JsonToken.START_OBJECT) {
- this.getForecastWeatherDataObjects(forecastWeatherData, jParser, fieldname);
- }
- if (nextToken == JsonToken.START_ARRAY) {
- JsonToken tokenNext = jParser.nextToken();
- while (tokenNext != JsonToken.END_ARRAY) {
- if (tokenNext == JsonToken.START_OBJECT) {
- this.getForecastWeatherDataObjects(forecastWeatherData, jParser, fieldname);
- }
- tokenNext = jParser.nextToken();
- }
- }
- if ((nextToken == JsonToken.VALUE_NUMBER_INT)
- || (nextToken == JsonToken.VALUE_STRING)) {
- this.getForecastWeatherDataObjects(forecastWeatherData, jParser, fieldname);
- }
- }
- }
- }
-
- private void getForecastWeatherDataObjects(final Forecast forecastWeatherData,
- final JsonParser jParser, final String fieldname) throws JsonParseException,
- IOException {
-
- if (fieldname == "cod") {
- final String stringCod = jParser.getText();
- forecastWeatherData.setCod(Long.valueOf(stringCod));
- }
- if (fieldname == "message") {
- forecastWeatherData.setMessage(jParser.getDoubleValue());
- }
- if (fieldname == "city") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- final JsonToken nextToken = jParser.nextToken(); // move to
- // value
- if ("id".equals(namefield)) {
- forecastWeatherData.getCity().setId(jParser.getLongValue());
- }
- if ("name".equals(namefield)) {
- forecastWeatherData.getCity().setName(jParser.getText());
- }
- if ("coord".equals(namefield)) {
- if (nextToken == JsonToken.START_OBJECT) {
- this.getForecastWeatherDataObjects(forecastWeatherData, jParser, namefield);
- }
- }
- if ("country".equals(namefield)) {
- forecastWeatherData.getCity().setCountry(jParser.getText());
- }
- if ("population".equals(namefield)) {
- forecastWeatherData.getCity().setPopulation(jParser.getLongValue());
- }
- }
- }
- if (fieldname == "cnt") {
- forecastWeatherData.setCnt(jParser.getIntValue());
- }
- if (fieldname == "coord") {
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("lon".equals(namefield)) {
- forecastWeatherData.getCity().getCoord().setLon(jParser.getDoubleValue());
- }
- if ("lat".equals(namefield)) {
- forecastWeatherData.getCity().getCoord().setLat(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "list") {
- final de.example.exampletdd.model.forecastweather.List list = new de.example.exampletdd.model.forecastweather.List();
- list.setTemp(new Temp());
- list.setWeather(new ArrayList<de.example.exampletdd.model.forecastweather.Weather>());
- forecastWeatherData.getList().add(list);
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- final JsonToken nextToken = jParser.nextToken(); // move to
- // value
- if ("dt".equals(namefield)) {
- list.setDt(jParser.getLongValue());
- }
- if ("temp".equals(namefield)) {
- if (nextToken == JsonToken.START_OBJECT) {
- this.getForecastWeatherDataObjects(forecastWeatherData, jParser, namefield);
- }
- }
- if ("pressure".equals(namefield)) {
- list.setPressure(jParser.getDoubleValue());
- }
- if ("humidity".equals(namefield)) {
- list.setHumidity(jParser.getDoubleValue());
- }
- if ("weather".equals(namefield)) {
- if (nextToken == JsonToken.START_ARRAY) {
- JsonToken tokenNext = jParser.nextToken();
- while (tokenNext != JsonToken.END_ARRAY) {
- if (tokenNext == JsonToken.START_OBJECT) {
- this.getForecastWeatherDataObjects(forecastWeatherData, jParser,
- namefield);
- }
- tokenNext = jParser.nextToken();
- }
- }
- }
- if ("speed".equals(namefield)) {
- list.setSpeed(jParser.getDoubleValue());
- }
- if ("deg".equals(namefield)) {
- list.setDeg(jParser.getDoubleValue());
- }
- if ("clouds".equals(namefield)) {
- list.setClouds(jParser.getDoubleValue());
- }
- if ("rain".equals(namefield)) {
- list.setRain(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "temp") {
- final de.example.exampletdd.model.forecastweather.List list = forecastWeatherData
- .getList().get(
- (forecastWeatherData.getList().size() - 1));
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
- if ("day".equals(namefield)) {
- list.getTemp().setDay(jParser.getDoubleValue());
- }
- if ("min".equals(namefield)) {
- list.getTemp().setMin(jParser.getDoubleValue());
- }
- if ("max".equals(namefield)) {
- list.getTemp().setMax(jParser.getDoubleValue());
- }
- if ("night".equals(namefield)) {
- list.getTemp().setNight(jParser.getDoubleValue());
- }
- if ("eve".equals(namefield)) {
- list.getTemp().setEve(jParser.getDoubleValue());
- }
- if ("morn".equals(namefield)) {
- list.getTemp().setMorn(jParser.getDoubleValue());
- }
- }
- }
- if (fieldname == "weather") {
- final de.example.exampletdd.model.forecastweather.List list = forecastWeatherData
- .getList().get(
- (forecastWeatherData.getList().size() - 1));
- final de.example.exampletdd.model.forecastweather.Weather weather = new de.example.exampletdd.model.forecastweather.Weather();
- while (jParser.nextToken() != JsonToken.END_OBJECT) {
- final String namefield = jParser.getCurrentName();
- jParser.nextToken(); // move to value
-
- if ("id".equals(namefield)) {
- weather.setId(jParser.getIntValue());
- }
- if ("main".equals(namefield)) {
- weather.setMain(jParser.getText());
- }
- if ("description".equals(namefield)) {
- weather.setDescription(jParser.getText());
- }
- if ("icon".equals(namefield)) {
- weather.setIcon(jParser.getText());
- }
- }
- list.getWeather().add(weather);
- }
- }
-}
+++ /dev/null
-package de.example.exampletdd.service;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import de.example.exampletdd.R;
-
-public enum IconsList {
- ICON_01d("01d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_clear;
- }
- },
- ICON_01n("01n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_clear_night;
- }
- },
- ICON_02d("02d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_few_clouds;
- }
- },
- ICON_02n("02n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_few_clouds_night;
- }
- },
- ICON_03d("03d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_few_clouds;
- }
- },
- ICON_03n("03n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_few_clouds;
- }
- },
- ICON_04d("04d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_overcast;
- }
- },
- ICON_04n("04n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_overcast;
- }
- },
- ICON_09d("09d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_showers;
- }
- },
- ICON_09n("09n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_showers;
- }
- },
- ICON_10d("10d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_showers_scattered;
- }
- },
- ICON_10n("10n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_showers_scattered;
- }
- },
- ICON_11d("11d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_storm;
- }
- },
- ICON_11n("11n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_storm;
- }
- },
- ICON_13d("13d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_snow;
- }
- },
- ICON_13n("13n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_snow;
- }
- },
- ICON_50d("50d") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_fog;
- }
- },
- ICON_50n("50n") {
- @Override
- public int getResourceDrawable() {
- return R.drawable.weather_fog;
- }
- };
-
- private final String icon;
- // Map with every enum constant. Class variable initializer. JLS§12.4.2
- // Executed in textual order.
- private static final Map<String, IconsList> codeMap = new HashMap<String, IconsList>();
-
- // Static initializer. JLS§12.4.2 Executed in textual order.
- static {
- for (final IconsList code : IconsList.values()) {
- codeMap.put(code.getIcon(), code);
- }
- }
-
- private IconsList(final String icon) {
- this.icon = icon;
- }
-
- public static final IconsList getIcon(final String icon) {
- return codeMap.get(icon);
- }
-
- private String getIcon() {
- return this.icon;
- }
-
- public abstract int getResourceDrawable();
-}
+++ /dev/null
-package de.example.exampletdd.service;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.StreamCorruptedException;
-
-import android.content.Context;
-import android.util.Log;
-import de.example.exampletdd.model.currentweather.Current;
-import de.example.exampletdd.model.forecastweather.Forecast;
-
-
-/**
- * TODO: show some error message when there is no enough space for saving files. :/
- *
- */
-public class PermanentStorage {
- private static final String TAG = "PermanentStorage";
- private static final String CURRENT_DATA_FILE = "current.file";
- private static final String FORECAST_DATA_FILE = "forecast.file";
- private final Context context;
-
- public PermanentStorage(final Context context) {
- this.context = context;
- }
-
- public void saveCurrent(final Current current) {
-
- try {
- this.saveObject(CURRENT_DATA_FILE, current);
- } catch (FileNotFoundException e) {
- Log.e(TAG, "saveCurrent exception: ", e);
- } catch (IOException e) {
- Log.e(TAG, "saveCurrent exception: ", e);
- }
- }
-
- public Current getCurrent() {
-
- try {
- return (Current) this.getObject(CURRENT_DATA_FILE);
- } catch (final StreamCorruptedException e) {
- Log.e(TAG, "getCurrent exception: ", e);
- } catch (final FileNotFoundException e) {
- Log.e(TAG, "getCurrent exception: ", e);
- } catch (final IOException e) {
- Log.e(TAG, "getCurrent exception: ", e);
- } catch (final ClassNotFoundException e) {
- Log.e(TAG, "getCurrent exception: ", e);
- }
-
- return null;
- }
-
- public void saveForecast(final Forecast forecast) {
-
- try {
- this.saveObject(FORECAST_DATA_FILE, forecast);
- } catch (FileNotFoundException e) {
- Log.e(TAG, "saveForecast exception: ", e);
- } catch (IOException e) {
- Log.e(TAG, "saveForecast exception: ", e);
- }
- }
-
- public Forecast getForecast() {
-
- try {
- return (Forecast) this.getObject(FORECAST_DATA_FILE);
- } catch (final StreamCorruptedException e) {
- Log.e(TAG, "getForecast exception: ", e);
- } catch (final FileNotFoundException e) {
- Log.e(TAG, "getForecast exception: ", e);
- } catch (final IOException e) {
- Log.e(TAG, "getForecast exception: ", e);
- } catch (final ClassNotFoundException e) {
- Log.e(TAG, "getForecast exception: ", e);
- }
-
- return null;
- }
-
- private void saveObject(final String fileName, final Object objectToStore)
- throws FileNotFoundException, IOException {
- final String temporaryFileName = fileName.concat(".tmp");
-
- final FileOutputStream tmpPersistFile = this.context.openFileOutput(
- temporaryFileName, Context.MODE_PRIVATE);
- try {
- final ObjectOutputStream oos = new ObjectOutputStream(tmpPersistFile);
- try {
- oos.writeObject(objectToStore);
-
- // Don't fear the fsync!
- // http://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/
- tmpPersistFile.flush();
- tmpPersistFile.getFD().sync();
- } finally {
- oos.close();
- }
- } finally {
- tmpPersistFile.close();
- }
-
- this.renameFile(temporaryFileName, fileName);
- }
-
- private Object getObject(final String fileName) throws StreamCorruptedException, FileNotFoundException,
- IOException, ClassNotFoundException {
- final InputStream persistFile = this.context.openFileInput(fileName);
- try {
- final ObjectInputStream ois = new ObjectInputStream(persistFile);
- try {
- return ois.readObject();
- } finally {
- ois.close();
- }
- } finally {
- persistFile.close();
- }
- }
-
- private void renameFile(final String fromFileName, final String toFileName) throws IOException {
- final File filesDir = this.context.getFilesDir();
- final File fromFile = new File(filesDir, fromFileName);
- final File toFile = new File(filesDir, toFileName);
- if (!fromFile.renameTo(toFile)) {
- if (!fromFile.delete()) {
- throw new IOException("PermanentStorage, delete file error");
- }
- throw new IOException("PermanentStorage, rename file error");
- }
- }
-}
-
+++ /dev/null
-package de.example.exampletdd.service;
-
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.Locale;
-
-import com.fasterxml.jackson.core.JsonParseException;
-
-import de.example.exampletdd.model.currentweather.Current;
-import de.example.exampletdd.model.forecastweather.Forecast;
-import de.example.exampletdd.parser.IJPOSParser;
-
-public class ServiceParser {
- private final IJPOSParser JPOSParser;
-
- public ServiceParser(final IJPOSParser JPOSWeatherParser) {
- this.JPOSParser = JPOSWeatherParser;
- }
-
- public Current retrieveCurrentFromJPOS(final String jsonData)
- throws JsonParseException, IOException {
- return this.JPOSParser.retrieveCurrenFromJPOS(jsonData);
- }
-
- public Forecast retrieveForecastFromJPOS(final String jsonData)
- throws JsonParseException, IOException {
- return this.JPOSParser.retrieveForecastFromJPOS(jsonData);
- }
-
- public String createURIAPIForecast(final String urlAPI, final String APIVersion,
- final double latitude, final double longitude, final String resultsNumber) {
-
- final MessageFormat formatURIAPI = new MessageFormat(urlAPI, Locale.US);
- final Object[] values = new Object[4];
- values[0] = APIVersion;
- values[1] = latitude;
- values[2] = longitude;
- values[3] = resultsNumber;
-
- return formatURIAPI.format(values);
- }
-
- public String createURIAPICurrent(final String urlAPI, final String APIVersion,
- final double latitude, final double longitude) {
-
- final MessageFormat formatURIAPI = new MessageFormat(urlAPI, Locale.US);
- final Object[] values = new Object[3];
- values[0] = APIVersion;
- values[1] = latitude;
- values[2] = longitude;
-
- return formatURIAPI.format(values);
- }
-
- public String createURIAPIicon(final String icon, final String urlAPI) {
-
- final MessageFormat formatURIAPI = new MessageFormat(urlAPI, Locale.US);
- final Object[] values = new Object[1];
- values[0] = icon;
-
- return formatURIAPI.format(values);
- }
-
-}
+++ /dev/null
-package de.example.exampletdd.widget;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.Fragment;
-import android.appwidget.AppWidgetManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import de.example.exampletdd.R;
-
-public class WidgetConfigure extends Activity {
- private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
-
- final View.OnClickListener mOnClickListener = new View.OnClickListener() {
- public void onClick(View v) {
-
-
- // When the button is clicked, save the string in our prefs and return that they
- // clicked OK.
- // Push widget update to surface with newly set prefix
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(
- WidgetConfigure.this.getApplicationContext());
- WidgetProvider.updateAppWidget(
- WidgetConfigure.this.getApplicationContext(),
- appWidgetManager,
- mAppWidgetId);
-
- // Make sure we pass back the original appWidgetId
- final Intent resultValue = new Intent();
- resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
- WidgetConfigure.this.setResult(RESULT_OK, resultValue);
- finish();
- }
- };
-
- @Override
- public void onCreate(final Bundle icicle) {
- super.onCreate(icicle);
-
- // Find the widget id from the intent.
- final Intent intent = getIntent();
- final Bundle extras = intent.getExtras();
- boolean isActionFromUser = false;
-
- if (extras != null) {
- mAppWidgetId = extras.getInt(
- AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
-
- isActionFromUser = extras.getBoolean("actionFromUser", false);
- }
-
- // If they gave us an intent without the widget id, just bail.
- if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
- this.finish();
- }
-
- if (!isActionFromUser) {
- // Set the result to CANCELED. This will cause the widget host to cancel
- // out of the widget placement if they press the back button.
- this.setResult(RESULT_CANCELED);
- }
-
- // Set the view layout resource to use.
- this.setContentView(R.layout.appwidget_configure);
-
- final Bundle args = new Bundle();
- args.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
- final Fragment preferences = new WidgetPreferences();
- preferences.setRetainInstance(true);
- preferences.setArguments(args);
- this.getFragmentManager()
- .beginTransaction()
- .replace(R.id.weather_appwidget_configure_preferences, preferences)
- .commit();
-
- // Bind the action for the save button.
- this.findViewById(R.id.weather_appwidget_configure_save_button).setOnClickListener(mOnClickListener);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- final ActionBar actionBar = this.getActionBar();
- actionBar.setTitle(this.getString(R.string.widget_preferences_action_settings));
- }
-}
+++ /dev/null
-package de.example.exampletdd.widget;
-
-import android.appwidget.AppWidgetManager;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.os.Bundle;
-import android.preference.ListPreference;
-import android.preference.PreferenceFragment;
-import android.preference.SwitchPreference;
-import de.example.exampletdd.R;
-
-/**
- * TODO:
- * IT DOES NOT WORK IF USER IS WORKING WITH TWO OR MORE WIDGET PREFERENCE WINDOWS AT THE SAME TIME
- * (hopefully nobody will realize...)
- * How to implement custom preference activities (no extending from PreferenceActivity or PreferenceFragment)
- * without pain?
- */
-public class WidgetPreferences extends PreferenceFragment implements OnSharedPreferenceChangeListener {
- private int appWidgetId;
-
- @Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Retain this fragment across configuration changes.
- this.setRetainInstance(true);
-
- final Bundle bundle = this.getArguments();
- appWidgetId = bundle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
-
- // Load the preferences from an XML resource
- this.addPreferencesFromResource(R.xml.appwidget_preferences);
-
-
- /******************* Show/hide country field *******************/
- String keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.widget_preferences_country_switch_key);
- String realKeyPreference = keyPreference + "_" + appWidgetId;
-
- // What was saved to permanent storage (or default values if it is the first time)
- boolean countryValue = this.getActivity().getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE)
- .getBoolean(realKeyPreference, false);
-
- // What is shown on the screen
- final SwitchPreference countryPref = (SwitchPreference) this.findPreference(keyPreference);
- countryPref.setChecked(countryValue);
-
- /********************* Temperature units **********************/
- final String[] values = this.getResources().getStringArray(R.array.weather_preferences_temperature);
- final String[] humanValues = this.getResources().getStringArray(R.array.weather_preferences_temperature_human_value);
-
- keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.widget_preferences_temperature_key);
- realKeyPreference = keyPreference + "_" + appWidgetId;
-
-
- // What was saved to permanent storage (or default values if it is the first time)
- final String tempValue = this.getActivity().getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE)
- .getString(realKeyPreference, this.getString(R.string.weather_preferences_temperature_celsius));
- String humanValue = this.getString(R.string.weather_preferences_temperature_celsius_human_value);
- int index = 0;
- if (tempValue.equals(values[0])) {
- index = 0;
- humanValue = humanValues[0];
- } else if (tempValue.equals(values[1])) {
- index = 1;
- humanValue = humanValues[1];
- } else if (tempValue.equals(values[2])) {
- index = 2;
- humanValue = humanValues[2];
- }
-
-
- // What is shown on the screen
- final ListPreference listPref = (ListPreference) this.findPreference(keyPreference);
- listPref.setSummary(humanValue);
- listPref.setValueIndex(index);
- listPref.setValue(tempValue);
- }
-
- @Override
- public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
-
- /******************* Show/hide country field *******************/
- String keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.widget_preferences_country_switch_key);
- if (key.equals(keyPreference)) {
- final String realKeyPreference = keyPreference + "_" + appWidgetId;
- // Saving to permanent storage.
- final SharedPreferences.Editor prefs =
- this.getActivity().getSharedPreferences(
- "WIDGET_PREFERENCES",
- Context.MODE_PRIVATE).edit();
- // What is shown on the screen
- final SwitchPreference preference = (SwitchPreference) this.findPreference(key);
- if (preference.isChecked())
- {
- // Saving to permanent storage.
- prefs.putBoolean(realKeyPreference, true);
- } else {
- // Saving to permanent storage.
- prefs.putBoolean(realKeyPreference, false);
- }
- prefs.commit();
- }
-
- /********************* Temperature units **********************/
- keyPreference = this.getActivity().getApplicationContext().getString(
- R.string.widget_preferences_temperature_key);
- if (key.equals(keyPreference)) {
- final String[] values = this.getResources().getStringArray(
- R.array.weather_preferences_temperature);
- final String[] humanValues = this.getResources().getStringArray(
- R.array.weather_preferences_temperature_human_value);
-
- // What is shown on the screen
- final ListPreference listPref = (ListPreference) this.findPreference(key);
- final String value = listPref.getValue();
- String humanValue = "";
- if (value.equals(values[0])) {
- humanValue = humanValues[0];
- } else if (value.equals(values[1])) {
- humanValue = humanValues[1];
- } else if (value.equals(values[2])) {
- humanValue = humanValues[2];
- }
- // Update data on screen
- listPref.setSummary(humanValue);
-
-
- // Saving to permanent storage.
- final String realKeyPreference = keyPreference + "_" + appWidgetId;
-
- final SharedPreferences.Editor prefs =
- this.getActivity().getSharedPreferences(
- "WIDGET_PREFERENCES",
- Context.MODE_PRIVATE).edit();
- prefs.putString(realKeyPreference, value);
- prefs.commit();
- return;
- }
-
-
-
- }
-
- @Override
- public void onResume() {
- super.onResume();
- this.getPreferenceManager().getSharedPreferences()
- .registerOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- this.getPreferenceManager().getSharedPreferences()
- .unregisterOnSharedPreferenceChangeListener(this);
- }
-
- public static void deletePreference(final Context context, final int appWidgetId) {
- final String keyPreference = context.getApplicationContext().getString(
- R.string.widget_preferences_temperature_key);
- final String realKeyPreference = keyPreference + "_" + appWidgetId;
-
- final SharedPreferences.Editor prefs = context.getSharedPreferences("WIDGET_PREFERENCES", Context.MODE_PRIVATE).edit();
- prefs.remove(realKeyPreference);
- prefs.commit();
- }
-}
+++ /dev/null
-package de.example.exampletdd.widget;
-
-
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProvider;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import de.example.exampletdd.WidgetIntentService;
-
-public class WidgetProvider extends AppWidgetProvider {
-
- @Override
- public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
- // For each widget that needs an update, get the text that we should display:
- // - Create a RemoteViews object for it
- // - Set the text in the RemoteViews object
- // - Tell the AppWidgetManager to show that views object for the widget.
- final int N = appWidgetIds.length;
- for (int i=0; i<N; i++) {
- int appWidgetId = appWidgetIds[i];
- // To prevent any ANR timeouts, we perform the update in a service
- final Intent intent = new Intent(context.getApplicationContext(), WidgetIntentService.class);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- intent.putExtra("updateByApp", false);
- context.startService(intent);
- }
- }
-
- @Override
- public void onDeleted(final Context context, final int[] appWidgetIds) {
- // When the user deletes the widget, delete the preference associated with it.
- final int N = appWidgetIds.length;
- for (int i=0; i<N; i++) {
- WidgetPreferences.deletePreference(context, appWidgetIds[i]);
- }
- }
-
- static void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId) {
-
- int widgetId;
- Bundle myOptions = appWidgetManager.getAppWidgetOptions(appWidgetId);
-
- // Get the value of OPTION_APPWIDGET_HOST_CATEGORY
- int category = myOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
-
- // If the value is WIDGET_CATEGORY_KEYGUARD, it's a lockscreen widget
- boolean isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
-
- // Once you know the widget's category, you can optionally load a different base layout, set different
- // properties, and so on. For example:
- //int baseLayout = isKeyguard ? R.layout.keyguard_widget_layout : R.layout.widget_layout;
-
- // Construct the RemoteViews object. It takes the package name (in our case, it's our
- // package, but it needs this because on the other side it's the widget host inflating
- // the layout from our package).
- //final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget);
-
- final Intent intent = new Intent(context.getApplicationContext(), WidgetIntentService.class);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- context.startService(intent);
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="de.example.exampletdd.test"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk android:minSdkVersion="18" android:maxSdkVersion="18" android:targetSdkVersion="18"/>
-
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="de.example.exampletdd" />
-
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <uses-library android:name="android.test.runner" />
- </application>
-
-</manifest>
\ No newline at end of file
+++ /dev/null
-/** Automatically generated file. DO NOT MODIFY */
-package de.example.exampletdd.test;
-
-public final class BuildConfig {
- public final static boolean DEBUG = true;
-}
\ No newline at end of file
+++ /dev/null
-/* AUTO-GENERATED FILE. DO NOT MODIFY.
- *
- * This class was automatically generated by the
- * aapt tool from the resource data it found. It
- * should not be modified by hand.
- */
-
-package de.example.exampletdd.test;
-
-public final class R {
- public static final class attr {
- }
- public static final class drawable {
- public static final int ic_launcher=0x7f020000;
- }
- public static final class string {
- public static final int app_name=0x7f030000;
- }
-}
+++ /dev/null
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
+++ /dev/null
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-18
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <string name="app_name">Weather Information Test</string>
-
-</resources>
+++ /dev/null
-package de.example.exampletdd.test;
-
-import junit.framework.TestCase;
-
-import org.json.JSONException;
-
-import de.example.exampletdd.model.WeatherData;
-import de.example.exampletdd.parser.JPOSWeatherParser;
-
-public class JPOSWeatherParserTest extends TestCase {
- private JPOSWeatherParser jposWeatherParser;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- this.jposWeatherParser = new JPOSWeatherParser();
- }
-
- public void testRetrieveWeatherFromJPOS() throws JSONException {
- // Arrange
- final String jsonData = "{\"coord\":{\"lon\":139,\"lat\":35}}";
- final double longitude = 139;
- final double latitude = 35;
- final WeatherData.Coord coord = new WeatherData.Coord(longitude, latitude);
- final WeatherData expectedWeather = new WeatherData.Builder().setCoord(coord).build();
-
- // Act
- final WeatherData finalWeather = this.jposWeatherParser.retrieveWeatherFromJPOS(jsonData);
-
- // Assert
- assertEquals(expectedWeather.toString(), finalWeather.toString());
- }
-
-}
+++ /dev/null
-package de.example.exampletdd.test;
-
-import android.content.Intent;
-import android.test.ActivityUnitTestCase;
-import android.widget.Button;
-import de.example.exampletdd.WeatherInformationActivity;
-
-public class WeatherInformationActivityUnitTest extends
- ActivityUnitTestCase<WeatherInformationActivity> {
-
- private WeatherInformationActivity activity;
-
- public WeatherInformationActivityUnitTest() {
- super(WeatherInformationActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- final Intent intent = new Intent(this.getInstrumentation().getTargetContext(),
- WeatherInformationActivity.class);
- this.startActivity(intent, null, null);
- this.activity = this.getActivity();
- }
-
- public void testIntentTriggerViaOnClick() {
- final int buttonweather = de.example.exampletdd.R.id.buttonweather;
- final Button view = (Button) this.activity.findViewById(buttonweather);
- assertNotNull("Button Weather not allowed to be null", view);
-
- view.performClick();
-
- // TouchUtils cannot be used, only allowed in
- // InstrumentationTestCase or ActivityInstrumentationTestCase2
-
- // Check the intent which was started
- final Intent triggeredIntent = this.getStartedActivityIntent();
- assertNotNull("Intent was null", triggeredIntent);
- final String data = triggeredIntent.getDataString();
-
- assertEquals("Incorrect data passed via the intent",
- "http://gumartinm.name", data);
- }
-}