From 07d13438d18b640fbd75cc704ffbeab2b8eddf5d Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 06:48:35 -0400 Subject: [PATCH 01/48] Create android.yml --- .github/workflows/android.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/android.yml diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 000000000..a2a373dbf --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,26 @@ +name: Android CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build From 3da9bf3043a209d208ee7fa23bda0f67955fa006 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 10:53:05 -0400 Subject: [PATCH 02/48] Update android.yml --- .github/workflows/android.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index a2a373dbf..498cd5dc1 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: set up JDK 11 + - name: set up JDK 17 uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '17' distribution: 'temurin' cache: gradle From a5745876f2e790cd3c5afaed1856e1dae94d32d8 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 11:03:21 -0400 Subject: [PATCH 03/48] Delete app/src/test/java/com/ds/avare directory --- .../AdsbMessageProcessingIntegrationTest.java | 124 ------- .../avare/adsb/AudibleTrafficAlertsTest.java | 241 ------------- .../com/ds/avare/test/DestinationGpsTest.java | 57 ---- .../com/ds/avare/test/DestinationTest.java | 129 ------- .../java/com/ds/avare/test/HelperTest.java | 59 ---- .../java/com/ds/avare/test/HtmlAsserts.java | 49 --- .../java/com/ds/avare/test/InterfaceTest.java | 182 ---------- .../com/ds/avare/test/LocationViewTest.java | 103 ------ .../avare/test/WebAppPlanInterfaceTest.java | 318 ------------------ .../ds/avare/test/WindsAloftHelperTest.java | 150 --------- 10 files changed, 1412 deletions(-) delete mode 100644 app/src/test/java/com/ds/avare/adsb/AdsbMessageProcessingIntegrationTest.java delete mode 100644 app/src/test/java/com/ds/avare/adsb/AudibleTrafficAlertsTest.java delete mode 100644 app/src/test/java/com/ds/avare/test/DestinationGpsTest.java delete mode 100644 app/src/test/java/com/ds/avare/test/DestinationTest.java delete mode 100644 app/src/test/java/com/ds/avare/test/HelperTest.java delete mode 100644 app/src/test/java/com/ds/avare/test/HtmlAsserts.java delete mode 100644 app/src/test/java/com/ds/avare/test/InterfaceTest.java delete mode 100644 app/src/test/java/com/ds/avare/test/LocationViewTest.java delete mode 100644 app/src/test/java/com/ds/avare/test/WebAppPlanInterfaceTest.java delete mode 100644 app/src/test/java/com/ds/avare/test/WindsAloftHelperTest.java diff --git a/app/src/test/java/com/ds/avare/adsb/AdsbMessageProcessingIntegrationTest.java b/app/src/test/java/com/ds/avare/adsb/AdsbMessageProcessingIntegrationTest.java deleted file mode 100644 index c7ad4537d..000000000 --- a/app/src/test/java/com/ds/avare/adsb/AdsbMessageProcessingIntegrationTest.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.ds.avare.adsb; - -import com.ds.avare.StorageService; -import com.ds.avare.adsb.gdl90.Crc; -import com.ds.avare.connections.BufferProcessor; -import com.ds.avare.gps.Gps; -import com.ds.avare.storage.Preferences; -import com.ds.avare.utils.Logger; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; - -import static org.mockito.Mockito.*; -import static org.junit.Assert.*; - -import java.util.Arrays; - -public class AdsbMessageProcessingIntegrationTest { - - private static final byte[] testTrafficMessage = new byte[] { - (byte) 0x7E, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x1D, (byte) 0x48, (byte) 0x97, (byte) 0xBB, - (byte) 0xC8, (byte) 0x7A, (byte) 0x0A, (byte) 0x89, (byte) 0x88, (byte) 0x00, (byte) 0x0F, (byte) 0xFF, (byte) 0xCA, (byte) 0x01, - (byte) 0x4E, (byte) 0x42, (byte) 0x4E, (byte) 0x44, (byte) 0x54, (byte) 0x33, (byte) 0x20, (byte) 0x20, (byte) 0x00, (byte) 0x8F, - (byte) 0x92, (byte) 0x7E - }; - private static final byte[] testOwnshipMessage = new byte[] { - (byte) 0x7e, (byte) 0x0a, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d, (byte) 0x49, (byte) 0x69, (byte) 0xbb, - (byte) 0xc2, (byte) 0x90, (byte) 0x08, (byte) 0xc9, (byte) 0x88, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x01, - (byte) 0x4e, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x20, (byte) 0x20, (byte) 0x00, (byte) 0xbe, - (byte) 0xdf, (byte) 0x7e - }; - - @Mock - TrafficCache trafficCache; - @InjectMocks - StorageService storageService; - - @Test - public void storageServiceGetDataFromIO_ownshipMessage_trafficCacheUpdatedWithOwnshipInfo() throws JSONException { - storageService = spy(StorageService.getInstance()); - trafficCache = mock(TrafficCache.class); - when(storageService.getTrafficCache()).thenReturn(trafficCache); - when(storageService.getGps()).thenReturn(mock(Gps.class)); - // new parameters (isairborne, vspeed) test #1 - final String jsonMsg = "{\"type\":\"ownship\",\"longitude\":-95.96248626708984,\"latitude\":41.184505462646484,\"isairborne\":true,\"speed\":0,\"vspeed\":192,\"bearing\":0,\"time\":1670140827383,\"altitude\":761,\"address\":0}"; - storageService.getDataFromIO(jsonMsg); - verify(trafficCache).setOwnVertVelocity(192); - verify(trafficCache).setOwnIsAirborne(true); - // new parameters (isairborne, vspeed) test #2 - final String jsonMsg2 = "{\"type\":\"ownship\",\"longitude\":-95.96248626708984,\"latitude\":41.184505462646484,\"isairborne\":false,\"speed\":0,\"vspeed\":-256,\"bearing\":0,\"time\":1670140827383,\"altitude\":761,\"address\":0}"; - storageService.getDataFromIO(jsonMsg2); - verify(trafficCache).setOwnVertVelocity(-256); - verify(trafficCache).setOwnIsAirborne(false); - } - - @Test - public void storageServiceGetDataFromIO_trafficMessage_trafficObjectAddedToCache() { - storageService = spy(StorageService.getInstance()); - trafficCache = mock(TrafficCache.class); - when(storageService.getTrafficCache()).thenReturn(trafficCache); - // new parameters (isairborne, vspeed) test #1 - final String jsonMsg = "{\"type\":\"traffic\",\"longitude\":-95.93000030517578,\"latitude\":41.179996490478516,\"isairborne\":true,\"speed\":0,\"vspeed\":-64,\"bearing\":284.0625,\"altitude\":3200,\"callsign\":\"NBNDT3 \",\"address\":3,\"time\":1670140829332}"; - storageService.getDataFromIO(jsonMsg); - verify(trafficCache).putTraffic(eq("NBNDT3 "), eq(3), eq(true), eq(41.179996f), - eq(-95.93f), eq(3200), eq(284.0625f), eq(0), eq(-64), anyLong()); - // new parameters (isairborne, vspeed) test #2 - final String jsonMsg2 = "{\"type\":\"traffic\",\"longitude\":-95.93000030517578,\"latitude\":41.179996490478516,\"isairborne\":false,\"speed\":0,\"vspeed\":-512,\"bearing\":284.0625,\"altitude\":3200,\"callsign\":\"NBNDT3 \",\"address\":3,\"time\":1670140829332}"; - storageService.getDataFromIO(jsonMsg2); - verify(trafficCache).putTraffic(eq("NBNDT3 "), eq(3), eq(false), eq(41.179996f), - eq(-95.93f), eq(3200), eq(284.0625f), eq(0), eq(-512), anyLong()); - } - - //TODO: This could super-set the message parsing tests above - @Test - public void bufferProcessor_trafficMessageDecode_properJsonMessageReturned() throws JSONException { - final BufferProcessor bp = new BufferProcessor(); - try (MockedStatic mockStaticLogger = mockStatic(Logger.class); MockedStatic mockStaticCrc = mockStatic(Crc.class)) { - mockStaticCrc.when(() -> Crc.checkCrc(any(), anyInt(), anyInt())).thenReturn(true); - JSONObject jsonResult; - // TODO: Validate lat, lon, etc. - // new parameters (isairborne, vspeed) test #1 - bp.put(testTrafficMessage, testTrafficMessage.length); - jsonResult = new JSONObject(bp.decode(mock(Preferences.class)).get(0)); - assertEquals("traffic", jsonResult.getString("type")); - assertEquals(true, jsonResult.getBoolean("isairborne")); - assertEquals(-64, jsonResult.getInt("vspeed")); - // new parameters (isairborne, vspeed) test #2 - bp.put(setAirborneFlagInCopy(testTrafficMessage, false), testTrafficMessage.length); - jsonResult = new JSONObject(bp.decode(mock(Preferences.class)).get(0)); - assertEquals(false, jsonResult.getBoolean("isairborne")); - } - } - - @Test - public void bufferProcessor_ownshipMessageDecode_properJsonMessageReturned() throws JSONException { - final BufferProcessor bp = new BufferProcessor(); - try (MockedStatic mockStaticLogger = mockStatic(Logger.class); MockedStatic mockStaticCrc = mockStatic(Crc.class)) { - mockStaticCrc.when(() -> Crc.checkCrc(any(), anyInt(), anyInt())).thenReturn(true); - JSONObject jsonResult; - // TODO: Validate lat, lon, etc. - // new parameters (isairborne, vspeed) test #1 - bp.put(testOwnshipMessage, testTrafficMessage.length); - jsonResult = new JSONObject(bp.decode(mock(Preferences.class)).get(0)); - assertEquals("ownship", jsonResult.getString("type")); - assertEquals(true, jsonResult.getBoolean("isairborne")); - assertEquals(192, jsonResult.getInt("vspeed")); - // new parameters (isairborne, vspeed) test #2 - bp.put(setAirborneFlagInCopy(testOwnshipMessage, false), testTrafficMessage.length); - jsonResult = new JSONObject(bp.decode(mock(Preferences.class)).get(0)); - assertEquals(false, jsonResult.getBoolean("isairborne")); - } - } - - private static final byte[] setAirborneFlagInCopy(final byte[] msg, boolean isAirborne) { - final byte[] newMsg = Arrays.copyOf(msg, msg.length); - newMsg[11+2] = (byte) (isAirborne ? (newMsg[11+2] | (1 << 3)) : (newMsg[11+2] & ~(1 << 3) )); - return newMsg; - } - -} diff --git a/app/src/test/java/com/ds/avare/adsb/AudibleTrafficAlertsTest.java b/app/src/test/java/com/ds/avare/adsb/AudibleTrafficAlertsTest.java deleted file mode 100644 index db154be14..000000000 --- a/app/src/test/java/com/ds/avare/adsb/AudibleTrafficAlertsTest.java +++ /dev/null @@ -1,241 +0,0 @@ -package com.ds.avare.adsb; - - -import android.content.Context; -import android.location.Location; - -import org.junit.Assert; -import org.junit.Test; - -import static org.mockito.Mockito.*; - -import com.ds.avare.storage.Preferences; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class AudibleTrafficAlertsTest { - - @Test - public void angleFromCoordinate_straightUp() { - Assert.assertEquals(0, AudibleTrafficAlerts.angleFromCoordinate(0, 0, 90, 0), 0); - } - - @Test - public void angleFromCoordinate_east() { - Assert.assertEquals(90, AudibleTrafficAlerts.angleFromCoordinate(0, 0, 0, 45), 0); - } - - @Test - public void angleFromCoordinate_west() { - Assert.assertEquals(270, AudibleTrafficAlerts.angleFromCoordinate(0, 90, 0, 45), 0); - } - - @Test - public void angleFromCoordinate_diagonal() { - Assert.assertEquals(225, AudibleTrafficAlerts.angleFromCoordinate(43.5439, -96.730, 42.57, -98.0421), 0.5); - } - - @Test - public void nearestClockHourFromHeadingAndLocations_east() { - Assert.assertEquals(3, - AudibleTrafficAlerts.nearestClockHourFromHeadingAndLocations( - 0, 0, 0, 45, 0)); - } - - @Test - public void nearestClockHourFromHeadingAndLocations_nearEnoughToEastRounded() { - Assert.assertEquals(3, - AudibleTrafficAlerts.nearestClockHourFromHeadingAndLocations( - 0, 0, 0, 45, 5)); - } - - @Test - public void nearestClockHourFromHeadingAndLocations_straightBehindFromAnAngle() { - Assert.assertEquals(6, - AudibleTrafficAlerts.nearestClockHourFromHeadingAndLocations( - 43.5439, -96.730, 42.57, -98.0421, 44.999)); - } - - @Test - public void nearestClockHourFromHeadingAndLocations_oneMinuteToMidnightRounded() { - Assert.assertEquals(12, - AudibleTrafficAlerts.nearestClockHourFromHeadingAndLocations( - 43.5439, -96.730, 44.8402, -96.7621, 0)); - } - - @Test - public void nearestClockHourFromHeadingAndLocations_oneMinutePastMidnightRounded() { - Assert.assertEquals(12, - AudibleTrafficAlerts.nearestClockHourFromHeadingAndLocations( - 43.5439, -96.730, 48.034, -96.654, 0)); - } - - @Test - public void nearestClockHourFromHeadingAndLocations_nearlySouthAndIFacingSouth() { - Assert.assertEquals(12, - AudibleTrafficAlerts.nearestClockHourFromHeadingAndLocations( - 43.5439, -96.730, 39.5718, -96.735, 180)); - } - - @Test - public void closestApproachTime_eastWestHeadOn() { - final double lat1 = 45, lat2 = 45, lon1 = -95, lon2 = -94; - final int velocity1 = 60, velocity2 = 60; - final float heading1 = 270, heading2 = 90; - final double caTime = AudibleTrafficAlerts.closestApproachTime(lat1, lon1, lat2, lon2, heading1, heading2, velocity1, velocity2); - Assert.assertEquals("Closest approach seconds", .35, Math.abs(caTime), .1); - } - - @Test - public void closestApproachTime_northSouthHeadOn() { - final double lat1 = 45, lat2 = 46, lon1 = -95, lon2 = -95; - final int velocity1 = 60, velocity2 = 60; - final float heading1 = 180, heading2 = 0; - final double caTime = AudibleTrafficAlerts.closestApproachTime(lat1, lon1, lat2, lon2, heading1, heading2, velocity1, velocity2); - Assert.assertEquals("Closest approach seconds", .5, Math.abs(caTime), .1); - } - - @Test - public void locationAfterTime_northAt60ktsIsOneDegreeLat() { - final double lat = 41, lon = -95, time = 1 /* hour */; - final float velocity = 60; /* knots */ - final float heading = 0; /* North */ - double[] latLonOverTime = AudibleTrafficAlerts.locationAfterTime(lat, lon, heading, velocity, time,200, 20); - Assert.assertEquals("new lat", 42, latLonOverTime[0], 0.1); - Assert.assertEquals("new lon the same", lon, latLonOverTime[1], 0.1); - } - - @Test - public void locationAfterTime_eastAt60ktsNearEquatorIsAboutOneDegreeLon() { - final double lat = 10, lon = -95, time = 1 /* hour */; - final float velocity = 60; /* knots */ - final float heading = 90; /* East */ - double[] latLonOverTime = AudibleTrafficAlerts.locationAfterTime(lat, lon, heading, velocity, time, 200, 20); - Assert.assertEquals("new lat the same", lat, latLonOverTime[0], 0.0); - Assert.assertEquals("new lon", -94, latLonOverTime[1], 0.1); - } - - @Test - public void locationAfterTime_eastForAShortTimeSlowlyShowsSomeMovement() { - final double lat = 41.184505, lon = -95.948730, time = .008952 /* hour */; - final float velocity = 37; /* knots */ - final float heading = 90; /* East */ - double[] latLonOverTime = AudibleTrafficAlerts.locationAfterTime(lat, lon, heading, velocity, time, 200, 20); - Assert.assertEquals("new lat the same", lat, latLonOverTime[0], 0.0); - Assert.assertNotEquals("new lon", lon, latLonOverTime[1], 0.0000001); - } - - @Test - public void locationAfterTime_eastAt60ktsNearEquatorIsAboutOneDegreeLonHalfHour() { - final double lat = 10, lon = -95, time = .5 /* hour */; - final float velocity = 60; /* knots */ - final float heading = 90; /* East */ - double[] latLonOverTime = AudibleTrafficAlerts.locationAfterTime(lat, lon, heading, velocity, time, 20, 20); - Assert.assertEquals("new lat the same", lat, latLonOverTime[0], 0.0); - Assert.assertEquals("new lon", -94.5, latLonOverTime[1], 0.1); - } - - @Test - public void buildAlertSoundIdSequence_numericListPrefSet_closingEventLessThanHalfSecond_PicksFirstMedia() { - AudibleTrafficAlerts ata = getTestAudibleTrafficAlerts(10); - ata.distanceCalloutOption = AudibleTrafficAlerts.DistanceCalloutOption.DECIMAL; - Location mockLoc = getMockLocation(41.3,-95.4, 200.0f); - AudibleTrafficAlerts.Alert alert = new AudibleTrafficAlerts.Alert( - "abc123", 2, 75, - new AudibleTrafficAlerts.Alert.ClosingEvent(.15, 1.0, false), 99.9f, 10 - ); - List media = ata.buildAlertSoundIdSequence(alert, 1f); - final int firstMedia = ata.numberSoundIds[0]; - Assert.assertTrue("First media ["+firstMedia+"] used: "+media, media.contains(firstMedia)); - } - - @Test - public void handleAudibleAlerts_handleTrafficRunnableIsGarbageCollected() { - AudibleTrafficAlerts spyAta = spy(getTestAudibleTrafficAlerts(10)); - CapturingSingleThreadExecutor capEx = new CapturingSingleThreadExecutor(); - doReturn(capEx).when(spyAta).getTrafficAlertProducerExecutor(); - spyAta.handleAudibleAlerts( - getMockLocation(45, 46, 270), new LinkedList(), mock(Preferences.class), 2200, true, 20); - WeakReference runnableRef = new WeakReference<>(capEx.runnables.get(0)); - capEx.runnables.clear(); - forceGc(); - Assert.assertNull("Reference to runnable after GC", runnableRef.get()); - } - - @Test - public void handleAudibleAlerts_nullLocationDoesNotCauseRunnableExecutionOrError() { - AudibleTrafficAlerts spyAta = spy(getTestAudibleTrafficAlerts(10)); - CapturingSingleThreadExecutor capEx = new CapturingSingleThreadExecutor(); - doReturn(capEx).when(spyAta).getTrafficAlertProducerExecutor(); - LinkedList someTraffic = new LinkedList<>(); - Traffic t = new Traffic(); - t.mIsAirborne = true; - someTraffic.add(t); - spyAta.handleAudibleAlerts( - null, someTraffic, mock(Preferences.class), 2200, true, 20); - Assert.assertEquals("Executed runnables", 0, capEx.runnables.size()); - } - - @Test - public void addNumericalAlertAudioSequence_numericListPrefSet_largeNumberWithDecimal() { - final AudibleTrafficAlerts ata = getTestAudibleTrafficAlerts(10); - ata.numberFormatOption = AudibleTrafficAlerts.NumberFormatOption.INDIVIDUAL_DIGIT; - ata.distanceCalloutOption = AudibleTrafficAlerts.DistanceCalloutOption.DECIMAL; - final ArrayList soundIds = new ArrayList<>(); - ata.addNumericalAlertAudio(soundIds, 1049.99, true); - Assert.assertEquals("SoundIds from number", - Arrays.asList(ata.numberSoundIds[1], ata.numberSoundIds[0], ata.numberSoundIds[4], ata.numberSoundIds[9], ata.pointSoundId, ata.numberSoundIds[9]), - soundIds); - } - - private AudibleTrafficAlerts getTestAudibleTrafficAlerts(int secondsCount) { - final int[] seconds = new int[secondsCount]; - for (int i = 0; i < secondsCount; i++) - seconds[i] = 2000 + i; - return new AudibleTrafficAlerts(getMockSoundPlayer(), mock(Context.class)); - } - - - private Location getMockLocation(double latitude, double longitude, float bearing) { - final Location mockLoc = mock(Location.class); - when(mockLoc.getLatitude()).thenReturn(latitude); - when(mockLoc.getLongitude()).thenReturn(longitude); - when(mockLoc.getBearing()).thenReturn(bearing); - return mockLoc; - } - - private void forceGc() { - //allocate quite some memory to make sure that the GC runs - byte[] bigChunkOfMemory = new byte[4000000]; - System.gc(); - } - - private AudibleTrafficAlerts.SequentialSoundPoolPlayer getMockSoundPlayer() { - AudibleTrafficAlerts.SequentialSoundPoolPlayer sp = mock(AudibleTrafficAlerts.SequentialSoundPoolPlayer.class); - when(sp.load(any(), any())) - .thenAnswer(invocation -> { - int[] regurg = new int[invocation.getArguments().length-1]; - for (int i = 1; i < invocation.getArguments().length; i++) - regurg[i-1] = (int) invocation.getArgument(i); - return regurg; - }); - return sp; - } - - private static class CapturingSingleThreadExecutor implements Executor { - private ArrayList runnables = new ArrayList<>(); - private ExecutorService executor = Executors.newSingleThreadExecutor(); - @Override - public void execute(Runnable r) { - runnables.add(r); - executor.execute(r); - } - } -} \ No newline at end of file diff --git a/app/src/test/java/com/ds/avare/test/DestinationGpsTest.java b/app/src/test/java/com/ds/avare/test/DestinationGpsTest.java deleted file mode 100644 index 48c4671e7..000000000 --- a/app/src/test/java/com/ds/avare/test/DestinationGpsTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ds.avare.test; - -import com.ds.avare.AvareApplication; -import com.ds.avare.BuildConfig; -import com.ds.avare.StorageService; -import com.ds.avare.place.Destination; -import com.ds.avare.place.DestinationFactory; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static junit.framework.TestCase.assertEquals; - -/** - * Created by pasniak on 4/24/2017. - */ - -@RunWith(RobolectricTestRunner.class) -@Config(application = AvareApplication.class) -@PowerMockIgnore({"org.mockito.", "org.robolectric."}) -@PrepareForTest({StorageService.class}) -public class DestinationGpsTest { - private StorageService mStorageService; - - @Before - public void setUp() { - mStorageService = Robolectric.setupService(StorageService.class); - } - @Test - public void Google() { - Destination d1 = DestinationFactory.build(mStorageService, "40.4747&-74.1844", Destination.GPS); - assertLatLon(40.4747, -74.1844, d1); - Destination d2 = DestinationFactory.build(mStorageService, "TEST@40.4747&-74.1844", Destination.GPS); - assertLatLon(40.4747, -74.1844, d2); - } - @Test - public void ICAOLong() { - Destination d1 = DestinationFactory.build(mStorageService, "402829N0741104W", Destination.GPS); - assertLatLon(40.4747, -74.1844, d1); - Destination d2 = DestinationFactory.build(mStorageService, "TEST@402829N0741104W", Destination.GPS); - assertLatLon(40.4747, -74.1844, d2); - Destination d3 = DestinationFactory.build(mStorageService, "402829S1741104E", Destination.GPS); - assertLatLon(-40.4747, 174.1844, d3); - } - private static void assertLatLon(double expectedLat, double expectedLon, Destination d) { - double lat = d.getLocation().getLatitude(); - double lon = d.getLocation().getLongitude(); - assertEquals("Latitude test fails", expectedLat, lat); - assertEquals("Longitude test fails", expectedLon, lon); - } -} diff --git a/app/src/test/java/com/ds/avare/test/DestinationTest.java b/app/src/test/java/com/ds/avare/test/DestinationTest.java deleted file mode 100644 index f8535b69b..000000000 --- a/app/src/test/java/com/ds/avare/test/DestinationTest.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.ds.avare.test; - -import android.content.Context; -import android.content.SharedPreferences; -import android.hardware.GeomagneticField; -import android.location.Location; -import android.preference.PreferenceManager; -import android.test.mock.MockContext; - -import com.ds.avare.R; -import com.ds.avare.StorageService; -import com.ds.avare.gps.GpsParams; -import com.ds.avare.place.Destination; -import com.ds.avare.storage.Preferences; -import com.ds.avare.utils.CalendarHelper; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.lang.reflect.Field; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.isNull; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; -import static org.powermock.api.mockito.PowerMockito.whenNew; - -/** - * Test Destination calculations - * Created by pasniak on 3/26/2017. - */ - -@RunWith(PowerMockRunner.class) -@PrepareForTest({StorageService.class, PreferenceManager.class, - GeomagneticField.class, Destination.class, CalendarHelper.class}) //classes which create the instance -public class DestinationTest { - - @Before - public void setUp() throws Exception { - - // mock the preferences used by Destination calculations - final Preferences prefs = mock(Preferences.class); - when(prefs.isSimulationMode()).thenReturn(true); - when(prefs.useBearingForETEA()).thenReturn(true); - when(prefs.getFuelBurn()).thenReturn(10.0f); - when(prefs.getDistanceUnit()).thenReturn("kt"); - when(prefs.getAircraftTAS()).thenReturn(60); - mockStatic(PreferenceManager.class); - whenNew(Preferences.class).withAnyArguments().thenReturn(prefs); - - /// mock shared preferences - final SharedPreferences sharedPrefs = mock(SharedPreferences.class); - when(sharedPrefs.getBoolean("SimulationMode", false)).thenReturn(true); - when(sharedPrefs.getString(anyString(), anyString())).thenReturn("kt"); - - final android.test.mock.MockContext ctx = mock(MockContext.class); - when(ctx.getString(R.string.DistKnot)).thenReturn("nm"); - when(PreferenceManager.getDefaultSharedPreferences((Context)isNull())) - .thenReturn(sharedPrefs); - when(PreferenceManager.getDefaultSharedPreferences((Context)any())) - .thenReturn(sharedPrefs); - - final GeomagneticField geoField = mock(GeomagneticField.class); - when(geoField.getDeclination()).thenReturn(0f); - whenNew(GeomagneticField.class).withAnyArguments().thenReturn(geoField); - } - - @Test - public void testUpdateTo() throws Exception { - - // mock storage service used to access preferences and GPS location - // in the Destination constructor - final StorageService storageService = mock(StorageService.class); - when(storageService.getApplicationContext()).thenReturn(null); - /// given the above returns null, the destination is at (0N, 0W) - Destination d = new Destination(storageService, "TEST"); - setField(d, "mFound", true); // mock that destination is found (?) - - // mock calendar set to 12:00 for ETA time calculations - when(mockCalendar.getHour()).thenReturn(12); - when(mockCalendar.getMinute()).thenReturn(0); - mockStatic(CalendarHelper.class); - when(CalendarHelper.getInstance(any(long.class))).thenReturn(mockCalendar); - - // mock GPS location - final Location loc1 = mock(Location.class); - when(loc1.getSpeed()).thenReturn(60f); - final GpsParams g = new GpsParams(loc1); - - // update destination with a location - d.updateTo(g); - - assertEquals("Wrong 0kt ETE", "00.00", d.getEte()); - assertEquals("Wrong 0kt ETA", "12:00", d.getEta()); - - // mock another GPS location, 1 degree off... - final Location loc2 = mock(Location.class); - when(loc2.getSpeed()).thenReturn(60f); - when(loc2.getLongitude()).thenReturn(1d); - when(loc2.getLatitude()).thenReturn(0d); - when(loc2.getAltitude()).thenReturn(0d); - final GpsParams g2 = new GpsParams(loc2); - - d.updateTo(g2); - - assertEquals("Wrong 60kt ETE", "01:00", d.getEte()); //... at 60kt we should be there in 1h - assertEquals("Wrong 60kt ETA", "13:00", d.getEta()); - } - - // sets a private field using reflection - private static void setField(Destination d, - String name, - Object value) throws Exception { - Field foundField = Destination.class.getDeclaredField(name); - foundField.setAccessible(true); - foundField.set(d, value); - - } - - @Mock - CalendarHelper mockCalendar; -} \ No newline at end of file diff --git a/app/src/test/java/com/ds/avare/test/HelperTest.java b/app/src/test/java/com/ds/avare/test/HelperTest.java deleted file mode 100644 index 8adc469c2..000000000 --- a/app/src/test/java/com/ds/avare/test/HelperTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.ds.avare.test; - -import com.ds.avare.utils.CalendarHelper; -import com.ds.avare.utils.Helper; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -import static org.junit.Assert.assertEquals; - -/** - * Created by pasniak on 2/16/2017. - */ -@RunWith(MockitoJUnitRunner.class) -public class HelperTest { - @Test - public void testCalculateEte() throws Exception { - assertEquals(Helper.calculateEte(0, 0, 10, true), "--:--"); - assertEquals(Helper.calculateEte(0, 0, 10, false), "00.10"); - assertEquals(Helper.calculateEte(100, 100, 0, true), "01:00"); - assertEquals(Helper.calculateEte(10, 100, 0, true), "06.00"); - } - @Test - public void testPerfOfCalculateEte() throws Exception { - // 750ms on my PC - for (int dist = 0; dist < 100000; dist++) { - for (int speed = 0; speed < 100; speed++) { - String res1 = Helper.calculateEte(dist, speed, 0, true); - } - } - } - @Mock - CalendarHelper mockCalendar; - - @Test - public void testCalculateEta() throws Exception { - - Mockito.when(mockCalendar.getHour()).thenReturn(12); - Mockito.when(mockCalendar.getMinute()).thenReturn(0); - - assertEquals(Helper.calculateEta(mockCalendar, 0, 0), "--:--"); - assertEquals(Helper.calculateEta(mockCalendar, 1000, 100), "22:00"); - } - - @Test - public void testPerfOfCalculateEta() throws Exception { - // 644ms on my PC - // was 900ms when Calendar.getInstance() is called twice - CalendarHelper ch = CalendarHelper.getInstance(0); - for (int dist = 0; dist < 13000; dist++) { - for (int speed = 0; speed < 100; speed++) { - String res1 = Helper.calculateEta(ch, dist, speed); - } - } - } -} \ No newline at end of file diff --git a/app/src/test/java/com/ds/avare/test/HtmlAsserts.java b/app/src/test/java/com/ds/avare/test/HtmlAsserts.java deleted file mode 100644 index 741bf2ad5..000000000 --- a/app/src/test/java/com/ds/avare/test/HtmlAsserts.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.ds.avare.test; - -import org.xmlunit.matchers.EvaluateXPathMatcher; - -import static org.hamcrest.CoreMatchers.endsWith; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.startsWith; - -/** - * Created by pasniak on 2/15/2017. - */ -public class HtmlAsserts { - public static void assertCells(String result, int row, String cells[]) { - String resultXml = xml(html(result)); - - for (int i = 0; i < cells.length; i++) { - assertTdEndsWith(resultXml, row, 1 + i, cells[i]); - } - } - - ///this is needed to make html fragments parsable - public static String html(String c) { return ""+c+""; } - public static String xml(String x) { return "\n" + - "\n" + - "]>\n" + x;} - - ///see https://github.com/xmlunit/xmlunit - private static void assertTdEndsWith(String result, int tr, int td, String end) { - assertThat(result, EvaluateXPathMatcher.hasXPath("//html/table/tr["+tr+"]/td["+td+"]/text()", - endsWith(end))); - } - private static void assertTdStartsWith(String result, int tr, int td, String end) { - assertThat(result, EvaluateXPathMatcher.hasXPath("//html/table/tr["+tr+"]/td["+td+"]/text()", - startsWith(end))); - } - - public static void assertRowCount (String result, int count) { - String resultXml = xml(html(result)); - assertThat(resultXml, EvaluateXPathMatcher.hasXPath("count(//html/table/tr)", - is(Integer.toString(count)))); - } - public static void assertCellCount (String result, int count) { - String resultXml = xml(html(result)); - assertThat(resultXml, EvaluateXPathMatcher.hasXPath("count(//html/table/tr/td)", - is(Integer.toString(count)))); - } -} diff --git a/app/src/test/java/com/ds/avare/test/InterfaceTest.java b/app/src/test/java/com/ds/avare/test/InterfaceTest.java deleted file mode 100644 index 72dd72b63..000000000 --- a/app/src/test/java/com/ds/avare/test/InterfaceTest.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.ds.avare.test; - -import android.content.Context; -import android.os.SystemClock; -import android.view.MotionEvent; -import android.webkit.WebView; - -import com.ds.avare.MainActivity; -import com.ds.avare.StorageService; -import com.ds.avare.storage.Preferences; -import com.ds.avare.utils.GenericCallback; -import com.google.common.io.Files; - -import org.junit.After; -import org.junit.Before; -import org.robolectric.Robolectric; -import org.robolectric.RuntimeEnvironment; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Enumeration; -import java.util.Scanner; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import static android.view.ViewConfiguration.getLongPressTimeout; - -/** - * Created by pasniak on 5/5/2017. - */ - -abstract class InterfaceTest { - private final static String SLASH = File.separator; - private MainActivity mMain; - private final Context mCtx = RuntimeEnvironment.application; - protected StorageService mStorageService; - protected WebView mWebView; - - private static String getCycle() throws IOException { - final String cycleUrl = "http://www.apps4av.org/new/version.php"; - final String currentCycle = new Scanner(new URL(cycleUrl).openStream(), "UTF-8").useDelimiter("\\A").next(); - if (currentCycle.isEmpty()) { throw new IOException("Unable to get cycle from "+cycleUrl); } - return currentCycle; - } - - private static String downloadDatabaseZip(Context ctx, String currentCycle, String fileName) throws IOException { - Preferences mPref = new Preferences(ctx); - final URL website = new URL(mPref.getRoot() + currentCycle + "/" + fileName); - final String avareAppDir = System.getProperty("user.dir", "./"); // sth like C:\Users\Michal\StudioProjects\avare\app\build\tmp\1705\databases.zip - final String cachedBuildFilePath = new File(avareAppDir).getAbsolutePath() - + SLASH + "build" + SLASH + "tmp" + SLASH + currentCycle + SLASH + fileName; - if (!org.codehaus.plexus.util.FileUtils.fileExists(cachedBuildFilePath)) { - System.out.println ("Creating dir " + cachedBuildFilePath); - Files.createParentDirs(new File(cachedBuildFilePath)); - System.out.println ("Downloading " + website); - ReadableByteChannel rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(cachedBuildFilePath); - long n = fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - System.out.println ("Downloaded " + n + " bytes to " + cachedBuildFilePath); - } else { - System.out.println ("Using " + cachedBuildFilePath); - } - return cachedBuildFilePath; - } - - private void unzipDb(String cachedBuildFilePath, String unzipFileNameRegex, String subDir) throws IOException { - final String roboTestDir = mMain.getFilesDir().getPath(); - final File activityFilesDir = new File(roboTestDir + (subDir=="" ? "" : SLASH + subDir)); - activityFilesDir.mkdirs(); - final ZipFile zip = new ZipFile(cachedBuildFilePath); - final Enumeration zipFileEntries = zip.entries(); - while (zipFileEntries.hasMoreElements()) { - ZipEntry zipEntry = (ZipEntry) zipFileEntries.nextElement(); - if (zipEntry.getName().matches(unzipFileNameRegex)) { - unzipFile(zip, zipEntry, zipEntry.getName(), activityFilesDir); - } - } - } - - private static void unzipFile(ZipFile zip, ZipEntry e, String unzipFileName, File toDirectory) throws IOException { - System.out.print ("Unzip " + unzipFileName + " to " + toDirectory); - BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(e)); - FileOutputStream fos = new FileOutputStream(toDirectory + SLASH + unzipFileName); - int got, all = 0; - final int BUFFER_SIZE = 1024 * 8; - byte buffer[] = new byte[BUFFER_SIZE]; - while ((got = bis.read(buffer)) != -1) { - fos.write(buffer, 0, got); - all += got; - } - System.out.println (" (" + all + " bytes)"); - } - - private void deleteDb() { - final String roboTestDir = mMain.getFilesDir().getPath(); - final File activityFilesDir = new File(roboTestDir); - System.out.println ("Del " + roboTestDir); - deleteDir(activityFilesDir); - } - - private static void deleteDir(File file) { - File[] contents = file.listFiles(); - if (contents != null) { - for (File f : contents) { - deleteDir(f); - } - } - file.delete(); - } - - protected void downloadDatabases () throws IOException { - String cachedBuildFilePath = downloadDatabaseZip(mCtx, getCycle(), "databases.zip"); // download database to the build cache - unzipDb(cachedBuildFilePath, "main.db", ""); // unzip to the test directory - } - - protected void downloadWeather () throws IOException { - String weatherCachedBuildFilePath = downloadDatabaseZip(mCtx, "", "weather.zip"); // download weather to the build cache - unzipDb(weatherCachedBuildFilePath, ".*", ""); // unzip all to the test directory - } - - @Before - public void setUp() throws IOException { - mMain = Robolectric.setupActivity(MainActivity.class); - - downloadDatabases(); // all tests require FAA database - downloadMore(); // some test require more data - - prepStorageService(); - setupWebView(); - setupInterface(mCtx); // setup test-specific GUIs - } - - @After - public void tearDown() { - deleteDb(); - System.out.println(); - } - - private void setupWebView() { - mWebView = new WebView(mCtx); - } - - abstract void setupInterface(Context ctx); - - private void prepStorageService() { - mStorageService = Robolectric.setupService(StorageService.class); - mStorageService.onCreate(); - } - - // override to download data beyond base FAA data - void downloadMore () throws IOException {} - - // test helpers - protected static class MyGenericCallback extends GenericCallback { - @Override - public Object callback(Object o1, Object o2) { - return null; - } - } - - protected static MotionEvent getLongPressEvent(float x, float y) { - // simulate long press - long longPressMillis = getLongPressTimeout(); - long downTime = SystemClock.uptimeMillis(); - long eventTime = SystemClock.uptimeMillis() + longPressMillis; - int metaState = 0; - return MotionEvent.obtain( - downTime, - eventTime, - MotionEvent.ACTION_DOWN, - x, - y, - metaState - ); - } - -} diff --git a/app/src/test/java/com/ds/avare/test/LocationViewTest.java b/app/src/test/java/com/ds/avare/test/LocationViewTest.java deleted file mode 100644 index 9711a69c4..000000000 --- a/app/src/test/java/com/ds/avare/test/LocationViewTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.ds.avare.test; - -import android.content.Context; -import android.location.Location; -import android.view.MotionEvent; - -import com.ds.avare.AvareApplication; -import com.ds.avare.BuildConfig; -import com.ds.avare.LocationActivity; -import com.ds.avare.R; -import com.ds.avare.gps.GpsParams; -import com.ds.avare.touch.LongTouchDestination; -import com.ds.avare.views.LocationView; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -/** - * Created by Michal on 5/5/2017. - */ - -@RunWith(RobolectricTestRunner.class) -@Config(application = AvareApplication.class) -@PowerMockIgnore({"org.mockito.", "org.robolectric."}) -public class LocationViewTest extends InterfaceTest { - - private LocationView mLocationView; - - @Test - public void smallAptPressed() throws Exception { - // set location - Location current = new Location("N51 location"); - current.setLatitude(40.582744444); - current.setLongitude(-74.736716667); - GpsParams params = new GpsParams(current); - mLocationView.initParams(params, mStorageService); - - // long press - MotionEvent motionEvent = getLongPressEvent(0,0); - mLocationView.dispatchTouchEvent(motionEvent); - - // assert destination pressed - LongTouchDestination d = mLocationView.getLongTouchDestination(); - assertEquals("N51 Airport not found", "N51", d.airport); - assertEquals("N51 Info not found", "0nm(S of) 013°", d.info); - assertNotNull("N51 SUA not found", d.sua); - assertNull("N51 TAF found", d.taf); // Solberg has no ATIS - assertNull("N51 METAR found", d.metar); - assertNull("N51 Performance found", d.performance); - HtmlAsserts.assertRowCount(d.navaids, 4); - } - - @Test - public void aptWithAtisAndTafPressed() throws Exception { - // set location - Location current = new Location("TTN location"); // TTN has ATIS and TAF - current.setLatitude(40.27617299393192); - current.setLongitude(-74.8124999934585); - GpsParams params = new GpsParams(current); - mLocationView.initParams(params, mStorageService); - - // long press - MotionEvent motionEvent = getLongPressEvent(0,0); - mLocationView.dispatchTouchEvent(motionEvent); - - // assert destination pressed - LongTouchDestination d = mLocationView.getLongTouchDestination(); - assertEquals("TTN Airport not found", "TTN", d.airport); - assertEquals("TTN Info not found", "0nm(SE of) 327°", d.info); - assertNotNull("TTN SUA not found", d.sua); - assertNotNull("TTN TAF not found", d.taf); // Trenton has TAF and ATIS - assertNotNull("TTN METAR not found", d.metar); - assertNotNull("TTN Performance not found", d.performance); - String[] perf = d.performance.split("\\n"); - assertTrue("Performance has time "+perf[0], perf[0].matches("\\d{6}Z")); - assertTrue("Performance has DA "+perf[1], perf[1].matches("Density Altitude -?\\d* ft")); - assertTrue("Performance has runway "+perf[2], perf[2].matches("Best Wind Runway \\d{2}")); - assertTrue("Performance has wind "+perf[3], perf[3].matches(" \\d{1,2}(G\\d{1,2})?KT (Head|Tail)")); - assertTrue("Performance has crosswind "+perf[4], perf[4].matches(" \\d{1,2}(G\\d{1,2})?KT (Left|Right) X")); - - HtmlAsserts.assertRowCount(d.navaids, 4); - } - - public void downloadMore () throws IOException { - downloadWeather(); - } - - public void setupInterface(Context ctx) { - final LocationActivity locationActivity = Robolectric.buildActivity(LocationActivity.class).create().get(); - mLocationView = (LocationView) locationActivity.findViewById(R.id.location); - } -} diff --git a/app/src/test/java/com/ds/avare/test/WebAppPlanInterfaceTest.java b/app/src/test/java/com/ds/avare/test/WebAppPlanInterfaceTest.java deleted file mode 100644 index 08cdc6e2a..000000000 --- a/app/src/test/java/com/ds/avare/test/WebAppPlanInterfaceTest.java +++ /dev/null @@ -1,318 +0,0 @@ -package com.ds.avare.test; - -import android.content.Context; -import android.location.Location; - -import com.ds.avare.AvareApplication; -import com.ds.avare.BuildConfig; -import com.ds.avare.place.Destination; -import com.ds.avare.place.Plan; -import com.ds.avare.webinfc.WebAppPlanInterface; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static org.robolectric.Shadows.shadowOf; - - -/** - * Created by pasniak on 4/1/2017. - * - * Note: if "Font not found at" error occurs this is due to a bug - * see https://github.com/robolectric/robolectric/issues/2647 - * and https://issuetracker.google.com/issues/37347564 - * A temporary workaround is to add task dependency on mergeDebugAssets - * in Run/Debug Configurations (see https://i.imgur.com/u6KSxQq.png) - */ - - -@RunWith(RobolectricTestRunner.class) -@Config(application = AvareApplication.class) -@PowerMockIgnore({"org.mockito.", "org.robolectric."}) -public class WebAppPlanInterfaceTest extends InterfaceTest { - - private WebAppPlanInterface mWebAppPlanInterface; - - @Test - public void airportSearch() throws Exception { - mWebAppPlanInterface.search("KCDW"); - assertEquals("Airport not found", "javascript:search_add('CDW','ESSEX COUNTY','Base','AIRPORT')", - getLastLoadedUrl()); - } - @Test - public void airportAdd() throws Exception { - mWebAppPlanInterface.addToPlan("CDW","Base","AIRPORT"); - assertEquals("Airport not added", 1, mStorageService.getPlan().getDestinationNumber()); - } - @Test - public void navaidSearch() throws Exception { - mWebAppPlanInterface.search("SBJ"); - assertEquals("Navaid not found", "javascript:search_add('SBJ','SOLBERG 112.90','Navaid','VOR/DME')", - getLastLoadedUrl()); - } - @Test - public void navaidAdd() throws Exception { - mWebAppPlanInterface.addToPlan("SBJ","Navaid","VOR/DME"); - assertEquals("Navaid not added", 1, mStorageService.getPlan().getDestinationNumber()); - } - @Test - public void wptSearch() throws Exception { - mWebAppPlanInterface.search("40.4747&-74.1844"); - assertEquals("User waypoint not found", "javascript:search_add('40.4747&-74.1844','GPS','GPS','GPS')", - getLastLoadedUrl()); - } - @Test - public void wptIcaoSearch() throws Exception { - mWebAppPlanInterface.search("402800N0741100W"); - assertEquals("User waypoint not found", "javascript:search_add('402800N0741100W','GPS','GPS','GPS')", - getLastLoadedUrl()); - } - @Test - public void wptAdd() throws Exception { - mWebAppPlanInterface.addToPlan("40.4747&-74.1844","GPS","GPS"); - assertEquals(1, mStorageService.getPlan().getDestinationNumber()); - } - @Test - public void wptIcaoAdd() throws Exception { - mWebAppPlanInterface.addToPlan("402800N0741100W","GPS","GPS"); - assertEquals(1, mStorageService.getPlan().getDestinationNumber()); - } - @Test - public void wptIcaoBadLatAdd() throws Exception { - // "9" cannot be in minutes/seconds - mWebAppPlanInterface.addToPlan("900000N0741000W","GPS","GPS"); - assertEquals("Able to add bad latitude degrees", 0, mStorageService.getPlan().getDestinationNumber()); - mWebAppPlanInterface.addToPlan("409000N0741000W","GPS","GPS"); - assertEquals("Able to add bad latitude minutes", 0, mStorageService.getPlan().getDestinationNumber()); - mWebAppPlanInterface.addToPlan("400090N0741000W","GPS","GPS"); - assertEquals("Able to add bad latitude seconds", 0, mStorageService.getPlan().getDestinationNumber()); - } - @Test - public void wptIcaoBadLonAdd() throws Exception { - // "9" cannot be in minutes/seconds - mWebAppPlanInterface.addToPlan("402000N1974100W","GPS","GPS"); - assertEquals("Able to add bad longitude degrees", 0, mStorageService.getPlan().getDestinationNumber()); - mWebAppPlanInterface.addToPlan("402000N0749000W","GPS","GPS"); - assertEquals("Able to add bad longitude minutes", 0, mStorageService.getPlan().getDestinationNumber()); - mWebAppPlanInterface.addToPlan("402000N0741090W","GPS","GPS"); - assertEquals("Able to add bad longitude seconds", 0, mStorageService.getPlan().getDestinationNumber()); - } - - final String PLAN1_DATA = "::::1,0,0,0,0,--:--,CDW,AIRPORT,-.-,-::::0,0,0,0,0,--:--,SBJ,VOR/DME,-.-,-:::: 0nm --:-- 360° -.-"; - final String PLAN2_DATA = "::::1,0,0,0,0,--:--,TTN,AIRPORT,-.-,-::::0,0,0,0,0,--:--,N51,AIRPORT,-.-,-:::: 0nm --:-- 360° -.-"; - final String PLAN3_DATA = "::::1,0,0,0,0,--:--,400000N0740000W,GPS,-.-,-::::0,0,0,0,0,--:--,410000N0740000W,GPS,-.-,-:::: 0nm --:-- 360° -.-"; - final String PLAN4_DATA = "::::1,0,0,0,0,--:--,40.00&-74.00,GPS,-.-,-::::0,0,0,0,0,--:--,41.00&-74.00,GPS,-.-,-:::: 0nm --:-- 360° -.-"; - - @Test - public void createLongCoast2CoastPlanFromSkyvector() throws Exception - { - // this is a copy-paste of a long plan from SkyVector, each point separated by is 1-3 spaces, 40 points total - mWebAppPlanInterface.createPlan(" 404411N0742217W N05 TIKLE 8PA0 405409N0771129W 405747N0774906W 405908N0790430W DISHE ACO KC66S 405658N0822541W 405710N0825236W 405242N0833633W 405000N0841346W 404755N0844847W 404808N0853707W 404833N0861950W 404706N0871226W 404603N0875932W 404352N0883612W 404352N0892237W 404321N0902506W 404308N0913949W 403858N0925716W 403808N0943536W 403507N0964408W 403327N0975223W 403339N0994109W 403231N1010935W 403134N1025146W 402512N1041434W 402646N1054358W 402204N1074645W AWLIJ 401901N1104801W 401032N1130326W 401110N1152501W 401110N1175116W 400948N1203157W 400858N1224827W "); - assertEquals("Long SkyVector plan creation failed", 40, mStorageService.getPlan().getDestinationNumber()); - } - @Test - public void createLongMEtoFLPlanFromSkyVector() throws Exception - { - // this is a copy-paste of a long plan along the E coast from SkyVector, each point separated by is 1-3 spaces, 24 points total - // https://skyvector.com/?ll=36.279707198143875,-87.7340698184927&chart=301&zoom=11&fpl=%20KFSO%204448N07307W%20BJA%204413N07315W%204351N07320W%204328N07343W%204244N07357W%204215N07403W%204139N07420W%204043N07433W%203943N07510W%203847N07549W%203724N07643W%203623N07642W%203544N07704W%203426N07848W%203322N07951W%203229N08119W%203054N08150W%202956N08148W%20KORL%202730N08110W%202638N08058W%202600N08046W%202516N08055W - mWebAppPlanInterface.createPlan(" 444758N0730707W BJA 441254N0731432W 435111N0732001W 432808N0734322W 424401N0735633W 421451N0740309W 413906N0741954W 404305N0743232W 394319N0750953W 384710N0754910W 372410N0764300W 362253N0764227W 354429N0770352W 342549N0784741W 332146N0795125W 322844N0811845W 305405N0814931W 295549N0814752W KORL 272937N0810958W 263815N0805809W 260021N0804531W 251546N0805524W "); - assertEquals("Long SkyVector plan creation failed", 24, mStorageService.getPlan().getDestinationNumber()); - assertMinMaxCoords(mStorageService.getPlan(), 45, 25, -82, -73); - } - - @Test - public void createAndLoadPlans() throws Exception { - String data; - - // create plan 1 with 2 points - mWebAppPlanInterface.createPlan("KCDW SBJ"); - assertEquals(2, mStorageService.getPlan().getDestinationNumber()); - data = mWebAppPlanInterface.getPlanData(); - final String PLAN1_DATA = "::::1,0,0,0,0,--:--,CDW,AIRPORT,-.-,-::::0,0,0,0,0,--:--,SBJ,VOR/DME,-.-,-:::: 0nm --:-- 360° -.-"; - assertEquals(PLAN1_DATA, data); - - //save it - mWebAppPlanInterface.savePlan("TEST1"); //to preferences - assertUrl("javascript:set_plan_count('1 - 1 of 1')"); - - // refresh - mWebAppPlanInterface.refreshPlanList(); - assertUrl("javascript:set_plan_count('1 - 1 of 1')"); - - // clean up the current plan - mWebAppPlanInterface.discardPlan(); - - - // create plan 2 - mWebAppPlanInterface.createPlan("KTTN N51"); - assertEquals(2, mStorageService.getPlan().getDestinationNumber()); - assertUrl("javascript:plan_add('N51','Base','SOLBERG-HUNTERDON')"); - - //save it to preferences - mWebAppPlanInterface.savePlan("TEST2"); - assertUrl("javascript:set_plan_count('1 - 2 of 2')"); - - // clean up the current plan - mWebAppPlanInterface.discardPlan(); - - - // create plan 3 with ICAO style coordinates - mWebAppPlanInterface.createPlan("400000N0740000W 410000N0740000W"); - assertEquals(2, mStorageService.getPlan().getDestinationNumber()); - assertUrl("javascript:plan_add('410000N0740000W','GPS','GPS')"); - - //save it to preferences - mWebAppPlanInterface.savePlan("TEST3"); - assertUrl("javascript:set_plan_count('1 - 3 of 3')"); - - // clean up the current plan - mWebAppPlanInterface.discardPlan(); - - - // create plan 4 with Google style coordinates - mWebAppPlanInterface.createPlan("40.00&-74.00 41.00&-74.00"); - assertEquals(2, mStorageService.getPlan().getDestinationNumber()); - assertUrl("javascript:plan_add('41.00&-74.00','GPS','GPS')"); - - //save it to preferences - mWebAppPlanInterface.savePlan("TEST4"); - assertUrl("javascript:set_plan_count('1 - 4 of 4')"); - - // clean up the current plan - mWebAppPlanInterface.discardPlan(); - - - // refresh - ArrayList plans = mWebAppPlanInterface.getPlanNames(10); - assertEquals("TEST1", plans.get(0)); - assertEquals("TEST2", plans.get(1)); - assertEquals("TEST3", plans.get(2)); - assertEquals("TEST4", plans.get(3)); - - //now retrieve plan 1 to N51 - mWebAppPlanInterface.loadPlan("TEST1"); - data = mWebAppPlanInterface.getPlanData(); - assertEquals("TEST1" + PLAN1_DATA, data); - assertUrl("javascript:plan_add('SBJ','Navaid','SOLBERG 112.90')"); - - // filter out the second plan - mWebAppPlanInterface.planFilter("2"); - assertUrl("javascript:set_plan_count('1 - 1 of 1')"); - - //now retrieve plan 2 to N51 - mWebAppPlanInterface.loadPlan("TEST2"); - data = mWebAppPlanInterface.getPlanData(); - assertEquals("TEST2" + PLAN2_DATA, data); - assertUrl("javascript:plan_add('N51','Base','SOLBERG-HUNTERDON')"); - - - //now retrieve plan 3 to 410000N0740000W - mWebAppPlanInterface.loadPlan("TEST3"); - data = mWebAppPlanInterface.getPlanData(); - assertEquals("TEST3" + PLAN3_DATA, data); - assertUrl("javascript:plan_add('410000N0740000W','GPS','GPS')"); - - - //now retrieve plan 4 to 41.00&-74.00 - mWebAppPlanInterface.loadPlan("TEST4"); - data = mWebAppPlanInterface.getPlanData(); - assertEquals("TEST4" + PLAN4_DATA, data); - assertUrl("javascript:plan_add('41.00&-74.00','GPS','GPS')"); - } - - private void assertUrl(String expected) { - String lastLoadedUrl = shadowOf(mWebView).getLastLoadedUrl(); // get state of the JS engine - assertEquals(expected, lastLoadedUrl); - } - - private String getLastLoadedUrl() { - return shadowOf(mWebView).getLastLoadedUrl(); - } - - @Test - public void createPlanWithUserWpt() throws Exception { - mWebAppPlanInterface.createPlan("KCDW SBJ 40.4747&-74.1844 410000N0740000W"); - assertEquals(4, mStorageService.getPlan().getDestinationNumber()); - } - @Test - public void createPlanWithAirway() throws Exception { - mWebAppPlanInterface.createPlan("SLATT V6 EMPYR V6 LGA"); - assertEquals(13, mStorageService.getPlan().getDestinationNumber()); - } - - @Test - public void planOperations() throws Exception { - // create plan with points spaced 1 degree lattitude = 60mn/log - final String PLAN = "40.00&-74.00 41.00&-74.00 42.00&-74.00 43.00&-74.00 44.00&-74.00 45.00&-74.00"; - final int nbWaypoints = 6; - - mWebAppPlanInterface.createPlan(PLAN); - assertEquals(nbWaypoints, mStorageService.getPlan().getDestinationNumber()); - - final Plan p = mStorageService.getPlan(); - - assertEquals("Plan track shape", (nbWaypoints-1)*4, p.getTrackShape().getNumCoords()); - - for (int i = 0; i < nbWaypoints ; i++) { - assertFalse("Check for not passed destinations", p.isPassed(i)); - assertEquals("Bearing calcs", 0, p.getBearing(i, i+1), 0.1); - } - assertNull("Access beyond last destination", p.getDestination(100)); - - p.simulate(); - assertEquals(300, p.getDistance(), 1); // so roughly 300nm - - mWebAppPlanInterface.activateToggle(); - p.simulate(); - - int lastLeg = nbWaypoints-1; - assertEquals("Last leg fuel calculation", "6.0", p.getDestination(lastLeg).getFuel()); // at default 10 gal/hour - - // add and remove waypoint - mWebAppPlanInterface.addToPlan("46.00&-74.00","GPS","GPS"); - assertEquals("Waypoint add", nbWaypoints+1, mStorageService.getPlan().getDestinationNumber()); - assertEquals("Plan track shape", (nbWaypoints-1)*4 + 4, p.getTrackShape().getNumCoords()); - - // check geosearch - int found = p.findClosePointId(-74, 46, 2); - assertEquals("Finding by position", lastLeg+1, found); - - p.remove(lastLeg+1); - p.simulate(); - assertEquals("Leg add and remove", 300, p.getDistance(), 1); - - p.advance(); - assertTrue("Check for passed destinations", p.isPassed(0)); - for (int i = 1; i < nbWaypoints ; i++) { - assertFalse("Check for not passed destinations failed", p.isPassed(i)); - } - - p.makeInactive(); - assertFalse("Deactivation failed", p.isActive()); - } - - public void setupInterface(Context ctx) { - mWebAppPlanInterface = new WebAppPlanInterface(ctx, mWebView, new MyGenericCallback()); - mWebAppPlanInterface.connect(mStorageService); - } - - private static void assertMinMaxCoords(Plan p, int latMax, int latMin, int lonMin, int lonMax) { - for (int i = 0; i < p.getDestinationNumber(); i++) { - Destination d = p.getDestination(i); - Location l = d.getLocation(); - double lat = l.getLatitude(), lon = l.getLongitude(); - assertTrue("Lat conversion "+lat+" failed at " + d.getStorageName(), latMax > lat && lat > latMin); - assertTrue("Lon conversion "+lon+" failed at "+ d.getStorageName(), lonMin < lon && lon < lonMax); - } - } - -} diff --git a/app/src/test/java/com/ds/avare/test/WindsAloftHelperTest.java b/app/src/test/java/com/ds/avare/test/WindsAloftHelperTest.java deleted file mode 100644 index f6b039f4c..000000000 --- a/app/src/test/java/com/ds/avare/test/WindsAloftHelperTest.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.ds.avare.test; - -import com.ds.avare.utils.WindsAloftHelper; -import com.ds.avare.weather.WindsAloft; - -import org.junit.Before; -import org.junit.Test; - -import static com.ds.avare.test.HtmlAsserts.assertCellCount; -import static com.ds.avare.test.HtmlAsserts.assertCells; -import static com.ds.avare.test.HtmlAsserts.assertRowCount; -import static junit.framework.Assert.assertEquals; - - -/** - * Created by pasniak on 2/12/2017. - * tests all public interfaces of WindsAloftHelper: - * formatWindsHTML - * DirSpeed.parseFrom - */ -public class WindsAloftHelperTest { - - @Before - public void setUp() throws Exception { - wa = new WindsAloft(); - } - - // test winds/temps parsing - @Test - public void testDirSpeedInterface() throws Exception { - WindsAloftHelper.DirSpeed wind = WindsAloftHelper.DirSpeed.parseFrom("1430"); - assertEquals(wind.Dir, 140); - assertEquals(wind.Speed, 30); - } - - @Test - public void testDirSpeedInterfaceWithTemps() throws Exception { - WindsAloftHelper.DirSpeed wind = WindsAloftHelper.DirSpeed.parseFrom("1212+00"); - assertEquals(wind.Dir, 120); - assertEquals(wind.Speed, 12); - } - - @Test (expected=StringIndexOutOfBoundsException.class) - public void testDirSpeedInterfaceWithBadData1() throws Exception { - WindsAloftHelper.DirSpeed wind = WindsAloftHelper.DirSpeed.parseFrom("+00"); - } - - @Test (expected=StringIndexOutOfBoundsException.class) - public void testDirSpeedInterfaceWithBadData2() throws Exception { - WindsAloftHelper.DirSpeed wind = WindsAloftHelper.DirSpeed.parseFrom("+"); - } - - @Test (expected=NumberFormatException.class) - public void testDirSpeedInterfaceGarbage() throws Exception { - WindsAloftHelper.DirSpeed.parseFrom("garbage"); - } - - // test output table formatting - @Test - public void testEmpty3000() throws Exception { - wa.w3k = ""; - wa.w6k = "2837+02"; - String result = WindsAloftHelper.formatWindsHTML(wa, 6); - - assertRowCount(result, 2); - } - - @Test - public void testLevel3000() throws Exception { - wa.w3k = "1430"; - String result = WindsAloftHelper.formatWindsHTML(wa, 3); - - assertCells(result, 1, new String[] {"3000" , "140°" ,"30kt"}); - } - - @Test - public void testLevel6000() throws Exception { - wa.w3k = "1430"; - wa.w6k = "2837+02"; - String result = WindsAloftHelper.formatWindsHTML(wa, 6); - - assertCells(result, 2, new String[] {"6000", "280°", "37kt", "2C"}); - } - - @Test - public void testLightAndVariable() throws Exception { - wa.w3k = "9900"; - wa.w6k = "9900-01"; - - String result = WindsAloftHelper.formatWindsHTML(wa, 6); - - assertCells(result, 1, new String[] {"3000", "0°", "0kt"}); - assertCells(result, 2, new String[] {"6000", "0°", "0kt", "-1C"}); - } - - - @Test - public void testAbove100kt() throws Exception { - wa.w3k = "780061"; - wa.w6k = "850459"; - String result = WindsAloftHelper.formatWindsHTML(wa, 6); - - assertCells(result, 1, new String[] {"3000", "280°", "100kt", "-61C"}); - assertCells(result, 2, new String[] {"6000", "350°", "104kt", "-59C"}); - } - - private void SetupFullTable() { - String[] winds = "9900 0214+13 3609+09 3410+03 3120-09 3126-22 292739 293148 772457".split(" "); - wa.w3k = winds[0]; - wa.w6k = winds[1]; - wa.w9k = winds[2]; - wa.w12k = winds[3]; - wa.w18k = winds[4]; // show up to this level so 5 rows - wa.w24k = winds[5]; - wa.w30k = winds[6]; - wa.w34k = winds[7]; - wa.w39k = winds[8]; - } - - @Test - public void TestFullTableUpTo18() throws Exception { - SetupFullTable(); - String result = WindsAloftHelper.formatWindsHTML(wa, 18); // up to w18k - - assertRowCount(result, 5); // 5 rows (3,6,9,12,18) up to w18k - assertCellCount(result, 5*4); - } - - @Test - public void TestFullTable() throws Exception { - SetupFullTable(); - String result = WindsAloftHelper.formatWindsHTML(wa, 39); - - assertRowCount(result, 9); // all 9 rows - assertCellCount(result, 9*4); - } - - @Test - public void testGarbage() throws Exception { - wa.w3k = "garbage"; - wa.w6k = "1212--"; // garbage temperature, parsing fails - wa.w9k = "12345678"; - wa.w12k = "+00"; // short string - String result = WindsAloftHelper.formatWindsHTML(wa, 12); - - assertRowCount(result, 4); - } - - private WindsAloft wa; -} \ No newline at end of file From 04f99f375bf78f31d2118e6665e07d54d746ede6 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 11:07:29 -0400 Subject: [PATCH 04/48] Update build.gradle --- app/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index d41dcb194..25cdf4fd6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,6 +62,5 @@ dependencies { testImplementation 'org.powermock:powermock-api-mockito2:1.7.0RC2' testImplementation 'org.powermock:powermock-classloading-xstream:1.7.0RC2' testImplementation 'org.powermock:powermock-module-junit4-rule:1.7.0RC2' - testImplementation 'org.robolectric:robolectric:4.3' testImplementation 'org.json:json:20220924' } From e260cd1ffc582d712028ed736e61554a7e8a2e58 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 11:36:04 -0400 Subject: [PATCH 05/48] Update android.yml --- .github/workflows/android.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 498cd5dc1..21c223d95 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -20,6 +20,11 @@ jobs: distribution: 'temurin' cache: gradle + - name: Create Google Services JSON File + env: + GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} + run: rm app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) + - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle From 4721b2f187b640890d06f6282fb36c336358b8cc Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 11:45:43 -0400 Subject: [PATCH 06/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 21c223d95..0acc3fe87 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: - name: Create Google Services JSON File env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: rm app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) + run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) - name: Grant execute permission for gradlew run: chmod +x gradlew From eb1f908b687184de5ca9470ffcefa7582aa893da Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 11:53:59 -0400 Subject: [PATCH 07/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 0acc3fe87..0893efffc 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: - name: Create Google Services JSON File env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) + run: echo ${{ secrets.GOOGLE_SERVICES_JSON }} && rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && cat app/google-services.json - name: Grant execute permission for gradlew run: chmod +x gradlew From 607dea2536012171b839500d6513900ebbf4045b Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 12:21:01 -0400 Subject: [PATCH 08/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 0893efffc..1b8e1560f 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: - name: Create Google Services JSON File env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: echo ${{ secrets.GOOGLE_SERVICES_JSON }} && rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && cat app/google-services.json + run: echo $GOOGLE_SERVICES_JSON && rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && cat app/google-services.json - name: Grant execute permission for gradlew run: chmod +x gradlew From 586d9f6993e4287f71a85d3db51c0e8b8a75cb85 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 13:16:46 -0400 Subject: [PATCH 09/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 1b8e1560f..0acc3fe87 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: - name: Create Google Services JSON File env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: echo $GOOGLE_SERVICES_JSON && rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && cat app/google-services.json + run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) - name: Grant execute permission for gradlew run: chmod +x gradlew From 2388dbd835a2b42749d7cb6d1752a81d20269064 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 13:19:02 -0400 Subject: [PATCH 10/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 0acc3fe87..313f5dcc8 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: - name: Create Google Services JSON File env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) + run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && && (echo $GOOGLE_SERVICES_JSON | base64 -di) - name: Grant execute permission for gradlew run: chmod +x gradlew From ab121f6e697d4549ceac8e95c6021f04fa988f08 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 13:20:45 -0400 Subject: [PATCH 11/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 313f5dcc8..413386f19 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: - name: Create Google Services JSON File env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && && (echo $GOOGLE_SERVICES_JSON | base64 -di) + run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && (echo $GOOGLE_SERVICES_JSON | base64 -di) - name: Grant execute permission for gradlew run: chmod +x gradlew From 834f0443abedf53778b2a11341a43ebb7eaf6b5a Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 13:30:05 -0400 Subject: [PATCH 12/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 413386f19..0acc3fe87 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: - name: Create Google Services JSON File env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} - run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) && (echo $GOOGLE_SERVICES_JSON | base64 -di) + run: rm -f app/google-services.json && (echo $GOOGLE_SERVICES_JSON | base64 -di > app/google-services.json) - name: Grant execute permission for gradlew run: chmod +x gradlew From 738fb6fac36da3d227eed3c8e8717b7cd2811980 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 15:23:26 -0400 Subject: [PATCH 13/48] Update android.yml --- .github/workflows/android.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 0acc3fe87..c6089f5e5 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -29,3 +29,19 @@ jobs: run: chmod +x gradlew - name: Build with Gradle run: ./gradlew build + + - name: Sign APK with keystore + uses: r0adkll/sign-android-release@v1 + id: sign_app + with: + releaseDirectory: app/build/outputs/apk/release + signingKeyBase64: ${{ secrets.KEY_STORE }} + alias: ${{ secrets.KEY_STORE_ALIAS }} + keyStorePassword: ${{ secrets.KEY_STORE_PASS }} + keyPassword: ${{ secrets.KEY_STORE_PASS }} + + - name: Upload release APK + uses: actions/upload-artifact@v2 + with: + name: app-release.apk + path: ${{steps.sign_app.outputs.signedReleaseFile}} From 11a5eb2e9c6e9062053f973b8e2aa643c92e36ca Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 2 May 2024 15:31:08 -0400 Subject: [PATCH 14/48] Update android.yml --- .github/workflows/android.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index c6089f5e5..1be34e58a 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -39,6 +39,8 @@ jobs: alias: ${{ secrets.KEY_STORE_ALIAS }} keyStorePassword: ${{ secrets.KEY_STORE_PASS }} keyPassword: ${{ secrets.KEY_STORE_PASS }} + env: + BUILD_TOOLS_VERSION: "34.0.0" - name: Upload release APK uses: actions/upload-artifact@v2 From b134a9dd0766f228373ac6264c27f5c5ddb50138 Mon Sep 17 00:00:00 2001 From: zkhan Date: Thu, 2 May 2024 20:07:04 -0400 Subject: [PATCH 15/48] 10.3.2. Added PHX Flyway and Volume button as camera removed to settings. --- .travis.yml | 25 ------ app/src/main/AndroidManifest.xml | 4 +- app/src/main/assets/help.html | 82 +++---------------- .../java/com/ds/avare/LocationActivity.java | 3 + .../java/com/ds/avare/place/Boundaries.java | 4 + .../com/ds/avare/storage/Preferences.java | 4 + app/src/main/res/values/arrays.xml | 12 +-- app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/preferences.xml | 6 ++ 9 files changed, 39 insertions(+), 104 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bd9bd5a85..000000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: android -jdk: oraclejdk8 -sudo: false - -android: - components: - # use the latest revision of Android SDK Tools - - tools - - platform-tools - # The BuildTools version used by the project - - build-tools-25.0.0 - # The SDK version used to compile the project - - android-25 - # Additional components, otherwise bild fails to find license signature - - extra-google-google_play_services - - extra-google-m2repository - - extra-android-m2repository - -licenses: - - 'android-sdk-preview-license-.+' - - 'android-sdk-license-.+' - - 'google-gdk-license-.+' - -script: - bash gradlew test --continue --stacktrace \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a83b9bbd9..f3c204741 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,8 +11,8 @@ Redistribution and use in source and binary forms, with or without modification, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index c50da40aa..75ff353d6 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -16,7 +16,7 @@ -

Avare Help

+

Avare Help

Donations
Apps4Av Inc. is a registered non-profit organization in the state of MA.
Avare is an open source project on GitHub. @@ -48,7 +48,6 @@
Thank you! -

Notice

ALL GPS applications on any handheld non-certified devices like smartphones and tablets are not approved by the FAA for IFR flights. None of the operating systems on such devices are tested according to rigorous FAA standards, hence any software running on them is unfit for use as a primary flight navigation tool. It is unwise to solely rely on any such device or any app running on one, @@ -60,6 +59,11 @@

Notice

CAUTION - Before flight the user must always ensure that Avare is updated to and thoroughly tested on the latest version, and ensure that all Avare databases and charts are kept current. If Avare and its databases and charts are not of the exact same version, the GPS position displayed may be inaccurate, because the FAA sometimes changes the format of their materials. Avare does not automatically fetch any databases and charts when they are expired, so it is the user's sole responsibility to update any expired charts and databases. To do so, ensure that your device has an internet connection and then just press the Map, Menu, Preferences, Download, and Update buttons in Avare.

Avare Releases

+

10.3.2

+
    +
  • Added Phoenix Flyway

  • +
  • Volume button for camera is now a setting under UI Settings.

  • +

10.3.1

  • Fixed FAA weather location changes

  • @@ -67,88 +71,22 @@

    Avare Releases

  • Increased map area size to reduce black borders in track up mode

  • Can start camera by pressing the volume button

  • SUAs show when pressed on map away from airports

  • -

10.3.0

  • Bug fixes in plan filing

  • -

10.2.9

  • Added multi aircraft settings, moved W&B and Lists under the Acft tab

  • -

10.2.8

  • Added auto pilot control over USB serial

  • -

10.2.7

  • Fix plate tagging

  • -

    -
-

10.2.6

-
    -
  • Improved help file

  • -

    -
-

10.2.5

-
    -
  • Improved audible traffic alerts for traffic

  • -

    -
-

10.2.4

-
    -
  • Stop bug fix on ->D -

    -
-

10.2.3

-
    -
  • Fix to IO GPS data loss -

    -
-

10.2.2

-
    -
  • Stop bug fixes -

    -
-

10.2.1

-
    -
  • Improved ADS-B traffic display -

    -
  • Added audible traffic alerts for - traffic -

    -
  • Improved weather display color -

    -
-

10.2.0

-
    -
  • Stop bug fixes -

    -
-

10.1.9

-
    -
  • Stop bug fix -

    -
-

10.1.8

-
    -
  • Bluetooth and USB connection - improvements -

    -
  • Changed UI for long-press in Find - and Search tabs -

    -
  • Improvements in drawing -

    -
-

10.1.7

-
    -
  • Stop bug fix -

Help Categories

Below is a list of your choices for Help with Avare (pronounced "Ah-vAir" - like "aware" with a "v"). Nearly all are available Offline (without internet access on your device), such as when you are flying or your device is in Airplane Mode.
@@ -172,14 +110,14 @@

Help Categories

Online* - Website & Forum

Online* - FAA Chart Maps
-

Online* - FAA TFR List +

Online* - FAA TFR List

Note: Under the Downloads list on the FAA website, select the chart type for which you'd like to see a map legend. For example, to see a map showing the area covered by each of the FAA Sectional charts, click on the "Sectional Raster Charts" link.


-

Avare Intro Videos

+< class="western" align="center">Avare Intro Videos> • Intro videos on YouTube at
      John Wiley's Avare Channel.
@@ -269,7 +207,7 @@

Quick Start - Intro     For convenience in selecting VORs, etc., airports are sorted toward the bottom since they can be quickly selected with a long-press in Map view. - +

Menu, the button on the lower left side of the Map screen, displays a list of additional options and configuration items for Avare. Use your Android Back key or gesture to return to the Map screen.
   ≡ The Preferences button for Avare is accessed via the Menu button, atop the following list of buttons for other features and options.
@@ -660,7 +598,7 @@

TPC and ONC charts

TPC and ONC charts are added for World coverage. These charts are expired and should not be used for navigation. To find the proper TPC chart for your area, see the TPC -Charts Grid while you are online. +Charts Grid while you are online.


  --- End of Avare offline Help file --- diff --git a/app/src/main/java/com/ds/avare/LocationActivity.java b/app/src/main/java/com/ds/avare/LocationActivity.java index a7ae4029e..417309728 100644 --- a/app/src/main/java/com/ds/avare/LocationActivity.java +++ b/app/src/main/java/com/ds/avare/LocationActivity.java @@ -268,6 +268,9 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { // start camera on volume down/up PackageManager packman = getPackageManager(); Intent intent; + if(!StorageService.getInstance().getPreferences().cameraButton()) { + return false; + } if (KeyEvent.KEYCODE_VOLUME_DOWN == event.getKeyCode()) { intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); } diff --git a/app/src/main/java/com/ds/avare/place/Boundaries.java b/app/src/main/java/com/ds/avare/place/Boundaries.java index 5d6ac4fb4..6a5d0b174 100644 --- a/app/src/main/java/com/ds/avare/place/Boundaries.java +++ b/app/src/main/java/com/ds/avare/place/Boundaries.java @@ -1252,6 +1252,10 @@ public static ArrayList getChartTypes() { "13","OrlandoFLY","-82.0368","27.8287", "13","OrlandoFLY","-80.1406","27.8287", "13","OrlandoFLY","-80.1406","29.2311", + "13","PhoenixFLY","-112.8704026","34.0841324", + "13","PhoenixFLY","-112.855721","32.782496", + "13","PhoenixFLY","-111.1819443","32.7827780", + "13","PhoenixFLY","-111.1675846","34.0844160", "13","SaltLakeCityFLY","-112.909","41.4207", "13","SaltLakeCityFLY","-112.909","40.1204", "13","SaltLakeCityFLY","-111.016","40.1204", 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 94271030c..cc2e3484c 100644 --- a/app/src/main/java/com/ds/avare/storage/Preferences.java +++ b/app/src/main/java/com/ds/avare/storage/Preferences.java @@ -1073,6 +1073,10 @@ public boolean removeB1Map() { return mPref.getBoolean(mContext.getString(R.string.b1map), false); } + public boolean cameraButton() { + return mPref.getBoolean(mContext.getString(R.string.cameraButton), false); + } + public boolean removeB3Plate() { return mPref.getBoolean(mContext.getString(R.string.b3plate), false); } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 8c1b9d9bd..3c24dfa8d 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -177,6 +177,7 @@ Redistribution and use in source and binary forms, with or without modification, Miami Flyway NewOrleans Flyway Orlando Flyway + Phoenix Flyway SaltLakeCity Flyway SanDiego Flyway SanFrancisco Flyway @@ -1940,6 +1941,7 @@ Redistribution and use in source and binary forms, with or without modification, MiamiFLY NewOrleansFLY OrlandoFLY + PhoenixFLY SaltLakeCityFLY SanDiegoFLY SanFranciscoFLY @@ -2323,7 +2325,7 @@ Redistribution and use in source and binary forms, with or without modification, "Change the time on the fuel timer via Instrumentation->Fuel Time Interval" "If the app is not locking on to a GPS, move to a different area, and check GPS NOTAMs" "If pre-downloaded SUA or weather disappear in flight, check Weather->Data Expiry and Use ADSB Weather" - "If you're not ADS/B Out equipped, most traffic might be obscured from you" + "If you\'re not ADS/B Out equipped, most traffic might be obscured from you" "Avare is developed by a team volunteers and is free to use, but consider donating to support it" "If the app is running slow, uninstall some background running apps" "If the app is not locking on to a GPS, allow the app to access your location in Android Application Settings" @@ -2342,21 +2344,21 @@ Redistribution and use in source and binary forms, with or without modification, "Choose minimal length for fields in the Near tab via Display->Near Runway Minimum Length" "Set how long weather and TFRs are displayed for via Weather->Data Expiry" "To see maps from different areas, use simulation mode and enter a destination in that areas" - "Don't just keep Avare's data up-to-date, update Avare itself regularly via Google Play" + "Don\'t just keep Avare\'s data up-to-date, update Avare itself regularly via Google Play" "Your email address is a signature you leave for signing a liability release form" "To get support or report bugs, go to apps4av.com and look for the forum link" "If chart download fails after completing more than 50%, make sure your device has enough storage" - "Arrivals, departure procedures, alternate minimums and other info are included with a field's plates" + "Arrivals, departure procedures, alternate minimums and other info are included with a field\'s plates" "Practicing using Avare when flying as a passenger will make you more proficient using it" "Long press on an airport to show its METAR, TAF, COMM and other information" "Avare includes density altitude information for airports" "Avare works with most ADS/B receivers. Confirm compatibility before purchasing one" "When Avare encounters unfamliar fixes on "Create New Plan," it skips those fixes" "Every time you find a bug and report it, you help make Avare a better product" - "Avare's taxi diagrams are automatically geo-tagged, plates are manually tagged by volunteers" + "Avare\'s taxi diagrams are automatically geo-tagged, plates are manually tagged by volunteers" "Update your maps and plates well before a flight, the download process can be lengthy" "If you like this app, please leave a positive review on the play store, and/or donate" - "It's best to update maps and plates via Wi-Fi, since it takes a significant amount of data" + "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 modify the quantity of fields on the top of the display by adjusting the Avare font size scaling at Preferences->UI Configuration->Adjust Font Size" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 93c402bcb..f2cd5bbff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -640,5 +640,8 @@ Redistribution and use in source and binary forms, with or without modification, AircraftTailNumber Acft User defined aircraft. + CameraButton + Use the volume button to launch the camera app + Camera App diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index f55c6c882..aa080c8cb 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -515,6 +515,12 @@ authors: zkhan, jlmcgraw android:title="@string/Io" /> + + Date: Sat, 15 Jun 2024 17:31:45 -0400 Subject: [PATCH 16/48] Go to new regions based charts --- app/build.gradle | 1 + .../java/com/ds/avare/PlatesActivity.java | 67 +- .../java/com/ds/avare/content/DataSource.java | 7 - .../ds/avare/place/DatabaseDestination.java | 51 +- .../com/ds/avare/storage/Preferences.java | 2 +- .../com/ds/avare/utils/PngCommentReader.java | 84 +-- app/src/main/res/values/arrays.xml | 609 +++++------------- 7 files changed, 229 insertions(+), 592 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 25cdf4fd6..93f233a93 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,6 +56,7 @@ dependencies { implementation 'com.google.firebase:firebase-analytics:17.2.2' implementation 'com.google.firebase:firebase-crashlytics:18.2.6' implementation 'com.github.mik3y:usb-serial-for-android:3.4.6' + implementation 'androidx.exifinterface:exifinterface:1.3.7' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:4.8.1' testImplementation 'org.powermock:powermock-module-junit4:1.7.0RC2' diff --git a/app/src/main/java/com/ds/avare/PlatesActivity.java b/app/src/main/java/com/ds/avare/PlatesActivity.java index aac9e24ac..11553bbc1 100644 --- a/app/src/main/java/com/ds/avare/PlatesActivity.java +++ b/app/src/main/java/com/ds/avare/PlatesActivity.java @@ -98,7 +98,6 @@ public class PlatesActivity extends BaseActivity implements Observer { private TankObserver mTankObserver; private TimerObserver mTimerObserver; - public static final String AD = "AIRPORT-DIAGRAM"; public static final String AREA = "AREA"; /* @@ -142,9 +141,6 @@ public static String getNameFromPath(String name) { * @return */ public float[] getMatrix(String name) { - if(name.equals(AD)) { - return(mMatrix); - } if(mService.getPlateDiagram() != null && mService.getPlateDiagram().getName() != null) { @@ -518,7 +514,7 @@ private void setPlateFromPos(int pos) { mPlatesView.setParams(null, true); float m[] = getMatrix(name); mService.setMatrix(null); // to small to show on map - if(name.startsWith(AD)) { + if(name.startsWith("APD")) { mPlatesView.setParams(m, true); } else if(name.startsWith(AREA)) { @@ -658,9 +654,8 @@ public boolean accept(File directory, String fileName) { String dplates[] = new File(mapFolder + "/plates/" + airport).list(filter); String aplates[] = new File(mapFolder + "/area/" + airport).list(filter); - String mins[] = mService.getDBResource().findMinimums(airport); - TreeMap plates = new TreeMap(new PlatesComparable()); + TreeMap plates = new TreeMap(); if (dplates != null) { for (String plate : dplates) { String tokens[] = plate.split(Preferences.IMAGE_EXTENSION); @@ -673,12 +668,6 @@ public boolean accept(File directory, String fileName) { plates.put(tokens[0], mapFolder + "/area/" + airport + "/" + tokens[0]); } } - if (mins != null) { - for (String plate : mins) { - String folder = plate.substring(0, 1) + "/"; - plates.put("Min. " + plate, mapFolder + "/minimums/" + folder + plate); - } - } if (plates.size() > 0) { mPlateFound = Arrays.asList(plates.values().toArray()).toArray(new String[plates.values().toArray().length]); mListPlates = new ArrayList(plates.keySet()); @@ -884,48 +873,6 @@ public void onResume() { } } - /** - * - * @author zkhan - * - */ - private class PlatesComparable implements Comparator{ - - @Override - public int compare(String o1, String o2) { - /* - * Airport diagram must be first - */ - String[] type = {AD, "AREA", "ILS-", "HI-ILS-", "LOC-", "HI-LOC-", "LDA-", "SDA-", "GPS-", "RNAV-GPS-", "RNAV-RNP-", "VOR-", "HI-VOR-", "TACAN-", "HI-TACAN-", "NDB-", "COPTER-", "CUSTOM-", "LAHSO", "HOT-SPOT", "Min."}; - - for(int i = 0; i < type.length; i++) { - if(o1.startsWith(type[i]) && (!o2.startsWith(type[i]))) { - return -1; - } - if(o2.startsWith(type[i]) && (!o1.startsWith(type[i]))) { - return 1; - } - } - - /* - * Continued must follow main - */ - String comp1 = o2.replace(Preferences.IMAGE_EXTENSION, ""); - if(o1.contains("-CONT.") && (!o2.contains("-CONT."))) { - if(o1.startsWith(comp1)) { - return 1; - } - } - String comp2 = o1.replace(Preferences.IMAGE_EXTENSION, ""); - if(o2.contains("-CONT.") && (!o1.contains("-CONT."))) { - if(o2.startsWith(comp2)) { - return -1; - } - } - - return o1.compareTo(o2); - } - } /** * @@ -944,7 +891,15 @@ public static boolean doesAirportHavePlates(String mapFolder, String id) { * @return */ public static boolean doesAirportHaveAirportDiagram(String mapFolder, String id) { - return new File(mapFolder + "/plates/" + id + "/" + AD + Preferences.IMAGE_EXTENSION).exists(); + String[] files = new File(mapFolder + "/plates/" + id + "/").list(); + if(null != files) { + for (String f : files) { + if (f.startsWith("APD")) { + return true; + } + } + } + return false; } diff --git a/app/src/main/java/com/ds/avare/content/DataSource.java b/app/src/main/java/com/ds/avare/content/DataSource.java index e6e3a0ff5..80af3a0df 100644 --- a/app/src/main/java/com/ds/avare/content/DataSource.java +++ b/app/src/main/java/com/ds/avare/content/DataSource.java @@ -137,13 +137,6 @@ public StringPreference searchOneNoCache(String name) { return LocationContentProviderHelper.searchOne(mContext, name, true); } - public String[] findMinimums(String airportId) { - return LocationContentProviderHelper.findMinimums(mContext, airportId); - } - - public LinkedList findAFD(String airportId) { - return LocationContentProviderHelper.findAFD(mContext, airportId); - } public String findLonLat(String name, String type) { return LocationContentProviderHelper.findLonLat(mContext, name, type); diff --git a/app/src/main/java/com/ds/avare/place/DatabaseDestination.java b/app/src/main/java/com/ds/avare/place/DatabaseDestination.java index 3be63a841..9a90b1226 100644 --- a/app/src/main/java/com/ds/avare/place/DatabaseDestination.java +++ b/app/src/main/java/com/ds/avare/place/DatabaseDestination.java @@ -122,35 +122,30 @@ protected Boolean doInBackground(Object... vals) { * Find Chart Supplement */ mAfdFound = null; - final LinkedList afdName = mDataSource.findAFD(mName); - if(afdName.size() > 0) { - FilenameFilter filter = new FilenameFilter() { - public boolean accept(File directory, String fileName) { - boolean match = false; - for(final String name : afdName) { - match |= fileName.matches(name + Preferences.IMAGE_EXTENSION) || - fileName.matches(name + "-[0-9]+" + Preferences.IMAGE_EXTENSION); - } - return match; - } - }; - String afd[] = null; - afd = new File(StorageService.getInstance().getPreferences().getServerDataFolder() + File.separator + "afd" + File.separator).list(filter); - if(null != afd) { - java.util.Arrays.sort(afd); - int len1 = afd.length; - String tmp1[] = new String[len1]; - for(int count = 0; count < len1; count++) { - /* - * Add Chart Supplement - */ - String tokens[] = afd[count].split(Preferences.IMAGE_EXTENSION); - tmp1[count] = StorageService.getInstance().getPreferences().getServerDataFolder() + File.separator + "afd" + File.separator + - tokens[0]; - } - if(len1 > 0) { - mAfdFound = tmp1; + String afd[] = null; + afd = new File(StorageService.getInstance().getPreferences().getServerDataFolder() + File.separator + "afd" + File.separator+ mName + File.separator).list(new FilenameFilter() { + @Override + public boolean accept(File file, String s) { + return !s.equals(".nomedia"); + } + }); + if(null != afd) { + java.util.Arrays.sort(afd); + int len1 = afd.length; + String tmp1[] = new String[len1]; + for(int count = 0; count < len1; count++) { + if(afd[count].equals(".nomedia")) { + continue; } + /* + * Add Chart Supplement + */ + String tokens[] = afd[count].split(Preferences.IMAGE_EXTENSION); + tmp1[count] = StorageService.getInstance().getPreferences().getServerDataFolder() + File.separator + "afd" + File.separator + mName + File.separator + + tokens[0]; + } + if(len1 > 0) { + mAfdFound = tmp1; } } } 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 cc2e3484c..84b828517 100644 --- a/app/src/main/java/com/ds/avare/storage/Preferences.java +++ b/app/src/main/java/com/ds/avare/storage/Preferences.java @@ -193,7 +193,7 @@ public String getRoot() { val = "0"; } if (val.equals("0")) { - return "http://www.apps4av.org/new/"; + return "http://www.apps4av.org/regions/"; } else if (val.equals("1")) { return "https://avare.bubble.org/"; } else if (val.equals("2")) { diff --git a/app/src/main/java/com/ds/avare/utils/PngCommentReader.java b/app/src/main/java/com/ds/avare/utils/PngCommentReader.java index 73670defe..57bc7a115 100644 --- a/app/src/main/java/com/ds/avare/utils/PngCommentReader.java +++ b/app/src/main/java/com/ds/avare/utils/PngCommentReader.java @@ -1,9 +1,9 @@ package com.ds.avare.utils; + +import androidx.exifinterface.media.ExifInterface; + import java.io.FileInputStream; -import java.nio.ByteOrder; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; /** * Created by zkhan on 3/14/17. @@ -13,65 +13,37 @@ public class PngCommentReader { public static float[] readPlate(String fileName) { - - FileChannel channel = null; - - try { // parsing a file causes unknown issues, so surround entire with exception catch - channel = new FileInputStream(fileName).getChannel(); - MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); - buffer.order(ByteOrder.BIG_ENDIAN); // BE for PNGs - - byte[] sign = new byte[8]; - buffer.get(sign); - if(sign[0] == (byte)0x89 && sign[1] == (byte)0x50 && sign[2] == (byte)0x4E && sign[3] == (byte)0x47 && sign[4] == (byte)0x0D && sign[5] == (byte)0x0A && sign[6] == (byte)0x1A && sign[7] == (byte)0x0A) { - // valid sign - int len = 0; - byte[] type = new byte[4]; - do { - len = buffer.getInt(); - buffer.get(type); - if('t' == type[0] && 'E' == type[1] && 'X' == type[2] && 't' == type[3]) { - byte[] data = new byte[len]; - buffer.get(data); - for(int count = 0; count < data.length; count++) { - if(0 == data[count]) { // remove nulls - data[count] = ' '; - } - } - String txt = new String(data); - if(txt.startsWith("Comment")) { - txt = txt.replace("Comment", ""); - String toks[] = txt.split("[|]"); - if(4 == toks.length) { - float matrix[] = new float[4]; - matrix[0] = (float)Double.parseDouble(toks[0]); - matrix[1] = (float)Double.parseDouble(toks[1]); - matrix[2] = (float)Double.parseDouble(toks[2]); - matrix[3] = (float)Double.parseDouble(toks[3]); - return matrix; - } - } - buffer.position(buffer.position() + 4); // 4 for CRC - } - else { - buffer.position(buffer.position() + len + 4); // 4 for CRC - } - } - while(len > 0); - - } - + ExifInterface exif; + try { + exif = new ExifInterface(new FileInputStream(fileName)); } catch (Exception e) { - + return null; } - try { - channel.close(); + String comment = exif.getAttribute("UserComment"); + if(comment == null) { + return null; } - catch (Exception e) { + String[] toks = comment.split("\\|"); + if(toks.length == 4) { + float[] matrix = new float[4]; + matrix[0] = (float)Double.parseDouble(toks[0]); + matrix[1] = (float)Double.parseDouble(toks[1]); + matrix[2] = (float)Double.parseDouble(toks[2]); + matrix[3] = (float)Double.parseDouble(toks[3]); + return matrix; + } + if(toks.length == 6) { + float[] matrix = new float[12]; + matrix[6] = (float)Double.parseDouble(toks[0]); + matrix[7] = (float)Double.parseDouble(toks[1]); + matrix[8] = (float)Double.parseDouble(toks[2]); + matrix[9] = (float)Double.parseDouble(toks[3]); + matrix[10] = (float)Double.parseDouble(toks[4]); + matrix[11] = (float)Double.parseDouble(toks[5]); + return matrix; } - return null; } } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 3c24dfa8d..84518f38f 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -45,59 +45,51 @@ Redistribution and use in source and binary forms, with or without modification, - Chart Supplement NE - Chart Supplement NC - Chart Supplement NW - Chart Supplement SE - Chart Supplement SC - Chart Supplement SW - Chart Supplement EC - Chart Supplement AK - Chart Supplement Pacific + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific - IFR Area ANC - IFR Area ATL - IFR Area DCA - IFR Area DEN - IFR Area DET - IFR Area DFW - IFR Area FAI - IFR Area GUA - IFR Area JAX - IFR Area JNU - IFR Area LAX - IFR Area MIA - IFR Area MKC - IFR Area MSP - IFR Area OME - IFR Area ORD - IFR Area PHX - IFR Area SFO - IFR Area STL - IFR Area VR + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific - IFR High Enroute NE - IFR High Enroute NC - IFR High Enroute NW - IFR High Enroute SE - IFR High Enroute SC - IFR High Enroute SW - IFR High Enroute AK + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific - IFR Low Enroute NE - IFR Low Enroute NC - IFR Low Enroute NW - IFR Low Enroute SE - IFR Low Enroute SC - IFR Low Enroute SW - IFR Low Enroute AK - IFR Low Enroute HI + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific @@ -125,180 +117,50 @@ Redistribution and use in source and binary forms, with or without modification, CJ-27 (Caribbean,PR,VI,DR) - Anchorage TAC - Atlanta TAC - Baltimore-Washington TAC - Boston TAC - Charlotte TAC - Chicago TAC - Cincinnati TAC - Cleveland TAC - Colorado Springs TAC - Dallas-FtWorth TAC - Denver TAC - Detroit TAC - Fairbanks TAC - Honolulu Inset - Houston TAC - Kansas City TAC - Las Vegas TAC - Los Angeles TAC - Memphis TAC - Miami TAC - Minneapolis-StPaul TAC - New Orleans TAC - New York TAC - Orlando TAC - Philadelphia TAC - Phoenix TAC - Pittsburgh TAC - Portland TAC - PuertoRico-VI TAC - Salt Lake City TAC - San Diego TAC - San Francisco TAC - Seattle TAC - St Louis TAC - Tampa TAC + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific - Atlanta Flyway - Baltimore-Washington Flyway - Charlotte Flyway - Chicago Flyway - Cincinnati Flyway - Dallas-FtWorth Flyway - Denver Flyway - Detroit Flyway - Houston Flyway - LasVegas Flyway - LosAngeles Flyway - Miami Flyway - NewOrleans Flyway - Orlando Flyway - Phoenix Flyway - SaltLakeCity Flyway - SanDiego Flyway - SanFrancisco Flyway - Seattle Flyway - StLouis Flyway - Tampa Flyway + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific - Albuquerque - Anchorage - Atlanta - Bethel - Billings - Brownsville - Cape Lisburne - Caribbean - 1 - Caribbean - 2 - Charlotte - Cheyenne - Chicago - Cincinnati - Cold Bay - Dallas-FtWorth - Dawson - Denver - Detroit - Dutch Harbor - El Paso - Fairbanks - Great Falls - Green Bay - Halifax - Hawaiian Islands - Houston - Jacksonville - Juneau - Kansas City - Ketchikan - Klamath Falls - Kodiak - Lake Huron - Las Vegas - Los Angeles - McGrath - Memphis - Miami - Montreal - New Orleans - New York - Nome - Omaha - Phoenix - Point Barrow - Salt Lake City - San Antonio - San Francisco - Seattle - Seward - St Louis - Twin Cities - Washington - Wichita + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific - Canada ADs - Minimums T/A - Alabama - Alaska - Arizona - Arkansas - California - Colorado - Connecticut - D.C. - Delaware - Florida - Georgia - Hawaii - Idaho - Illinois - Indiana - Iowa - Kansas - Kentucky - Louisiana - Maine - Maryland - Massachusetts - Michigan - Minnesota - Mississippi - Missouri - Montana - Nebraska - Nevada - New Hampshire - New Jersey - New Mexico - New York - North Carolina - North Dakota - Ohio - Oklahoma - Oregon - Pennsylvania - Puerto Rico - Rhode Island - South Carolina - South Dakota - Tennessee - Texas - Utah - Vermont - Virginia - Virgin Islands - Washington - West Virginia - Wisconsin - Wyoming - Others + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific VFR Area Canada @@ -465,19 +327,17 @@ Redistribution and use in source and binary forms, with or without modification, Canada Grid 340 Canada Grid 560 - + - Grand Canyon - Baltimore Heli - Boston Heli - Chicago Heli - Dallas-Ft-Worth Heli - Detroit Heli - Houston Heli - Los Angeles Heli - New York Heli - US Gulf Coast Heli - Washington Heli + Northeast + North Central + Northwest + Southeast + South Central + Southwest + East Central + Alaska + Pacific @@ -1513,59 +1373,51 @@ Redistribution and use in source and binary forms, with or without modification, - ELUS_NE - ELUS_NC - ELUS_NW - ELUS_SE - ELUS_SC - ELUS_SW - ELUS_AK - ELUS_HI + NE_ENR_L + NC_ENR_L + NW_ENR_L + SE_ENR_L + SC_ENR_L + SW_ENR_L + EC_ENR_L + AK_ENR_L + PAC_ENR_L - EHUS_NE - EHUS_NC - EHUS_NW - EHUS_SE - EHUS_SC - EHUS_SW - EHUS_AK + NE_ENR_H + NC_ENR_H + NW_ENR_H + SE_ENR_H + SC_ENR_H + SW_ENR_H + EC_ENR_H + AK_ENR_H + PAC_ENR_H - ENRA_ANC - ENRA_ATL - ENRA_DCA - ENRA_DEN - ENRA_DET - ENRA_DFW - ENRA_FAI - ENRA_GUA - ENRA_JAX - ENRA_JNU - ENRA_LAX - ENRA_MIA - ENRA_MKC - ENRA_MSP - ENRA_OME - ENRA_ORD - ENRA_PHX - ENRA_SFO - ENRA_STL - ENRA_VR + NE_ENR_A + NC_ENR_A + NW_ENR_A + SE_ENR_A + SC_ENR_A + SW_ENR_A + EC_ENR_A + AK_ENR_A + PAC_ENR_A - AFD_NE - AFD_NC - AFD_NW - AFD_SE - AFD_SC - AFD_SW - AFD_EC - AFD_AK - AFD_PAC + NE_CSUP + NC_CSUP + NW_CSUP + SE_CSUP + SC_CSUP + SW_CSUP + EC_CSUP + AK_CSUP + PAC_CSUP @@ -1593,156 +1445,39 @@ Redistribution and use in source and binary forms, with or without modification, CJ-27 - AnchorageTAC - AtlantaTAC - Baltimore-WashingtonTAC - BostonTAC - CharlotteTAC - ChicagoTAC - CincinnatiTAC - ClevelandTAC - ColoradoSpringsTAC - Dallas-FtWorthTAC - DenverTAC - DetroitTAC - FairbanksTAC - HonoluluInset - HoustonTAC - KansasCityTAC - LasVegasTAC - LosAngelesTAC - MemphisTAC - MiamiTAC - Minneapolis-StPaulTAC - NewOrleansTAC - NewYorkTAC - OrlandoTAC - PhiladelphiaTAC - PhoenixTAC - PittsburghTAC - PortlandTAC - PuertoRico-VITAC - SaltLakeCityTAC - SanDiegoTAC - SanFranciscoTAC - SeattleTAC - StLouisTAC - TampaTAC + NE_TAC + NC_TAC + NW_TAC + SE_TAC + SC_TAC + SW_TAC + EC_TAC + AK_TAC + PAC_TAC + - Albuquerque - Anchorage - Atlanta - Bethel - Billings - Brownsville - CapeLisburne - Caribbean1 - Caribbean2 - Charlotte - Cheyenne - Chicago - Cincinnati - ColdBay - Dallas-FtWorth - Dawson - Denver - Detroit - DutchHarbor - ElPaso - Fairbanks - GreatFalls - GreenBay - Halifax - HawaiianIslands - Houston - Jacksonville - Juneau - KansasCity - Ketchikan - KlamathFalls - Kodiak - LakeHuron - LasVegas - LosAngeles - McGrath - Memphis - Miami - Montreal - NewOrleans - NewYork - Nome - Omaha - Phoenix - PointBarrow - SaltLakeCity - SanAntonio - SanFrancisco - Seattle - Seward - StLouis - TwinCities - Washington - Wichita + NE_SEC + NC_SEC + NW_SEC + SE_SEC + SC_SEC + SW_SEC + EC_SEC + AK_SEC + PAC_SEC - CAN_ADS - alternates - AL_PLATES - AK_PLATES - AZ_PLATES - AR_PLATES - CA_PLATES - CO_PLATES - CT_PLATES - DC_PLATES - DE_PLATES - FL_PLATES - GA_PLATES - HI_PLATES - ID_PLATES - IL_PLATES - IN_PLATES - IA_PLATES - KS_PLATES - KY_PLATES - LA_PLATES - ME_PLATES - MD_PLATES - MA_PLATES - MI_PLATES - MN_PLATES - MS_PLATES - MO_PLATES - MT_PLATES - NE_PLATES - NV_PLATES - NH_PLATES - NJ_PLATES - NM_PLATES - NY_PLATES - NC_PLATES - ND_PLATES - OH_PLATES - OK_PLATES - OR_PLATES - PA_PLATES - PR_PLATES - RI_PLATES - SC_PLATES - SD_PLATES - TN_PLATES - TX_PLATES - UT_PLATES - VT_PLATES - VA_PLATES - VI_PLATES - WA_PLATES - WV_PLATES - WI_PLATES - WY_PLATES - XX_PLATES + NE_TPP + NC_TPP + NW_TPP + SE_TPP + SC_TPP + SW_TPP + EC_TPP + AK_TPP + PAC_TPP @@ -1911,43 +1646,29 @@ Redistribution and use in source and binary forms, with or without modification, CAN_340 CAN_560 - + - GrandCanyon - BaltimoreHeli - BostonHeli - ChicagoHeli - Dallas-FtWorthHeli - DetroitHeli - HoustonHeli - LosAngelesHeli - NewYorkHeli - USGulfCoastHeli - WashingtonHeli + NE_HEL + NC_HEL + NW_HEL + SE_HEL + SC_HEL + SW_HEL + EC_HEL + AK_HEL + PAC_HEL - AtlantaFLY - Baltimore-WashingtonFLY - CharlotteFLY - ChicagoFLY - CincinnatiFLY - Dallas-FtWorthFLY - DenverFLY - DetroitFLY - HoustonFLY - LasVegasFLY - LosAngelesFLY - MiamiFLY - NewOrleansFLY - OrlandoFLY - PhoenixFLY - SaltLakeCityFLY - SanDiegoFLY - SanFranciscoFLY - SeattleFLY - StLouisFLY - TampaFLY + NE_FLY + NC_FLY + NW_FLY + SE_FLY + SC_FLY + SW_FLY + EC_FLY + AK_FLY + PAC_FLY From f86c144867d5c6e1cad015c20f71160f7697e208 Mon Sep 17 00:00:00 2001 From: zkhan Date: Wed, 26 Jun 2024 20:03:01 -0400 Subject: [PATCH 17/48] Go to new regions based charts, release 11.0.0. --- app/src/main/AndroidManifest.xml | 4 ++-- app/src/main/assets/help.html | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f3c204741..992333876 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,8 +11,8 @@ Redistribution and use in source and binary forms, with or without modification, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index 75ff353d6..621b39560 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -59,6 +59,10 @@

Notice

CAUTION - Before flight the user must always ensure that Avare is updated to and thoroughly tested on the latest version, and ensure that all Avare databases and charts are kept current. If Avare and its databases and charts are not of the exact same version, the GPS position displayed may be inaccurate, because the FAA sometimes changes the format of their materials. Avare does not automatically fetch any databases and charts when they are expired, so it is the user's sole responsibility to update any expired charts and databases. To do so, ensure that your device has an internet connection and then just press the Map, Menu, Preferences, Download, and Update buttons in Avare.

Avare Releases

+

11.0.0

+
    +
  • Charts are divided into regions now. *** Users must re-download all charts for correct operation ***
  • +

10.3.2

  • Added Phoenix Flyway

  • From bd0d4a00fa56cc080f8986a128c3ae0a8f387e81 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Tue, 9 Jul 2024 13:12:25 -0400 Subject: [PATCH 18/48] Update build.gradle update to tools ver 34 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 93f233a93..1eed5957e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,8 +2,8 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' android { - compileSdkVersion 33 - buildToolsVersion '33.0.2' + compileSdkVersion 34 + buildToolsVersion '34.0.0' defaultConfig { applicationId "com.ds.avare" From a25fed817041756548c1b0579d088a2859b975c7 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 18 Jul 2024 18:59:28 -0400 Subject: [PATCH 19/48] Update README.md for AvareX --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bfc5c6c6f..00f73ddb3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ avare ===== +Note: A more modern multi platofrm version of Avare is available as AvareX on Android Play Store, Apple App Store, Windows App Store, and Linux Snapcraft Store. + Avare Aviation GPS for Android. Avare is pronounced "Ah-vAir" - like "aware" with a "v" and can be manually installed from our servers (see our website). Download from the Google Play Store: https://play.google.com/store/apps/details?id=com.ds.avare&hl=en From 365d2d0d1cb117ad677b9ee0fbd3025678b3b9aa Mon Sep 17 00:00:00 2001 From: zkhan Date: Sat, 27 Jul 2024 17:50:16 -0400 Subject: [PATCH 20/48] 11.0.1 optional registration now --- app/build.gradle | 8 ++++---- app/src/main/AndroidManifest.xml | 4 ++-- app/src/main/assets/help.html | 4 ++++ app/src/main/java/com/ds/avare/RegisterActivity.java | 6 +++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 93f233a93..84dcf1487 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,13 +2,13 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' android { - compileSdkVersion 33 - buildToolsVersion '33.0.2' + compileSdk 35 + buildToolsVersion '34.0.0' defaultConfig { applicationId "com.ds.avare" - minSdkVersion 20 // android 5 is minimum - targetSdkVersion 33 + minSdkVersion 20 + targetSdk 35// android 5 is minimum } compileOptions { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 992333876..459044e26 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,8 +11,8 @@ Redistribution and use in source and binary forms, with or without modification, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index 621b39560..3046fd75d 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -59,6 +59,10 @@

    Notice

    CAUTION - Before flight the user must always ensure that Avare is updated to and thoroughly tested on the latest version, and ensure that all Avare databases and charts are kept current. If Avare and its databases and charts are not of the exact same version, the GPS position displayed may be inaccurate, because the FAA sometimes changes the format of their materials. Avare does not automatically fetch any databases and charts when they are expired, so it is the user's sole responsibility to update any expired charts and databases. To do so, ensure that your device has an internet connection and then just press the Map, Menu, Preferences, Download, and Update buttons in Avare.

    Avare Releases

    +

    11.0.1

    +
      +
    • Registration with the server is now optional.
    • +

    11.0.0

    • Charts are divided into regions now. *** Users must re-download all charts for correct operation ***
    • diff --git a/app/src/main/java/com/ds/avare/RegisterActivity.java b/app/src/main/java/com/ds/avare/RegisterActivity.java index 9c20d86c2..101c58308 100644 --- a/app/src/main/java/com/ds/avare/RegisterActivity.java +++ b/app/src/main/java/com/ds/avare/RegisterActivity.java @@ -41,7 +41,7 @@ */ public class RegisterActivity extends BaseActivity { - private static final int MAX_ATTEMPTS = 5; + private static final int MAX_ATTEMPTS = 3; private static final int BACKOFF_MILLI_SECONDS = 2000; static AsyncTask mRegisterTask = null; @@ -183,7 +183,7 @@ protected Boolean doInBackground(Void... vals) { } backoff *= 2; } - return false; + return true; // pass anyways as people keep using old devices } @Override @@ -258,7 +258,7 @@ protected Boolean doInBackground(Void... vals) { backoff *= 2; } } - return false; + return true; // pass anyways as people keep using old devices } @Override From 24db333f4da6b58197da22a89f612526623e0fd7 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 14:12:10 -0400 Subject: [PATCH 21/48] building weather on github actions --- .github/workflows/weather.yml | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/weather.yml diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml new file mode 100644 index 000000000..c590dfea8 --- /dev/null +++ b/.github/workflows/weather.yml @@ -0,0 +1,38 @@ +name: Android CI + +on: + push: + branches: [ "master" ] + +# schedule: +# - cron: '*/7 * * * *' + +jobs: + build: + + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.12 + uses: actions/setup-python@v3 + with: + python-version: "3.12" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + sudo apt-get install gdal-bin python3-gdal + pip install bs4 tqdm numpy regex urllib3 glob2 + - name: Build weather + run: | + cd extra/mamba && ./put_tenmin.sh + + - name: SSH to mamba + uses: appleboy/scp-action@v0.1.7 + with: + host: apps4av.org + username: apps4av + password: ${{ secrets.MAMBA_PASSWORD }} + port: 22 + source: "TFRs.zip weather.zip conus.zip" + target: /home/apps4av/mamba.dreamhosters.com/new/staging \ No newline at end of file From 5903d4df26b5d8c25a3d8a6d4f79cc6ead27a73f Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 14:14:34 -0400 Subject: [PATCH 22/48] building weather on github actions --- extra/mamba/put_tenmin.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/extra/mamba/put_tenmin.sh b/extra/mamba/put_tenmin.sh index 0b28ff088..383279eb4 100755 --- a/extra/mamba/put_tenmin.sh +++ b/extra/mamba/put_tenmin.sh @@ -19,8 +19,4 @@ ./gentfr.sh -mv TFRs.zip weather.zip conus.zip ~/www - - -sshpass -f "/home/bitnami/.ssh/mamba.passwd" scp /home/bitnami/www/*.zip apps4av@apps4av.org:/home/apps4av/mamba.dreamhosters.com/new From 410a1f49a7a3d987fa4644044a34642dccf5ba83 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 14:20:30 -0400 Subject: [PATCH 23/48] building weather on github actions --- .github/workflows/weather.yml | 4 ++-- extra/mamba/radar.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index c590dfea8..f7b48f217 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -1,4 +1,4 @@ -name: Android CI +name: Weather CI on: push: @@ -21,7 +21,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - sudo apt-get install gdal-bin python3-gdal + sudo apt-get install gdal-bin python3-gdal imagemagick pip install bs4 tqdm numpy regex urllib3 glob2 - name: Build weather run: | diff --git a/extra/mamba/radar.py b/extra/mamba/radar.py index 0aab07472..a1fe9772d 100755 --- a/extra/mamba/radar.py +++ b/extra/mamba/radar.py @@ -13,7 +13,7 @@ # import requests -import bs4 +from bs4 import BeautifulSoup import re import os import datetime @@ -25,7 +25,7 @@ url = 'https://mrms.ncep.noaa.gov/data/RIDGEII/L2/CONUS/CREF_QCD/' #parse html -soup = bs4.BeautifulSoup(requests.get(url).text, 'lxml') +soup = BeautifulSoup(requests.get(url).text, 'lxml') table = soup.find('table') listOfFiles = [] From 7d430663143e2036be70db05d0de3f884ec90e76 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 14:27:34 -0400 Subject: [PATCH 24/48] building weather on github actions --- .github/workflows/weather.yml | 4 ++-- extra/mamba/radar.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index f7b48f217..db4aaef12 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -21,8 +21,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - sudo apt-get install gdal-bin python3-gdal imagemagick - pip install bs4 tqdm numpy regex urllib3 glob2 + sudo apt-get install gdal-bin python3-gdal imagemagick python3-bs4 + pip install regex urllib3 - name: Build weather run: | cd extra/mamba && ./put_tenmin.sh diff --git a/extra/mamba/radar.py b/extra/mamba/radar.py index a1fe9772d..33ade0616 100755 --- a/extra/mamba/radar.py +++ b/extra/mamba/radar.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 #Copyright (c) 2021, Apps4Av Inc. (apps4av@gmail.com) #All rights reserved. # @@ -37,7 +37,7 @@ floc = td[0].find('a').get('href') if None != floc: # parse time out of file names - fm = re.search("^CONUS_L2_CREF_QCD_(\d*)_(\d*).tif.gz$", floc) + fm = re.search("^CONUS_L2_CREF_QCD_([0-9]*)_([0-9]*).tif.gz$", floc) if None != fm: datetimeStr = fm.group(1) + fm.group(2) d = {} From c0513a296ac0166d4d79f69c23c16ff05dad5279 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 14:33:16 -0400 Subject: [PATCH 25/48] building weather on github actions --- .github/workflows/weather.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index db4aaef12..481f6bbea 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -1,11 +1,8 @@ name: Weather CI on: - push: - branches: [ "master" ] - -# schedule: -# - cron: '*/7 * * * *' + schedule: + - cron: '*/7 * * * *' jobs: build: From 00cfd0749307dfe8a8e361f3e1cae7649b6657ba Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 14:45:30 -0400 Subject: [PATCH 26/48] building weather on github actions --- .github/workflows/weather.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index 481f6bbea..413878938 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -31,5 +31,5 @@ jobs: username: apps4av password: ${{ secrets.MAMBA_PASSWORD }} port: 22 - source: "TFRs.zip weather.zip conus.zip" + source: "extra/mamba/TFRs.zip extra/mamba/weather.zip extra/mamba/conus.zip" target: /home/apps4av/mamba.dreamhosters.com/new/staging \ No newline at end of file From 4aed4870b16c9e49fdb8cbd648dd1d7578e26f65 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 14:54:50 -0400 Subject: [PATCH 27/48] building weather on github actions --- .github/workflows/weather.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index 413878938..7d8304258 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -31,5 +31,5 @@ jobs: username: apps4av password: ${{ secrets.MAMBA_PASSWORD }} port: 22 - source: "extra/mamba/TFRs.zip extra/mamba/weather.zip extra/mamba/conus.zip" + source: "extra/mamba/TFRs.zip,extra/mamba/weather.zip,extra/mamba/conus.zip" target: /home/apps4av/mamba.dreamhosters.com/new/staging \ No newline at end of file From 67de819a1f20dd03888cc23427f9ecf63bf00808 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 15:04:57 -0400 Subject: [PATCH 28/48] building weather on github actions --- .github/workflows/weather.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index 7d8304258..3d701679b 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -31,5 +31,6 @@ jobs: username: apps4av password: ${{ secrets.MAMBA_PASSWORD }} port: 22 + strip_components: 2 source: "extra/mamba/TFRs.zip,extra/mamba/weather.zip,extra/mamba/conus.zip" target: /home/apps4av/mamba.dreamhosters.com/new/staging \ No newline at end of file From 27a70f09f6f0ed699dcb6847b72482af809aec5b Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 11 Aug 2024 15:09:56 -0400 Subject: [PATCH 29/48] live weather --- .github/workflows/weather.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index 3d701679b..a73d736d6 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -33,4 +33,4 @@ jobs: port: 22 strip_components: 2 source: "extra/mamba/TFRs.zip,extra/mamba/weather.zip,extra/mamba/conus.zip" - target: /home/apps4av/mamba.dreamhosters.com/new/staging \ No newline at end of file + target: /home/apps4av/mamba.dreamhosters.com/new \ No newline at end of file From 6dda51e59f2c92efda27176db90dac78140cf8d1 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Fri, 20 Sep 2024 14:03:46 -0400 Subject: [PATCH 30/48] Update weather.yml install missing libperlwww --- .github/workflows/weather.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index a73d736d6..f83c54a67 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -18,7 +18,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - sudo apt-get install gdal-bin python3-gdal imagemagick python3-bs4 + sudo apt-get install gdal-bin python3-gdal imagemagick python3-bs4 libwww-perl pip install regex urllib3 - name: Build weather run: | @@ -33,4 +33,4 @@ jobs: port: 22 strip_components: 2 source: "extra/mamba/TFRs.zip,extra/mamba/weather.zip,extra/mamba/conus.zip" - target: /home/apps4av/mamba.dreamhosters.com/new \ No newline at end of file + target: /home/apps4av/mamba.dreamhosters.com/new From 9e901fd2c35a6059f875f5855ff4d98edcb4b524 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Fri, 20 Sep 2024 14:10:39 -0400 Subject: [PATCH 31/48] Update weather.yml --- .github/workflows/weather.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index f83c54a67..a50c0cf90 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -18,7 +18,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - sudo apt-get install gdal-bin python3-gdal imagemagick python3-bs4 libwww-perl + sudo apt-get install gdal-bin python3-gdal imagemagick python3-bs4 libwww-perl libxml-parser-perl pip install regex urllib3 - name: Build weather run: | From a88765500abb1c0a660fac500a23082764df397d Mon Sep 17 00:00:00 2001 From: "Jon S. Stumpf" Date: Sun, 22 Sep 2024 16:04:02 -0400 Subject: [PATCH 32/48] Resolve #501 --- app/src/main/java/com/ds/avare/connections/MsfsConnection.java | 1 + app/src/main/java/com/ds/avare/connections/WifiConnection.java | 1 + app/src/main/java/com/ds/avare/connections/XplaneConnection.java | 1 + 3 files changed, 3 insertions(+) diff --git a/app/src/main/java/com/ds/avare/connections/MsfsConnection.java b/app/src/main/java/com/ds/avare/connections/MsfsConnection.java index ba9205e26..d7d3b4807 100644 --- a/app/src/main/java/com/ds/avare/connections/MsfsConnection.java +++ b/app/src/main/java/com/ds/avare/connections/MsfsConnection.java @@ -160,6 +160,7 @@ public boolean connect(String to, boolean secure) { try { mSocket = new DatagramSocket(mPort); + mSocket.setReuseAddress(true); } catch(Exception e) { Logger.Logit("Failed! Connecting socket " + e.getMessage()); diff --git a/app/src/main/java/com/ds/avare/connections/WifiConnection.java b/app/src/main/java/com/ds/avare/connections/WifiConnection.java index f65453bb7..5604ec0dd 100644 --- a/app/src/main/java/com/ds/avare/connections/WifiConnection.java +++ b/app/src/main/java/com/ds/avare/connections/WifiConnection.java @@ -148,6 +148,7 @@ public boolean connect(String to, boolean secure) { try { mSocket = new DatagramSocket(mPort); + mSocket.setReuseAddress(true); } catch(Exception e) { Logger.Logit("Failed! Connecting socket " + e.getMessage()); diff --git a/app/src/main/java/com/ds/avare/connections/XplaneConnection.java b/app/src/main/java/com/ds/avare/connections/XplaneConnection.java index 698ab9e1d..a9f783667 100644 --- a/app/src/main/java/com/ds/avare/connections/XplaneConnection.java +++ b/app/src/main/java/com/ds/avare/connections/XplaneConnection.java @@ -147,6 +147,7 @@ public boolean connect(String to, boolean secure) { try { mSocket = new DatagramSocket(mPort); + mSocket.setReuseAddress(true); } catch(Exception e) { Logger.Logit("Failed! Connecting socket " + e.getMessage()); From 01e9ac0d853f1184099c8760a5d628c9f426ffd3 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 3 Oct 2024 10:39:38 -0400 Subject: [PATCH 33/48] New LMFS website --- app/src/main/java/com/ds/avare/message/NetworkHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/ds/avare/message/NetworkHelper.java b/app/src/main/java/com/ds/avare/message/NetworkHelper.java index 33404e6f7..0c553d4b5 100644 --- a/app/src/main/java/com/ds/avare/message/NetworkHelper.java +++ b/app/src/main/java/com/ds/avare/message/NetworkHelper.java @@ -47,7 +47,7 @@ public class NetworkHelper { * This has to be provided by apps4av */ public static String getServer() { - return "https://apps4av.net/new/"; + return "https://www.apps4av.org/site/"; } /** From 9a17f2663095cbecabfb9d4070cd2c28d85ca53d Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 3 Oct 2024 10:40:31 -0400 Subject: [PATCH 34/48] 11.0.2 --- app/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 459044e26..39c80c1ed 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,8 +11,8 @@ Redistribution and use in source and binary forms, with or without modification, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> From ee9fa8e72735da2aa9377dfc5eb5ac1dce62892f Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 3 Oct 2024 10:41:40 -0400 Subject: [PATCH 35/48] 11.0.2 --- app/src/main/assets/help.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index 3046fd75d..4a25555f4 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -59,6 +59,10 @@

      Notice

      CAUTION - Before flight the user must always ensure that Avare is updated to and thoroughly tested on the latest version, and ensure that all Avare databases and charts are kept current. If Avare and its databases and charts are not of the exact same version, the GPS position displayed may be inaccurate, because the FAA sometimes changes the format of their materials. Avare does not automatically fetch any databases and charts when they are expired, so it is the user's sole responsibility to update any expired charts and databases. To do so, ensure that your device has an internet connection and then just press the Map, Menu, Preferences, Download, and Update buttons in Avare.

      Avare Releases

      +

      11.0.2

      +
        +
      • New LMFS website.
      • +

      11.0.1

      • Registration with the server is now optional.
      • From 9685528153479f23ac75bf167cb790875bb008e7 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Thu, 3 Oct 2024 10:45:33 -0400 Subject: [PATCH 36/48] Update android.yml --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 1be34e58a..e984122eb 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -43,7 +43,7 @@ jobs: BUILD_TOOLS_VERSION: "34.0.0" - name: Upload release APK - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: app-release.apk path: ${{steps.sign_app.outputs.signedReleaseFile}} From 8f36abe849aa7e4262dce8c7db0c97e9794bbb73 Mon Sep 17 00:00:00 2001 From: zkhan Date: Wed, 6 Nov 2024 21:26:27 -0500 Subject: [PATCH 37/48] fix for android 15 screen edge to edge. v 11.0.3 --- app/src/main/AndroidManifest.xml | 4 ++-- app/src/main/assets/help.html | 4 ++++ app/src/main/java/com/ds/avare/BaseActivity.java | 7 +++++++ app/src/main/java/com/ds/avare/PrefActivity.java | 7 +++++++ app/src/main/res/values-v35/values-v35.xml | 7 +++++++ 5 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/values-v35/values-v35.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 39c80c1ed..43c89c917 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,8 +11,8 @@ Redistribution and use in source and binary forms, with or without modification, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index 4a25555f4..92e99c74f 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -59,6 +59,10 @@

        Notice

        CAUTION - Before flight the user must always ensure that Avare is updated to and thoroughly tested on the latest version, and ensure that all Avare databases and charts are kept current. If Avare and its databases and charts are not of the exact same version, the GPS position displayed may be inaccurate, because the FAA sometimes changes the format of their materials. Avare does not automatically fetch any databases and charts when they are expired, so it is the user's sole responsibility to update any expired charts and databases. To do so, ensure that your device has an internet connection and then just press the Map, Menu, Preferences, Download, and Update buttons in Avare.

        Avare Releases

        +

        11.0.3

        +
          +
        • Fix for Android - 15 screen.
        • +

        11.0.2

        • New LMFS website.
        • diff --git a/app/src/main/java/com/ds/avare/BaseActivity.java b/app/src/main/java/com/ds/avare/BaseActivity.java index d024338e8..f0efce8f6 100644 --- a/app/src/main/java/com/ds/avare/BaseActivity.java +++ b/app/src/main/java/com/ds/avare/BaseActivity.java @@ -3,6 +3,7 @@ import android.app.Activity; import android.location.GpsStatus; import android.location.Location; +import android.os.Build; import android.os.Bundle; import android.view.Window; @@ -21,6 +22,12 @@ public class BaseActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { Helper.setTheme(this); + //apply theme style + + // apply this for android v35 or above, opt out of edge to edge enforcement + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + this.getTheme().applyStyle(R.style.OptOutEdgeToEdgeEnforcement, /* force */ false); + } super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/ds/avare/PrefActivity.java b/app/src/main/java/com/ds/avare/PrefActivity.java index 2d5b1bda9..cf39e8595 100644 --- a/app/src/main/java/com/ds/avare/PrefActivity.java +++ b/app/src/main/java/com/ds/avare/PrefActivity.java @@ -20,6 +20,7 @@ import android.content.ServiceConnection; import android.location.GpsStatus; import android.location.Location; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.preference.PreferenceActivity; @@ -59,6 +60,12 @@ public void enabledCallback(boolean enabled) { public void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); Helper.setTheme(this); + + // apply this for android v35 or above, opt out of edge to edge enforcement + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + this.getTheme().applyStyle(R.style.OptOutEdgeToEdgeEnforcement, /* force */ false); + } + super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); diff --git a/app/src/main/res/values-v35/values-v35.xml b/app/src/main/res/values-v35/values-v35.xml new file mode 100644 index 000000000..aa4c096cd --- /dev/null +++ b/app/src/main/res/values-v35/values-v35.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file From d14ae061c11dfd566ed15db6fecf9a200faddc95 Mon Sep 17 00:00:00 2001 From: ninelima Date: Fri, 13 Dec 2024 16:51:23 +0800 Subject: [PATCH 38/48] Add HeartbeatMessage to BufferProcessor --- .../ds/avare/adsb/gdl90/HeartbeatMessage.java | 6 ++--- .../ds/avare/connections/BufferProcessor.java | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/ds/avare/adsb/gdl90/HeartbeatMessage.java b/app/src/main/java/com/ds/avare/adsb/gdl90/HeartbeatMessage.java index 8040a63ff..f01db02fb 100644 --- a/app/src/main/java/com/ds/avare/adsb/gdl90/HeartbeatMessage.java +++ b/app/src/main/java/com/ds/avare/adsb/gdl90/HeartbeatMessage.java @@ -22,9 +22,9 @@ public class HeartbeatMessage extends Message { int mMinute; int mSecond; - Boolean mGpsPositionValid; - Boolean mBatteryLow; - Boolean mDeviceRunning; + public Boolean mGpsPositionValid; + public Boolean mBatteryLow; + public Boolean mDeviceRunning; public HeartbeatMessage() { super(MessageType.HEARTBEAT); diff --git a/app/src/main/java/com/ds/avare/connections/BufferProcessor.java b/app/src/main/java/com/ds/avare/connections/BufferProcessor.java index 691514f2f..890eb51a4 100644 --- a/app/src/main/java/com/ds/avare/connections/BufferProcessor.java +++ b/app/src/main/java/com/ds/avare/connections/BufferProcessor.java @@ -35,6 +35,7 @@ import com.ds.avare.adsb.gdl90.Constants; import com.ds.avare.adsb.gdl90.FisBuffer; import com.ds.avare.adsb.gdl90.FisGraphics; +import com.ds.avare.adsb.gdl90.HeartbeatMessage; import com.ds.avare.adsb.gdl90.Id11Product; import com.ds.avare.adsb.gdl90.Id12Product; import com.ds.avare.adsb.gdl90.Id13Product; @@ -156,7 +157,29 @@ else if(nmeaOwnship.addMessage(m)) { /* * Post on UI thread. */ - + + if(m instanceof HeartbeatMessage) { + + /* + * Make a GPS heartbeat message from ADSB heartbeat message. + */ + JSONObject object = new JSONObject(); + HeartbeatMessage tm = (HeartbeatMessage)m; + try { + object.put("type", "heartbeat"); + object.put("timestamp", (long)tm.getTime()); + object.put("gpsvalid", (boolean)tm.mGpsPositionValid); + object.put("lowbattery", (boolean)tm.mBatteryLow); + object.put("running", (boolean)tm.mDeviceRunning); + } catch (JSONException e1) { + continue; + } + + objs.add(object.toString()); + + } + + if(m instanceof TrafficReportMessage) { /* From 7dc69fe88e5b037b26c8e089aa2712326ff0c196 Mon Sep 17 00:00:00 2001 From: ninelima Date: Wed, 25 Dec 2024 21:13:17 +0800 Subject: [PATCH 39/48] Add NIC and NACP to OwnshipMessage and BufferProcessor --- app/src/main/java/com/ds/avare/adsb/gdl90/OwnshipMessage.java | 4 ++-- .../main/java/com/ds/avare/connections/BufferProcessor.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/ds/avare/adsb/gdl90/OwnshipMessage.java b/app/src/main/java/com/ds/avare/adsb/gdl90/OwnshipMessage.java index ec0ce019b..96fdda7dd 100644 --- a/app/src/main/java/com/ds/avare/adsb/gdl90/OwnshipMessage.java +++ b/app/src/main/java/com/ds/avare/adsb/gdl90/OwnshipMessage.java @@ -27,8 +27,8 @@ public class OwnshipMessage extends Message { public boolean mIsAirborne; boolean mIsExtrapolated; int mTrackType; - int mNIC; - int mNACP; + public int mNIC; + public int mNACP; boolean mIsTrackHeadingValid; boolean mIsTrackHeadingTrueTrackAngle; boolean mIsTrackHeadingHeading; diff --git a/app/src/main/java/com/ds/avare/connections/BufferProcessor.java b/app/src/main/java/com/ds/avare/connections/BufferProcessor.java index 890eb51a4..582e587dd 100644 --- a/app/src/main/java/com/ds/avare/connections/BufferProcessor.java +++ b/app/src/main/java/com/ds/avare/connections/BufferProcessor.java @@ -180,7 +180,7 @@ else if(nmeaOwnship.addMessage(m)) { } - if(m instanceof TrafficReportMessage) { + else if(m instanceof TrafficReportMessage) { /* * Make a GPS locaiton message from ADSB ownship message. @@ -546,6 +546,8 @@ else if(m instanceof OwnshipMessage) { object.put("time", (long)om.getTime()); object.put("altitude", (double) om.mAltitude); object.put("address", (int)om.mIcaoAddress); + object.put("nic", (int)om.mNIC); + object.put("nacp", (int)om.mNACP); } catch (JSONException e1) { continue; } From 0403292f800ee9b97f1cffe51b4c32b77bc6c587 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 5 Jan 2025 19:59:07 -0500 Subject: [PATCH 40/48] fix crash bug in plates --- app/src/main/java/com/ds/avare/views/PlatesView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/ds/avare/views/PlatesView.java b/app/src/main/java/com/ds/avare/views/PlatesView.java index 9b5bc75fa..f9130c651 100644 --- a/app/src/main/java/com/ds/avare/views/PlatesView.java +++ b/app/src/main/java/com/ds/avare/views/PlatesView.java @@ -244,7 +244,7 @@ public void onDraw(Canvas canvas) { */ - if (mShowingAD) { + if (mShowingAD && mMatrix.length == 12) { /* * Mike's matrix */ From 51ebffb46f6e153fbabaf4dcc3b9fde125b1c91a Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 5 Jan 2025 20:02:44 -0500 Subject: [PATCH 41/48] fix crash bug in plates --- app/src/main/AndroidManifest.xml | 4 ++-- app/src/main/assets/help.html | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 43c89c917..d03b26a19 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,8 +11,8 @@ Redistribution and use in source and binary forms, with or without modification, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index 92e99c74f..e7ce6f87f 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -59,6 +59,10 @@

          Notice

          CAUTION - Before flight the user must always ensure that Avare is updated to and thoroughly tested on the latest version, and ensure that all Avare databases and charts are kept current. If Avare and its databases and charts are not of the exact same version, the GPS position displayed may be inaccurate, because the FAA sometimes changes the format of their materials. Avare does not automatically fetch any databases and charts when they are expired, so it is the user's sole responsibility to update any expired charts and databases. To do so, ensure that your device has an internet connection and then just press the Map, Menu, Preferences, Download, and Update buttons in Avare.

          Avare Releases

          +

          11.0.4

          +
            +
          • Stop bug in plates fixed.
          • +

          11.0.3

          • Fix for Android - 15 screen.
          • From 87cad1ddbdacd91d07d2333ba70652608133f78c Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 2 Mar 2025 10:24:50 -0500 Subject: [PATCH 42/48] new way for TFR3 --- extra/mamba/tfr.pl | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/extra/mamba/tfr.pl b/extra/mamba/tfr.pl index 36922a25d..b9d680241 100755 --- a/extra/mamba/tfr.pl +++ b/extra/mamba/tfr.pl @@ -16,10 +16,12 @@ use strict; use warnings; use LWP::Simple; +use LWP::UserAgent; use HTML::LinkExtor; use XML::Parser; use File::stat; use Time::localtime; +use JSON qw( decode_json ); my $printit = 0; @@ -33,17 +35,6 @@ my $printuomlo = 0; my $tfr = ""; my @linksXml; -sub cb { - my($tag, %links) = @_; - my $lk = "@{[%links]}\n"; - if ($lk and (-1 != index($lk, "save_pages"))) { -#replace html to xml to get XML - $lk =~ s/\.html/.xml/g; - $lk =~ s/href\s*//g; -#put in an array - push(@linksXml, $lk); - } -} # The Handlers sub hdl_start{ @@ -176,17 +167,22 @@ sub hdl_char { }); # get TFR list -my $response = get('http://tfr.faa.gov/tfr2/list.html') or die; -# extract links from it -my $LX = new HTML::LinkExtor(\&cb, 'http://tfr.faa.gov/'); -$LX->parse($response); -#throw away duplicate links -my %hash = map { $_ => 1 } @linksXml; -my @unique = keys %hash; +my $ua = LWP::UserAgent->new( + ssl_opts => { verify_hostname => 0 }, +); +my $req = new HTTP::Request('GET','https://tfr.faa.gov/tfrapi/getTfrList'); +my $response = $ua->request($req) or die; +my $decoded_json = decode_json($response->content()); +for my $notam (@$decoded_json) { + my $nid = $notam->{"notam_id"}; + my $nn = $nid =~ s/\//_/r; + push(@linksXml, "https://tfr.faa.gov/download/detail_" . $nn . ".xml"); +} # Now process each TFR XML -for my $url( @{unique} ) { +for my $url( @{linksXml} ) { $url =~ s/\/\.\.\//\//g; - if(my $data_xml = get($url)) { + my $req = new HTTP::Request('GET', $url); + if(my $data_xml = $ua->request($req)->content()) { $parser->parse($data_xml); } } From a9dac2633bcb06ed00fd551d0b16ba3fe7f59e4e Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Sat, 29 Mar 2025 11:30:17 -0400 Subject: [PATCH 43/48] Update weather.yml --- .github/workflows/weather.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index a50c0cf90..6297ea58f 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -18,7 +18,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - sudo apt-get install gdal-bin python3-gdal imagemagick python3-bs4 libwww-perl libxml-parser-perl + sudo apt-get update + sudo apt-get install --fix-missing gdal-bin python3-gdal imagemagick python3-bs4 libwww-perl libxml-parser-perl pip install regex urllib3 - name: Build weather run: | From bc743bf90d3c6ffcb0ca1995fbb841fa1cf20a4f Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Mon, 1 Sep 2025 16:16:00 -0400 Subject: [PATCH 44/48] Update weather.yml --- .github/workflows/weather.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index 6297ea58f..e27864a88 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -1,5 +1,6 @@ name: Weather CI + on: schedule: - cron: '*/7 * * * *' From 500c883815ccb28039d7ff46bfb4d649aacf3244 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Mon, 1 Sep 2025 16:28:08 -0400 Subject: [PATCH 45/48] Update weather.yml --- .github/workflows/weather.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weather.yml b/.github/workflows/weather.yml index e27864a88..d8918e4b7 100644 --- a/.github/workflows/weather.yml +++ b/.github/workflows/weather.yml @@ -3,7 +3,7 @@ name: Weather CI on: schedule: - - cron: '*/7 * * * *' + - cron: '*/10 * * * *' jobs: build: From 6e7ef1e203c9c8ae4c0afff4d57951db4a0d1b7d Mon Sep 17 00:00:00 2001 From: Jon Howell Date: Sun, 5 Oct 2025 23:06:38 -0700 Subject: [PATCH 46/48] Fix tile rendering positioning bug and improve tile coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partial fix to issue #365 This commit addresses two issues with tile rendering that cause the display to have black regions (missing tiles) where it shouldn't. In Preferences.java, it increases the tile budget by a factor of 2. Specifically, it divides by 0.5, my understanding of the smallest zoom size before we flip to the next zoom level. I used a float there as documentation because maybe someday that magic number changes? ==> But let me know if I should just ditch the goofy float math and int-multiply by 2. That fix wasn't enough, because I'd still see missing tiles because the budget gets clipped by getTilesNumber to the MEM_*_{X,Y} memory limits. The biggest memory limit was based on a whopping 192MB device. My tablet has 4GB and would like more tiles, please. I added a MEM_512 tier with 13×11 tiles. ==> I don't know how the MEM_512_OH value should be calculated. Suggestions invited. In the process of diagnosing these issues, I was getting terribly confused by the draw loop in Tile.java. I refactored it a little to extract some expressions that have intuitive meaning (tileXIndex, tileYIndex, centerTileX, centerTileY) and compute based on those. I think this change is just aesthetic. I tested this manually on an Android emulator by reproducing zoom levels that cause trouble on my tablet. --- .../main/java/com/ds/avare/shapes/Tile.java | 10 ++++++++-- .../java/com/ds/avare/storage/Preferences.java | 18 ++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/ds/avare/shapes/Tile.java b/app/src/main/java/com/ds/avare/shapes/Tile.java index 6dcd3ef09..4a4ba5708 100644 --- a/app/src/main/java/com/ds/avare/shapes/Tile.java +++ b/app/src/main/java/com/ds/avare/shapes/Tile.java @@ -332,10 +332,16 @@ else if(null == tile.getBitmap()) { */ tile.getTransform().setScale(scaleFactor, scaleFactor); + + int tileXIndex = tilen % tiles.getXTilesNum(); + int tileYIndex = tilen / tiles.getXTilesNum(); + int centerTileX = (int)(tiles.getXTilesNum() / 2); + int centerTileY = (int)(tiles.getYTilesNum() / 2); + tile.getTransform().postTranslate( ctx.view.getWidth() / 2.f + ( - BitmapHolder.WIDTH / 2.f - + ((tilen % tiles.getXTilesNum()) * BitmapHolder.WIDTH - BitmapHolder.WIDTH * (int)(tiles.getXTilesNum() / 2)) + + ((tileXIndex - centerTileX) * BitmapHolder.WIDTH) + ctx.pan.getMoveX() + ctx.pan.getTileMoveX() * BitmapHolder.WIDTH - (float)ctx.movement.getOffsetLongitude()) * scaleFactor, @@ -343,7 +349,7 @@ else if(null == tile.getBitmap()) { ctx.view.getHeight() / 2.f + ( - BitmapHolder.HEIGHT / 2.f + ctx.pan.getMoveY() - + ((tilen / tiles.getXTilesNum()) * BitmapHolder.HEIGHT - BitmapHolder.HEIGHT * (int)(tiles.getYTilesNum() / 2)) + + ((tileYIndex - centerTileY) * BitmapHolder.HEIGHT) + ctx.pan.getTileMoveY() * BitmapHolder.HEIGHT - (float)ctx.movement.getOffsetLatitude() ) * scaleFactor); 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 84b828517..fa7bdcdd4 100644 --- a/app/src/main/java/com/ds/avare/storage/Preferences.java +++ b/app/src/main/java/com/ds/avare/storage/Preferences.java @@ -83,13 +83,16 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi /* * Max memory and max screen size it will support */ + public static final long MEM_512 = 512 * 1024 * 1024; public static final long MEM_256 = 256 * 1024 * 1024; public static final long MEM_192 = 192 * 1024 * 1024; public static final long MEM_128 = 128 * 1024 * 1024; public static final long MEM_64 = 64 * 1024 * 1024; public static final long MEM_32 = 32 * 1024 * 1024; - + public static final int MEM_512_X = 13; // For modern devices (512MB+ heap) + public static final int MEM_512_Y = 11; + public static final int MEM_512_OH = 13; public static final int MEM_192_X = 9; public static final int MEM_192_Y = 7; public static final int MEM_192_OH = 13; @@ -218,7 +221,11 @@ public static int[] getTilesNumber(Context ctx, boolean useScreenSize) { */ long mem = Runtime.getRuntime().maxMemory(); - if (mem >= MEM_192) { + if (mem >= MEM_512) { + ret[0] = MEM_512_X; + ret[1] = MEM_512_Y; + ret[2] = MEM_512_OH; + } else if (mem >= MEM_192) { ret[0] = MEM_192_X; ret[1] = MEM_192_Y; ret[2] = MEM_192_OH; @@ -248,8 +255,11 @@ public static int[] getTilesNumber(Context ctx, boolean useScreenSize) { defaultDisplay.getMetrics(displayMetrics); int width = displayMetrics.widthPixels; int height = displayMetrics.heightPixels; - int tilesx = (width / BitmapHolder.WIDTH) + 2; // add 1 for round up, and 1 for zoom - int tilesy = (height / BitmapHolder.HEIGHT) + 2; + // Account for minimum effective zoom (scaleFactor * macroFactor minimum is 0.5) + // At 0.5x zoom, tiles appear half size, so we need 2x as many to cover the screen + float minEffectiveZoom = 0.5f; + int tilesx = (int)Math.ceil((width / BitmapHolder.WIDTH) / minEffectiveZoom) + 2; // +2 for rounding and buffer + int tilesy = (int)Math.ceil((height / BitmapHolder.HEIGHT) / minEffectiveZoom) + 2; // odd tiles only if (tilesx % 2 == 0) { From 49a32eaebfb8bf4d0b28d1ef915120c29d8fd950 Mon Sep 17 00:00:00 2001 From: zkhan Date: Sun, 26 Oct 2025 08:27:15 -0400 Subject: [PATCH 47/48] release 11.0.5 --- app/src/main/AndroidManifest.xml | 2 +- app/src/main/assets/help.html | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d03b26a19..85895bdc1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ Redistribution and use in source and binary forms, with or without modification, --> diff --git a/app/src/main/assets/help.html b/app/src/main/assets/help.html index e7ce6f87f..ada1c75a9 100644 --- a/app/src/main/assets/help.html +++ b/app/src/main/assets/help.html @@ -59,6 +59,10 @@

            Notice

            CAUTION - Before flight the user must always ensure that Avare is updated to and thoroughly tested on the latest version, and ensure that all Avare databases and charts are kept current. If Avare and its databases and charts are not of the exact same version, the GPS position displayed may be inaccurate, because the FAA sometimes changes the format of their materials. Avare does not automatically fetch any databases and charts when they are expired, so it is the user's sole responsibility to update any expired charts and databases. To do so, ensure that your device has an internet connection and then just press the Map, Menu, Preferences, Download, and Update buttons in Avare.

            Avare Releases

            +

            11.0.5

            +
              +
            • Fixed black area at the edges.
            • +

            11.0.4

            • Stop bug in plates fixed.
            • From 5263807a9638e206bd2daf4844d24d687be96803 Mon Sep 17 00:00:00 2001 From: Zubair Khan Date: Sun, 26 Oct 2025 10:00:28 -0400 Subject: [PATCH 48/48] Increment versionCode from 404 to 405 --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 85895bdc1..f00a8f270 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ Redistribution and use in source and binary forms, with or without modification, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -->