/* Copyright 2011 Torstein Ingebrigtsen Bø This file is part of OpenAndroidWeather. OpenAndroidWeather is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenAndroidWeather is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenAndroidWeather. If not, see <http://www.gnu.org/licenses/>. */ package no.firestorm.wsklima; import java.util.List; import no.firestorm.ui.stationpicker.Station; import no.firestorm.weathernotificatonservice.UpdateLocation; import no.firestorm.weathernotificatonservice.UpdateLocationListener; import no.firestorm.wsklima.database.WsKlimaDataBaseHelper; import no.firestorm.wsklima.exception.NoLocationException; import org.apache.http.HttpException; import android.accounts.NetworkErrorException; import android.app.Service; import android.content.Context; import android.location.Criteria; import android.location.Location; import android.location.LocationManager; import android.os.Looper; public class GetWeather implements UpdateLocationListener { private Float accuracyDemand = Float.MAX_VALUE; private Context mContext = null; private final static int LOCATION_MAX_AGE = 5 * 60 * 1000; private Location mLocation = null; private WsKlimaProxy mProxy; private WsKlimaDataBaseHelper mDb; private Station mStation = null; public GetWeather(Context context) { mContext = context; mProxy = new WsKlimaProxy(); mDb = new WsKlimaDataBaseHelper(context); } /** * Gets the temperature from the closest weather station that has a new * weather report. If the closest station does not deliver a result, the * second closest station is then asked and so on. The station is saved in * the object and can be found by calling getStation() * * @return Weather temperature * @throws NetworkErrorException if it can't connect to the web service * @throws NoLocationException if it can't get a location * @throws HttpException if it get response from a webserver but it is corrupted (e.g., login page of public wlan) */ public WeatherElement getWeatherElement() throws NetworkErrorException, NoLocationException, HttpException { updateLocation(); List<Station> stations = getNearestStations(); for (Station station : stations) { WeatherElement weather = getWeather(station); if (weather != null) { mStation = station; return weather; } } return null; } private List<Station> getNearestStations() { return mDb.getStationsSortedByLocation(mLocation, true); } // Get weather from wsklimaproxy private WeatherElement getWeather(Station station) throws NetworkErrorException, HttpException { return mProxy.getTemperatureNow(station.getId(), mContext); } // Use location from mLocation and find the nearest station that is not // ignored in ignoredStationNumbers // Get the current location private void updateLocation() throws NoLocationException { // Check old results Location loc = getLastLocation(); if (loc != null && isAccurateEnough(loc)) { mLocation = loc; return; } // Find location provider final LocationManager locMan = (LocationManager) mContext .getSystemService(Service.LOCATION_SERVICE); final Criteria criteria = new Criteria(); criteria.setPowerRequirement(Criteria.POWER_LOW); final String provider = locMan.getBestProvider(criteria, true); if (provider != null) { // Register provider UpdateLocation getLocation = new UpdateLocation(this, mContext); locMan.requestLocationUpdates(provider, 0, 0, getLocation, Looper.getMainLooper()); // Wait for the updating of station to complete synchronized (this) { try { this.wait(2 * 60 * 1000); } catch (final InterruptedException e) { // If it did not get a good enough accuracy within 2 // minutes, use the latest one getLocation.stop(); loc = getLocation.getLocation(); if (loc == null) { throw new NoLocationException(null); } else { mLocation = loc; } } } loc = getLocation.getLocation(); if (loc == null) { throw new NoLocationException(null); } else mLocation = loc; } else throw new NoLocationException(null); } /** * Return station for weather, must be called after getWeatherElement * * @return station */ public Station getStation() { return mStation; } @Override public void locationUpdated(Location loc) { mLocation = loc; synchronized (this) { this.notifyAll(); } } private Location getLastLocation() { final LocationManager locman = (LocationManager) mContext .getSystemService(Context.LOCATION_SERVICE); final List<String> providers = locman.getAllProviders(); for (final String p : providers) { final Location loc = locman.getLastKnownLocation(p); if (loc != null) { final long age = System.currentTimeMillis() - loc.getTime(); if (age < LOCATION_MAX_AGE && isAccurateEnough(loc)) return loc; } } return null; } public boolean isAccurateEnough(Location location) { // Check if location is within accuracy demand if (!location.hasAccuracy()){ return true; } else if (location.getAccuracy() < accuracyDemand) { // update accuracy demand final WsKlimaDataBaseHelper db = new WsKlimaDataBaseHelper(mContext); final List<Station> stations = db.getStationsSortedByLocation( location, true); accuracyDemand = stations.get(1).getDistanceToCurrentPosition() - stations.get(0).getDistanceToCurrentPosition(); db.close(); if (location.getAccuracy() < accuracyDemand) return true; } return false; } }