diff --git a/.gitignore b/.gitignore index 8406aafff..ccdf3330f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ gen/ # Local configuration file (sdk path, etc) local.properties +gradle.properties # Eclipse project files .classpath diff --git a/app/build.gradle b/app/build.gradle index 29f8ceb0c..f9b426f69 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,7 +17,7 @@ android { buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } diff --git a/app/src/main/assets/plan.html b/app/src/main/assets/plan.html index b6224bd97..51f170cea 100644 --- a/app/src/main/assets/plan.html +++ b/app/src/main/assets/plan.html @@ -45,12 +45,9 @@ var CELL_FUEL = 6; var CELL_LAST = 7; -var plan_poll_timer = setInterval(function () {loadplan()}, 1000); - // load plan from Android then display every second -function loadplan() { +function loadplan(str) { //var str = "myplanname::::1,102,18,BOS,NAVAID--:--::::0,5,23,--:--BVY,AIRPORT::::Total 82nm --:-- 102° 10.1"; - var str = AndroidPlan.getPlanData(); // split plan data encoded in :: var plans = str.split("::::"); plan_setname(plans[0]); diff --git a/app/src/main/java/com/ds/avare/LocationActivity.java b/app/src/main/java/com/ds/avare/LocationActivity.java index ebda44dc0..380c5ebd4 100644 --- a/app/src/main/java/com/ds/avare/LocationActivity.java +++ b/app/src/main/java/com/ds/avare/LocationActivity.java @@ -63,6 +63,7 @@ import com.ds.avare.utils.OptionButton; import com.ds.avare.utils.Tips; import com.ds.avare.views.LocationView; +import com.ds.avare.views.LongPressedDestination; import com.ds.avare.webinfc.WebAppMapInterface; import java.io.File; @@ -144,7 +145,7 @@ public class LocationActivity extends Activity implements Observer { private AnimateButton mAnimateHelp; private AnimateButton mAnimateDownload; private AnimateButton mAnimatePref; - private String mAirportPressed; + private LongPressedDestination mDestinationPressed; private AlertDialog mAlertDialogDestination; private WebAppMapInterface mInfc; @@ -492,7 +493,7 @@ public void gestureCallBack(int event, LongTouchDestination data) { * Show the popout * Now populate the pop out weather etc. */ - mAirportPressed = data.airport; + mDestinationPressed = new LongPressedDestination(data.destinationName, data.destinationType) ; } } @@ -896,7 +897,7 @@ public Object callback(Object o, Object o1) { mAlertDialogDestination.dismiss(); - if (null == mAirportPressed) { + if (null == mDestinationPressed) { return null; } if (mService == null) { @@ -907,41 +908,32 @@ public Object callback(Object o, Object o1) { /* * A/FD */ - if (!mAirportPressed.contains("&")) { - mService.setLastAfdAirport(mAirportPressed); + if (mDestinationPressed.getType() == Destination.BASE) { + mService.setLastAfdAirport(mDestinationPressed.getName()); ((MainActivity) LocationActivity.this.getParent()).showAfdTab(); } - mAirportPressed = null; + mDestinationPressed = null; } else if (param.equals("Plate")) { /* * Plate */ - if (!mAirportPressed.contains("&")) { - mService.setLastPlateAirport(mAirportPressed); + if (mDestinationPressed.getType() == Destination.BASE) { + mService.setLastPlateAirport(mDestinationPressed.getName()); mService.setLastPlateIndex(0); ((MainActivity) LocationActivity.this.getParent()).showPlatesTab(); } - mAirportPressed = null; + mDestinationPressed = null; } else if (param.equals("+Plan")) { - String type = Destination.BASE; - if (mAirportPressed.contains("&")) { - type = Destination.GPS; - } - planTo(mAirportPressed, type); - mAirportPressed = null; + planTo(mDestinationPressed.getName(), mDestinationPressed.getType()); + mDestinationPressed = null; } else if (param.equals("->D")) { /* * On click, find destination that was pressed on in view * If button pressed was a destination go there, otherwise if none, then delete current dest */ - String dest = mAirportPressed; - mAirportPressed = null; - String type = Destination.BASE; - if (dest.contains("&")) { - type = Destination.GPS; - } - goTo(dest, type); + goTo(mDestinationPressed.getName(), mDestinationPressed.getType()); + mDestinationPressed = null; } return null; } diff --git a/app/src/main/java/com/ds/avare/PlanActivity.java b/app/src/main/java/com/ds/avare/PlanActivity.java index 288dee9e3..583dce78d 100644 --- a/app/src/main/java/com/ds/avare/PlanActivity.java +++ b/app/src/main/java/com/ds/avare/PlanActivity.java @@ -414,12 +414,16 @@ public void handleMessage(Message msg) { else if(msg.what == UNSHOW_BUSY) { mProgressBarSearch.setVisibility(View.INVISIBLE); } - else if(msg.what == ACTIVE) { - mActivateButton.setText(getString(R.string.Active)); - } - else if(msg.what == INACTIVE) { - mActivateButton.setText(getString(R.string.Inactive)); - } + else if(msg.what == ACTIVE) { + if (mActivateButton.getText().equals(getString(R.string.Inactive))) { + mActivateButton.setText(getString(R.string.Active)); + } + } + else if(msg.what == INACTIVE) { + if (mActivateButton.getText().equals(getString(R.string.Active))) { + mActivateButton.setText(getString(R.string.Inactive)); + } + } else if(msg.what == MESSAGE) { // Show an important message DecoratedAlertDialogBuilder builder = new DecoratedAlertDialogBuilder(mContext); diff --git a/app/src/main/java/com/ds/avare/storage/Preferences.java b/app/src/main/java/com/ds/avare/storage/Preferences.java index 1fe44c0f4..5e550a7a1 100644 --- a/app/src/main/java/com/ds/avare/storage/Preferences.java +++ b/app/src/main/java/com/ds/avare/storage/Preferences.java @@ -64,6 +64,7 @@ public class Preferences { public static final int MAX_AREA_AIRPORTS = 20; public static final double MIN_TOUCH_MOVEMENT_SQ_DISTANCE = 0.001; + public static final double NAVAID_TOUCH_DISTANCE = .5; /* * Max memory and max screen size it will support @@ -1208,6 +1209,13 @@ public void setRateAskCount(int set) { mPref.edit().putInt("rateAskLastCount", set).commit(); } + public int getWindsAloftCeiling() { + try { + return Integer.parseInt(mPref.getString(mContext.getString(R.string.WindsAloftCeiling), "39")); + } catch (Exception x) { + return 39; + } + } } diff --git a/app/src/main/java/com/ds/avare/touch/LongTouchDestination.java b/app/src/main/java/com/ds/avare/touch/LongTouchDestination.java index f632f300b..52396f4e8 100644 --- a/app/src/main/java/com/ds/avare/touch/LongTouchDestination.java +++ b/app/src/main/java/com/ds/avare/touch/LongTouchDestination.java @@ -26,7 +26,8 @@ */ public class LongTouchDestination { - public String airport; + public String destinationName; + public String destinationType; public String info; public String tfr; public String mets; diff --git a/app/src/main/java/com/ds/avare/utils/Helper.java b/app/src/main/java/com/ds/avare/utils/Helper.java index 2e7378e7c..5047dc5df 100644 --- a/app/src/main/java/com/ds/avare/utils/Helper.java +++ b/app/src/main/java/com/ds/avare/utils/Helper.java @@ -52,6 +52,8 @@ */ public class Helper { + private static Calendar mCalendar = new GregorianCalendar(); + // All elevation is calculated in feet // ranges -364 to 20150 feet (hence 20150 in 3D is +z) public static final double ALTITUDE_FT_ELEVATION_PER_PIXEL_SLOPE = 24.5276170372963 * Preferences.heightConversion; @@ -691,23 +693,22 @@ public static boolean leftOfCourseLine(double brgTrue, double brgCourse) { return true; return false; } - + /** - * + * */ public static String millisToGMT(long millis) { SimpleDateFormat df = new SimpleDateFormat("MM_dd_yyyy_hh_mm", Locale.getDefault()); df.setTimeZone(TimeZone.getTimeZone("GMT")); return df.format(millis) + "_UTC"; } - + /** * * @return */ public static long getMillisGMT() { - Calendar calendar = new GregorianCalendar(); - TimeZone mTimeZone = calendar.getTimeZone(); + TimeZone mTimeZone = mCalendar.getTimeZone(); int offset = mTimeZone.getOffset(System.currentTimeMillis()); return System.currentTimeMillis() - offset; } diff --git a/app/src/main/java/com/ds/avare/utils/NavAidHelper.java b/app/src/main/java/com/ds/avare/utils/NavAidHelper.java index 58aba6148..6a034b2a4 100644 --- a/app/src/main/java/com/ds/avare/utils/NavAidHelper.java +++ b/app/src/main/java/com/ds/avare/utils/NavAidHelper.java @@ -75,25 +75,34 @@ private String getNavaidLocationAsHtml(Coordinate navaidCoordinate, int navaidVa boolean isReceived = isVorReceived(distanceToNavAid, navaidClass, altitudeReference - navaidElevation) || !("TLH".contains(navaidClass) || navaidClass.isEmpty()); long radial = Math.round(Helper.getMagneticHeading(p.getBearing(), navaidVariation)); - return (!isReceived ? "" : "") - + String.format(Locale.getDefault(), "%03d", radial) + final String LIGHT_RED = "#ff6666", LIGHT_GREEN = "#99ff66"; + return String.format(Locale.getDefault(), "%03d", radial) + + "" + Math.round(distanceToNavAid) - + (!isReceived ? "" : "") + + "" ; } /** format vector of navaids as a string */ public String toHtmlString(Vector navaids) { - String result = ""; + String result = ""; if (navaids != null) { for (NavAid na : navaids) { - result += (result != "" ? "" : "") // fields' order same as Chart Supplement convention - + na.getLocationId() - + getNavaidLocationAsHtml(na.getCoords(), na.getVariation(), na.getNavaidClass(), na.getElevation()) + " " - + na.getFrequency() - + (na.hasHiwas() ? "(H)" : ""); + result += + "" // fields' order same as Chart Supplement convention + + "" + + na.getLocationId() + + getNavaidLocationAsHtml(na.getCoords(), na.getVariation(), na.getNavaidClass(), na.getElevation()) + + "" + + " " + + na.getFrequency() + + "" + + " " + + (na.hasHiwas() ? "HIWAS" : "") + + "" + + ""; } } - return result; + return result + ""; } } diff --git a/app/src/main/java/com/ds/avare/utils/WeatherHelper.java b/app/src/main/java/com/ds/avare/utils/WeatherHelper.java index d32be9aa0..9344b1912 100644 --- a/app/src/main/java/com/ds/avare/utils/WeatherHelper.java +++ b/app/src/main/java/com/ds/avare/utils/WeatherHelper.java @@ -14,7 +14,6 @@ import android.util.Pair; import java.util.LinkedList; -import java.util.Locale; public class WeatherHelper { @@ -501,132 +500,6 @@ else if(vis >= 1) { return output; } - /** - * Wind decoder - * @param wind - * @return - */ - public static String decodeWind(String wind) { - - if(wind.length() < 4) { - return ""; - } - - int dir; - int speed; - try { - dir = Integer.parseInt(wind.substring(0, 2)) * 10; - speed = Integer.parseInt(wind.substring(2, 4)); - } - catch(Exception e) { - return ""; - } - - if(wind.length() == 4) { - - if(dir == 990 && speed == 0) { - /* - * Light and variable - */ - return "000°000kt"; - } - if(dir >= 510) { - dir -= 500; - speed += 100; - } - - String out = String.format(Locale.getDefault(), "%03d°%03dkt", dir, speed); - return(out); - } - - if(wind.length() == 7) { - String temp = wind.substring(4, 7); - - if(dir == 990 && speed == 0) { - /* - * Light and variable - */ - return "000°000kt" + temp + "C"; - } - if(dir >= 510) { - dir -= 500; - speed += 100; - } - - String out = String.format(Locale.getDefault(), "%03d°%03dkt", dir, speed) + temp + "C"; - return(out); - - } - - if(wind.length() == 6) { - String temp = "-" + wind.substring(4, 6); - - if(dir == 990 && speed == 0) { - /* - * Light and variable - */ - return "000°000kt" + temp + "C"; - } - if(dir >= 510) { - dir -= 500; - speed += 100; - } - - String out = String.format(Locale.getDefault(), "%03d°%03dkt", dir, speed) + temp + "C"; - return(out); - } - - return ""; - } - - /** - * See decodeWind - * @param wind - * @return - */ - public static int decodeWindSpeed(String wind) { - String windsd = decodeWind(wind); - String w[] = windsd.split("°"); - int speed = 0; - try { - speed = Integer.parseInt(w[1].split("kt")[0]); - } - catch (Exception e) { - - } - return speed; - } - - /** - * See decodeWind - * @param wind - * @return - */ - public static int decodeWindDir(String wind) { - String windsd = decodeWind(wind); - String w[] = windsd.split("°"); - int dir = 0; - try { - dir = Integer.parseInt(w[0]); - } - catch (Exception e) { - - } - return dir; - } - - /** - * - * @return - */ - public static String getNamMosLegend() { - /* - * Legend - */ - return - "NAM Forecast Legend"; - - } /** * Returns time from METAR diff --git a/app/src/main/java/com/ds/avare/utils/WindsAloftHelper.java b/app/src/main/java/com/ds/avare/utils/WindsAloftHelper.java new file mode 100644 index 000000000..883ceac2c --- /dev/null +++ b/app/src/main/java/com/ds/avare/utils/WindsAloftHelper.java @@ -0,0 +1,139 @@ +package com.ds.avare.utils; + +import android.util.Pair; + +import com.ds.avare.weather.WindsAloft; + +import java.util.Locale; + +/** + * @author pasniak + */ + public class WindsAloftHelper { + /** + * Wind decoder: public interface + * @param wa + * @param upToAltitude + * @return HTML fragment with a table containing decoded Winds Aloft up to up to altitude + */ + public static String formatWindsHTML(WindsAloft wa, int upToAltitude) { + String header = wa.station + "" + wa.time + ""; + String winds; + winds = (upToAltitude > 0) ? formatWindRow("3000", wa.w3k) : ""; + winds += (upToAltitude > 3) ? formatWindRow("6000", wa.w6k) : ""; + winds += (upToAltitude > 6) ? formatWindRow("9000", wa.w9k) : ""; + winds += (upToAltitude > 9) ? formatWindRow("12000", wa.w12k) : ""; + winds += (upToAltitude > 12) ? formatWindRow("18000", wa.w18k) : ""; + winds += (upToAltitude > 18) ? formatWindRow("24000", wa.w24k) : ""; + winds += (upToAltitude > 24) ? formatWindRow("30000", wa.w30k) : ""; + winds += (upToAltitude > 30) ? formatWindRow("34000", wa.w34k) : ""; + winds += (upToAltitude > 34) ? formatWindRow("39000", wa.w39k) : ""; + return header + table(winds); + } + + /** + * Wind decoder: format table row with altitude, decoded wind and temperature + * @param wind + * @return formatted HTML table row + */ + private static String formatWindRow(String alt, String wind) { + DirSpeedTemp w = parseWindAndTemperature(wind); + return (w.IsNull) ? tr("") : tr(td(alt) + td(w.Dir) + td(w.Speed) + td(w.Temp)); + } + + //nbsp is used here to nicely space out cells in the row + private static String td(String c) { return " "+c+""; } + private static String tr(String r) { return ""+r+""; } + private static String table(String t) { return ""+t+""; } + + //WA string lengths + private static int ONLY_WIND_LEN = 4, WIND_NEG_TEMP_LEN = 6, WIND_AND_TEMP_LEN = 7, TEMP_LEN = 4; + + /** + * Wind decoder : parse wind and temperature + * @param wind + * @return + */ + private static DirSpeedTemp parseWindAndTemperature(String wind) { + final int wl = wind.length(); + if (wl == ONLY_WIND_LEN || wl == WIND_AND_TEMP_LEN || wl == WIND_NEG_TEMP_LEN) { + DirSpeed ds; + try { + ds = DirSpeed.parseFrom(wind); + } catch (Exception e) { + return new DirSpeedTemp(); + } + String temperature = (wl == ONLY_WIND_LEN) ? "" : + Integer.parseInt((wl == WIND_NEG_TEMP_LEN ? "-" : "") + wind.substring(TEMP_LEN, wl)) + + "C"; + return new DirSpeedTemp(formatDirAndSpeed(ds), temperature); + } else { + return new DirSpeedTemp(); + } + } + + /** + * Wind decoder: + * @param ds Direction and Speed + * @return (direction, speed) strings pair + */ + private static Pair formatDirAndSpeed(DirSpeed ds) { + return new Pair(String.format(Locale.getDefault(), "%03d°", ds.Dir), + String.format(Locale.getDefault(), "%dkt", ds.Speed)); + } + + + private static class DirSpeedTemp { + final public String Dir, Speed, Temp; + final boolean IsNull; + + private DirSpeedTemp(Pair wind, String t) + { + Dir = wind.first; Speed = wind.second; Temp = t; + IsNull = false; + } + private DirSpeedTemp() { + Dir = Speed = Temp = ""; + IsNull = true; + } + } + + /** + * Wind decoder: parser for numeric wind direction and speed + */ + public static class DirSpeed { + final public int Dir, Speed; + + /** + * Decode wind and direction values based on WA table logic + * @param wind + */ + private DirSpeed(String wind) { + if (wind.startsWith("9900")) // Light and variable + { + Dir = 0; + Speed = 0; + } + else + { + int dir = Integer.parseInt(wind.substring(0, 2)) * 10; + int speed = Integer.parseInt(wind.substring(2, 4)); + if (dir >= 510) { + dir -= 500; + speed += 100; + } + Dir = dir; + Speed = speed; + } + } + + /** + * Wind decoder: public interface + * @param wind + * @return + */ + public static DirSpeed parseFrom(String wind) { + return new DirSpeed(wind); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ds/avare/views/LocationView.java b/app/src/main/java/com/ds/avare/views/LocationView.java index 06591d6fc..148989bea 100644 --- a/app/src/main/java/com/ds/avare/views/LocationView.java +++ b/app/src/main/java/com/ds/avare/views/LocationView.java @@ -1138,7 +1138,7 @@ public Object callback(Object map, Object tu) { * @author zkhan * */ - private class ClosestAirportTask extends AsyncTask { + private class ClosestAirportTask extends AsyncTask { private Double lon; private Double lat; private String tfr = ""; @@ -1157,13 +1157,13 @@ private class ClosestAirportTask extends AsyncTask { * @see android.os.AsyncTask#doInBackground(Params[]) */ @Override - protected String doInBackground(Object... vals) { + protected LongPressedDestination doInBackground(Object... vals) { Thread.currentThread().setName("Closest"); if(null == mService) { return null; } - String airport = null; + String destination = "", type = ""; lon = (Double)vals[0]; lat = (Double)vals[1]; @@ -1176,7 +1176,7 @@ protected String doInBackground(Object... vals) { } if(isCancelled()) - return ""; + return null; /* * Get TFR tfr if touched on its top @@ -1216,33 +1216,37 @@ protected String doInBackground(Object... vals) { } } - airport = mService.getDBResource().findClosestAirportID(lon, lat); + final String airport = mService.getDBResource().findClosestAirportID(lon, lat); if(isCancelled()) { - return ""; + return null; } if(null == airport) { - airport = "" + Helper.truncGeo(lat) + "&" + Helper.truncGeo(lon); + type = Destination.GPS; + destination = "" + Helper.truncGeo(lat) + "&" + Helper.truncGeo(lon); } else { + type = Destination.BASE; + destination = airport; + taf = mService.getDBResource().getTAF(airport); if(isCancelled()) { - return ""; + return null; } metar = mService.getDBResource().getMETAR(airport); if(isCancelled()) { - return ""; + return null; } runways = mService.getDBResource().findRunways(airport); if(isCancelled()) { - return ""; + return null; } elev = mService.getDBResource().findElev(airport); if(isCancelled()) { - return ""; + return null; } } @@ -1253,41 +1257,55 @@ protected String doInBackground(Object... vals) { if(!mPref.useAdsbWeather()) { aireps = mService.getDBResource().getAireps(lon, lat); if(isCancelled()) { - return ""; + return null; } wa = mService.getDBResource().getWindsAloft(lon, lat); if(isCancelled()) { - return ""; + return null; } sua = mService.getDBResource().getSua(lon, lat); if(isCancelled()) { - return ""; + return null; } if(mLayer != null) { layer = mLayer.getDate(); } if(isCancelled()) { - return ""; + return null; } } navaids = mService.getDBResource().findNavaidsNearby(lat, lon); + // if user pressed on a navaid, set this as destination unless she pressed on an airport + if (type != Destination.BASE) { + for (NavAid n : navaids) { + double navaidDistance = Projection.getStaticDistance(lat, lon, + n.getCoords().getLatitude(), n.getCoords().getLongitude()); + if (navaidDistance < Preferences.NAVAID_TOUCH_DISTANCE) { + type = Destination.NAVAID; + destination = n.getLocationId(); + } + } + } + mPointProjection = new Projection(mGpsParams.getLongitude(), mGpsParams.getLatitude(), lon, lat); - return airport; + + return new LongPressedDestination(destination, type); } /* (non-Javadoc) * @see android.os.AsyncTask#onPostExecute(java.lang.Object) */ @Override - protected void onPostExecute(String airport) { - if(null != mGestureCallBack && null != mPointProjection && null != airport) { + protected void onPostExecute(LongPressedDestination destination) { + if(null != mGestureCallBack && null != mPointProjection && null != destination) { mLongTouchDestination = new LongTouchDestination(); - mLongTouchDestination.airport = airport; + mLongTouchDestination.destinationName = destination.getName(); // here we assign destination name + mLongTouchDestination.destinationType = destination.getType(); mLongTouchDestination.info = Math.round(mPointProjection.getDistance()) + Preferences.distanceConversionUnit + "(" + mPointProjection.getGeneralDirectionFrom(mGpsParams.getDeclinition()) + ") " + Helper.correctConvertHeading(Math.round(Helper.getMagneticHeading(mPointProjection.getBearing(), mGpsParams.getDeclinition()))) + '\u00B0'; @@ -1303,8 +1321,8 @@ protected void onPostExecute(String airport) { */ if(mPref.useAdsbWeather()) { - taf = mService.getAdsbWeather().getTaf(airport); - metar = mService.getAdsbWeather().getMETAR(airport); + taf = mService.getAdsbWeather().getTaf(destination.getName()); // MAYBE SHOULD MAKE THIS CONDITIONAL ON TYPE? + metar = mService.getAdsbWeather().getMETAR(destination.getName()); aireps = mService.getAdsbWeather().getAireps(lon, lat); wa = mService.getAdsbWeather().getWindsAloft(lon, lat); layer = mService.getAdsbWeather().getNexrad().getDate(); diff --git a/app/src/main/java/com/ds/avare/views/LongPressedDestination.java b/app/src/main/java/com/ds/avare/views/LongPressedDestination.java new file mode 100644 index 000000000..aab3ed0a5 --- /dev/null +++ b/app/src/main/java/com/ds/avare/views/LongPressedDestination.java @@ -0,0 +1,21 @@ +package com.ds.avare.views; + +/** + * Created by pasniak on 12/4/2016. + */ +public class LongPressedDestination { + private String name, type; + + public LongPressedDestination(String name, String type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } +} diff --git a/app/src/main/java/com/ds/avare/weather/WindsAloft.java b/app/src/main/java/com/ds/avare/weather/WindsAloft.java index f2fb5f580..af631025d 100644 --- a/app/src/main/java/com/ds/avare/weather/WindsAloft.java +++ b/app/src/main/java/com/ds/avare/weather/WindsAloft.java @@ -13,7 +13,7 @@ import com.ds.avare.position.Projection; import com.ds.avare.storage.Preferences; -import com.ds.avare.utils.WeatherHelper; +import com.ds.avare.utils.WindsAloftHelper; /** * @@ -86,8 +86,7 @@ public void updateStationWithLocation(double lon0, double lat0, double variation */ public double[] getWindAtAltitude(double altitude) { - String wstring1 = ""; - String wstring2 = ""; + String wstring1, wstring2; double wind[] = new double[2]; // speed, direction double fac = 0; if(altitude < 3000) { @@ -98,42 +97,42 @@ public double[] getWindAtAltitude(double altitude) { else if(altitude >= 3000 && altitude < 6000) { wstring1 = w3k; wstring2 = w6k; - fac = ((double)altitude - 3000) / altitude; + fac = (altitude - 3000) / altitude; } else if(altitude >= 6000 && altitude < 9000) { wstring1 = w6k; wstring2 = w9k; - fac = ((double)altitude - 6000) / altitude; + fac = (altitude - 6000) / altitude; } else if(altitude >= 9000 && altitude < 12000) { wstring1 = w9k; wstring2 = w12k; - fac = ((double)altitude - 9000) / altitude; + fac = (altitude - 9000) / altitude; } else if(altitude >= 12000 && altitude < 18000) { wstring1 = w12k; wstring2 = w18k; - fac = ((double)altitude - 12000) / altitude; + fac = (altitude - 12000) / altitude; } else if(altitude >= 18000 && altitude < 24000) { wstring1 = w18k; wstring2 = w24k; - fac = ((double)altitude - 18000) / altitude; + fac = (altitude - 18000) / altitude; } else if(altitude >= 24000 && altitude < 30000) { wstring1 = w24k; wstring2 = w30k; - fac = ((double)altitude - 24000) / altitude; + fac = (altitude - 24000) / altitude; } else if(altitude >= 30000 && altitude < 34000) { wstring1 = w30k; wstring2 = w34k; - fac = ((double)altitude - 30000) / altitude; + fac = (altitude - 30000) / altitude; } else if(altitude >= 34000 && altitude <= 39000) { wstring1 = w34k; wstring2 = w39k; - fac = ((double)altitude - 34000) / altitude; + fac = (altitude - 34000) / altitude; } else { wstring1 = w39k; @@ -142,13 +141,10 @@ else if(altitude >= 34000 && altitude <= 39000) { } // interpolate wind - int d1 = WeatherHelper.decodeWindDir(wstring1); - int s1 = WeatherHelper.decodeWindSpeed(wstring1); - int d2 = WeatherHelper.decodeWindDir(wstring2); - int s2 = WeatherHelper.decodeWindSpeed(wstring2); - - wind[0] = ((double)s2 - (double)s1) * fac + s1; - wind[1] = (((double)d2 - (double)d1) * fac + d1) % 360; + WindsAloftHelper.DirSpeed wind1 = WindsAloftHelper.DirSpeed.parseFrom(wstring1); + WindsAloftHelper.DirSpeed wind2 = WindsAloftHelper.DirSpeed.parseFrom(wstring2); + wind[0] = ((double)wind2.Speed - (double)wind1.Speed) * fac + wind1.Speed; + wind[1] = (((double)wind2.Dir - (double)wind1.Dir) * fac + wind1.Dir) % 360; return wind; } diff --git a/app/src/main/java/com/ds/avare/webinfc/WebAppMapInterface.java b/app/src/main/java/com/ds/avare/webinfc/WebAppMapInterface.java index f96d3cf19..c18d4123b 100644 --- a/app/src/main/java/com/ds/avare/webinfc/WebAppMapInterface.java +++ b/app/src/main/java/com/ds/avare/webinfc/WebAppMapInterface.java @@ -24,6 +24,7 @@ import com.ds.avare.utils.GenericCallback; import com.ds.avare.utils.Helper; import com.ds.avare.utils.WeatherHelper; +import com.ds.avare.utils.WindsAloftHelper; import com.ds.avare.weather.Airep; /** @@ -152,16 +153,7 @@ public void handleMessage(Message msg) { String winds = ""; if(data.wa != null) { winds = "Winds/Temp. Aloft "; - winds += data.wa.station + data.wa.time + ""; - winds += "@ 03000 ft: " + WeatherHelper.decodeWind(data.wa.w3k) + ""; - winds += "@ 06000 ft: " + WeatherHelper.decodeWind(data.wa.w6k) + ""; - winds += "@ 09000 ft: " + WeatherHelper.decodeWind(data.wa.w9k) + ""; - winds += "@ 12000 ft: " + WeatherHelper.decodeWind(data.wa.w12k) + ""; - winds += "@ 18000 ft: " + WeatherHelper.decodeWind(data.wa.w18k) + ""; - winds += "@ 24000 ft: " + WeatherHelper.decodeWind(data.wa.w24k) + ""; - winds += "@ 30000 ft: " + WeatherHelper.decodeWind(data.wa.w30k) + ""; - winds += "@ 34000 ft: " + WeatherHelper.decodeWind(data.wa.w34k) + ""; - winds += "@ 39000 ft: " + WeatherHelper.decodeWind(data.wa.w39k); + winds += WindsAloftHelper.formatWindsHTML(data.wa, mPref.getWindsAloftCeiling()); } String navaids = ""; @@ -171,7 +163,7 @@ public void handleMessage(Message msg) { mWebView.loadUrl("javascript:plan_clear()"); String func = "javascript:setData('" + - Helper.formatJsArgs(data.airport) + "','" + + Helper.formatJsArgs(data.destinationName) + "','" + "Position " + Helper.formatJsArgs(data.info) + "','" + Helper.formatJsArgs(metar) + "','" + Helper.formatJsArgs(taf) + "','" + diff --git a/app/src/main/java/com/ds/avare/webinfc/WebAppPlanInterface.java b/app/src/main/java/com/ds/avare/webinfc/WebAppPlanInterface.java index 1e48e2c51..d43a98fc0 100644 --- a/app/src/main/java/com/ds/avare/webinfc/WebAppPlanInterface.java +++ b/app/src/main/java/com/ds/avare/webinfc/WebAppPlanInterface.java @@ -84,7 +84,8 @@ public class WebAppPlanInterface implements Observer { private static final int MSG_ERROR = 15; private static final int MSG_PREV_HIDE = 16; private static final int MSG_NEXT_HIDE = 17; - private static final int MSG_PLAN_COUNT = 18; + private static final int MSG_TIMER_LOAD = 18; + private static final int MSG_PLAN_COUNT = 19; private static final int MAX_PLANS_SHOWN = 5; @@ -117,7 +118,8 @@ public void connect(StorageService s) { * */ public void timer() { - + mHandler.sendEmptyMessage(MSG_TIMER_LOAD); + Plan plan = mService.getPlan(); // If we are in sim mode, then send a message @@ -676,8 +678,7 @@ public void search(String value) { /** * JS polls every second to get all plan data. */ - @JavascriptInterface - public String getPlanData() { + private String getPlanData() { Plan plan = mService.getPlan(); /* @@ -953,6 +954,10 @@ else if(MSG_ADD_SEARCH == msg.what) { else if (MSG_TIMER == msg.what) { plan.simulate(); } + else if (MSG_TIMER_LOAD == msg.what) { + String func = "javascript:loadplan('" + Helper.formatJsArgs(getPlanData()) + "')"; + mWebView.loadUrl(func); + } else if(MSG_CLEAR_PLAN_SAVE == msg.what) { String func = "javascript:save_clear()"; mWebView.loadUrl(func); diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index cf7ac2eed..8f72a19a5 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -2218,6 +2218,20 @@ Redistribution and use in source and binary forms, with or without modification, 100000 + + 3 + 6 + 9 + 12 + 18 + 24 + 30 + 24 + 34 + 39 + + + No Layer METAR @@ -2319,6 +2333,7 @@ Redistribution and use in source and binary forms, with or without modification, "It's best to update maps and plates via Wi-Fi, since it takes a significant amount of data" "You can save and restore your data to Google Drive from Preferences->Application State->Sync Data" "You can change the shown chart type in Map screen by long pressing on the Map tab" + "You can shorten the Winds Aloft list by selecting Winds Aloft Ceiling in Weather preferences" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 41a6e790e..7220666e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -558,4 +558,7 @@ Redistribution and use in source and binary forms, with or without modification, "Maybe Later" "Never Rate" + "Winds/Temp. Aloft Filter" + "Select Winds/Temperature Aloft upper limit altitude (thousands of feet)" + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 25a888203..339ddd3a8 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -108,6 +108,13 @@ authors: zkhan, jlmcgraw android:key="@string/ShowLabelMETARS" android:summary="@string/ShowLabelMETARSSummary" android:title="@string/ShowLabelMETARS" /> +