+ * See
+ * Android Design: Settings for design guidelines and the Settings
+ * API Guide for more information on developing a Settings UI.
+ */
+public class SettingsActivity extends PreferenceActivity
+ implements Preference.OnPreferenceChangeListener {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Add 'general' preferences, defined in the XML file
+ addPreferencesFromResource(R.xml.pref_general);
+
+ // For all preferences, attach an OnPreferenceChangeListener so the UI summary can be
+ // updated when the preference changes.
+ bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_location_key)));
+ bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_units_key)));
+ }
+
+ /**
+ * Attaches a listener so the summary is always updated with the preference value.
+ * Also fires the listener once, to initialize the summary (so it shows up before the value
+ * is changed.)
+ */
+ private void bindPreferenceSummaryToValue(Preference preference) {
+ // Set the listener to watch for value changes.
+ preference.setOnPreferenceChangeListener(this);
+
+ // Trigger the listener immediately with the preference's
+ // current value.
+ onPreferenceChange(preference,
+ PreferenceManager
+ .getDefaultSharedPreferences(preference.getContext())
+ .getString(preference.getKey(), ""));
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object value) {
+ String stringValue = value.toString();
+
+ if (preference instanceof ListPreference) {
+ // For list preferences, look up the correct display value in
+ // the preference's 'entries' list (since they have separate labels/values).
+ ListPreference listPreference = (ListPreference) preference;
+ int prefIndex = listPreference.findIndexOfValue(stringValue);
+ if (prefIndex >= 0) {
+ preference.setSummary(listPreference.getEntries()[prefIndex]);
+ }
+ } else {
+ // For other preferences, set the summary to the value's simple string representation.
+ preference.setSummary(stringValue);
+ }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android/sunshine/app/data/WeatherContract.java b/app/src/main/java/com/example/android/sunshine/app/data/WeatherContract.java
new file mode 100644
index 000000000..11ef79db1
--- /dev/null
+++ b/app/src/main/java/com/example/android/sunshine/app/data/WeatherContract.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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.
+ */
+package com.example.android.sunshine.app.data;
+
+import android.provider.BaseColumns;
+import android.text.format.Time;
+
+/**
+ * Defines table and column names for the weather database.
+ */
+public class WeatherContract {
+
+ // To make it easy to query for the exact date, we normalize all dates that go into
+ // the database to the start of the the Julian day at UTC.
+ public static long normalizeDate(long startDate) {
+ // normalize the start date to the beginning of the (UTC) day
+ Time time = new Time();
+ time.set(startDate);
+ int julianDay = Time.getJulianDay(startDate, time.gmtoff);
+ return time.setJulianDay(julianDay);
+ }
+
+ /*
+ Inner class that defines the table contents of the location table
+ Students: This is where you will add the strings. (Similar to what has been
+ done for WeatherEntry)
+ */
+ public static final class LocationEntry implements BaseColumns {
+ public static final String TABLE_NAME = "location";
+
+ }
+
+ /* Inner class that defines the table contents of the weather table */
+ public static final class WeatherEntry implements BaseColumns {
+
+ public static final String TABLE_NAME = "weather";
+
+ // Column with the foreign key into the location table.
+ public static final String COLUMN_LOC_KEY = "location_id";
+ // Date, stored as long in milliseconds since the epoch
+ public static final String COLUMN_DATE = "date";
+ // Weather id as returned by API, to identify the icon to be used
+ public static final String COLUMN_WEATHER_ID = "weather_id";
+
+ // Short description and long description of the weather, as provided by API.
+ // e.g "clear" vs "sky is clear".
+ public static final String COLUMN_SHORT_DESC = "short_desc";
+
+ // Min and max temperatures for the day (stored as floats)
+ public static final String COLUMN_MIN_TEMP = "min";
+ public static final String COLUMN_MAX_TEMP = "max";
+
+ // Humidity is stored as a float representing percentage
+ public static final String COLUMN_HUMIDITY = "humidity";
+
+ // Humidity is stored as a float representing percentage
+ public static final String COLUMN_PRESSURE = "pressure";
+
+ // Windspeed is stored as a float representing windspeed mph
+ public static final String COLUMN_WIND_SPEED = "wind";
+
+ // Degrees are meteorological degrees (e.g, 0 is north, 180 is south). Stored as floats.
+ public static final String COLUMN_DEGREES = "degrees";
+ }
+}
diff --git a/app/src/main/java/com/example/android/sunshine/app/data/WeatherDbHelper.java b/app/src/main/java/com/example/android/sunshine/app/data/WeatherDbHelper.java
new file mode 100644
index 000000000..ac33ea26a
--- /dev/null
+++ b/app/src/main/java/com/example/android/sunshine/app/data/WeatherDbHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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.
+ */
+package com.example.android.sunshine.app.data;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import com.example.android.sunshine.app.data.WeatherContract.LocationEntry;
+import com.example.android.sunshine.app.data.WeatherContract.WeatherEntry;
+
+/**
+ * Manages a local database for weather data.
+ */
+public class WeatherDbHelper extends SQLiteOpenHelper {
+
+ // If you change the database schema, you must increment the database version.
+ private static final int DATABASE_VERSION = 2;
+
+ static final String DATABASE_NAME = "weather.db";
+
+ public WeatherDbHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase sqLiteDatabase) {
+ final String SQL_CREATE_WEATHER_TABLE = "CREATE TABLE " + WeatherEntry.TABLE_NAME + " (" +
+ // Why AutoIncrement here, and not above?
+ // Unique keys will be auto-generated in either case. But for weather
+ // forecasting, it's reasonable to assume the user will want information
+ // for a certain date and all dates *following*, so the forecast data
+ // should be sorted accordingly.
+ WeatherEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+
+ // the ID of the location entry associated with this weather data
+ WeatherEntry.COLUMN_LOC_KEY + " INTEGER NOT NULL, " +
+ WeatherEntry.COLUMN_DATE + " INTEGER NOT NULL, " +
+ WeatherEntry.COLUMN_SHORT_DESC + " TEXT NOT NULL, " +
+ WeatherEntry.COLUMN_WEATHER_ID + " INTEGER NOT NULL," +
+
+ WeatherEntry.COLUMN_MIN_TEMP + " REAL NOT NULL, " +
+ WeatherEntry.COLUMN_MAX_TEMP + " REAL NOT NULL, " +
+
+ WeatherEntry.COLUMN_HUMIDITY + " REAL NOT NULL, " +
+ WeatherEntry.COLUMN_PRESSURE + " REAL NOT NULL, " +
+ WeatherEntry.COLUMN_WIND_SPEED + " REAL NOT NULL, " +
+ WeatherEntry.COLUMN_DEGREES + " REAL NOT NULL, " +
+
+ // Set up the location column as a foreign key to location table.
+ " FOREIGN KEY (" + WeatherEntry.COLUMN_LOC_KEY + ") REFERENCES " +
+ LocationEntry.TABLE_NAME + " (" + LocationEntry._ID + "), " +
+
+ // To assure the application have just one weather entry per day
+ // per location, it's created a UNIQUE constraint with REPLACE strategy
+ " UNIQUE (" + WeatherEntry.COLUMN_DATE + ", " +
+ WeatherEntry.COLUMN_LOC_KEY + ") ON CONFLICT REPLACE);";
+
+ sqLiteDatabase.execSQL(SQL_CREATE_WEATHER_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
+ // This database is only a cache for online data, so its upgrade policy is
+ // to simply to discard the data and start over
+ // Note that this only fires if you change the version number for your database.
+ // It does NOT depend on the version number for your application.
+ // If you want to update the schema without wiping data, commenting out the next 2 lines
+ // should be your top priority before modifying this method.
+ sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + LocationEntry.TABLE_NAME);
+ sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + WeatherEntry.TABLE_NAME);
+ onCreate(sqLiteDatabase);
+ }
+}
diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml
new file mode 100644
index 000000000..3ecaa61f8
--- /dev/null
+++ b/app/src/main/res/layout/activity_detail.xml
@@ -0,0 +1,5 @@
+