From 7df35cd54a13a729dcd0a1fe72c8f563175c63db Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 29 Sep 2025 17:09:03 +0300 Subject: [PATCH 1/6] Fix concurrent modification exception for detectors --- CHANGELOG.md | 3 ++ .../gestures/AndroidGesturesManager.java | 3 +- .../gestures/AndroidGesturesManagerTest.java | 32 +++++++++++++++---- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d35f6f9..74862f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog for the Mapbox Gestures for Android +## Main +* Fix concurrent modification exception for detectors + ## 0.9.1 - November 27, 2023 Minor release with internal fixes for publishing library diff --git a/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java b/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java index fb99cc5..41dd955 100644 --- a/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java +++ b/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java @@ -12,6 +12,7 @@ import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; /** * Entry point for all of the detectors. Set listener for gestures you'd like to be notified about @@ -58,7 +59,7 @@ public class AndroidGesturesManager { public static final int GESTURE_TYPE_QUICK_SCALE = 15; private final List> mutuallyExclusiveGestures = new ArrayList<>(); - private final List detectors = new ArrayList<>(); + private final List detectors = new CopyOnWriteArrayList<>(); private final StandardGestureDetector standardGestureDetector; private final StandardScaleGestureDetector standardScaleGestureDetector; diff --git a/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java b/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java index 2f14926..aba9a10 100644 --- a/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java +++ b/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java @@ -1,5 +1,11 @@ package com.mapbox.android.gestures; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.view.MotionEvent; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -11,9 +17,6 @@ import java.util.List; import java.util.Set; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) public class AndroidGesturesManagerTest { private AndroidGesturesManager androidGesturesManager; @@ -44,9 +47,9 @@ public void setUp() throws Exception { mutuallyExclusivesList.add(set3); androidGesturesManager = - new AndroidGesturesManager( - RuntimeEnvironment.application.getApplicationContext(), - mutuallyExclusivesList, true); + new AndroidGesturesManager( + RuntimeEnvironment.application.getApplicationContext(), + mutuallyExclusivesList, true); } @Test @@ -69,4 +72,21 @@ public void setMutuallyExclusivesTest() throws Exception { androidGesturesManager.setMutuallyExclusiveGestures(mutuallyExclusivesList); assertEquals(androidGesturesManager.getMutuallyExclusiveGestures(), mutuallyExclusivesList); } + + @Test + public void onSingleTapModifyDetectorsTest() { + final StandardGestureDetector standardGestureDetector = new StandardGestureDetector(RuntimeEnvironment.getApplication().getApplicationContext(), androidGesturesManager); + + androidGesturesManager.setStandardGestureListener(new StandardGestureDetector.SimpleStandardOnGestureListener() { + @Override + public boolean onDown(MotionEvent e) { + androidGesturesManager.getDetectors().add(standardGestureDetector); + return true; + } + }); + + MotionEvent downEvent = TestUtils.INSTANCE.getMotionEvent(MotionEvent.ACTION_DOWN, 0, 0, null); + androidGesturesManager.onTouchEvent(downEvent); + assertTrue(androidGesturesManager.getDetectors().contains(standardGestureDetector)); + } } From 5cc2afdd4ed099d20383d09d951c8a8e24b1467a Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 29 Sep 2025 17:24:00 +0300 Subject: [PATCH 2/6] Construct detectors with pre-defined detectors --- .../gestures/AndroidGesturesManager.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java b/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java index 41dd955..f9e9aca 100644 --- a/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java +++ b/library/src/main/java/com/mapbox/android/gestures/AndroidGesturesManager.java @@ -59,7 +59,7 @@ public class AndroidGesturesManager { public static final int GESTURE_TYPE_QUICK_SCALE = 15; private final List> mutuallyExclusiveGestures = new ArrayList<>(); - private final List detectors = new CopyOnWriteArrayList<>(); + private final List detectors; private final StandardGestureDetector standardGestureDetector; private final StandardScaleGestureDetector standardScaleGestureDetector; @@ -129,13 +129,15 @@ public AndroidGesturesManager(Context context, List> exclusiveGestu moveGestureDetector = new MoveGestureDetector(context, this); standardGestureDetector = new StandardGestureDetector(context, this); - detectors.add(rotateGestureDetector); - detectors.add(standardScaleGestureDetector); - detectors.add(shoveGestureDetector); - detectors.add(sidewaysShoveGestureDetector); - detectors.add(multiFingerTapGestureDetector); - detectors.add(moveGestureDetector); - detectors.add(standardGestureDetector); + detectors = new CopyOnWriteArrayList(Arrays.asList( + rotateGestureDetector, + standardScaleGestureDetector, + shoveGestureDetector, + sidewaysShoveGestureDetector, + multiFingerTapGestureDetector, + moveGestureDetector, + standardGestureDetector + )); if (applyDefaultThresholds) { initDefaultThresholds(); From f8d21a9e0bb937378c7f6089ad37c2c6808b6ecf Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 29 Sep 2025 17:24:41 +0300 Subject: [PATCH 3/6] Add version to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74862f0..a7461e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog for the Mapbox Gestures for Android -## Main +## 0.9.2 - September 29, 2025 * Fix concurrent modification exception for detectors ## 0.9.1 - November 27, 2023 From 2fb93413c73b3fc3318cb28db11c73798ff426e6 Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 29 Sep 2025 17:33:17 +0300 Subject: [PATCH 4/6] Fix codestyle --- .../mapbox/android/gestures/AndroidGesturesManagerTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java b/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java index aba9a10..3d87a2d 100644 --- a/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java +++ b/library/src/test/java/com/mapbox/android/gestures/AndroidGesturesManagerTest.java @@ -75,7 +75,10 @@ public void setMutuallyExclusivesTest() throws Exception { @Test public void onSingleTapModifyDetectorsTest() { - final StandardGestureDetector standardGestureDetector = new StandardGestureDetector(RuntimeEnvironment.getApplication().getApplicationContext(), androidGesturesManager); + final StandardGestureDetector standardGestureDetector = new StandardGestureDetector( + RuntimeEnvironment.getApplication().getApplicationContext(), + androidGesturesManager + ); androidGesturesManager.setStandardGestureListener(new StandardGestureDetector.SimpleStandardOnGestureListener() { @Override From b88b572bc37a970163def2aa64c229834f5a885b Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 1 Oct 2025 08:53:01 +0300 Subject: [PATCH 5/6] Convert CircleCI build job to GHA --- .github/workflows/main.yml | 76 ++++++++++++++++++++++++++++++++++++++ build.gradle | 14 ------- circle.yml | 33 ----------------- 3 files changed, 76 insertions(+), 47 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..1b22701 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,76 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ '**' ] + +jobs: + build: + runs-on: ubuntu-latest + container: + image: mbgl/android-sdk:latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check code style + run: make checkstyle + + - name: Run Lint + run: ./gradlew lint + + - name: Run unit-test in Android libraries + run: make test + + - name: Upload reports + uses: actions/upload-artifact@v4 + with: + name: reports + path: app/build/reports + + - name: Upload test results + uses: actions/upload-artifact@v4 + with: + name: test-results + path: app/build/test-results + +# release: +# runs-on: ubuntu-latest +# container: +# image: mbgl/android-ndk-r21e:latest +# if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')) +# steps: +# - uses: actions/checkout@v3 +# +# - name: Init aws with mbx-ci +# run: | +# curl -Ls https://mapbox-release-engineering.s3.amazonaws.com/mbx-ci/latest/mbx-ci-linux-amd64 > mbx-ci && chmod 755 ./mbx-ci +# ./mbx-ci aws setup +# +# - name: Update version name +# run: | +# if [[ $GITHUB_REF == refs/tags/v* ]]; then +# VERSION_NAME=${GITHUB_REF#refs/tags/v} +# sed -i -e "s/^VERSION_NAME=.*/VERSION_NAME=${VERSION_NAME}/" library/gradle.properties +# elif [[ $GITHUB_REF == refs/heads/master ]]; then +# COMMIT_SHA=$(git rev-parse --short HEAD) +# sed -i -e "s/-SNAPSHOT.*/-${COMMIT_SHA}-SNAPSHOT/" library/gradle.properties +# fi +# +# - name: Build libraries +# run: make release +# +# - name: Publish to the SDK registry +# env: +# GITHUB_TOKEN: ${{ secrets.SDK_REGISTRY_TOKEN }} +# run: | +# git config --global user.email "MapboxCI@users.noreply.github.com" +# git config --global user.name "MapboxCI" +# if [[ $GITHUB_REF == refs/heads/master ]] || [[ $GITHUB_REF == refs/tags/v* ]]; then +# make sdkRegistryUpload +# fi +# if [[ $GITHUB_REF == refs/tags/v* ]]; then +# make sdkRegistryPublish +# fi \ No newline at end of file diff --git a/build.gradle b/build.gradle index 568b306..0c5a5af 100644 --- a/build.gradle +++ b/build.gradle @@ -5,13 +5,6 @@ buildscript { mavenCentral() maven { url 'https://api.mapbox.com/downloads/v2/releases/maven' - authentication { - basic(BasicAuthentication) - } - credentials { - username = "mapbox" - password = System.getenv("SDK_REGISTRY_TOKEN") ?: project.property("SDK_REGISTRY_TOKEN") as String - } } } dependencies { @@ -28,13 +21,6 @@ allprojects { mavenCentral() maven { url 'https://api.mapbox.com/downloads/v2/releases/maven' - authentication { - basic(BasicAuthentication) - } - credentials { - username = "mapbox" - password = password = System.getenv("SDK_REGISTRY_TOKEN") ?: project.property("SDK_REGISTRY_TOKEN") as String - } } } } diff --git a/circle.yml b/circle.yml index faea1b7..5131fdf 100644 --- a/circle.yml +++ b/circle.yml @@ -13,39 +13,6 @@ workflows: only: /^v.*/ jobs: - build: - working_directory: ~/code - docker: - - image: mbgl/android-ndk-r21e:latest - environment: - JVM_OPTS: -Xmx3200m - steps: - - checkout - - restore_cache: - key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "library/build.gradle" }}-{{ checksum "gradle/dependencies.gradle" }} - - run: - name: Download Dependencies - command: ./gradlew androidDependencies - - save_cache: - paths: - - ~/.gradle - key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "library/build.gradle" }}-{{ checksum "gradle/dependencies.gradle" }} - - run: - name: Check code style - command: make checkstyle - - run: - name: Run Lint - command: ./gradlew lint - - run: - name: Run unit-test in Android libraries - command: make test - - store_artifacts: - path: app/build/reports - destination: reports - - store_test_results: - path: app/build/test-results - -# ------------------------------------------------------------------------------ release: docker: - image: mbgl/android-ndk-r21e:latest From 339ab068368d872bc8f2218664a7763abb40acf4 Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 1 Oct 2025 11:06:03 +0300 Subject: [PATCH 6/6] Remove release from GHA main.yml and fix circle.yml --- .github/workflows/main.yml | 41 +------------------------------------- circle.yml | 1 - 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1b22701..bc53be3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,43 +34,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: test-results - path: app/build/test-results - -# release: -# runs-on: ubuntu-latest -# container: -# image: mbgl/android-ndk-r21e:latest -# if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')) -# steps: -# - uses: actions/checkout@v3 -# -# - name: Init aws with mbx-ci -# run: | -# curl -Ls https://mapbox-release-engineering.s3.amazonaws.com/mbx-ci/latest/mbx-ci-linux-amd64 > mbx-ci && chmod 755 ./mbx-ci -# ./mbx-ci aws setup -# -# - name: Update version name -# run: | -# if [[ $GITHUB_REF == refs/tags/v* ]]; then -# VERSION_NAME=${GITHUB_REF#refs/tags/v} -# sed -i -e "s/^VERSION_NAME=.*/VERSION_NAME=${VERSION_NAME}/" library/gradle.properties -# elif [[ $GITHUB_REF == refs/heads/master ]]; then -# COMMIT_SHA=$(git rev-parse --short HEAD) -# sed -i -e "s/-SNAPSHOT.*/-${COMMIT_SHA}-SNAPSHOT/" library/gradle.properties -# fi -# -# - name: Build libraries -# run: make release -# -# - name: Publish to the SDK registry -# env: -# GITHUB_TOKEN: ${{ secrets.SDK_REGISTRY_TOKEN }} -# run: | -# git config --global user.email "MapboxCI@users.noreply.github.com" -# git config --global user.name "MapboxCI" -# if [[ $GITHUB_REF == refs/heads/master ]] || [[ $GITHUB_REF == refs/tags/v* ]]; then -# make sdkRegistryUpload -# fi -# if [[ $GITHUB_REF == refs/tags/v* ]]; then -# make sdkRegistryPublish -# fi \ No newline at end of file + path: app/build/test-results \ No newline at end of file diff --git a/circle.yml b/circle.yml index 5131fdf..3b47d03 100644 --- a/circle.yml +++ b/circle.yml @@ -4,7 +4,6 @@ workflows: version: 2 default: jobs: - - build - release: filters: branches: