From d764e9829eab48d2b6122ce2285f5ed95a366c6f Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 14 Jan 2016 16:27:29 +0100 Subject: [PATCH 01/19] [android] #3450 - fix rotation when enabling user location --- .../src/main/java/com/mapbox/mapboxsdk/views/MapView.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java index 5810e390f..ee74ab4d0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java @@ -139,6 +139,7 @@ public final class MapView extends FrameLayout { private static final String STATE_DEFAULT_TRANSITION_DURATION = "defaultTransitionDuration"; private static final String STATE_MY_LOCATION_ENABLED = "myLocationEnabled"; private static final String STATE_MY_LOCATION_TRACKING_MODE = "myLocationTracking"; + private static final String STATE_MY_BEARING_TRACKING_MODE = "myBearingTracking"; private static final String STATE_COMPASS_ENABLED = "compassEnabled"; private static final String STATE_COMPASS_GRAVITY = "compassGravity"; private static final String STATE_COMPASS_MARGIN_LEFT = "compassMarginLeft"; @@ -973,6 +974,8 @@ public final class MapView extends FrameLayout { //noinspection ResourceType setMyLocationTrackingMode(savedInstanceState.getInt(STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); + //noinspection ResourceType + setMyBearingTrackingMode(savedInstanceState.getInt(STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); } // Force a check for an access token @@ -1025,6 +1028,7 @@ public final class MapView extends FrameLayout { outState.putLong(STATE_DEFAULT_TRANSITION_DURATION, mNativeMapView.getDefaultTransitionDuration()); outState.putBoolean(STATE_MY_LOCATION_ENABLED, isMyLocationEnabled()); outState.putInt(STATE_MY_LOCATION_TRACKING_MODE, mUserLocationView.getMyLocationTrackingMode()); + outState.putInt(STATE_MY_BEARING_TRACKING_MODE, mUserLocationView.getMyBearingTrackingMode()); // Compass LayoutParams compassParams = (LayoutParams) mCompassView.getLayoutParams(); From 3fa63fa5e8fb59daef86ad267d39c2b45e9b6a22 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 15 Jan 2016 09:04:35 +0100 Subject: [PATCH 02/19] [android] #3052 - update gradle to 2.10 --- platform/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/build.gradle b/platform/android/build.gradle index 2f5700c87..f3a1cc06b 100644 --- a/platform/android/build.gradle +++ b/platform/android/build.gradle @@ -22,5 +22,5 @@ allprojects { } task wrapper(type: Wrapper) { - gradleVersion = '2.8' + gradleVersion = '2.10' } From e22b0270f486cbece252f7faec55cd927403200d Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 15 Jan 2016 08:51:44 +0100 Subject: [PATCH 03/19] [android] #3559 - don't show InfoWindow when marker is invalid --- .../main/java/com/mapbox/mapboxsdk/views/MapView.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java index ee74ab4d0..af8113047 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java @@ -2704,8 +2704,9 @@ public final class MapView extends FrameLayout { } if (!handledDefaultClick) { - // default behaviour show InfoWindow - mInfoWindows.add(marker.showInfoWindow()); + if (isInfoWindowValidForMarker(marker)) { + mInfoWindows.add(marker.showInfoWindow()); + } } mSelectedMarkers.add(marker); @@ -2746,6 +2747,10 @@ public final class MapView extends FrameLayout { mSelectedMarkers.remove(marker); } + private boolean isInfoWindowValidForMarker(@NonNull Marker marker) { + return !TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet()); + } + // // Mapbox Core GL Camera // From 2631f5bf9358e386286129f984beda90c1b9010e Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 15 Jan 2016 13:14:13 +0100 Subject: [PATCH 04/19] [android] #3517 - recreating InfoWindow with correct MapView instance --- .../com/mapbox/mapboxsdk/annotations/InfoWindow.java | 4 +++- .../java/com/mapbox/mapboxsdk/annotations/Marker.java | 10 ++++------ .../main/java/com/mapbox/mapboxsdk/views/MapView.java | 8 +++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java index c74cf478d..65f89c48e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -194,9 +194,11 @@ public class InfoWindow { * * @param overlayItem the tapped overlay item */ - void adaptDefaultMarker(Marker overlayItem) { + void adaptDefaultMarker(Marker overlayItem, MapView mapView) { View view = mView.get(); if (view != null) { + mMapView = new WeakReference<>(mapView); + overlayItem.setMapView(mapView); String title = overlayItem.getTitle(); ((TextView) view.findViewById(mTitleId /*R.id.title*/)).setText(title); String snippet = overlayItem.getSnippet(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java index 8978d4be4..9482afaa2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.annotations; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; @@ -84,11 +85,8 @@ public final class Marker extends Annotation { /** * Do not use this method. Used internally by the SDK. */ - public InfoWindow showInfoWindow() { - if (getMapView() == null) { - return null; - } - + public InfoWindow showInfoWindow(@NonNull MapView mapView) { + setMapView(mapView); MapView.InfoWindowAdapter infoWindowAdapter = getMapView().getInfoWindowAdapter(); if (infoWindowAdapter != null) { // end developer is using a custom InfoWindowAdapter @@ -100,7 +98,7 @@ public final class Marker extends Annotation { } } - getInfoWindow().adaptDefaultMarker(this); + getInfoWindow().adaptDefaultMarker(this, mapView); return showInfoWindow(getInfoWindow()); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java index af8113047..c475eccf1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java @@ -2705,7 +2705,7 @@ public final class MapView extends FrameLayout { if (!handledDefaultClick) { if (isInfoWindowValidForMarker(marker)) { - mInfoWindows.add(marker.showInfoWindow()); + mInfoWindows.add(marker.showInfoWindow(this)); } } @@ -2888,10 +2888,8 @@ public final class MapView extends FrameLayout { for (Marker marker : mSelectedMarkers) { if (marker.isInfoWindowShown()) { - Marker temp = marker; - temp.hideInfoWindow(); - temp.showInfoWindow(); - marker = temp; + marker.hideInfoWindow(); + marker.showInfoWindow(this); } } } From a79ef8bcc3a4981975a5c78a47f022e26671186c Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 15 Jan 2016 17:35:44 +0100 Subject: [PATCH 05/19] [android] #3052 - upgrade gradle to 2.10 --- .../android/gradle/wrapper/gradle-wrapper.jar | Bin 52141 -> 53636 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 +- platform/android/gradlew | 10 +- platform/android/gradlew.bat | 180 +++++++++--------- 4 files changed, 95 insertions(+), 100 deletions(-) diff --git a/platform/android/gradle/wrapper/gradle-wrapper.jar b/platform/android/gradle/wrapper/gradle-wrapper.jar index 085a1cdc27db1185342f15a00441734e74fe3735..13372aef5e24af05341d49695ee84e5f9b594659 100644 GIT binary patch delta 19154 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 QWZ5;@_o5+N`!0|u0Eye;x&QzG diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties index 426759170..8f7944df8 100644 --- a/platform/android/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ -#Thu Nov 05 15:43:10 CST 2015 +#Fri Jan 15 17:23:43 CET 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-bin.zip -distributionSha256Sum=a88db9c2f104defdaa8011c58cf6cda6c114298ae3695ecfb8beb30da3a903cb +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip diff --git a/platform/android/gradlew b/platform/android/gradlew index 91a7e269e..9d82f7891 100755 --- a/platform/android/gradlew +++ b/platform/android/gradlew @@ -42,11 +42,6 @@ case "`uname`" in ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do fi done SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- +cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" -cd "$SAVED" >&- +cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -114,6 +109,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` diff --git a/platform/android/gradlew.bat b/platform/android/gradlew.bat index 8a0b282aa..aec99730b 100644 --- a/platform/android/gradlew.bat +++ b/platform/android/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 300d908bfc8bcaad777ba632c7e0c918b142670d Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Fri, 15 Jan 2016 12:23:09 -0600 Subject: [PATCH 06/19] [android] #3052 Adding distributionSha256Sum --- platform/android/gradle/wrapper/gradle-wrapper.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties index 8f7944df8..02ccb5a55 100644 --- a/platform/android/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/gradle/wrapper/gradle-wrapper.properties @@ -4,3 +4,4 @@ distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip +distributionSha256Sum=a88db9c2f104defdaa8011c58cf6cda6c114298ae3695ecfb8beb30da3a903cb From 2dae355cbd7097cb8adbc34e2cdf51db789b6739 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Fri, 15 Jan 2016 12:46:16 -0600 Subject: [PATCH 07/19] [android] #3052 - Generating actual SHA for 2.10 zip file --- platform/android/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties index 02ccb5a55..b4ada9d74 100644 --- a/platform/android/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/gradle/wrapper/gradle-wrapper.properties @@ -4,4 +4,4 @@ distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip -distributionSha256Sum=a88db9c2f104defdaa8011c58cf6cda6c114298ae3695ecfb8beb30da3a903cb +distributionSha256Sum=66406247f745fc6f05ab382d3f8d3e120c339f34ef54b86f6dc5f6efc18fbb13 From 74a9c505f9e390ec25fc16904c432dd19cc900f2 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 18 Jan 2016 09:10:17 +0100 Subject: [PATCH 08/19] [android] #3573 - Marker clicks stop working after orientation change --- .../mapboxsdk/annotations/InfoWindow.java | 68 +++++-------------- .../mapbox/mapboxsdk/annotations/Marker.java | 8 +-- 2 files changed, 22 insertions(+), 54 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java index 65f89c48e..2ace201c9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -1,8 +1,8 @@ package com.mapbox.mapboxsdk.annotations; -import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; +import android.support.annotation.LayoutRes; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -31,18 +31,12 @@ public class InfoWindow { private boolean mIsVisible; protected WeakReference mView; - static int mTitleId = 0; - static int mDescriptionId = 0; - static int mSubDescriptionId = 0; - static int mImageId = 0; + @LayoutRes + private int mLayoutRes; InfoWindow(int layoutResId, MapView mapView) { + mLayoutRes = layoutResId; View view = LayoutInflater.from(mapView.getContext()).inflate(layoutResId, mapView, false); - - if (mTitleId == 0) { - setResIds(mapView.getContext()); - } - initialize(view, mapView); } @@ -86,7 +80,7 @@ public class InfoWindow { * This allows to offset the view from the object position. * @return this infowindow */ - InfoWindow open(Marker boundMarker, LatLng position, int offsetX, int offsetY) { + InfoWindow open(MapView mapView, Marker boundMarker, LatLng position, int offsetX, int offsetY) { setBoundMarker(boundMarker); MapView.LayoutParams lp = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, MapView.LayoutParams.WRAP_CONTENT); @@ -99,21 +93,21 @@ public class InfoWindow { mMarkerHeightOffset = -view.getMeasuredHeight() + offsetY; // Calculate default Android x,y coordinate - mCoordinates = mMapView.get().toScreenLocation(position); + mCoordinates = mapView.toScreenLocation(position); float x = mCoordinates.x - (view.getMeasuredWidth() / 2) + offsetX; float y = mCoordinates.y - view.getMeasuredHeight() + offsetY; if (view instanceof InfoWindowView) { // only apply repositioning/margin for InfoWindowView - Resources resources = mMapView.get().getContext().getResources(); + Resources resources = mapView.getContext().getResources(); // get right/left popup window float rightSideInfowWindow = x + view.getMeasuredWidth(); float leftSideInfoWindow = x; // get right/left map view - final float mapRight = mMapView.get().getRight(); - final float mapLeft = mMapView.get().getLeft(); + final float mapRight = mapView.getRight(); + final float mapLeft = mapView.getLeft(); float marginHorizontal = resources.getDimension(R.dimen.infowindow_margin); float tipViewOffset = resources.getDimension(R.dimen.infowindow_tipview_width) / 2; @@ -164,7 +158,7 @@ public class InfoWindow { mViewWidthOffset = x - mCoordinates.x - offsetX; close(); //if it was already opened - mMapView.get().addView(view, lp); + mapView.addView(view, lp); mIsVisible = true; } return this; @@ -196,25 +190,15 @@ public class InfoWindow { */ void adaptDefaultMarker(Marker overlayItem, MapView mapView) { View view = mView.get(); - if (view != null) { - mMapView = new WeakReference<>(mapView); - overlayItem.setMapView(mapView); - String title = overlayItem.getTitle(); - ((TextView) view.findViewById(mTitleId /*R.id.title*/)).setText(title); - String snippet = overlayItem.getSnippet(); - ((TextView) view.findViewById(mDescriptionId /*R.id.description*/)).setText(snippet); + if (view == null) { + view = LayoutInflater.from(mapView.getContext()).inflate(mLayoutRes, mapView, false); + initialize(view, mapView); } -/* - //handle sub-description, hiding or showing the text view: - TextView subDescText = (TextView) mView.findViewById(mSubDescriptionId); - String subDesc = overlayItem.getSubDescription(); - if ("".equals(subDesc)) { - subDescText.setVisibility(View.GONE); - } else { - subDescText.setText(subDesc); - subDescText.setVisibility(View.VISIBLE); - } -*/ + mMapView = new WeakReference<>(mapView); + String title = overlayItem.getTitle(); + ((TextView) view.findViewById(R.id.infowindow_title)).setText(title); + String snippet = overlayItem.getSnippet(); + ((TextView) view.findViewById(R.id.infowindow_description)).setText(snippet); } private void onClose() { @@ -233,22 +217,6 @@ public class InfoWindow { return mBoundMarker.get(); } - /** - * Given a context, set the resource ids for the layout - * of the InfoWindow. - * - * @param context the apps Context - */ - private static void setResIds(Context context) { - String packageName = context.getPackageName(); //get application package name - mTitleId = context.getResources().getIdentifier("id/infowindow_title", null, packageName); - mDescriptionId = - context.getResources().getIdentifier("id/infowindow_description", null, packageName); - mSubDescriptionId = context.getResources() - .getIdentifier("id/infowindow_subdescription", null, packageName); - mImageId = context.getResources().getIdentifier("id/infowindow_image", null, packageName); - } - public void update() { MapView mapView = mMapView.get(); Marker marker = mBoundMarker.get(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java index 9482afaa2..8b4b66a2a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -93,17 +93,17 @@ public final class Marker extends Annotation { View content = infoWindowAdapter.getInfoWindow(this); if (content != null) { infoWindow = new InfoWindow(content, getMapView()); - showInfoWindow(infoWindow); + showInfoWindow(infoWindow, mapView); return infoWindow; } } getInfoWindow().adaptDefaultMarker(this, mapView); - return showInfoWindow(getInfoWindow()); + return showInfoWindow(getInfoWindow(), mapView); } - private InfoWindow showInfoWindow(InfoWindow iw) { - iw.open(this, getPosition(), 0, topOffsetPixels); + private InfoWindow showInfoWindow(InfoWindow iw, MapView mapView) { + iw.open(mapView, this, getPosition(), 0, topOffsetPixels); infoWindowShown = true; return iw; } From 89b051f3865cb48fbe38a450336a6ca4517f6a07 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 18 Jan 2016 10:18:35 +0100 Subject: [PATCH 09/19] [android] #3593 - added double map view example --- .../src/main/AndroidManifest.xml | 3 + .../mapboxsdk/testapp/DoubleMapActivity.java | 147 ++++++++++++++++++ .../mapboxsdk/testapp/MainActivity.java | 17 +- .../src/main/res/drawable/ic_dns_24dp.xml | 9 ++ .../main/res/layout/fragment_double_map.xml | 27 ++++ .../src/main/res/menu/menu_drawer.xml | 15 +- .../src/main/res/values/strings.xml | 2 + 7 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/DoubleMapActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_dns_24dp.xml create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index af74d52c2..3d5862b51 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -66,6 +66,9 @@ + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml new file mode 100644 index 000000000..0695fafd1 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_double_map.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml index ad9deba18..54be85162 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml @@ -78,10 +78,11 @@ android:icon="@drawable/ic_tilt" android:title="@string/action_tilt" /> - + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index c096284fd..6b30fa7ac 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -20,6 +20,7 @@ Animate Coordinate Change Custom Layer Directions Activity + Double Map Activity Main Activity Controls Main Activity Styles @@ -43,6 +44,7 @@ Set Visible Bounds Center map around 2 markers Remove polylines + Double MapView Move Ease From 0ebf5fcaaee7ec90c81ed79b1ecd9843242c35c0 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 18 Jan 2016 12:17:59 +0100 Subject: [PATCH 10/19] [android] #3507 - fix location listener leak in UserLocationView --- .../mapboxsdk/views/UserLocationView.java | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java index 67dc9a349..d0f278a52 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java @@ -34,11 +34,13 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.LocationListener; import com.mapbox.mapboxsdk.location.LocationServices; +import java.lang.ref.WeakReference; + /** * This view shows the user's location, as determined from GPS, on the map * as a dot annotation. */ -final class UserLocationView extends View implements LocationListener { +final class UserLocationView extends View { private MapView mMapView; @@ -85,6 +87,7 @@ final class UserLocationView extends View implements LocationListener { private boolean mPaused = false; private Location mUserLocation; + private UserLocationListener mUserLocationListener; MapView.OnMyLocationChangeListener mOnMyLocationChangeListener; @@ -377,14 +380,18 @@ final class UserLocationView extends View implements LocationListener { setLocation(lastLocation); } + if(mUserLocationListener==null){ + mUserLocationListener = new UserLocationListener(this); + } + // Register for Location Updates - locationServices.addLocationListener(this); + locationServices.addLocationListener(mUserLocationListener); } else { // Disable location and user dot setLocation(null); // Deregister for Location Updates - locationServices.removeLocationListener(this); + locationServices.removeLocationListener(mUserLocationListener); } locationServices.toggleGPS(enableGps); @@ -498,17 +505,27 @@ final class UserLocationView extends View implements LocationListener { } } - /** - * Callback method for receiving location updates from LocationServices. - * - * @param location The new Location data - */ - @Override - public void onLocationChanged(Location location) { - if (mPaused) { - return; + private static class UserLocationListener implements LocationListener{ + + private WeakReference mUserLocationView; + + public UserLocationListener(UserLocationView userLocationView) { + mUserLocationView = new WeakReference<>(userLocationView); + } + + + /** + * Callback method for receiving location updates from LocationServices. + * + * @param location The new Location data + */ + @Override + public void onLocationChanged(Location location) { + UserLocationView locationView = mUserLocationView.get(); + if(locationView!=null && !locationView.isPaused()){ + locationView.setLocation(location); + } } - setLocation(location); } private boolean isStale(Location location) { @@ -751,4 +768,8 @@ final class UserLocationView extends View implements LocationListener { } } + public boolean isPaused(){ + return mPaused; + } + } From 78bedff8f9238c69e29c8c1ccbc6b1136b7786b3 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 18 Jan 2016 12:41:20 +0100 Subject: [PATCH 11/19] [android] #3556 - Added test to trigger NaN value on same point, updated LatLng model to handle calls for distance calls of same point --- .../com/mapbox/mapboxsdk/geometry/LatLng.java | 5 +++- .../src/test/java/LatLngTest.java | 27 ++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java index c340b09e0..f1d05542d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java @@ -129,7 +129,6 @@ public class LatLng implements ILatLng, Parcelable, Serializable { LatLng latLng = (LatLng) o; return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 && Double.compare(latLng.longitude, longitude) == 0; - } @Override @@ -168,6 +167,10 @@ public class LatLng implements ILatLng, Parcelable, Serializable { * @return distance in meters */ public double distanceTo(LatLng other) { + if(latitude == other.latitude && longitude == other.longitude){ + // return 0.0 to avoid a NaN + return 0.0; + } final double a1 = MathConstants.DEG2RAD * this.latitude; final double a2 = MathConstants.DEG2RAD * this.longitude; diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java index dd075f327..5b24f32b6 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java @@ -6,6 +6,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -43,6 +44,23 @@ public class LatLngTest { assertEquals("altitude default value", latLng2.getAltitude(), altitude, DELTA); } + @Test + public void testDistanceTo() { + LatLng latLng1 = new LatLng(0.0, 0.0); + LatLng latLng2 = new LatLng(1.0, 1.0); + assertEquals("distances should match", + latLng1.distanceTo(latLng2), + 157425.53710839353, DELTA); + } + + @Test + public void testDistanceToSamePoint() { + LatLng latLng1 = new LatLng(40.71199035644531, -74.0081); + LatLng latLng2 = new LatLng(40.71199035644531, -74.0081); + double distance = latLng1.distanceTo(latLng2); + assertEquals("distance should match", 0.0, distance, DELTA); + } + /* * A sample test where Mockito is necessary */ @@ -86,13 +104,4 @@ public class LatLngTest { "LatLng [longitude=3.4, latitude=1.2, altitude=5.6]"); } - @Test - public void testDistanceTo() { - LatLng latLng1 = new LatLng(0.0, 0.0); - LatLng latLng2 = new LatLng(1.0, 1.0); - assertEquals("distances should match", - latLng1.distanceTo(latLng2), - 157425.53710839353, DELTA); - } - } From fabc457adf04977bd73fd115b9e19383a89402f3 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Mon, 18 Jan 2016 13:26:23 +0100 Subject: [PATCH 12/19] [android] #3338 - add javadoc annotations package --- .../java/com/mapbox/mapboxsdk/MapFragment.java | 14 ++++++++++++++ .../mapbox/mapboxsdk/annotations/Annotation.java | 8 +++++--- .../com/mapbox/mapboxsdk/annotations/Icon.java | 4 ++++ .../mapboxsdk/annotations/IconFactory.java | 4 ++++ .../mapbox/mapboxsdk/annotations/InfoWindow.java | 9 ++++++--- .../com/mapbox/mapboxsdk/annotations/Marker.java | 16 +++++++++++++--- .../mapboxsdk/annotations/MarkerOptions.java | 6 +++--- .../mapbox/mapboxsdk/annotations/MultiPoint.java | 3 +++ .../mapboxsdk/annotations/PolygonOptions.java | 5 +++++ .../mapboxsdk/annotations/PolylineOptions.java | 5 +++++ .../mapboxsdk/geometry/CoordinateBounds.java | 2 +- .../mapboxsdk/geometry/CoordinateRegion.java | 2 +- .../mapboxsdk/geometry/CoordinateSpan.java | 2 +- .../com/mapbox/mapboxsdk/geometry/ILatLng.java | 2 +- .../mapboxsdk/geometry/IProjectedMeters.java | 3 +++ .../com/mapbox/mapboxsdk/geometry/LatLng.java | 5 +++-- .../mapbox/mapboxsdk/geometry/LatLngZoom.java | 3 +++ .../mapboxsdk/geometry/ProjectedMeters.java | 6 ++++-- 18 files changed, 79 insertions(+), 20 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapFragment.java index 98d0f7965..572598996 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapFragment.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapFragment.java @@ -10,6 +10,20 @@ import android.view.ViewGroup; import com.mapbox.mapboxsdk.utils.ApiAccess; import com.mapbox.mapboxsdk.views.MapView; +/** + * Fragment wrapper around a {@link MapView}. + *

+ * A Map component in an app. This fragment is the simplest way to place a map in an application. + * It's a wrapper around a view of a map to automatically handle the necessary life cycle needs. + * Being a fragment, this component can be added to an activity's layout or can dynamically be added + * using a FragmentManager. + *

+ *

+ * To get a reference to the MapView, use {@link #getMap()} + *

+ * + * @see #getMap() + */ public class MapFragment extends Fragment { // diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java index bf8999878..813e489e9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java @@ -5,10 +5,12 @@ import android.support.annotation.NonNull; import com.mapbox.mapboxsdk.views.MapView; /** - * Annotation is the most general kind of overlay on top of a map, - * from which {@link InfoWindow} and {@link Marker} are derived: it manages - * attachment to a map and identification, but does not require + * Annotation is a overlay on top of a {@link MapView}, + * from which {@link Polygon}, {@link Polyline} and {@link Marker} are derived. + *

+ * it manages attachment to a map and identification, but does not require * content to be placed at a geographical point. + *

*/ public abstract class Annotation implements Comparable { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java index d7e28dde7..b9691914e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java @@ -2,6 +2,10 @@ package com.mapbox.mapboxsdk.annotations; import android.graphics.Bitmap; +/** + * Icon is the visual representation of a {@link Marker} on a {@link com.mapbox.mapboxsdk.views.MapView}. + * @see Marker + */ public final class Icon { private Bitmap mBitmap; private String mId; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java index 8d58866ac..bee4ec47c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java @@ -22,6 +22,10 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +/** + * Factory for creating {@link Icon} objects. + * @see Icon + */ public final class IconFactory { private static final String ICON_ID_PREFIX = "com.mapbox.icons.icon_"; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java index 2ace201c9..696301cf5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -17,19 +17,22 @@ import java.lang.ref.WeakReference; /** *

- * A tooltip view. This is a UI element placed over a map at a specific geographic - * location. + * InfoWindow is a tooltip shown when a {@link Marker} is tapped. + *

+ *

+ * This is a UI element placed over a map at a specific geographic location. *

*/ public class InfoWindow { private WeakReference mBoundMarker; private WeakReference mMapView; + protected WeakReference mView; + private float mMarkerHeightOffset; private float mViewWidthOffset; private PointF mCoordinates; private boolean mIsVisible; - protected WeakReference mView; @LayoutRes private int mLayoutRes; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java index 8b4b66a2a..346380144 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -9,9 +9,10 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.views.MapView; /** - * A marker is a map overlay that shows an icon image at a specific - * geographical location and can be associated with a {@link InfoWindow} - * that is shown when the marker is tapped. + * Marker is an annotation that shows an icon image at a geographical location. + *

+ * An {@link InfoWindow} can be shown when a Marker is pressed + *

*/ public final class Marker extends Annotation { @@ -54,6 +55,8 @@ public final class Marker extends Annotation { /** * Do not use this method. Used internally by the SDK. + * + * @return boolean State of a InfoWindow */ public boolean isInfoWindowShown() { return infoWindowShown; @@ -69,6 +72,8 @@ public final class Marker extends Annotation { /** * Do not use this method. Used internally by the SDK. + * + * @param icon The icon to be used as Marker image */ public void setIcon(@Nullable Icon icon) { this.icon = icon; @@ -84,6 +89,9 @@ public final class Marker extends Annotation { /** * Do not use this method. Used internally by the SDK. + * + * @param mapView The MapView to show the InfoWindow on. + * @return infoWindow The infoWindow to show */ public InfoWindow showInfoWindow(@NonNull MapView mapView) { setMapView(mapView); @@ -127,6 +135,8 @@ public final class Marker extends Annotation { /** * Do not use this method. Used internally by the SDK. + * + * @param topOffsetPixels the pixels to have as offset */ public void setTopOffsetPixels(int topOffsetPixels) { this.topOffsetPixels = topOffsetPixels; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java index 69e8b03bd..a83a6991b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java @@ -10,9 +10,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng; /** *

- * A builder object for the options configuration {@link com.mapbox.mapboxsdk.annotations.Marker} and - * {@link com.mapbox.mapboxsdk.annotations.InfoWindow} - * instances on maps. + * Builder for composing {@link com.mapbox.mapboxsdk.annotations.Marker} objects. *

* *

Example

@@ -70,6 +68,8 @@ public final class MarkerOptions implements Parcelable { /** * Do not use this method. Used internally by the SDK. + * + * @return Marker The build marker */ public Marker getMarker() { return marker; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java index 5c1dfb119..d2aaea1d1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java @@ -5,6 +5,9 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import java.util.ArrayList; import java.util.List; +/** + * Multipoint is an abstract annotation for combining geographical locations. + */ public abstract class MultiPoint extends Annotation { private List points; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java index c716d10ed..30847807b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java @@ -9,6 +9,9 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import java.util.ArrayList; import java.util.List; +/** + * Builder for composing {@link Polygon} objects. + */ public final class PolygonOptions implements Parcelable { public static final Parcelable.Creator CREATOR @@ -96,6 +99,8 @@ public final class PolygonOptions implements Parcelable { /** * Do not use this method. Used internally by the SDK. + * + * @return Polygon the Polygon to return */ public Polygon getPolygon() { return polygon; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java index d48858c7d..1e625c10f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java @@ -8,6 +8,9 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import java.util.ArrayList; import java.util.List; +/** + * Builder for composing {@link Polyline} objects. + */ public final class PolylineOptions implements Parcelable { @@ -83,6 +86,7 @@ public final class PolylineOptions implements Parcelable { * Sets the color of the polyline. * * @param color - the color in ARGB format + * @return PolyLineOptions The builder used to build a Polyline */ public PolylineOptions color(int color) { polyline.setColor(color); @@ -95,6 +99,7 @@ public final class PolylineOptions implements Parcelable { /** * Do not use this method. Used internally by the SDK. + * @return PolyLine The polyline build by this class. */ public Polyline getPolyline() { return polyline; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java index 1ad584f8c..4d3e94f78 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.geometry; /** - * Implementation of iOS MGLCoordinateBounds + * A rectangular geograpical region defined by a south west {@link LatLng} and a north east {@link LatLng}. */ public class CoordinateBounds { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java index a70bb05a4..65b30746f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.geometry; /** - * Implementation of iOS MKCoordinateRegion + * A geographical region defined by a {@link LatLng} and a {@link CoordinateSpan}. */ public class CoordinateRegion { private LatLng center; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java index 79361f725..097e88a76 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.geometry; /** - * Implementation of iOS MKCoordinateSpan + * A geographical span defined by its latitude and longitude span. */ public class CoordinateSpan { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java index 892d0ad4a..afd22e5dd 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.geometry; /** - * A Latitude, Longitude point. + * Describes a latitude, longitude point. */ public interface ILatLng { double getLatitude(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java index 5aa5f607e..43fe25f8e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java @@ -1,5 +1,8 @@ package com.mapbox.mapboxsdk.geometry; +/** + * Describes a projection in Mercator meters. + */ public interface IProjectedMeters { double getNorthing(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java index f1d05542d..876a12720 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java @@ -10,9 +10,10 @@ import com.mapbox.mapboxsdk.constants.MathConstants; import java.io.Serializable; /** + * A geographical location which contains a single latitude, longitude pair, with + * optional altitude. *

- * This class is container for a single latitude, longitude pair, with - * optional altitude. Latitude and longitude are expressed as decimal degrees + * Latitude and longitude are expressed as decimal degrees * in the WGS84 datum. By default, altitude is 0.0, or sea level. *

*

diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java index 9e453a391..349c09898 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java @@ -5,6 +5,9 @@ import android.os.Parcelable; import java.io.Serializable; +/** + * A geographical location which contains a {@link LatLng}, zoom pair. + */ public class LatLngZoom extends LatLng implements Parcelable, Serializable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java index fc821e887..61a03ff15 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java @@ -6,10 +6,12 @@ import android.os.Parcelable; import java.io.Serializable; /** - * ProjectedMeters is an internal representation of longitude, latitude points that - * have been projected into Mapbox GL's Mercator projection. Instead of decimal + * ProjectedMeters is a projection of longitude, latitude points in Mercator meters. + *

+ * these have been projected into Mapbox GL's Mercator projection. Instead of decimal * degrees, it uses Mercator meters (which are notably not equivalent to SI meters) * except at the equator. + *

*/ public class ProjectedMeters implements IProjectedMeters, Parcelable, Serializable { From 5ff95d45240cc340d22c37bb13e4289b4eab40b7 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 19 Jan 2016 12:03:52 +0100 Subject: [PATCH 13/19] [android] #3525 - fix ConnectivityManager context leak --- .../src/main/java/com/mapbox/mapboxsdk/views/MapView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java index c475eccf1..fdfc3faaf 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java @@ -805,7 +805,7 @@ public final class MapView extends FrameLayout { mZoomButtonsController.setOnZoomListener(new OnZoomListener()); // Check current connection status - ConnectivityManager connectivityManager = (ConnectivityManager) context + ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext() .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); boolean isConnected = (activeNetwork != null) && activeNetwork.isConnectedOrConnecting(); From 6b3745c68dcfe98d746d478539b035ea8699f736 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 19 Jan 2016 10:25:05 +0100 Subject: [PATCH 14/19] [android] #3156 - improving marker selection touch handling --- .../com/mapbox/mapboxsdk/views/MapView.java | 60 ++++++------------- 1 file changed, 17 insertions(+), 43 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java index fdfc3faaf..8db7fbf77 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java @@ -3186,9 +3186,9 @@ public final class MapView extends FrameLayout { // Open / Close InfoWindow PointF tapPoint = new PointF(e.getX(), e.getY()); - final float toleranceSides = 30 * mScreenDensity; - final float toleranceTop = 40 * mScreenDensity; - final float toleranceBottom = 10 * mScreenDensity; + final float toleranceSides = 15 * mScreenDensity; + final float toleranceTop = 20 * mScreenDensity; + final float toleranceBottom = 5 * mScreenDensity; RectF tapRect = new RectF(tapPoint.x - toleranceSides, tapPoint.y + toleranceTop, tapPoint.x + toleranceSides, tapPoint.y - toleranceBottom); @@ -3201,52 +3201,27 @@ public final class MapView extends FrameLayout { ); BoundingBox tapBounds = BoundingBox.fromLatLngs(corners); - List nearbyMarkers = getMarkersInBounds(tapBounds); + long newSelectedMarkerId = -1; - long newSelectedMarkerId; - - if (nearbyMarkers.size() > 0) { - - // there is at least one nearby marker; select one - // - // first, sort for comparison and iteration + if (nearbyMarkers!=null && nearbyMarkers.size() > 0) { Collections.sort(nearbyMarkers); - - if (nearbyMarkers == mMarkersNearLastTap) { - - // TODO: We still need to adapt this logic to the new mSelectedMarkers list, - // though the basic functionality is there. - - // the selection candidates haven't changed; cycle through them -// if (mSelectedMarker != null -// && (mSelectedMarker.getId() == mMarkersNearLastTap.get(mMarkersNearLastTap.size() - 1).getId())) { -// // the selected marker is the last in the set; cycle back to the first -// // note: this could be the selected marker if only one in set -// newSelectedMarkerId = mMarkersNearLastTap.get(0).getId(); -// } else if (mSelectedMarker != null) { -// // otherwise increment the selection through the candidates -// long result = mMarkersNearLastTap.indexOf(mSelectedMarker); -// newSelectedMarkerId = mMarkersNearLastTap.get((int) result + 1).getId(); -// } else { - // no current selection; select the first one - newSelectedMarkerId = mMarkersNearLastTap.get(0).getId(); -// } - } else { - // start tracking a new set of nearby markers - mMarkersNearLastTap = nearbyMarkers; - - // select the first one - newSelectedMarkerId = mMarkersNearLastTap.get(0).getId(); + for (Marker nearbyMarker : nearbyMarkers) { + boolean found = false; + for (Marker selectedMarker : mSelectedMarkers) { + if(selectedMarker.equals(nearbyMarker)){ + found = true; + } + } + if(!found){ + newSelectedMarkerId = nearbyMarker.getId(); + break; + } } - - } else { - // there are no nearby markers; deselect if necessary - newSelectedMarkerId = -1; + mMarkersNearLastTap = nearbyMarkers; } if (newSelectedMarkerId >= 0) { - int count = mAnnotations.size(); for (int i = 0; i < count; i++) { Annotation annotation = mAnnotations.get(i); @@ -3259,7 +3234,6 @@ public final class MapView extends FrameLayout { } } } - } else { // deselect any selected marker deselectMarkers(); From 06e420939f1dc172260adc2a7a8ee1a4e5ba62fc Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 19 Jan 2016 12:37:52 +0100 Subject: [PATCH 15/19] [android] #3604 - polyline activity memory leak fix --- .../mapboxsdk/testapp/PolylineActivity.java | 75 +++++++++---------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java index e000cf079..d2d266a31 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/PolylineActivity.java @@ -22,6 +22,12 @@ import java.util.List; public class PolylineActivity extends AppCompatActivity { private static final String STATE_POLYLINE_OPTIONS = "polylineOptions"; + private static final LatLng ANDORRA = new LatLng(42.505777, 1.52529); + private static final LatLng LUXEMBOURG = new LatLng(49.815273, 6.129583); + private static final LatLng MONACO = new LatLng(43.738418, 7.424616); + private static final LatLng VATICAN_CITY = new LatLng(41.902916, 12.453389); + private static final LatLng SAN_MARINO = new LatLng(43.942360, 12.457777); + private static final LatLng LIECHTENSTEIN = new LatLng(47.166000, 9.555373); private List mPolylines; private ArrayList mPolylineOptions = new ArrayList<>(); @@ -48,8 +54,9 @@ public class PolylineActivity extends AppCompatActivity { if (savedInstanceState != null) { mPolylineOptions = savedInstanceState.getParcelableArrayList(STATE_POLYLINE_OPTIONS); } else { - mPolylineOptions.addAll(PolylineProvider.getAll()); + mPolylineOptions.addAll(getAllPolylines()); } + mPolylines = mMapView.addPolylines(mPolylineOptions); findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() { @@ -65,12 +72,38 @@ public class PolylineActivity extends AppCompatActivity { } } mPolylineOptions.clear(); - mPolylineOptions.addAll(PolylineProvider.getRandomLine()); + mPolylineOptions.addAll(getRandomLine()); mPolylines = mMapView.addPolylines(mPolylineOptions); } }); } + private List getAllPolylines() { + List options = new ArrayList<>(); + options.add(generatePolyline(ANDORRA, LUXEMBOURG, "#F44336")); + options.add(generatePolyline(ANDORRA, MONACO, "#FF5722")); + options.add(generatePolyline(MONACO, VATICAN_CITY, "#673AB7")); + options.add(generatePolyline(VATICAN_CITY, SAN_MARINO, "#009688")); + options.add(generatePolyline(SAN_MARINO, LIECHTENSTEIN, "#795548")); + options.add(generatePolyline(LIECHTENSTEIN, LUXEMBOURG, "#3F51B5")); + return options; + } + + private PolylineOptions generatePolyline(LatLng start, LatLng end, String color) { + PolylineOptions line = new PolylineOptions(); + line.add(start); + line.add(end); + line.color(Color.parseColor(color)); + return line; + } + + public List getRandomLine() { + final List randomLines = getAllPolylines(); + Collections.shuffle(randomLines); + return new ArrayList(){{ + add(randomLines.get(0)); + }}; + } @Override protected void onStart() { @@ -139,42 +172,4 @@ public class PolylineActivity extends AppCompatActivity { } } - private static class PolylineProvider { - private static final LatLng ANDORRA = new LatLng(42.505777, 1.52529); - private static final LatLng LUXEMBOURG = new LatLng(49.815273, 6.129583); - private static final LatLng MONACO = new LatLng(43.738418, 7.424616); - private static final LatLng VATICAN_CITY = new LatLng(41.902916, 12.453389); - private static final LatLng SAN_MARINO = new LatLng(43.942360, 12.457777); - private static final LatLng LIECHTENSTEIN = new LatLng(47.166000, 9.555373); - - private static final List POLYLINES = new ArrayList() {{ - add(generatePolyline(ANDORRA, LUXEMBOURG, "#F44336")); - add(generatePolyline(ANDORRA, MONACO, "#FF5722")); - add(generatePolyline(MONACO, VATICAN_CITY, "#673AB7")); - add(generatePolyline(VATICAN_CITY, SAN_MARINO, "#009688")); - add(generatePolyline(SAN_MARINO, LIECHTENSTEIN, "#795548")); - add(generatePolyline(LIECHTENSTEIN, LUXEMBOURG, "#3F51B5")); - }}; - - private static PolylineOptions generatePolyline(LatLng start, LatLng end, String color) { - PolylineOptions line = new PolylineOptions(); - line.add(start); - line.add(end); - line.color(Color.parseColor(color)); - return line; - } - - public static List getAll() { - return POLYLINES; - } - - public static List getRandomLine() { - List randomLines = new ArrayList<>(); - Collections.shuffle(POLYLINES); - randomLines.add(POLYLINES.get(0)); - return randomLines; - } - - } - } From 8ffe776141bc5740438f65ef6b66ff9663c6204e Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 19 Jan 2016 13:24:46 +0100 Subject: [PATCH 16/19] [android] #3503 - remove serialisable interface from classes in geometry package, implemented parcable on CoordinateBounds, CoordinateRegion and CoordinateSpan. Enforced Android code conventions on those classes. --- .../mapboxsdk/geometry/BoundingBox.java | 2 +- .../mapboxsdk/geometry/CoordinateBounds.java | 65 ++++++++++++++----- .../mapboxsdk/geometry/CoordinateRegion.java | 58 +++++++++++++---- .../mapboxsdk/geometry/CoordinateSpan.java | 62 +++++++++++++----- .../com/mapbox/mapboxsdk/geometry/LatLng.java | 2 +- .../mapbox/mapboxsdk/geometry/LatLngZoom.java | 2 +- .../mapboxsdk/geometry/ProjectedMeters.java | 2 +- .../src/test/java/CoordinateBoundsTest.java | 2 +- 8 files changed, 148 insertions(+), 47 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/BoundingBox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/BoundingBox.java index ca805b38e..72a851e1a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/BoundingBox.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/BoundingBox.java @@ -9,7 +9,7 @@ import java.util.List; /** * A rectangular geographical area defined in latitude and longitude units. */ -public final class BoundingBox implements Parcelable, Serializable { +public final class BoundingBox implements Parcelable { private final double mLatNorth; private final double mLatSouth; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java index 4d3e94f78..fefc2502d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateBounds.java @@ -1,41 +1,52 @@ package com.mapbox.mapboxsdk.geometry; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + /** * A rectangular geograpical region defined by a south west {@link LatLng} and a north east {@link LatLng}. */ -public class CoordinateBounds { +public class CoordinateBounds implements Parcelable { - private LatLng southWest; - private LatLng northEast; + private LatLng mSouthWest; + private LatLng mNorthEast; - public CoordinateBounds(LatLng southWest, LatLng northEast) { - this.southWest = southWest; - this.northEast = northEast; + public CoordinateBounds(@NonNull Parcel in) { + mSouthWest = in.readParcelable(LatLng.class.getClassLoader()); + mNorthEast = in.readParcelable(LatLng.class.getClassLoader()); } + public CoordinateBounds(@NonNull LatLng southWest, @NonNull LatLng northEast) { + mSouthWest = southWest; + mNorthEast = northEast; + } + + @NonNull public LatLng getSouthWest() { - return southWest; + return mSouthWest; } - public void setSouthWest(LatLng southWest) { - this.southWest = southWest; + public void setSouthWest(@NonNull LatLng mSouthWest) { + this.mSouthWest = mSouthWest; } + @NonNull public LatLng getNorthEast() { - return northEast; + return mNorthEast; } - public void setNorthEast(LatLng northEast) { - this.northEast = northEast; + public void setNorthEast(@NonNull LatLng mNorthEast) { + this.mNorthEast = mNorthEast; } @Override public int hashCode() { int result; long temp; - temp = southWest.hashCode(); + temp = mSouthWest.hashCode(); result = (int) (temp ^ (temp >>> 32)); - temp = northEast.hashCode(); + temp = mNorthEast.hashCode(); result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } @@ -53,6 +64,30 @@ public class CoordinateBounds { @Override public String toString() { - return "CoordinateBounds [northEast[" + getNorthEast() + "], southWest[]" + getSouthWest() + "]"; + return "CoordinateBounds [mNorthEast[" + getNorthEast() + "], mSouthWest[]" + getSouthWest() + "]"; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public CoordinateBounds createFromParcel(Parcel in) { + return new CoordinateBounds(in); + } + + @Override + public CoordinateBounds[] newArray(int size) { + return new CoordinateBounds[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int arg1) { + out.writeParcelable(mSouthWest, arg1); + out.writeParcelable(mNorthEast, arg1); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java index 65b30746f..c7c0aa1c4 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateRegion.java @@ -1,30 +1,64 @@ package com.mapbox.mapboxsdk.geometry; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + /** * A geographical region defined by a {@link LatLng} and a {@link CoordinateSpan}. */ -public class CoordinateRegion { - private LatLng center; - private CoordinateSpan span; +public class CoordinateRegion implements Parcelable{ - public CoordinateRegion(final LatLng center, final CoordinateSpan span) { - this.center = center; - this.span = span; + private LatLng mCenter; + private CoordinateSpan mSpan; + + public CoordinateRegion(@NonNull Parcel in){ + mCenter = in.readParcelable(LatLng.class.getClassLoader()); + mSpan = in.readParcelable(CoordinateSpan.class.getClassLoader()); + } + + public CoordinateRegion(@NonNull LatLng center, @NonNull CoordinateSpan span) { + mCenter = center; + mSpan = span; } public LatLng getCenter() { - return center; + return mCenter; } - public void setCenter(final LatLng center) { - this.center = center; + public void setCenter(@NonNull LatLng center) { + mCenter = center; } public CoordinateSpan getSpan() { - return span; + return mSpan; } - public void setSpan(final CoordinateSpan span) { - this.span = span; + public void setSpan(@NonNull CoordinateSpan span) { + this.mSpan = span; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public CoordinateRegion createFromParcel(Parcel in) { + return new CoordinateRegion(in); + } + + @Override + public CoordinateRegion[] newArray(int size) { + return new CoordinateRegion[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int arg1) { + out.writeParcelable(mCenter, arg1); + out.writeParcelable(mSpan, arg1); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java index 097e88a76..a43757713 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/CoordinateSpan.java @@ -1,32 +1,41 @@ package com.mapbox.mapboxsdk.geometry; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + /** * A geographical span defined by its latitude and longitude span. */ -public class CoordinateSpan { +public class CoordinateSpan implements Parcelable { - private double latitudeSpan; - private double longitudeSpan; + private double mLatitudeSpan; + private double mLongitudeSpan; - public CoordinateSpan(final double latitudeSpan, final double longitudeSpan) { - this.latitudeSpan = latitudeSpan; - this.longitudeSpan = longitudeSpan; + public CoordinateSpan(@NonNull Parcel in){ + mLatitudeSpan = in.readDouble(); + mLongitudeSpan = in.readDouble(); + } + + public CoordinateSpan(double latitudeSpan, double longitudeSpan) { + mLatitudeSpan = latitudeSpan; + mLongitudeSpan = longitudeSpan; } public double getLatitudeSpan() { - return latitudeSpan; + return mLatitudeSpan; } - public void setLatitudeSpan(final double latitudeSpan) { - this.latitudeSpan = latitudeSpan; + public void setLatitudeSpan(double latitudeSpan) { + mLatitudeSpan = latitudeSpan; } public double getLongitudeSpan() { - return longitudeSpan; + return mLongitudeSpan; } - public void setLongitudeSpan(final double longitudeSpan) { - this.longitudeSpan = longitudeSpan; + public void setLongitudeSpan(double longitudeSpan) { + mLongitudeSpan = longitudeSpan; } @Override @@ -34,10 +43,33 @@ public class CoordinateSpan { if (this == o) return true; if (o instanceof CoordinateSpan) { CoordinateSpan other = (CoordinateSpan) o; - return longitudeSpan == other.getLongitudeSpan() - && latitudeSpan == other.getLatitudeSpan(); + return mLongitudeSpan == other.getLongitudeSpan() + && mLatitudeSpan == other.getLatitudeSpan(); } return false; } -} + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public CoordinateSpan createFromParcel(Parcel in) { + return new CoordinateSpan(in); + } + + @Override + public CoordinateSpan[] newArray(int size) { + return new CoordinateSpan[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int arg1) { + out.writeDouble(mLatitudeSpan); + out.writeDouble(mLongitudeSpan); + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java index 876a12720..f24c2ed43 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java @@ -21,7 +21,7 @@ import java.io.Serializable; * data automatically, so all data enters in the WGS84 datum. *

*/ -public class LatLng implements ILatLng, Parcelable, Serializable { +public class LatLng implements ILatLng, Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public LatLng createFromParcel(Parcel in) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java index 349c09898..6e24faaa9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngZoom.java @@ -8,7 +8,7 @@ import java.io.Serializable; /** * A geographical location which contains a {@link LatLng}, zoom pair. */ -public class LatLngZoom extends LatLng implements Parcelable, Serializable { +public class LatLngZoom extends LatLng implements Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public LatLngZoom createFromParcel(Parcel in) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java index 61a03ff15..06a58fe8a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java @@ -13,7 +13,7 @@ import java.io.Serializable; * except at the equator. *

*/ -public class ProjectedMeters implements IProjectedMeters, Parcelable, Serializable { +public class ProjectedMeters implements IProjectedMeters, Parcelable { public static final Creator CREATOR = new Creator() { public ProjectedMeters createFromParcel(Parcel in) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateBoundsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateBoundsTest.java index a5d389130..1dc4be723 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateBoundsTest.java @@ -44,7 +44,7 @@ public class CoordinateBoundsTest { CoordinateBounds coordinateBounds = new CoordinateBounds(northEast, southWest); assertEquals("string should match", coordinateBounds.toString(), - "CoordinateBounds [northEast[" + coordinateBounds.getNorthEast() + "], southWest[]" + coordinateBounds.getSouthWest() + "]"); + "CoordinateBounds [mNorthEast[" + coordinateBounds.getNorthEast() + "], mSouthWest[]" + coordinateBounds.getSouthWest() + "]"); } @Test From fa84283a9d2b1b38332012abc989f992d29d31f0 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 19 Jan 2016 14:56:52 +0100 Subject: [PATCH 17/19] [android] #3608 - upgrade okhttp3 to version 2 --- platform/android/MapboxGLAndroidSDK/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 55beb8dea..c194a8c34 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -25,7 +25,7 @@ dependencies { compile "com.android.support:support-annotations:${supportLibVersion}" compile "com.android.support:support-v4:${supportLibVersion}" compile "com.android.support:design:${supportLibVersion}" - compile 'com.squareup.okhttp3:okhttp:3.0.0' + compile 'com.squareup.okhttp3:okhttp:3.0.1' compile 'com.mapzen.android:lost:1.0.1' } From 9672f2ba505587927f92112ca892258b28a721a3 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Wed, 13 Jan 2016 17:22:14 -0500 Subject: [PATCH 18/19] sample geocoder activity --- .../MapboxGLAndroidSDKTestApp/build.gradle | 5 + .../src/main/AndroidManifest.xml | 3 + .../mapboxsdk/testapp/GeocoderActivity.java | 158 ++++++++++++++++++ .../mapboxsdk/testapp/MainActivity.java | 6 +- .../src/main/res/layout/activity_geocoder.xml | 27 +++ .../src/main/res/menu/menu_drawer.xml | 15 +- .../src/main/res/values/strings.xml | 1 + 7 files changed, 208 insertions(+), 7 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index 815fe8d00..41d75cc0b 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -86,6 +86,11 @@ dependencies { transitive=true } + // Geocoder SDK + compile ('com.mapbox.mapboxsdk:mapbox-android-geocoder:1.0.0@aar'){ + transitive=true + } + // Testing dependencies testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.10.19' diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 3d5862b51..d5a6df956 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -66,6 +66,9 @@ + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java new file mode 100644 index 000000000..200ca8ac0 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/GeocoderActivity.java @@ -0,0 +1,158 @@ +package com.mapbox.mapboxsdk.testapp; + +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.widget.TextView; + +import com.mapbox.geocoder.GeocoderCriteria; +import com.mapbox.geocoder.MapboxGeocoder; +import com.mapbox.geocoder.service.models.GeocoderFeature; +import com.mapbox.geocoder.service.models.GeocoderResponse; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.utils.ApiAccess; +import com.mapbox.mapboxsdk.views.MapView; + +import java.util.List; + +import retrofit.Callback; +import retrofit.Response; +import retrofit.Retrofit; + +public class GeocoderActivity extends AppCompatActivity { + + private static final String LOG_TAG = "GeocoderActivity"; + + private MapView mapView; + private TextView textView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_geocoder); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); + } + + textView = (TextView) findViewById(R.id.message); + setMessage("Tap the map to trigger the geocoder."); + + LatLng dupontCircle = new LatLng(38.90962, -77.04341); + + mapView = (MapView) findViewById(R.id.mapView); + mapView.setAccessToken(ApiAccess.getToken(this)); + mapView.setStyleUrl(Style.MAPBOX_STREETS); + mapView.setCenterCoordinate(dupontCircle); + mapView.setZoomLevel(15); + mapView.onCreate(savedInstanceState); + + mapView.setOnMapClickListener(new MapView.OnMapClickListener() { + @Override + public void onMapClick(LatLng point) { + setMessage("Geocoding..."); + mapView.removeAllAnnotations(); + mapView.addMarker(new MarkerOptions() + .position(point) + .title("Your finger is here")); + geocode(point); + } + }); + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + public void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + /* + * Forward geocoding + */ + + private void geocode(LatLng point) { + MapboxGeocoder client = new MapboxGeocoder.Builder() + .setAccessToken(ApiAccess.getToken(this)) + .setCoordinates(point.getLongitude(), point.getLatitude()) + .setType(GeocoderCriteria.TYPE_POI) + .build(); + + client.enqueue(new Callback() { + @Override + public void onResponse(Response response, Retrofit retrofit) { + List results = response.body().getFeatures(); + if (results.size() > 0) { + String placeName = results.get(0).getPlaceName(); + setSuccess(placeName); + } else { + setMessage("No results."); + } + } + + @Override + public void onFailure(Throwable t) { + setError(t.getMessage()); + } + }); + + } + + /* + * Update text view + */ + + private void setMessage(String message) { + Log.d(LOG_TAG, "Message: " + message); + textView.setText(message); + } + + private void setSuccess(String placeName) { + Log.d(LOG_TAG, "Place name: " + placeName); + textView.setText(placeName); + } + + private void setError(String message) { + Log.e(LOG_TAG, "Error: " + message); + textView.setText("Error: " + message); + } + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java index a6920567f..645104644 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MainActivity.java @@ -182,8 +182,6 @@ public class MainActivity extends AppCompatActivity { mFpsTextView = (TextView) findViewById(R.id.view_fps); mFpsTextView.setText(""); - mMapView.setRotateEnabled(false); - mLocationFAB = (FloatingActionButton) findViewById(R.id.locationFAB); mLocationFAB.setOnClickListener(new View.OnClickListener() { @Override @@ -422,6 +420,10 @@ public class MainActivity extends AppCompatActivity { } return true; + case R.id.action_geocoder: + startActivity(new Intent(getApplicationContext(), GeocoderActivity.class)); + return true; + default: return changeMapStyle(menuItem.getItemId()); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml new file mode 100644 index 000000000..ce0802385 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml index 54be85162..2fd9e6c75 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_drawer.xml @@ -78,11 +78,10 @@ android:icon="@drawable/ic_tilt" android:title="@string/action_tilt" /> - + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index 6b30fa7ac..6caf0f7df 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -20,6 +20,7 @@ Animate Coordinate Change Custom Layer Directions Activity + Geocoder Activity Double Map Activity Main Activity Controls From 3797bbf75c783900b6fa9af1942953c624c2e588 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 20 Jan 2016 11:26:34 -0500 Subject: [PATCH 19/19] [android] #3537 - Updating version to 3.1.0 for release and fabric --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- .../fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index 8b50b5b17..bd2d4f385 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=3.1.0-SNAPSHOT +VERSION_NAME=3.1.0 POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native diff --git a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties index 030ebae5c..e09bb0110 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties +++ b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties @@ -1,3 +1,3 @@ fabric-identifier=com.mapbox.mapboxsdk.mapbox-android-sdk -fabric-version=3.0.0 +fabric-version=3.1.0 fabric-build-type=binary