├── .github └── CODEOWNERS ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── Makefile ├── README.md ├── THANKS.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mapbox │ │ └── android │ │ └── gestures │ │ ├── GesturesUiTestUtils.kt │ │ ├── MoveGestureDetectorTest.kt │ │ ├── MultiFingerTapGestureDetectorTest.kt │ │ └── ScaleGestureDetectorTest.kt │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── mapbox │ │ └── android │ │ └── gestures │ │ └── testapp │ │ ├── HelpDialogFragment.java │ │ ├── MainActivity.java │ │ ├── MapboxActivity.java │ │ ├── MyApplication.java │ │ ├── TestActivity.java │ │ ├── TestView.java │ │ └── Utils.java │ └── res │ ├── drawable-hdpi │ ├── ic_help_outline.png │ └── logo.png │ ├── drawable-mdpi │ ├── ic_help_outline.png │ └── logo.png │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ ├── ic_help_outline.png │ └── logo.png │ ├── drawable-xxhdpi │ ├── ic_help_outline.png │ └── logo.png │ ├── drawable-xxxhdpi │ ├── ic_help_outline.png │ └── logo.png │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_mapbox.xml │ ├── activity_test.xml │ └── fragment_help_dialog.xml │ ├── menu │ └── menu.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── circle.yml ├── config └── checkstyle │ └── checkstyle.xml ├── gradle.properties ├── gradle ├── artifact-settings.gradle ├── checkstyle.gradle ├── dependencies.gradle ├── javadoc.gradle ├── sdk-registry.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── mapbox │ │ │ └── android │ │ │ └── gestures │ │ │ ├── AndroidGesturesManager.java │ │ │ ├── BaseGesture.java │ │ │ ├── Constants.java │ │ │ ├── MoveDistancesObject.java │ │ │ ├── MoveGestureDetector.java │ │ │ ├── MultiFingerDistancesObject.java │ │ │ ├── MultiFingerGesture.java │ │ │ ├── MultiFingerTapGestureDetector.java │ │ │ ├── PermittedActionsGuard.java │ │ │ ├── PointerDistancePair.java │ │ │ ├── ProgressiveGesture.java │ │ │ ├── RotateGestureDetector.java │ │ │ ├── ShoveGestureDetector.java │ │ │ ├── SidewaysShoveGestureDetector.java │ │ │ ├── StandardGestureDetector.java │ │ │ ├── StandardScaleGestureDetector.java │ │ │ └── Utils.java │ └── res │ │ └── values │ │ └── dimens.xml │ └── test │ └── java │ └── com │ └── mapbox │ └── android │ └── gestures │ ├── AbstractGestureDetectorTest.java │ ├── AndroidGesturesManagerTest.java │ ├── MoveGestureDetectorTest.java │ ├── MultiFingerTapGestureDetectorTest.java │ ├── PointersManagementTest.java │ ├── RotateGestureDetectorTest.java │ ├── ShoveGestureDetectorTest.java │ ├── SidewaysShoveGestureDetectorTest.java │ ├── StandardGestureDetectorTest.java │ └── TestUtils.kt └── settings.gradle /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @mapbox/maps-android 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle/ 3 | local.properties 4 | .idea/ 5 | *.iml 6 | .DS_Store 7 | build/ 8 | captures/ 9 | .externalNativeBuild 10 | app/src/main/res/values/developer-config.xml -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog for the Mapbox Gestures for Android 2 | 3 | ## 0.9.1 - November 27, 2023 4 | Minor release with internal fixes for publishing library 5 | 6 | ## 0.9.0 - November 24, 2023 7 | #### Breaking changes 8 | - Increase minimum supported Android SDK version to 19 (KITKAT) 9 | #### Minor features 10 | - Support compile SDK 30 11 | 12 | ## 0.8.0 - August 19, 2022 13 | #### Minor features 14 | - Updated dependencies : Maps 10.7.0, targetSdk 31, compileSdk 30. [#101](https://github.com/mapbox/mapbox-gestures-android/pull/101) 15 | #### Breaking changes 16 | - Remove NonNull annotations from SimpleStandardOnGestureListener that have no such annotations in Android sources. [#101](https://github.com/mapbox/mapbox-gestures-android/pull/101) 17 | 18 | ## 0.7.0 - April 30, 2020 19 | #### Minor features 20 | - Expose a `MoveGestureDetector#moveThresholdRect`. When set, the defined screen area prohibits move gesture to be started. [#96](https://github.com/mapbox/mapbox-gestures-android/pull/96) 21 | 22 | ## 0.6.0 - January 8, 2020 23 | #### Major changes 24 | - Replace appcompat dependencies with AndroidX [#94](https://github.com/mapbox/mapbox-gestures-android/pull/94) 25 | 26 | #### Minor features and bug fixes 27 | - Use NonNull in gesture listener interfaces to improve consumption with the Kotlin programming language [#95](https://github.com/mapbox/mapbox-gestures-android/pull/95) 28 | 29 | ## 0.5.1 - August 20, 2019 30 | #### Bug fixes 31 | - Fixed a bug where quick-scale was registered during a move gesture that followed a double-tap [#88](https://github.com/mapbox/mapbox-gestures-android/pull/88) 32 | 33 | ## 0.5.0 - August 14, 2019 34 | #### Major changes 35 | - Introduce a custom scale gesture detector implementation. The library doesn't rely on the compat gesture detector anymore. This is a breaking changing because the underlying scale gesture detector reference has been removed. [#73](https://github.com/mapbox/mapbox-gestures-android/pull/73) 36 | 37 | #### Minor features and bug fixes 38 | - Calculate focal point for every motion event, not only MOVE. Fixes an issue where detectors that do not rely on movement would return cached, historic focal points. [#77](https://github.com/mapbox/mapbox-gestures-android/pull/77) 39 | - Adjust scale gesture's required pointer count based on type. Fixes an issue where quick-scale was not properly interrupted. [#74](https://github.com/mapbox/mapbox-gestures-android/pull/74) 40 | - Guard against move events coming from different view trees. Might prevent rare crashes that are out of control of the gestures library. [#71](https://github.com/mapbox/mapbox-gestures-android/pull/71) 41 | - Expose scale span getters. [#75](https://github.com/mapbox/mapbox-gestures-android/pull/75) 42 | 43 | ## 0.4.2 - April 26, 2019 44 | - Query display metrics only in touch down [#67](https://github.com/mapbox/mapbox-gestures-android/pull/67) 45 | 46 | ## 0.4.1 - April 16, 2019 47 | - Try getting real device display metrics for sloppy gesture calculations [#61](https://github.com/mapbox/mapbox-gestures-android/pull/61) 48 | - Remove obsolete string values [#62](https://github.com/mapbox/mapbox-gestures-android/pull/62) 49 | 50 | ## 0.4.0 - January 31, 2019 51 | - Removed Timber dependency [#54](https://github.com/mapbox/mapbox-gestures-android/pull/54) 52 | - Prepare the project to be consumed as a submodule [#55](https://github.com/mapbox/mapbox-gestures-android/pull/55) 53 | - Update tooling and CI image [#56](https://github.com/mapbox/mapbox-gestures-android/pull/56) 54 | - Remove deprecated javadoc source declaration [#58](https://github.com/mapbox/mapbox-gestures-android/pull/58) 55 | - Exclude maven plugin and checkstyle from the child build.gradle [#57](https://github.com/mapbox/mapbox-gestures-android/pull/57) 56 | 57 | ## 0.3.0 - October 30, 2018 58 | - Increase missing events protection [#46](https://github.com/mapbox/mapbox-gestures-android/pull/46) 59 | - Limit support library usage [#47](https://github.com/mapbox/mapbox-gestures-android/pull/47) 60 | 61 | ## 0.2.0 - March 27, 2018 62 | - SidewaysShoveGestureDetector [#27](https://github.com/mapbox/mapbox-gestures-android/pull/27) 63 | - Decrease minimum span required to register scale gesture [#30](https://github.com/mapbox/mapbox-gestures-android/pull/30) 64 | 65 | ## 0.1.0 - March 19, 2018 66 | - Initial release! -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We welcome contributions to this gestures repository. If you're interested in helping develop the library, please follow these steps: 4 | 5 | - [Open a ticket](https://github.com/mapbox/mapbox-gestures-android/issues/new) to kick off a conversation, feel free to tag the `@mapbox/android` team. It's a good idea to explain your plans before you push any code to make sure no one else is working on something similar and to discuss the best approaches to tackle your particular idea. 6 | 7 | - Create a new branch that will contain the code for your additions. 8 | 9 | - Pull requests are gladly accepted. If there are any changes that developers should be aware of, please update the [change log](CHANGELOG.md) 10 | 11 | - Mapbox uses checkstyle to enforce good Java code standards. Make sure to read the [Mapbox GL Native Wiki entry](https://github.com/mapbox/mapbox-gl-native/wiki/Setting-up-Mapbox-checkstyle) and setup. CI will fail if your PR contains any mistakes. 12 | 13 | # Code of conduct 14 | Everyone is invited to participate in Mapbox’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Mapbox organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/). 15 | 16 | You can learn more about our open source philosophy on [mapbox.com](https://www.mapbox.com/about/open/). -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2018, Mapbox 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | =========================================================================== 27 | 28 | Mapbox Gestures for Android uses portions of Android Gesture Detectors Framework. 29 | 30 | Copyright (c) 2012, Almer Thie 31 | 32 | All rights reserved. 33 | 34 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 35 | 36 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 37 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 38 | 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. 39 | 40 | =========================================================================== 41 | 42 | Mapbox Gestures for Android uses portions of Android Support Library. 43 | 44 | Copyright (c) 2005-2013, The Android Open Source Project 45 | 46 | Licensed under the Apache License, Version 2.0 (the "License"); 47 | you may not use this file except in compliance with the License. 48 | You may obtain a copy of the License at 49 | 50 | http://www.apache.org/licenses/LICENSE-2.0 51 | 52 | Unless required by applicable law or agreed to in writing, software 53 | distributed under the License is distributed on an "AS IS" BASIS, 54 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 55 | See the License for the specific language governing permissions and 56 | limitations under the License. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | checkstyle: 2 | ./gradlew checkstyle 3 | 4 | javadoc: 5 | # Output is (module)/build/docs/javadoc/release 6 | ./gradlew library:javadocrelease 7 | 8 | test: 9 | ./gradlew :library:test -i 10 | 11 | release: 12 | ./gradlew :library:assembleRelease 13 | 14 | sdkRegistryUpload: 15 | ./gradlew :library:mapboxSDKRegistryUpload 16 | 17 | sdkRegistryPublish: 18 | ./gradlew :library:mapboxSDKRegistryPublish 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mapbox Gestures for Android 2 | 3 | The Mapbox Gestures for Android library wraps [GestureDetectorCompat](https://developer.android.com/reference/android/support/v4/view/GestureDetectorCompat.html) and introduces implementation of scale, rotate, move, shove and tap gesture detectors. 4 | 5 | Mapbox Gestures for Android was inspired by [Android Gesture Detector Framework](https://github.com/Almeros/android-gesture-detectors) and offers the same functionality with some additional features on top. 6 | 7 | The library is implemented in the projects found below, where you can head for more examples: 8 | 9 | - [The Mapbox Maps SDK for Android](https://github.com/mapbox/mapbox-maps-android) 10 | - [This library's sample app](https://github.com/mapbox/mapbox-gestures-android/tree/master/app/src/main/java/com/mapbox/android/gestures/testapp) included in this repository 11 | 12 | Are you using the library in your project as well? Let us know or create a PR, we'll be more than happy to add it to the list! 13 | 14 | 15 | ## Documentation 16 | 17 | You'll find all of this library's documentation on [our Maps Guides user interaction page](https://docs.mapbox.com/android/maps/guides/user-interaction/). This includes information on installation, using the API, and links to the API reference. 18 | 19 | 20 | ## Getting Started 21 | 22 | If you are looking to include Mapbox Gestures for Android inside of your project, please take a look at [the detailed instructions](https://docs.mapbox.com/android/maps/guides/user-interaction/) found in our docs. If you are interested in building from source, read the contributing guide inside of this project. 23 | 24 | To use the Gestures library, you need to set the SDK registry (own Mapbox Maven repo) first. 25 | Please follow the instructions provided at the general [Maps install page](https://docs.mapbox.com/android/maps/guides/install/#add-the-dependency). 26 | 27 | Then add the Mapbox Android Gestures library : 28 | 29 | ```java 30 | // In the app build.gradle file 31 | dependencies { 32 | implementation 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.8.0' 33 | } 34 | ``` 35 | 36 | #### Mapbox access tokens 37 | 38 | To build test application you need to configure Mapbox access tokens as described at https://docs.mapbox.com/android/maps/guides/install/#configure-credentials. 39 | To build the project you need to specify SDK_REGISTRY_TOKEN as an environmental variable or a gradle property. It is a secret token used to access the SDK Registry (Mapbox Maven instance) during compile time, with a scope set to `DOWNLOADS:READ`. 40 | To run the specific Mapbox activity in this repo's test application, you need to include public token in the [app/src/main/res/values/developer-config.xml] resource file. 41 | 42 | ## Getting Help 43 | 44 | - **Need help with your code?**: Look for previous questions on the [#mapbox tag](https://stackoverflow.com/questions/tagged/mapbox+android) — or [ask a new question](https://stackoverflow.com/questions/tagged/mapbox+android). 45 | - **Have a bug to report?** [Open an issue](https://github.com/mapbox/mapbox-gestures-android/issues). If possible, include the version of Mapbox Core that you're using, a full log, and a project that shows the issue. 46 | - **Have a feature request?** [Open an issue](https://github.com/mapbox/mapbox-gestures-android/issues/new). Tell us what the feature should do and why you want the feature. 47 | 48 | ## Sample code 49 | 50 | [This repo's test app](https://github.com/mapbox/mapbox-gestures-android/tree/master/app/src/main/java/com/mapbox/android/gestures/testapp) can also help you get started with the Gestures library. 51 | 52 | ## Contributing 53 | 54 | We welcome feedback, translations, and code contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details. 55 | 56 | ## Version 57 | 58 | Noting here, that `0.x` versions series of `Mapbox Gestures for Android` is still in an experimental phase. Breaking changes can occur with every iteration. 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /THANKS.md: -------------------------------------------------------------------------------- 1 | Authors of this library would like to send huge thanks to creators of [Android Gesture Detectors Framework](https://github.com/Almeros/android-gesture-detectors) for inspiration and a great library that served us for so many years. -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion androidVersions.compileSdkVersion 7 | 8 | defaultConfig { 9 | applicationId "com.mapbox.android.gestures.testapp" 10 | minSdkVersion androidVersions.minSdkVersion 11 | targetSdkVersion androidVersions.targetSdkVersion 12 | versionCode 1 13 | versionName "0.1.0" 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | } 16 | 17 | compileOptions { 18 | sourceCompatibility JavaVersion.VERSION_1_8 19 | targetCompatibility JavaVersion.VERSION_1_8 20 | } 21 | 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | 29 | testOptions { 30 | unitTests { 31 | returnDefaultValues true 32 | // Roboelectric 4.0 required config 33 | // http://robolectric.org/migrating/#migrating-to-40 34 | 35 | includeAndroidResources = true 36 | } 37 | } 38 | } 39 | 40 | dependencies { 41 | implementation dependenciesList.kotlinLib 42 | implementation dependenciesList.supportAppcompatV7 43 | implementation dependenciesList.timber 44 | implementation(dependenciesList.mapboxMaps) { 45 | exclude group: 'com.mapbox.mapboxsdk', module: 'mapbox-android-gestures' 46 | } 47 | implementation("androidx.core:core-ktx") { 48 | version { 49 | strictly("1.6.0") 50 | } 51 | } 52 | implementation("androidx.core:core") { 53 | version { 54 | strictly("1.6.0") 55 | } 56 | } 57 | 58 | 59 | testImplementation dependenciesList.junit 60 | testImplementation dependenciesList.mockito 61 | testImplementation dependenciesList.robolectric 62 | androidTestImplementation dependenciesList.mockitoAndroid 63 | androidTestImplementation dependenciesList.testRunner 64 | androidTestImplementation dependenciesList.testEspressoCore 65 | androidTestImplementation dependenciesList.testEspressoIntents 66 | 67 | implementation project(":library") 68 | } 69 | 70 | apply from: "${rootDir}/gradle/checkstyle.gradle" 71 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/mapbox/android/gestures/MoveGestureDetectorTest.kt: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures 2 | 3 | import GesturesUiTestUtils.DEFAULT_GESTURE_DURATION 4 | import GesturesUiTestUtils.move 5 | import android.graphics.PointF 6 | import android.graphics.RectF 7 | import androidx.test.espresso.Espresso 8 | import androidx.test.espresso.matcher.ViewMatchers 9 | import androidx.test.ext.junit.runners.AndroidJUnit4 10 | import androidx.test.rule.ActivityTestRule 11 | import com.mapbox.android.gestures.testapp.R 12 | import com.mapbox.android.gestures.testapp.TestActivity 13 | import org.junit.Assert 14 | import org.junit.Before 15 | import org.junit.Rule 16 | import org.junit.Test 17 | import org.junit.runner.RunWith 18 | import java.util.concurrent.CountDownLatch 19 | import java.util.concurrent.TimeUnit 20 | 21 | @RunWith(AndroidJUnit4::class) 22 | class MoveGestureDetectorTest { 23 | 24 | @Rule 25 | @JvmField 26 | val activityTestRule = ActivityTestRule(TestActivity::class.java) 27 | 28 | private lateinit var gesturesManager: AndroidGesturesManager 29 | 30 | @Before 31 | fun setup() { 32 | gesturesManager = activityTestRule.activity.gesturesManager 33 | } 34 | 35 | @Test 36 | fun move_ignoredWithRectThreshold() { 37 | val rect = RectF(400f, 400f, 600f, 600f) 38 | gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener { 39 | override fun onMoveBegin(detector: MoveGestureDetector) = true 40 | 41 | override fun onMove( 42 | detector: MoveGestureDetector, 43 | distanceX: Float, 44 | distanceY: Float 45 | ): Boolean = throw AssertionError("onMove shouldn't be called if threshold was not met") 46 | 47 | override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit 48 | 49 | }) 50 | gesturesManager.moveGestureDetector.moveThresholdRect = rect 51 | Espresso.onView(ViewMatchers.withId(R.id.content)).perform( 52 | move( 53 | deltaX = 50f, 54 | deltaY = 50f, 55 | startPoint = PointF(rect.right - 100f, rect.bottom - 100f) 56 | ) 57 | ) 58 | } 59 | 60 | @Test 61 | fun move_executedWhenOutsideOfRect() { 62 | val latch = CountDownLatch(1) 63 | val rect = RectF(400f, 400f, 600f, 600f) 64 | gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener { 65 | override fun onMoveBegin(detector: MoveGestureDetector) = true 66 | 67 | override fun onMove( 68 | detector: MoveGestureDetector, 69 | distanceX: Float, 70 | distanceY: Float 71 | ): Boolean { 72 | Assert.assertFalse(rect.contains(detector.focalPoint.x, detector.focalPoint.y)) 73 | latch.countDown() 74 | return true 75 | } 76 | 77 | override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit 78 | 79 | }) 80 | gesturesManager.moveGestureDetector.moveThresholdRect = rect 81 | Espresso.onView(ViewMatchers.withId(R.id.content)).perform( 82 | move( 83 | deltaX = 100f, 84 | deltaY = 100f, 85 | startPoint = PointF(rect.right + 50f, rect.bottom + 50f) 86 | ) 87 | ) 88 | if (!latch.await(DEFAULT_GESTURE_DURATION, TimeUnit.MILLISECONDS)) { 89 | Assert.fail("move was not called") 90 | } 91 | } 92 | 93 | @Test 94 | fun move_executedWhenRectThresholdMet() { 95 | val latch = CountDownLatch(1) 96 | val rect = RectF(400f, 400f, 600f, 600f) 97 | gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener { 98 | override fun onMoveBegin(detector: MoveGestureDetector) = true 99 | 100 | override fun onMove( 101 | detector: MoveGestureDetector, 102 | distanceX: Float, 103 | distanceY: Float 104 | ): Boolean { 105 | Assert.assertFalse(rect.contains(detector.focalPoint.x, detector.focalPoint.y)) 106 | latch.countDown() 107 | return true 108 | } 109 | 110 | override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit 111 | 112 | }) 113 | gesturesManager.moveGestureDetector.moveThresholdRect = rect 114 | Espresso.onView(ViewMatchers.withId(R.id.content)).perform( 115 | move( 116 | deltaX = -150f, 117 | deltaY = -150f, 118 | startPoint = PointF(500f, 500f) 119 | ) 120 | ) 121 | if (!latch.await(DEFAULT_GESTURE_DURATION, TimeUnit.MILLISECONDS)) { 122 | Assert.fail("move was not called") 123 | } 124 | } 125 | 126 | @Test 127 | fun move_whenOutsideOfRect_executeWhenMoveThresholdMet() { 128 | val latch = CountDownLatch(1) 129 | val rect = RectF(400f, 400f, 600f, 600f) 130 | gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener { 131 | override fun onMoveBegin(detector: MoveGestureDetector) = true 132 | 133 | override fun onMove( 134 | detector: MoveGestureDetector, 135 | distanceX: Float, 136 | distanceY: Float 137 | ): Boolean { 138 | Assert.assertFalse(rect.contains(detector.focalPoint.x, detector.focalPoint.y)) 139 | latch.countDown() 140 | return true 141 | } 142 | 143 | override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit 144 | 145 | }) 146 | gesturesManager.moveGestureDetector.moveThresholdRect = rect 147 | gesturesManager.moveGestureDetector.moveThreshold = 50f 148 | Espresso.onView(ViewMatchers.withId(R.id.content)).perform( 149 | move( 150 | deltaX = 100f, 151 | deltaY = 100f, 152 | startPoint = PointF(rect.right + 50f, rect.bottom + 50f) 153 | ) 154 | ) 155 | if (!latch.await(DEFAULT_GESTURE_DURATION, TimeUnit.MILLISECONDS)) { 156 | Assert.fail("move was not called") 157 | } 158 | } 159 | 160 | @Test 161 | fun move_whenOutsideOfRect_ignoredWhenMoveThreshold() { 162 | val rect = RectF(400f, 400f, 600f, 600f) 163 | gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener { 164 | override fun onMoveBegin(detector: MoveGestureDetector) = true 165 | 166 | override fun onMove( 167 | detector: MoveGestureDetector, 168 | distanceX: Float, 169 | distanceY: Float 170 | ): Boolean = throw AssertionError("onMove shouldn't be called if threshold was not met") 171 | 172 | override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit 173 | 174 | }) 175 | gesturesManager.moveGestureDetector.moveThresholdRect = rect 176 | gesturesManager.moveGestureDetector.moveThreshold = 50f 177 | Espresso.onView(ViewMatchers.withId(R.id.content)).perform( 178 | move( 179 | deltaX = 25f, 180 | deltaY = 25f, 181 | startPoint = PointF(rect.right + 50f, rect.bottom + 50f) 182 | ) 183 | ) 184 | } 185 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/mapbox/android/gestures/MultiFingerTapGestureDetectorTest.kt: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures 2 | 3 | import GesturesUiTestUtils.DEFAULT_GESTURE_DURATION 4 | import GesturesUiTestUtils.twoTap 5 | import androidx.test.espresso.Espresso 6 | import androidx.test.espresso.matcher.ViewMatchers 7 | import androidx.test.rule.ActivityTestRule 8 | import androidx.test.ext.junit.runners.AndroidJUnit4 9 | import com.mapbox.android.gestures.testapp.R 10 | import com.mapbox.android.gestures.testapp.TestActivity 11 | import org.junit.Assert 12 | import org.junit.Before 13 | import org.junit.Rule 14 | import org.junit.Test 15 | import org.junit.runner.RunWith 16 | import java.util.concurrent.CountDownLatch 17 | import java.util.concurrent.TimeUnit 18 | 19 | @RunWith(AndroidJUnit4::class) 20 | class MultiFingerTapGestureDetectorTest { 21 | 22 | @Rule 23 | @JvmField 24 | val activityTestRule = ActivityTestRule(TestActivity::class.java) 25 | 26 | private lateinit var gesturesManager: AndroidGesturesManager 27 | 28 | @Before 29 | fun setup() { 30 | gesturesManager = activityTestRule.activity.gesturesManager 31 | } 32 | 33 | @Test 34 | fun noMove_focalPoint_invalidated() { 35 | val latch = CountDownLatch(1) 36 | gesturesManager.setMultiFingerTapGestureListener { detector, pointersCount -> 37 | Assert.assertEquals(2, pointersCount) 38 | Assert.assertEquals(Utils.determineFocalPoint(detector.currentEvent), detector.focalPoint) 39 | latch.countDown() 40 | true 41 | } 42 | Espresso.onView(ViewMatchers.withId(R.id.content)).perform(twoTap(300f)) 43 | 44 | if (!latch.await(DEFAULT_GESTURE_DURATION, TimeUnit.MILLISECONDS)) { 45 | Assert.fail("two-tap was not called") 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 29 | 30 | 38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/mapbox/android/gestures/testapp/HelpDialogFragment.java: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures.testapp; 2 | 3 | import android.app.DialogFragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.Button; 9 | 10 | public class HelpDialogFragment extends DialogFragment { 11 | static final String TAG = "help_dialog_fragment_tag"; 12 | 13 | public HelpDialogFragment() { 14 | // Required empty public constructor 15 | } 16 | 17 | public static HelpDialogFragment newInstance() { 18 | return new HelpDialogFragment(); 19 | } 20 | 21 | @Override 22 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 23 | Bundle savedInstanceState) { 24 | View view = inflater.inflate(R.layout.fragment_help_dialog, container, false); 25 | Button gotItButton = (Button) view.findViewById(R.id.button_help_got_it); 26 | gotItButton.setOnClickListener(new View.OnClickListener() { 27 | @Override 28 | public void onClick(View v) { 29 | dismiss(); 30 | } 31 | }); 32 | return view; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/mapbox/android/gestures/testapp/MapboxActivity.java: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures.testapp; 2 | 3 | import android.os.Bundle; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import android.text.TextUtils; 6 | 7 | import com.mapbox.maps.MapView; 8 | import com.mapbox.maps.Style; 9 | 10 | import timber.log.Timber; 11 | 12 | /** 13 | * Test activity showcasing a simple MapView with current mapbox-gestures-android library commit. 14 | */ 15 | public class MapboxActivity extends AppCompatActivity { 16 | 17 | private static final String DEFAULT_MAPBOX_ACCESS_TOKEN = "YOUR_MAPBOX_ACCESS_TOKEN_GOES_HERE"; 18 | private static final String ACCESS_TOKEN_NOT_SET_MESSAGE = 19 | "In order to run the Mapbox map Activity you need to set a valid " 20 | + "access token. During development, you can set the MAPBOX_ACCESS_TOKEN environment variable for the SDK to " 21 | + "automatically include it in the Test App. Otherwise, you can manually include it in the " 22 | + "res/values/developer-config.xml file in the mapbox-gestures-android/app folder."; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | 28 | String mapboxAccessToken = Utils.getMapboxAccessToken(getApplicationContext()); 29 | if (TextUtils.isEmpty(mapboxAccessToken) || mapboxAccessToken.equals(DEFAULT_MAPBOX_ACCESS_TOKEN)) { 30 | Timber.e(ACCESS_TOKEN_NOT_SET_MESSAGE); 31 | } 32 | 33 | setContentView(R.layout.activity_mapbox); 34 | 35 | MapView mapView = (MapView) findViewById(R.id.map_view); 36 | mapView.getMapboxMap().loadStyleUri(Style.MAPBOX_STREETS); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/mapbox/android/gestures/testapp/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures.testapp; 2 | 3 | import android.app.Application; 4 | 5 | import timber.log.Timber; 6 | 7 | public class MyApplication extends Application { 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | 13 | if (BuildConfig.DEBUG) { 14 | Timber.plant(new Timber.DebugTree()); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/mapbox/android/gestures/testapp/TestActivity.java: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures.testapp; 2 | 3 | import android.os.Bundle; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import android.view.MotionEvent; 6 | 7 | import com.mapbox.android.gestures.AndroidGesturesManager; 8 | 9 | public class TestActivity extends AppCompatActivity { 10 | 11 | public AndroidGesturesManager gesturesManager; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_test); 17 | gesturesManager = new AndroidGesturesManager(this); 18 | } 19 | 20 | @Override 21 | public boolean onTouchEvent(MotionEvent event) { 22 | return gesturesManager.onTouchEvent(event) || super.onTouchEvent(event); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/mapbox/android/gestures/testapp/TestView.java: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures.testapp; 2 | 3 | import android.content.Context; 4 | import androidx.annotation.Nullable; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | 9 | import com.mapbox.android.gestures.AndroidGesturesManager; 10 | 11 | public class TestView extends View { 12 | 13 | private AndroidGesturesManager androidGesturesManager; 14 | 15 | public TestView(Context context) { 16 | this(context, null); 17 | } 18 | 19 | public TestView(Context context, @Nullable AttributeSet attrs) { 20 | super(context, attrs); 21 | init(context); 22 | } 23 | 24 | private void init(Context context) { 25 | androidGesturesManager = new AndroidGesturesManager(context); 26 | } 27 | 28 | @Override 29 | public boolean onTouchEvent(MotionEvent event) { 30 | return androidGesturesManager.onTouchEvent(event) || super.onTouchEvent(event); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/mapbox/android/gestures/testapp/Utils.java: -------------------------------------------------------------------------------- 1 | package com.mapbox.android.gestures.testapp; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | public class Utils { 8 | 9 | /** 10 | *

11 | * Returns the Mapbox access token set in the app resources. 12 | *

13 | * It will attempt to load the access token from the 14 | * {@code res/values/developer-config.xml} development file. 15 | * 16 | * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}. 17 | * @return The Mapbox access token or null if not found. 18 | */ 19 | public static String getMapboxAccessToken(@NonNull Context context) { 20 | int tokenResId = context.getResources().getIdentifier( 21 | "mapbox_access_token", "string", context.getPackageName()); 22 | return tokenResId != 0 ? context.getString(tokenResId) : null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_help_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-hdpi/ic_help_outline.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-hdpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_help_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-mdpi/ic_help_outline.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-mdpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_help_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-xhdpi/ic_help_outline.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-xhdpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_help_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-xxhdpi/ic_help_outline.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-xxhdpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_help_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-xxxhdpi/ic_help_outline.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-gestures-android/60bcff932b6fc00d1fa4dab660af8787aaa48369/app/src/main/res/drawable-xxxhdpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 20 | 21 | 28 | 29 | 35 | 36 |