/* * Copyright 2015. Appsi Mobile * * 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.appsimobile.appsii.module.weather; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.support.annotation.NonNull; import android.text.TextUtils; import android.text.format.Time; import android.util.Log; import android.util.SparseArray; import com.appsimobile.appsii.BitmapUtils; import com.appsimobile.appsii.R; import com.appsimobile.appsii.module.weather.loader.WeatherData; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import javax.inject.Inject; import javax.inject.Singleton; /** * Created by Nick on 20/02/14. */ @Singleton public class WeatherUtils { public static final int FLAG_TEMPERATURE_NO_UNIT = 1; static final Time sTime = new Time(); final BitmapUtils mBitmapUtils; @Inject public WeatherUtils(BitmapUtils bitmapUtils) { mBitmapUtils = bitmapUtils; } public SparseArray<ForecastInfo> getForecastForDays(Context context, int startJulianDay, String woeid) { ContentResolver resolver = context.getContentResolver(); String[] projection = new String[]{ WeatherContract.ForecastColumns.COLUMN_NAME_CONDITION_CODE, WeatherContract.ForecastColumns.COLUMN_NAME_FORECAST_DAY, WeatherContract.ForecastColumns.COLUMN_NAME_TEMPERATURE_HIGH, WeatherContract.ForecastColumns.COLUMN_NAME_TEMPERATURE_LOW, WeatherContract.ForecastColumns.COLUMN_NAME_LAST_UPDATED, WeatherContract.ForecastColumns.COLUMN_NAME_UNIT, }; String selection = WeatherContract.ForecastColumns.COLUMN_NAME_LOCATION_WOEID + "= ? AND " + WeatherContract.ForecastColumns.COLUMN_NAME_FORECAST_DAY + " >= ?"; String[] selectionArgs = new String[]{woeid, String.valueOf(startJulianDay)}; Cursor cursor = resolver.query(WeatherContract.ForecastColumns.CONTENT_URI, projection, selection, selectionArgs, WeatherContract.ForecastColumns.COLUMN_NAME_LAST_UPDATED + " DESC"); if (cursor == null) return null; SparseArray<ForecastInfo> result = new SparseArray<>(); try { while (cursor.moveToNext()) { int julianDay = cursor.getInt(1); //julian day if (julianDay >= startJulianDay) { ForecastInfo info = new ForecastInfo(); info.conditionCode = cursor.getInt(0); info.tempHigh = cursor.getInt(2); info.tempLow = cursor.getInt(3); info.lastUpdate = cursor.getLong(4); info.unit = cursor.getString(5); info.julianDay = julianDay; result.put(julianDay, info); } } } finally { cursor.close(); } return result; } public WeatherData getWeatherData(Context context, String woeid) { ContentResolver resolver = context.getContentResolver(); String selection = WeatherContract.WeatherColumns.COLUMN_NAME_WOEID + "= ?"; String[] selectionArgs = new String[]{woeid}; Cursor cursor = resolver.query( WeatherContract.WeatherColumns.CONTENT_URI, WeatherDataQuery.PROJECTION, selection, selectionArgs, null); if (cursor == null) return null; try { if (cursor.moveToNext()) { WeatherData result = new WeatherData(); result.unit = cursor.getString(WeatherDataQuery.UNIT); result.lastUpdated = cursor.getLong(WeatherDataQuery.LAST_UPDATED); result.location = cursor.getString(WeatherDataQuery.CITY); result.nowConditionCode = cursor.getInt(WeatherDataQuery.NOW_CONDITION_CODE); result.nowTemperature = cursor.getInt(WeatherDataQuery.NOW_TEMPERATURE); result.windChill = cursor.getInt(WeatherDataQuery.WIND_CHILL); result.windDirection = cursor.getInt(WeatherDataQuery.WIND_DIRECTION); result.windSpeed = cursor.getInt(WeatherDataQuery.WIND_SPEED); result.atmosphereHumidity = cursor.getInt(WeatherDataQuery.ATMOSPHERE_HUMIDITY); result.atmospherePressure = cursor.getFloat(WeatherDataQuery.ATMOSPHERE_PRESSURE); result.atmosphereRising = cursor.getInt(WeatherDataQuery.ATMOSPHERE_RISING); result.atmosphereVisible = cursor.getFloat(WeatherDataQuery.ATMOSPHERE_VISIBILITY); result.sunrise = cursor.getString(WeatherDataQuery.SUNRISE); result.sunset = cursor.getString(WeatherDataQuery.SUNSET); result.woeid = woeid; return result; } } finally { cursor.close(); } return null; } public String formatTemperature(Context context, int temp, String tempUnit, String displayUnit) { return formatTemperature(context, temp, tempUnit, displayUnit, 0); } public String formatTemperature(Context context, int temp, String tempUnit, String displayUnit, int flags) { if (!TextUtils.equals(tempUnit, displayUnit)) { if ("c".equals(displayUnit)) { temp = Math.round(toCelsius(temp)); } else { temp = Math.round(toFahrenheit(temp)); } } int unitResId; if (flags == FLAG_TEMPERATURE_NO_UNIT) { unitResId = R.string.degrees; } else { unitResId = "c".equals(displayUnit) ? R.string.degrees_c : R.string.degrees_f; } String suffix = context.getString(unitResId); return context.getString(R.string.temperature_high_unit, temp, suffix); } public float toCelsius(int degrees) { return (degrees - 32f) * (5f / 9.0f); } public float toFahrenheit(int degrees) { return (9f * degrees) / 5f + 32; } public String formatWindSpeed(Context context, float speed, String tempUnit, String displayUnit) { int displaySpeed; if (!TextUtils.equals(tempUnit, displayUnit)) { if ("c".equals(displayUnit)) { displaySpeed = Math.round(toKph(speed)); } else { displaySpeed = Math.round(toMph(speed)); } } else { displaySpeed = Math.round(speed); } int unitResId = "c".equals(displayUnit) ? R.string.speed_kph : R.string.speed_mph; String suffix = context.getString(unitResId); return context.getString(R.string.temperature_high_unit, displaySpeed, suffix); } public float toKph(float speedMph) { return speedMph * 1.609344f; } public float toMph(float speeKph) { return speeKph / 1.609344f; } public boolean isDay(String timezone, WeatherData weatherData) { sTime.timezone = timezone; sTime.normalize(false); sTime.setToNow(); int minuteNow = sTime.hour * 60 + sTime.minute; int sunrise = weatherData.getSunriseMinuteOfDay(); if (minuteNow < sunrise) return false; int sunset = weatherData.getSunsetMinuteOfDay(); if (minuteNow > sunset) return false; return true; } public int getConditionCodeIconResId(int conditionCode, boolean day) { // http://developer.yahoo.com/weather/ switch (conditionCode) { case 19: // dust or sand case 21: // haze return R.drawable.ic_weather_haze; case 20: // foggy case 22: // smoky return R.drawable.ic_weather_fog; case 24: // windy return R.drawable.ic_weather_wind; case 25: // cold case 26: // cloudy return day ? R.drawable.ic_weather_clouds : R.drawable.ic_weather_clouds_night; case 27: // mostly cloudy (night) return R.drawable.ic_weather_clouds_night; case 28: // mostly cloudy (day) return R.drawable.ic_weather_clouds; case 29: // partly cloudy (night) return R.drawable.ic_weather_few_clouds_night; case 30: // partly cloudy (day) return R.drawable.ic_weather_few_clouds; case 44: // partly cloudy return day ? R.drawable.ic_weather_few_clouds : R.drawable.ic_weather_few_clouds_night; case 31: // clear (night) return R.drawable.ic_weather_clear_night; case 33: // fair (night) return R.drawable.ic_weather_few_clouds_night; case 34: // fair (day) return R.drawable.ic_weather_few_clouds; case 32: // sunny case 36: // hot return day ? R.drawable.ic_weather_clear : R.drawable.ic_weather_clear_night; case 0: // tornado case 2: // hurricane return R.drawable.ic_weather_wind; case 1: // tropical storm case 3: // severe thunderstorms case 4: // thunderstorms case 23: // blustery return R.drawable.ic_weather_storm; case 5: // mixed rain and snow case 6: // mixed rain and sleet case 7: // mixed snow and sleet case 8: // freezing drizzle case 10: // freezing rain case 18: // sleet return R.drawable.ic_weather_snow_rain; case 9: // drizzle return day ? R.drawable.ic_weather_drizzle : R.drawable.ic_weather_drizzle_night; case 11: // showers case 12: // showers return day ? R.drawable.ic_weather_showers : R.drawable.ic_weather_showers_night; case 17: // hail case 35: // mixed rain and hail return R.drawable.ic_weather_hail; case 37: // isolated thunderstorms case 38: // scattered thunderstorms case 39: // scattered thunderstorms return day ? R.drawable.ic_weather_light_storm : R.drawable.ic_weather_light_storm_night; case 40: // scattered showers return day ? R.drawable.ic_weather_rain : R.drawable.ic_weather_rain_night; case 45: // thundershowers case 47: // isolated thundershowers return R.drawable.ic_weather_storm; case 13: // snow flurries case 14: // light snow showers case 42: // scattered snow showers case 15: // blowing snow return day ? R.drawable.ic_weather_snow_scattered : R.drawable.ic_weather_snow_scattered_night; case 16: // snow case 41: // heavy snow case 43: // heavy snow case 46: // snow showers return R.drawable.ic_weather_big_snow; } return R.drawable.ic_weather_unknown; } public int getConditionCodeTinyIconResId(int conditionCode, boolean day) { // http://developer.yahoo.com/weather/ switch (conditionCode) { case 19: // dust or sand case 21: // haze case 20: // foggy case 22: // smoky return R.drawable.ic_small_heavy_fog; case 24: // windy case 25: // cold case 26: // cloudy case 27: // mostly cloudy (night) case 28: // mostly cloudy (day) case 29: // partly cloudy (night) case 30: // partly cloudy (day) case 44: // partly cloudy return R.drawable.ic_small_clouds; case 31: // clear (night) case 33: // fair (night) return R.drawable.ic_small_clear_night; case 34: // fair (day) case 32: // sunny case 36: // hot return day ? R.drawable.ic_small_clear_day : R.drawable.ic_small_clear_night; case 0: // tornado case 2: // hurricane case 1: // tropical storm case 3: // severe thunderstorms case 4: // thunderstorms case 23: // blustery case 37: // isolated thunderstorms case 38: // scattered thunderstorms case 39: // scattered thunderstorms case 45: // thundershowers case 47: // isolated thundershowers return R.drawable.ic_small_thunder; case 5: // mixed rain and snow case 6: // mixed rain and sleet case 7: // mixed snow and sleet case 8: // freezing drizzle case 10: // freezing rain case 18: // sleet case 9: // drizzle case 11: // showers case 12: // showers case 17: // hail case 35: // mixed rain and hail case 40: // scattered showers case 13: // snow flurries case 14: // light snow showers case 42: // scattered snow showers case 15: // blowing snow case 16: // snow case 41: // heavy snow case 43: // heavy snow case 46: // snow showers return R.drawable.ic_small_rain; } return R.drawable.ic_small_clear_day; } public String formatConditionCode(int conditionCode) { // http://developer.yahoo.com/weather/ switch (conditionCode) { case 19: // dust or sand return "Dust or sand"; case 21: // haze return "Haze"; case 20: // foggy return "Foggy"; case 22: // smoky return "Smoky"; case 24: // windy return "Windy"; case 25: // cold return "Cold"; case 26: // cloudy return "Cloudy"; case 27: // mostly cloudy (night) case 28: // mostly cloudy (day) return "Mostly cloudy"; case 29: // partly cloudy (night) case 30: // partly cloudy (day) case 44: // partly cloudy return "Partly cloudy"; case 31: // clear (night) return "Clear"; case 33: // fair (night) case 34: // fair (day) return "Fair"; case 32: // sunny return "Sunny"; case 36: // hot return "Hot"; case 0: // tornado return "Tornado"; case 2: // hurricane return "Hurricane"; case 1: // tropical storm return "Tropical storm"; case 3: // severe thunderstorms return "Severe thunderstorms"; case 4: // thunderstorms return "Thunderstorms"; case 23: // blustery return "Blustery"; case 5: // mixed rain and snow return "Mixed rain and snow"; case 6: // mixed rain and sleet return "Mixed rain and sleet"; case 7: // mixed snow and sleet return "Mixed snow and sleet"; case 8: // freezing drizzle return "Freezing drizzle"; case 10: // freezing rain return "Freezing rain"; case 18: // sleet return "Sleet"; case 9: // drizzle return "Drizzle"; case 11: // showers case 12: // showers return "Showers"; case 17: // hail return "Hail"; case 35: // mixed rain and hail return "Mixed rain and hail"; case 37: // isolated thunderstorms return "Isolated thunderstorms"; case 38: // scattered thunderstorms case 39: // scattered thunderstorms return "Scattered thunderstorms"; case 40: // scattered showers return "Scattered showers"; case 45: // thundershowers return "Thundershowers"; case 47: // isolated thundershowers return "Isolated thundershowers"; case 13: // snow flurries return "Snow flurries"; case 14: // light snow showers return "Light snow showers"; case 42: // scattered snow showers return "Scattered snow showers"; case 15: // blowing snow return "Blowing snow"; case 16: // snow return "Snow"; case 41: // heavy snow case 43: // heavy snow return "Heavy Snow"; case 46: // snow showers return "Heavy Showers"; } return "Unknown"; } public File[] getCityPhotos(Context context, String woeid) { File cacheDir = getWeatherPhotoCacheDir(context); int validCount = 0; for (int i = 0; i < 5; i++) { String name = createPhotoFileName(woeid, i); File photoImage = new File(cacheDir, name); if (photoImage.exists()) { validCount++; } else { break; } } if (validCount == 0) return null; File[] result = new File[validCount]; for (int i = 0; i < validCount; i++) { String name = createPhotoFileName(woeid, i); File photoImage = new File(cacheDir, name); result[i] = photoImage; } return result; } public File getWeatherPhotoCacheDir(Context context) { File path = mBitmapUtils.externalFilesFolder(); File result = new File(path, "weather"); if (!result.exists()) { result.mkdirs(); } return result; } public String createPhotoFileName(String woeid, int idx) { return woeid + "-" + idx + ".jpg"; } public void clearCityPhotos(Context context, String woeid, int startIdx) { File cacheDir = getWeatherPhotoCacheDir(context); for (int i = startIdx; i < 5; i++) { String name = createPhotoFileName(woeid, i); File photoImage = new File(cacheDir, name); photoImage.delete(); } } boolean saveBitmap(Context context, Bitmap bitmap, String woeid, int idx) { File photoImage = getWeatherImageFile(context, woeid, idx); boolean result; try { OutputStream out = new BufferedOutputStream(new FileOutputStream(photoImage)); result = bitmap.compress(Bitmap.CompressFormat.JPEG, 95, out); out.flush(); out.close(); } catch (IOException e) { Log.e("Weather", "error saving weather image", e); result = false; } return result; } @NonNull public File getWeatherImageFile(Context context, String woeid, int idx) { File cacheDir = getWeatherPhotoCacheDir(context); String name = createPhotoFileName(woeid, idx); return new File(cacheDir, name); } public static class ForecastInfo implements Comparable<ForecastInfo> { public int julianDay; public int conditionCode; public int tempLow; public int tempHigh; public long lastUpdate; public String unit; private static int intCompare(int lhs, int rhs) { return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1); } @Override public int compareTo(@NonNull ForecastInfo another) { return intCompare(julianDay, another.julianDay); } } static class WeatherDataQuery { static final String[] PROJECTION = new String[]{ WeatherContract.WeatherColumns.COLUMN_NAME_UNIT, WeatherContract.WeatherColumns.COLUMN_NAME_LAST_UPDATED, WeatherContract.WeatherColumns.COLUMN_NAME_CITY, WeatherContract.WeatherColumns.COLUMN_NAME_NOW_CONDITION_CODE, WeatherContract.WeatherColumns.COLUMN_NAME_NOW_TEMPERATURE, WeatherContract.WeatherColumns.COLUMN_NAME_WIND_CHILL, WeatherContract.WeatherColumns.COLUMN_NAME_WIND_DIRECTION, WeatherContract.WeatherColumns.COLUMN_NAME_WIND_SPEED, WeatherContract.WeatherColumns.COLUMN_NAME_ATMOSPHERE_HUMIDITY, WeatherContract.WeatherColumns.COLUMN_NAME_ATMOSPHERE_PRESSURE, WeatherContract.WeatherColumns.COLUMN_NAME_ATMOSPHERE_RISING, WeatherContract.WeatherColumns.COLUMN_NAME_ATMOSPHERE_VISIBILITY, WeatherContract.WeatherColumns.COLUMN_NAME_SUNRISE, WeatherContract.WeatherColumns.COLUMN_NAME_SUNSET, }; static final int UNIT = 0; static final int LAST_UPDATED = 1; static final int CITY = 2; static final int NOW_CONDITION_CODE = 3; static final int NOW_TEMPERATURE = 4; static final int WIND_CHILL = 5; static final int WIND_DIRECTION = 6; static final int WIND_SPEED = 7; static final int ATMOSPHERE_HUMIDITY = 8; static final int ATMOSPHERE_PRESSURE = 9; static final int ATMOSPHERE_RISING = 10; static final int ATMOSPHERE_VISIBILITY = 11; static final int SUNRISE = 12; static final int SUNSET = 13; } }