diff --git a/app/build.gradle b/app/build.gradle index 19167f951..f7ffae8fd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,6 +17,9 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + buildTypes.each { + it.buildConfigField 'String', 'OPEN_WEATHER_MAP_API_KEY', MyOpenWeatherMapApiKey + } } dependencies { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fcad107a6..54ce75263 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + mForecastAdapter; + + public ForecastFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Add this line in order for this fragment to handle menu events. + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.forecastfragment, menu); + } + + @Override + public boolean onOptionsItemSelected(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. + int id = item.getItemId(); + if (id == R.id.action_refresh) { + FetchWeatherTask weatherTask = new FetchWeatherTask(); + weatherTask.execute("94043"); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + // Create some dummy data for the ListView. Here's a sample weekly forecast + String[] data = { + "Mon 6/23 - Sunny - 31/17", + "Tue 6/24 - Foggy - 21/8", + "Wed 6/25 - Cloudy - 22/17", + "Thurs 6/26 - Rainy - 18/11", + "Fri 6/27 - Foggy - 21/10", + "Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18", + "Sun 6/29 - Sunny - 20/7" + }; + List weekForecast = new ArrayList(Arrays.asList(data)); + + // Now that we have some dummy forecast data, create an ArrayAdapter. + // The ArrayAdapter will take data from a source (like our dummy forecast) and + // use it to populate the ListView it's attached to. + mForecastAdapter = + new ArrayAdapter( + getActivity(), // The current context (this activity) + R.layout.list_item_forecast, // The name of the layout ID. + R.id.list_item_forecast_textview, // The ID of the textview to populate. + weekForecast); + + View rootView = inflater.inflate(R.layout.fragment_main, container, false); + + // Get a reference to the ListView, and attach this adapter to it. + ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast); + listView.setAdapter(mForecastAdapter); + + return rootView; + } + + public class FetchWeatherTask extends AsyncTask { + + private final String LOG_TAG = FetchWeatherTask.class.getSimpleName(); + + @Override + protected Void doInBackground(String... params) { + + // If there's no zip code, there's nothing to look up. Verify size of params. + if (params.length == 0) { + return null; + } + + // These two need to be declared outside the try/catch + // so that they can be closed in the finally block. + HttpURLConnection urlConnection = null; + BufferedReader reader = null; + + // Will contain the raw JSON response as a string. + String forecastJsonStr = null; + + String format = "json"; + String units = "metric"; + int numDays = 7; + + try { + // Construct the URL for the OpenWeatherMap query + // Possible parameters are avaiable at OWM's forecast API page, at + // http://openweathermap.org/API#forecast + final String FORECAST_BASE_URL = + "http://api.openweathermap.org/data/2.5/forecast/daily?"; + final String QUERY_PARAM = "q"; + final String FORMAT_PARAM = "mode"; + final String UNITS_PARAM = "units"; + final String DAYS_PARAM = "cnt"; + final String APPID_PARAM = "APPID"; + + Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon() + .appendQueryParameter(QUERY_PARAM, params[0]) + .appendQueryParameter(FORMAT_PARAM, format) + .appendQueryParameter(UNITS_PARAM, units) + .appendQueryParameter(DAYS_PARAM, Integer.toString(numDays)) + .appendQueryParameter(APPID_PARAM, BuildConfig.OPEN_WEATHER_MAP_API_KEY) + .build(); + + URL url = new URL(builtUri.toString()); + + Log.v(LOG_TAG, "Built URI " + builtUri.toString()); + + // Create the request to OpenWeatherMap, and open the connection + urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setRequestMethod("GET"); + urlConnection.connect(); + + // Read the input stream into a String + InputStream inputStream = urlConnection.getInputStream(); + StringBuffer buffer = new StringBuffer(); + if (inputStream == null) { + // Nothing to do. + return null; + } + reader = new BufferedReader(new InputStreamReader(inputStream)); + + String line; + while ((line = reader.readLine()) != null) { + // Since it's JSON, adding a newline isn't necessary (it won't affect parsing) + // But it does make debugging a *lot* easier if you print out the completed + // buffer for debugging. + buffer.append(line + "\n"); + } + + if (buffer.length() == 0) { + // Stream was empty. No point in parsing. + return null; + } + forecastJsonStr = buffer.toString(); + } catch (IOException e) { + Log.e(LOG_TAG, "Error ", e); + // If the code didn't successfully get the weather data, there's no point in attemping + // to parse it. + return null; + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + if (reader != null) { + try { + reader.close(); + } catch (final IOException e) { + Log.e(LOG_TAG, "Error closing stream", e); + } + } + } + return null; + } + } +} diff --git a/app/src/main/java/com/example/android/sunshine/app/MainActivity.java b/app/src/main/java/com/example/android/sunshine/app/MainActivity.java index 348cf7efb..e8729e77d 100644 --- a/app/src/main/java/com/example/android/sunshine/app/MainActivity.java +++ b/app/src/main/java/com/example/android/sunshine/app/MainActivity.java @@ -1,14 +1,24 @@ +/* + * 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; -import android.support.v7.app.ActionBarActivity; -import android.support.v4.app.Fragment; import android.os.Bundle; -import android.view.LayoutInflater; +import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - public class MainActivity extends ActionBarActivity { @@ -18,7 +28,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() - .add(R.id.container, new PlaceholderFragment()) + .add(R.id.container, new ForecastFragment()) .commit(); } } @@ -44,20 +54,4 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - - /** - * A placeholder fragment containing a simple view. - */ - public static class PlaceholderFragment extends Fragment { - - public PlaceholderFragment() { - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_main, container, false); - return rootView; - } - } } diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index bb3dd4604..372b60d63 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -1,12 +1,17 @@ - + tools:context=".MainActivity$ForecastFragment"> - + - + diff --git a/app/src/main/res/layout/list_item_forecast.xml b/app/src/main/res/layout/list_item_forecast.xml new file mode 100644 index 000000000..965bd5714 --- /dev/null +++ b/app/src/main/res/layout/list_item_forecast.xml @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/menu/forecastfragment.xml b/app/src/main/res/menu/forecastfragment.xml new file mode 100644 index 000000000..50bd1256d --- /dev/null +++ b/app/src/main/res/menu/forecastfragment.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ec03bdf4d..94bda40e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,8 +1,21 @@ + Sunshine - Hello world! + + Settings + + Refresh + Hello world! +