package edu.purdue.app.weather; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; import org.json.JSONObject; import org.json.JSONTokener; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Shader.TileMode; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.Spannable; import android.text.SpannableString; import android.text.style.RelativeSizeSpan; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import edu.purdue.app.R; // Free icon packs downloaded from: // http://bharathp666.deviantart.com/art/Android-Weather-Extended-191851717 // http://bharathp666.deviantart.com/art/Android-Weather-Icons-180719113 // TODO Add caching of weather data. Example: If the weather API we use only updates once an hour, we should cache the request per hour. public class WeatherActivity extends Activity { private Handler timeTaskHandler = new Handler(); private final ArrayList<HourlyForecastData> hourlyDataList = new ArrayList<HourlyForecastData>(); // Used to prevent UI action from occuring after the onStop method has been called. private boolean appHasStopped = false; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.weather_page_layout); // Initialize the colors for the weekly forecast viewer WeatherUIHelper.colorizeWeeklyForecastView(this); this.setTitle("Purdue Weather"); timeTaskHandler.removeCallbacks(updateTimeTask); timeTaskHandler.postDelayed(updateTimeTask, 500); final TextView hourlyTime = (TextView) findViewById(R.id.hourlyTime); final TextView hourlyTemp = (TextView) findViewById(R.id.hourlyTemp); final TextView hourlySummary = (TextView) findViewById(R.id.hourlySummary); final SeekBar seekbar = (SeekBar) findViewById(R.id.hourlySeekBar); final TextView temperatureTextView = (TextView) findViewById(R.id.temperatureTextView); final WeatherActivity weatherActivity = this; // Retrieve the weather data either from cache or web and fill in the UI fields updateWeatherData(); // Add a gradient effect to the temperature text view temperatureTextView.getPaint().setShader(new LinearGradient(0, temperatureTextView.getTextSize()*3, 0, 0, Color.BLACK , Color.WHITE, TileMode.CLAMP)); // Display differing hourly stats when seeker bar is changed seekbar.setEnabled(false); seekbar.setOnSeekBarChangeListener( new OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar hourlyseekbar, int currentProgress, boolean userInitiatedChange) { // TODO Auto-generated method stub if (!hourlyDataList.isEmpty()) { hourlyTime.setText(hourlyDataList.get(currentProgress).getTime()); String currentHourlyTemp = WeatherUIHelper.getScaledTempString(weatherActivity, hourlyDataList.get(currentProgress).getTemp()); hourlyTemp.setText(currentHourlyTemp); hourlySummary.setText(hourlyDataList.get(currentProgress).getSummary()); WeatherUIHelper.updateWeatherIcon((ImageView) findViewById(R.id.hourlyIcon), hourlyDataList.get(currentProgress).getIconTitle()); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } @Override public void onStopTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } }); } @Override public void onStop() { super.onStop(); appHasStopped = true; } @Override public void onResume() { super.onResume(); appHasStopped = false; } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = this.getMenuInflater(); inflater.inflate(R.menu.weather_actionbarmenu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.weather_actionbar_settings: // Show the info dialogue WeatherSettingsDialog settingsDialog = new WeatherSettingsDialog(); settingsDialog.show(getFragmentManager(), "settings"); break; case R.id.weather_actionbar_info: // Show the info dialogue WeatherInfoDialog infoDialog = new WeatherInfoDialog(); infoDialog.show(getFragmentManager(), "info"); break; case R.id.weather_actionbar_refresh: // Refresh the weather data updateWeatherData(); break; } return super.onOptionsItemSelected(item); } private boolean isNetworkAvailable() { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return activeNetworkInfo != null && activeNetworkInfo.isConnected(); } private Runnable updateTimeTask = new Runnable() { public void run() { // Get the current date and time and update the date/time text views final TextView dateTextView = (TextView) findViewById(R.id.date); Calendar cal = Calendar.getInstance(); dateTextView.setText(cal.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US)+". "+cal.get(Calendar.DAY_OF_MONTH)); final TextView timeTextView = (TextView) findViewById(R.id.time); String hour = cal.get(Calendar.HOUR)!=0?(""+cal.get(Calendar.HOUR)):"12"; String minute = cal.get(Calendar.MINUTE)>=10?(""+cal.get(Calendar.MINUTE)):("0"+cal.get(Calendar.MINUTE)); // The time is a spannable string so the AM/PM suffix can be given a smaller font SpannableString timeString = new SpannableString(hour+":"+minute+(cal.get(Calendar.AM_PM)==0?"AM":"PM")); timeString.setSpan(new RelativeSizeSpan(.5f), timeString.length()-2, timeString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //Reduce size of AM/PM timeTextView.setText(timeString); timeTaskHandler.postDelayed(updateTimeTask, 500); } }; /* * Retrieves weather data from cache or from web and updates the UI components with the data. * If there is valid cached weather data that is less than an hour old, use it. Otherwise, use web data. */ protected void updateWeatherData() { final TextView hourlyTime = (TextView) findViewById(R.id.hourlyTime); final TextView hourlyTemp = (TextView) findViewById(R.id.hourlyTemp); final TextView hourlySummary = (TextView) findViewById(R.id.hourlySummary); final SeekBar seekbar = (SeekBar) findViewById(R.id.hourlySeekBar); final TextView descriptionTextView = (TextView) findViewById(R.id.weatherDescTextView); final TextView temperatureTextView = (TextView) findViewById(R.id.temperatureTextView); // Create the weather data loading dialogue final ProgressDialog weatherPD = new ProgressDialog(this); weatherPD.setTitle(""); weatherPD.setCancelable(false); weatherPD.setMessage("Loading Weather Data..."); final Bundle args = new Bundle(); // Use argument bundle to pass message to weather dialogue final WeatherDataErrorDialog dataErrorDialog = new WeatherDataErrorDialog(); final WeatherActivity weatherActivity = this; // Check if network connection is available to retrieve the weather data if(!isNetworkAvailable() && !WeatherAPI.isCachedDataValid(WeatherAPI.readJSONFromCache(this, "cachedWeatherJSON.json"))) { args.putString("message", "No network connection. Please ensure you are connected to a network and try again."); dataErrorDialog.setArguments(args); dataErrorDialog.show(getFragmentManager(), "weather_error"); } else { // Make an HTTP GET request to retrieve the JSON weather data weatherPD.show(); new Thread(new Runnable() { public void run() { final String weatherResponse = WeatherAPI.getWeatherData(weatherActivity.getApplicationContext()); // If the weather data was retrieved successfully, parse and place the data into the UI Handler handler = new Handler(Looper.getMainLooper()); // Handler is necessary to gain reference to UI thread. handler.post(new Runnable(){ @Override public void run() { try{ if (weatherResponse != null) { // Parse the weekly forecast data and update the weekly forecast view WeatherUIHelper.updateWeeklyForecastView(weatherActivity, weatherResponse); JSONObject object = (JSONObject) new JSONTokener(weatherResponse).nextValue(); // JSON parsing to get the current weather in West Lafayette String weatherDescription = (String) object.getJSONObject("currently").get("summary"); String currentIconTitle = (String) object.getJSONObject("currently").get("icon"); double currentTemp = Double.parseDouble(object.getJSONObject("currently").get("temperature")+""); // Parse the hourly forecast data and store data in hourlyDataList WeatherAPI.parseHourlyData(object, hourlyDataList); // Update the UI components with the parsed data WeatherUIHelper.updateWeatherIcon((ImageView) findViewById(R.id.currentWeatherIcon), currentIconTitle); weatherPD.dismiss(); WeatherUIHelper.updateWeatherIcon((ImageView) findViewById(R.id.hourlyIcon), hourlyDataList.get(seekbar.getProgress()).getIconTitle()); temperatureTextView.setText(WeatherUIHelper.getScaledTempString(weatherActivity, currentTemp)); descriptionTextView.setText("{ "+weatherDescription+" }"); hourlyTime.setText(hourlyDataList.get(seekbar.getProgress()).getTime()); hourlyTemp.setText(WeatherUIHelper.getScaledTempString(weatherActivity, hourlyDataList.get(seekbar.getProgress()).getTemp())); hourlySummary.setText(hourlyDataList.get(seekbar.getProgress()).getSummary()); seekbar.setEnabled(true); } else { // Unable to retrieve data weatherPD.dismiss(); if (!appHasStopped) { args.putString("message", "Failed to retrieve weather data."); dataErrorDialog.setArguments(args); dataErrorDialog.show(getFragmentManager(), "weather_error"); } } } catch (Exception e) { // Unable to retrieve data weatherPD.dismiss(); if (!appHasStopped) { args.putString("message", "Failed to retrieve weather data."); dataErrorDialog.setArguments(args); dataErrorDialog.show(getFragmentManager(), "weather_error"); } e.printStackTrace(); } } }); } }).start(); } } }