Java tutorial
/** * The MIT License (MIT) * * Copyright (c) 2015 Yoel Nunez <dev@nunez.guru> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ package net.digitalphantom.app.weatherapp; import android.Manifest; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.preference.PreferenceManager; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import net.digitalphantom.app.weatherapp.data.Channel; import net.digitalphantom.app.weatherapp.data.Condition; import net.digitalphantom.app.weatherapp.data.LocationResult; import net.digitalphantom.app.weatherapp.data.Units; import net.digitalphantom.app.weatherapp.fragments.WeatherConditionFragment; import net.digitalphantom.app.weatherapp.listener.GeocodingServiceListener; import net.digitalphantom.app.weatherapp.listener.WeatherServiceListener; import net.digitalphantom.app.weatherapp.service.WeatherCacheService; import net.digitalphantom.app.weatherapp.service.GoogleMapsGeocodingService; import net.digitalphantom.app.weatherapp.service.YahooWeatherService; public class WeatherActivity extends AppCompatActivity implements WeatherServiceListener, GeocodingServiceListener, LocationListener { public static int GET_WEATHER_FROM_CURRENT_LOCATION = 0x00001; private ImageView weatherIconImageView; private TextView temperatureTextView; private TextView conditionTextView; private TextView locationTextView; private YahooWeatherService weatherService; private GoogleMapsGeocodingService geocodingService; private WeatherCacheService cacheService; private ProgressDialog loadingDialog; // weather service fail flag private boolean weatherServicesHasFailed = false; private SharedPreferences preferences = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weather); weatherIconImageView = (ImageView) findViewById(R.id.weatherIconImageView); temperatureTextView = (TextView) findViewById(R.id.temperatureTextView); conditionTextView = (TextView) findViewById(R.id.highTemperatureTextView); locationTextView = (TextView) findViewById(R.id.lowTemperatureTextView); preferences = PreferenceManager.getDefaultSharedPreferences(this); weatherService = new YahooWeatherService(this); weatherService.setTemperatureUnit(preferences.getString(getString(R.string.pref_temperature_unit), null)); geocodingService = new GoogleMapsGeocodingService(this); cacheService = new WeatherCacheService(this); if (preferences.getBoolean(getString(R.string.pref_needs_setup), true)) { startSettingsActivity(); } } @Override protected void onStart() { super.onStart(); loadingDialog = new ProgressDialog(this); loadingDialog.setMessage(getString(R.string.loading)); loadingDialog.setCancelable(false); loadingDialog.show(); String location = null; if (preferences.getBoolean(getString(R.string.pref_geolocation_enabled), true)) { String locationCache = preferences.getString(getString(R.string.pref_cached_location), null); if (locationCache == null) { getWeatherFromCurrentLocation(); } else { location = locationCache; } } else { location = preferences.getString(getString(R.string.pref_manual_location), null); } if (location != null) { weatherService.refreshWeather(location); } } private void getWeatherFromCurrentLocation() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_FINE_LOCATION, }, GET_WEATHER_FROM_CURRENT_LOCATION); return; } // system's LocationManager final LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); Criteria locationCriteria = new Criteria(); if (isNetworkEnabled) { locationCriteria.setAccuracy(Criteria.ACCURACY_COARSE); } else if (isGPSEnabled) { locationCriteria.setAccuracy(Criteria.ACCURACY_FINE); } locationManager.requestSingleUpdate(locationCriteria, this, null); } public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == WeatherActivity.GET_WEATHER_FROM_CURRENT_LOCATION) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { getWeatherFromCurrentLocation(); } else { loadingDialog.hide(); AlertDialog messageDialog = new AlertDialog.Builder(this) .setMessage(getString(R.string.location_permission_needed)).setPositiveButton( getString(R.string.disable_geolocation), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { startSettingsActivity(); } }) .create(); messageDialog.show(); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); return true; } private void startSettingsActivity() { Intent intent = new Intent(this, SettingsActivity.class); startActivity(intent); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.currentLocation: loadingDialog.show(); getWeatherFromCurrentLocation(); return true; case R.id.settings: startSettingsActivity(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void serviceSuccess(Channel channel) { loadingDialog.hide(); Condition condition = channel.getItem().getCondition(); Units units = channel.getUnits(); Condition[] forecast = channel.getItem().getForecast(); int weatherIconImageResource = getResources().getIdentifier("icon_" + condition.getCode(), "drawable", getPackageName()); weatherIconImageView.setImageResource(weatherIconImageResource); temperatureTextView.setText( getString(R.string.temperature_output, condition.getTemperature(), units.getTemperature())); conditionTextView.setText(condition.getDescription()); locationTextView.setText(channel.getLocation()); for (int day = 0; day < forecast.length; day++) { if (day >= 5) { break; } Condition currentCondition = forecast[day]; int viewId = getResources().getIdentifier("forecast_" + day, "id", getPackageName()); WeatherConditionFragment fragment = (WeatherConditionFragment) getSupportFragmentManager() .findFragmentById(viewId); if (fragment != null) { fragment.loadForecast(currentCondition, channel.getUnits()); } } } @Override public void serviceFailure(Exception exception) { // display error if this is the second failure if (weatherServicesHasFailed) { loadingDialog.hide(); Toast.makeText(this, exception.getMessage(), Toast.LENGTH_LONG).show(); } else { // error doing reverse geocoding, load weather data from cache weatherServicesHasFailed = true; // OPTIONAL: let the user know an error has occurred then fallback to the cached data Toast.makeText(this, exception.getMessage(), Toast.LENGTH_SHORT).show(); cacheService.load(this); } } @Override public void geocodeSuccess(LocationResult location) { // completed geocoding successfully weatherService.refreshWeather(location.getAddress()); SharedPreferences.Editor editor = preferences.edit(); editor.putString(getString(R.string.pref_cached_location), location.getAddress()); editor.apply(); } @Override public void geocodeFailure(Exception exception) { // GeoCoding failed, try loading weather data from the cache cacheService.load(this); } @Override public void onLocationChanged(Location location) { geocodingService.refreshLocation(location); } @Override public void onStatusChanged(String s, int i, Bundle bundle) { // OPTIONAL: implement your custom logic here } @Override public void onProviderEnabled(String s) { // OPTIONAL: implement your custom logic here } @Override public void onProviderDisabled(String s) { // OPTIONAL: implement your custom logic here } }