Merge remote-tracking branch 'mapbox/master' into 2317-espresso
Conflicts: android/java/MapboxGLAndroidSDKTestApp/build.gradle
3
android/java/.gitignore
vendored
@@ -18,3 +18,6 @@ local.properties
|
||||
|
||||
# Token file
|
||||
MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt
|
||||
|
||||
# Twitter Fabric / Crashlytics
|
||||
fabric.properties
|
||||
|
||||
@@ -3,7 +3,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0'
|
||||
}
|
||||
}
|
||||
@@ -28,10 +28,11 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'commons-validator:commons-validator:1.4.1'
|
||||
compile 'com.android.support:support-annotations:22.1.1'
|
||||
compile 'com.android.support:support-v4:22.1.1'
|
||||
compile 'com.squareup.okhttp:okhttp:2.3.0'
|
||||
compile 'com.android.support:support-annotations:23.0.1'
|
||||
compile 'com.android.support:support-v4:23.0.1'
|
||||
compile 'com.android.support:design:23.0.1'
|
||||
compile 'com.squareup.okhttp:okhttp:2.4.0'
|
||||
compile 'com.mapzen.android:lost:1.0.1'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -64,9 +65,8 @@ android {
|
||||
}
|
||||
|
||||
release {
|
||||
minifyEnabled false
|
||||
jniDebuggable false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
consumerProguardFiles 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ POM_LICENCE_DIST=repo
|
||||
POM_DEVELOPER_ID=mapbox
|
||||
POM_DEVELOPER_NAME=Mapbox
|
||||
|
||||
ANDROID_MIN_SDK=8
|
||||
ANDROID_BUILD_TARGET_SDK_VERSION=22
|
||||
ANDROID_BUILD_TOOLS_VERSION=22.0.1
|
||||
ANDROID_BUILD_SDK_VERSION=22
|
||||
ANDROID_MIN_SDK=15
|
||||
ANDROID_BUILD_TARGET_SDK_VERSION=23
|
||||
ANDROID_BUILD_TOOLS_VERSION=23.0.1
|
||||
ANDROID_BUILD_SDK_VERSION=23
|
||||
|
||||
POM_NAME=Mapbox GL Android SDK
|
||||
POM_ARTIFACT_ID=mapbox-gl-android-sdk
|
||||
|
||||
24
android/java/MapboxGLAndroidSDK/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ../sdk/tools/proguard/proguard-android.txt,
|
||||
# contents of this file will be appended into proguard-android.txt
|
||||
|
||||
# Square okio, ignoring warnings,
|
||||
# see https://github.com/square/okio/issues/60
|
||||
-dontwarn okio.**
|
||||
|
||||
# Package: annotations
|
||||
-keep class com.mapbox.mapboxgl.annotations.** { *; }
|
||||
|
||||
# Package: geometry
|
||||
-keep class com.mapbox.mapboxgl.geometry.** { *; }
|
||||
|
||||
# Package: http
|
||||
-keep class com.mapbox.mapboxgl.http.** { *; }
|
||||
|
||||
# Package views
|
||||
-keep class com.mapbox.mapboxgl.views.MapView**
|
||||
-keep class com.mapbox.mapboxgl.views.NativeMapView**
|
||||
-keepclassmembers class com.mapbox.mapboxgl.views.NativeMapView** {
|
||||
*;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mapbox.mapboxgl.views">
|
||||
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
package com.almeros.android.multitouch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com)
|
||||
* Copyright (c) 2013, Almer Thie (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public abstract class BaseGestureDetector {
|
||||
protected final Context mContext;
|
||||
protected boolean mGestureInProgress;
|
||||
|
||||
protected MotionEvent mPrevEvent;
|
||||
protected MotionEvent mCurrEvent;
|
||||
|
||||
protected float mCurrPressure;
|
||||
protected float mPrevPressure;
|
||||
protected long mTimeDelta;
|
||||
|
||||
|
||||
/**
|
||||
* This value is the threshold ratio between the previous combined pressure
|
||||
* and the current combined pressure. When pressure decreases rapidly
|
||||
* between events the position values can often be imprecise, as it usually
|
||||
* indicates that the user is in the process of lifting a pointer off of the
|
||||
* device. This value was tuned experimentally.
|
||||
*/
|
||||
protected static final float PRESSURE_THRESHOLD = 0.67f;
|
||||
|
||||
|
||||
public BaseGestureDetector(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* All gesture detectors need to be called through this method to be able to
|
||||
* detect gestures. This method delegates work to handler methods
|
||||
* (handleStartProgressEvent, handleInProgressEvent) implemented in
|
||||
* extending classes.
|
||||
*
|
||||
* @param event MotionEvent
|
||||
* @return true
|
||||
*/
|
||||
public boolean onTouchEvent(MotionEvent event){
|
||||
final int actionCode = event.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (!mGestureInProgress) {
|
||||
handleStartProgressEvent(actionCode, event);
|
||||
} else {
|
||||
handleInProgressEvent(actionCode, event);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current event occurred when NO gesture is in progress
|
||||
* yet. The handling in this implementation may set the gesture in progress
|
||||
* (via mGestureInProgress) or out of progress
|
||||
* @param actionCode Action Code from MotionEvent
|
||||
* @param event MotionEvent
|
||||
*/
|
||||
protected abstract void handleStartProgressEvent(int actionCode, MotionEvent event);
|
||||
|
||||
/**
|
||||
* Called when the current event occurred when a gesture IS in progress. The
|
||||
* handling in this implementation may set the gesture out of progress (via
|
||||
* mGestureInProgress).
|
||||
* @param actionCode Action Code from MotionEvent
|
||||
* @param event MotionEvent
|
||||
*/
|
||||
protected abstract void handleInProgressEvent(int actionCode, MotionEvent event);
|
||||
|
||||
|
||||
protected void updateStateByEvent(MotionEvent curr){
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
|
||||
// Reset mCurrEvent
|
||||
if (mCurrEvent != null) {
|
||||
mCurrEvent.recycle();
|
||||
mCurrEvent = null;
|
||||
}
|
||||
mCurrEvent = MotionEvent.obtain(curr);
|
||||
|
||||
|
||||
// Delta time
|
||||
mTimeDelta = curr.getEventTime() - prev.getEventTime();
|
||||
|
||||
// Pressure
|
||||
mCurrPressure = curr.getPressure(curr.getActionIndex());
|
||||
mPrevPressure = prev.getPressure(prev.getActionIndex());
|
||||
}
|
||||
|
||||
protected void resetState() {
|
||||
if (mPrevEvent != null) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = null;
|
||||
}
|
||||
if (mCurrEvent != null) {
|
||||
mCurrEvent.recycle();
|
||||
mCurrEvent = null;
|
||||
}
|
||||
mGestureInProgress = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a gesture is currently in progress.
|
||||
* @return {@code true} if a gesture is currently in progress, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isInProgress() {
|
||||
return mGestureInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time difference in milliseconds between the previous accepted
|
||||
* GestureDetector event and the current GestureDetector event.
|
||||
*
|
||||
* @return Time difference since the last move event in milliseconds.
|
||||
*/
|
||||
public long getTimeDelta() {
|
||||
return mTimeDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event time of the current GestureDetector event being
|
||||
* processed.
|
||||
*
|
||||
* @return Current GestureDetector event time in milliseconds.
|
||||
*/
|
||||
public long getEventTime() {
|
||||
return mCurrEvent.getEventTime();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
package com.almeros.android.multitouch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
import com.almeros.android.multitouch.BaseGestureDetector;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com)
|
||||
* Copyright (c) 2013, Almer Thie (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public class MoveGestureDetector extends BaseGestureDetector {
|
||||
|
||||
/**
|
||||
* Listener which must be implemented which is used by MoveGestureDetector
|
||||
* to perform callbacks to any implementing class which is registered to a
|
||||
* MoveGestureDetector via the constructor.
|
||||
*
|
||||
* @see MoveGestureDetector.SimpleOnMoveGestureListener
|
||||
*/
|
||||
public interface OnMoveGestureListener {
|
||||
public boolean onMove(MoveGestureDetector detector);
|
||||
public boolean onMoveBegin(MoveGestureDetector detector);
|
||||
public void onMoveEnd(MoveGestureDetector detector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class which may be extended and where the methods may be
|
||||
* implemented. This way it is not necessary to implement all methods
|
||||
* of OnMoveGestureListener.
|
||||
*/
|
||||
public static class SimpleOnMoveGestureListener implements OnMoveGestureListener {
|
||||
public boolean onMove(MoveGestureDetector detector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onMoveBegin(MoveGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onMoveEnd(MoveGestureDetector detector) {
|
||||
// Do nothing, overridden implementation may be used
|
||||
}
|
||||
}
|
||||
|
||||
private static final PointF FOCUS_DELTA_ZERO = new PointF();
|
||||
|
||||
private final OnMoveGestureListener mListener;
|
||||
|
||||
private PointF mCurrFocusInternal;
|
||||
private PointF mPrevFocusInternal;
|
||||
private PointF mFocusExternal = new PointF();
|
||||
private PointF mFocusDeltaExternal = new PointF();
|
||||
|
||||
|
||||
public MoveGestureDetector(Context context, OnMoveGestureListener listener) {
|
||||
super(context);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleStartProgressEvent(int actionCode, MotionEvent event){
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
resetState(); // In case we missed an UP/CANCEL event
|
||||
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
mTimeDelta = 0;
|
||||
|
||||
updateStateByEvent(event);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mGestureInProgress = mListener.onMoveBegin(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInProgressEvent(int actionCode, MotionEvent event){
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mListener.onMoveEnd(this);
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
updateStateByEvent(event);
|
||||
|
||||
// Only accept the event if our relative pressure is within
|
||||
// a certain limit. This can help filter shaky data as a
|
||||
// finger is lifted.
|
||||
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
|
||||
final boolean updatePrevious = mListener.onMove(this);
|
||||
if (updatePrevious) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateStateByEvent(MotionEvent curr) {
|
||||
super.updateStateByEvent(curr);
|
||||
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
|
||||
// Focus intenal
|
||||
mCurrFocusInternal = determineFocalPoint(curr);
|
||||
mPrevFocusInternal = determineFocalPoint(prev);
|
||||
|
||||
// Focus external
|
||||
// - Prevent skipping of focus delta when a finger is added or removed
|
||||
boolean mSkipNextMoveEvent = prev.getPointerCount() != curr.getPointerCount();
|
||||
mFocusDeltaExternal = mSkipNextMoveEvent ? FOCUS_DELTA_ZERO : new PointF(mCurrFocusInternal.x - mPrevFocusInternal.x, mCurrFocusInternal.y - mPrevFocusInternal.y);
|
||||
|
||||
// - Don't directly use mFocusInternal (or skipping will occur). Add
|
||||
// unskipped delta values to mFocusExternal instead.
|
||||
mFocusExternal.x += mFocusDeltaExternal.x;
|
||||
mFocusExternal.y += mFocusDeltaExternal.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine (multi)finger focal point (a.k.a. center point between all
|
||||
* fingers)
|
||||
*
|
||||
* @param MotionEvent e
|
||||
* @return PointF focal point
|
||||
*/
|
||||
private PointF determineFocalPoint(MotionEvent e){
|
||||
// Number of fingers on screen
|
||||
final int pCount = e.getPointerCount();
|
||||
float x = 0f;
|
||||
float y = 0f;
|
||||
|
||||
for(int i = 0; i < pCount; i++){
|
||||
x += e.getX(i);
|
||||
y += e.getY(i);
|
||||
}
|
||||
|
||||
return new PointF(x/pCount, y/pCount);
|
||||
}
|
||||
|
||||
public float getFocusX() {
|
||||
return mFocusExternal.x;
|
||||
}
|
||||
|
||||
public float getFocusY() {
|
||||
return mFocusExternal.y;
|
||||
}
|
||||
|
||||
public PointF getFocusDelta() {
|
||||
return mFocusDeltaExternal;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package com.almeros.android.multitouch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com)
|
||||
* Copyright (c) 2013, Almer Thie (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public class RotateGestureDetector extends TwoFingerGestureDetector {
|
||||
|
||||
/**
|
||||
* Listener which must be implemented which is used by RotateGestureDetector
|
||||
* to perform callbacks to any implementing class which is registered to a
|
||||
* RotateGestureDetector via the constructor.
|
||||
*
|
||||
* @see RotateGestureDetector.SimpleOnRotateGestureListener
|
||||
*/
|
||||
public interface OnRotateGestureListener {
|
||||
public boolean onRotate(RotateGestureDetector detector);
|
||||
public boolean onRotateBegin(RotateGestureDetector detector);
|
||||
public void onRotateEnd(RotateGestureDetector detector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class which may be extended and where the methods may be
|
||||
* implemented. This way it is not necessary to implement all methods
|
||||
* of OnRotateGestureListener.
|
||||
*/
|
||||
public static class SimpleOnRotateGestureListener implements OnRotateGestureListener {
|
||||
public boolean onRotate(RotateGestureDetector detector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onRotateBegin(RotateGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onRotateEnd(RotateGestureDetector detector) {
|
||||
// Do nothing, overridden implementation may be used
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final OnRotateGestureListener mListener;
|
||||
private boolean mSloppyGesture;
|
||||
|
||||
public RotateGestureDetector(Context context, OnRotateGestureListener listener) {
|
||||
super(context);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleStartProgressEvent(int actionCode, MotionEvent event){
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// At least the second finger is on screen now
|
||||
|
||||
resetState(); // In case we missed an UP/CANCEL event
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
mTimeDelta = 0;
|
||||
|
||||
updateStateByEvent(event);
|
||||
|
||||
// See if we have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if(!mSloppyGesture){
|
||||
// No, start gesture now
|
||||
mGestureInProgress = mListener.onRotateBegin(this);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
// See if we still have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if(!mSloppyGesture){
|
||||
// No, start normal gesture now
|
||||
mGestureInProgress = mListener.onRotateBegin(this);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void handleInProgressEvent(int actionCode, MotionEvent event){
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
// Gesture ended but
|
||||
updateStateByEvent(event);
|
||||
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onRotateEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onRotateEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
updateStateByEvent(event);
|
||||
|
||||
// Only accept the event if our relative pressure is within
|
||||
// a certain limit. This can help filter shaky data as a
|
||||
// finger is lifted.
|
||||
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
|
||||
final boolean updatePrevious = mListener.onRotate(this);
|
||||
if (updatePrevious) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
super.resetState();
|
||||
mSloppyGesture = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the rotation difference from the previous rotate event to the current
|
||||
* event.
|
||||
*
|
||||
* @return The current rotation //difference in degrees.
|
||||
*/
|
||||
public float getRotationDegreesDelta() {
|
||||
double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX) - Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX);
|
||||
return (float) (diffRadians * 180 / Math.PI);
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
package com.almeros.android.multitouch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* @author Robert Nordan (robert.nordan@norkart.no)
|
||||
*
|
||||
* Copyright (c) 2013, Norkart AS
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public class ShoveGestureDetector extends TwoFingerGestureDetector {
|
||||
|
||||
/**
|
||||
* Listener which must be implemented which is used by ShoveGestureDetector
|
||||
* to perform callbacks to any implementing class which is registered to a
|
||||
* ShoveGestureDetector via the constructor.
|
||||
*
|
||||
* @see ShoveGestureDetector.SimpleOnShoveGestureListener
|
||||
*/
|
||||
public interface OnShoveGestureListener {
|
||||
public boolean onShove(ShoveGestureDetector detector);
|
||||
public boolean onShoveBegin(ShoveGestureDetector detector);
|
||||
public void onShoveEnd(ShoveGestureDetector detector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class which may be extended and where the methods may be
|
||||
* implemented. This way it is not necessary to implement all methods
|
||||
* of OnShoveGestureListener.
|
||||
*/
|
||||
public static class SimpleOnShoveGestureListener implements OnShoveGestureListener {
|
||||
public boolean onShove(ShoveGestureDetector detector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onShoveBegin(ShoveGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onShoveEnd(ShoveGestureDetector detector) {
|
||||
// Do nothing, overridden implementation may be used
|
||||
}
|
||||
}
|
||||
|
||||
private float mPrevAverageY;
|
||||
private float mCurrAverageY;
|
||||
|
||||
private final OnShoveGestureListener mListener;
|
||||
private boolean mSloppyGesture;
|
||||
|
||||
public ShoveGestureDetector(Context context, OnShoveGestureListener listener) {
|
||||
super(context);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleStartProgressEvent(int actionCode, MotionEvent event){
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// At least the second finger is on screen now
|
||||
|
||||
resetState(); // In case we missed an UP/CANCEL event
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
mTimeDelta = 0;
|
||||
|
||||
updateStateByEvent(event);
|
||||
|
||||
// See if we have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if(!mSloppyGesture){
|
||||
// No, start gesture now
|
||||
mGestureInProgress = mListener.onShoveBegin(this);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
// See if we still have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if(!mSloppyGesture){
|
||||
// No, start normal gesture now
|
||||
mGestureInProgress = mListener.onShoveBegin(this);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void handleInProgressEvent(int actionCode, MotionEvent event){
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
// Gesture ended but
|
||||
updateStateByEvent(event);
|
||||
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onShoveEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onShoveEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
updateStateByEvent(event);
|
||||
|
||||
// Only accept the event if our relative pressure is within
|
||||
// a certain limit. This can help filter shaky data as a
|
||||
// finger is lifted. Also check that shove is meaningful.
|
||||
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD
|
||||
&& Math.abs(getShovePixelsDelta()) > 0.5f) {
|
||||
final boolean updatePrevious = mListener.onShove(this);
|
||||
if (updatePrevious) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
super.resetState();
|
||||
mSloppyGesture = false;
|
||||
mPrevAverageY = 0.0f;
|
||||
mCurrAverageY = 0.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateStateByEvent(MotionEvent curr){
|
||||
super.updateStateByEvent(curr);
|
||||
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
float py0 = prev.getY(0);
|
||||
float py1 = prev.getY(1);
|
||||
mPrevAverageY = (py0 + py1) / 2.0f;
|
||||
|
||||
float cy0 = curr.getY(0);
|
||||
float cy1 = curr.getY(1);
|
||||
mCurrAverageY = (cy0 + cy1) / 2.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSloppyGesture(MotionEvent event){
|
||||
boolean sloppy = super.isSloppyGesture(event);
|
||||
if (sloppy)
|
||||
return true;
|
||||
|
||||
// If it's not traditionally sloppy, we check if the angle between fingers
|
||||
// is acceptable.
|
||||
double angle = Math.abs(Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX));
|
||||
//about 20 degrees, left or right
|
||||
return !(( 0.0f < angle && angle < 0.35f)
|
||||
|| 2.79f < angle && angle < Math.PI);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the distance in pixels from the previous shove event to the current
|
||||
* event.
|
||||
*
|
||||
* @return The current distance in pixels.
|
||||
*/
|
||||
public float getShovePixelsDelta() {
|
||||
return mCurrAverageY - mPrevAverageY;
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
package com.almeros.android.multitouch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com)
|
||||
* Copyright (c) 2013, Almer Thie (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public abstract class TwoFingerGestureDetector extends BaseGestureDetector {
|
||||
|
||||
private final float mEdgeSlop;
|
||||
private float mRightSlopEdge;
|
||||
private float mBottomSlopEdge;
|
||||
|
||||
protected float mPrevFingerDiffX;
|
||||
protected float mPrevFingerDiffY;
|
||||
protected float mCurrFingerDiffX;
|
||||
protected float mCurrFingerDiffY;
|
||||
|
||||
private float mCurrLen;
|
||||
private float mPrevLen;
|
||||
|
||||
public TwoFingerGestureDetector(Context context) {
|
||||
super(context);
|
||||
|
||||
ViewConfiguration config = ViewConfiguration.get(context);
|
||||
mEdgeSlop = config.getScaledEdgeSlop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract void handleStartProgressEvent(int actionCode, MotionEvent event);
|
||||
|
||||
@Override
|
||||
protected abstract void handleInProgressEvent(int actionCode, MotionEvent event);
|
||||
|
||||
protected void updateStateByEvent(MotionEvent curr){
|
||||
super.updateStateByEvent(curr);
|
||||
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
|
||||
mCurrLen = -1;
|
||||
mPrevLen = -1;
|
||||
|
||||
// Previous
|
||||
final float px0 = prev.getX(0);
|
||||
final float py0 = prev.getY(0);
|
||||
final float px1 = prev.getX(1);
|
||||
final float py1 = prev.getY(1);
|
||||
final float pvx = px1 - px0;
|
||||
final float pvy = py1 - py0;
|
||||
mPrevFingerDiffX = pvx;
|
||||
mPrevFingerDiffY = pvy;
|
||||
|
||||
// Current
|
||||
final float cx0 = curr.getX(0);
|
||||
final float cy0 = curr.getY(0);
|
||||
final float cx1 = curr.getX(1);
|
||||
final float cy1 = curr.getY(1);
|
||||
final float cvx = cx1 - cx0;
|
||||
final float cvy = cy1 - cy0;
|
||||
mCurrFingerDiffX = cvx;
|
||||
mCurrFingerDiffY = cvy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current distance between the two pointers forming the
|
||||
* gesture in progress.
|
||||
*
|
||||
* @return Distance between pointers in pixels.
|
||||
*/
|
||||
public float getCurrentSpan() {
|
||||
if (mCurrLen == -1) {
|
||||
final float cvx = mCurrFingerDiffX;
|
||||
final float cvy = mCurrFingerDiffY;
|
||||
mCurrLen = (float)Math.sqrt(cvx*cvx + cvy*cvy);
|
||||
}
|
||||
return mCurrLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the previous distance between the two pointers forming the
|
||||
* gesture in progress.
|
||||
*
|
||||
* @return Previous distance between pointers in pixels.
|
||||
*/
|
||||
public float getPreviousSpan() {
|
||||
if (mPrevLen == -1) {
|
||||
final float pvx = mPrevFingerDiffX;
|
||||
final float pvy = mPrevFingerDiffY;
|
||||
mPrevLen = (float)Math.sqrt(pvx*pvx + pvy*pvy);
|
||||
}
|
||||
return mPrevLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* MotionEvent has no getRawX(int) method; simulate it pending future API approval.
|
||||
* @param event
|
||||
* @param pointerIndex
|
||||
* @return Raw X value or 0
|
||||
*/
|
||||
protected static float getRawX(MotionEvent event, int pointerIndex) {
|
||||
float offset = event.getX() - event.getRawX();
|
||||
if(pointerIndex < event.getPointerCount()){
|
||||
return event.getX(pointerIndex) + offset;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* MotionEvent has no getRawY(int) method; simulate it pending future API approval.
|
||||
* @param event
|
||||
* @param pointerIndex
|
||||
* @return Raw Y value or 0
|
||||
*/
|
||||
protected static float getRawY(MotionEvent event, int pointerIndex) {
|
||||
float offset = event.getY() - event.getRawY();
|
||||
if(pointerIndex < event.getPointerCount()){
|
||||
return event.getY(pointerIndex) + offset;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have a sloppy gesture. Sloppy gestures can happen if the edge
|
||||
* of the user's hand is touching the screen, for example.
|
||||
*
|
||||
* @param event MotionEvent
|
||||
* @return {@code true} if is a sloppy gesture, {@code false} if not
|
||||
*/
|
||||
protected boolean isSloppyGesture(MotionEvent event){
|
||||
// As orientation can change, query the metrics in touch down
|
||||
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
|
||||
mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
|
||||
mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
|
||||
|
||||
final float edgeSlop = mEdgeSlop;
|
||||
final float rightSlop = mRightSlopEdge;
|
||||
final float bottomSlop = mBottomSlopEdge;
|
||||
|
||||
final float x0 = event.getRawX();
|
||||
final float y0 = event.getRawY();
|
||||
final float x1 = getRawX(event, 1);
|
||||
final float y1 = getRawY(event, 1);
|
||||
|
||||
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
|
||||
|| x0 > rightSlop || y0 > bottomSlop;
|
||||
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
|
||||
|| x1 > rightSlop || y1 > bottomSlop;
|
||||
|
||||
if (p0sloppy && p1sloppy) {
|
||||
return true;
|
||||
} else if (p0sloppy) {
|
||||
return true;
|
||||
} else if (p1sloppy) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.views.MapView;
|
||||
|
||||
public abstract class Annotation implements Comparable<Annotation> {
|
||||
|
||||
/**
|
||||
* The annotation id
|
||||
*
|
||||
* Internal C++ id is stored as unsigned int.
|
||||
*/
|
||||
protected long id = -1; // -1 unless added to a MapView
|
||||
protected MapView mapView;
|
||||
|
||||
float alpha = 1.0f;
|
||||
boolean visible = true;
|
||||
|
||||
public Annotation() {}
|
||||
|
||||
public float getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (mapView == null) return;
|
||||
mapView.removeAnnotation(this);
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setMapView(MapView mapView) {
|
||||
this.mapView = mapView;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
// TODO: Implement getZIndex of Google Maps Android API
|
||||
// public float getZIndex() {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement setZIndex of Google Maps Android API
|
||||
// public void setZIndex(float zIndex) {
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (o instanceof Annotation) {
|
||||
Annotation comp = (Annotation) o;
|
||||
return id == comp.id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Annotation annotation) {
|
||||
|
||||
if (annotation == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (id < annotation.getId()) {
|
||||
return 1;
|
||||
} else if (id > annotation.getId()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Equal
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
public abstract class AnnotationOptions {
|
||||
|
||||
protected Annotation annotation;
|
||||
|
||||
public AnnotationOptions() {}
|
||||
|
||||
public AnnotationOptions alpha(float alpha) {
|
||||
annotation.alpha = alpha;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return annotation.alpha;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return annotation.visible;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
*
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1882
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1726
|
||||
*/
|
||||
public class Circle extends Annotation {
|
||||
|
||||
LatLng center;
|
||||
int fillColor = Color.BLACK;
|
||||
double radius;
|
||||
int strokeColor = Color.BLACK;
|
||||
float strokeWidth = 10; // Google Maps API defaults to 10
|
||||
|
||||
public LatLng getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the circle's radius, in meters.
|
||||
*
|
||||
* @return radius in meters
|
||||
*/
|
||||
public double getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
public int getStrokeColor() {
|
||||
return strokeColor;
|
||||
}
|
||||
|
||||
public float getStrokeWidth() {
|
||||
return strokeWidth;
|
||||
}
|
||||
|
||||
public void setCenter(LatLng center) {
|
||||
this.center = center;
|
||||
}
|
||||
|
||||
public void setFillColor(int color) {
|
||||
fillColor = color;
|
||||
}
|
||||
|
||||
public void setRadius(double radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public void setStrokeColor (int color) {
|
||||
strokeColor = color;
|
||||
}
|
||||
|
||||
public void setStrokeWidth (float width) {
|
||||
strokeWidth = width;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
*
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1882
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1726
|
||||
*/
|
||||
public class CircleOptions extends AnnotationOptions {
|
||||
|
||||
private Circle circle;
|
||||
|
||||
public CircleOptions() {
|
||||
circle = new Circle();
|
||||
}
|
||||
public CircleOptions center(LatLng center) {
|
||||
circle.center = center;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CircleOptions fillColor(int color) {
|
||||
circle.fillColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LatLng getCenter() {
|
||||
return circle.center;
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return circle.fillColor;
|
||||
}
|
||||
|
||||
public double getRadius() {
|
||||
return circle.radius;
|
||||
}
|
||||
|
||||
public int getStrokeColor () {
|
||||
return circle.strokeColor;
|
||||
}
|
||||
|
||||
public float getStrokeWidth() {
|
||||
return circle.strokeWidth;
|
||||
}
|
||||
|
||||
public CircleOptions radius (double radius) {
|
||||
circle.radius = radius;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CircleOptions strokeColor(int color) {
|
||||
circle.strokeColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CircleOptions strokeWidth (float width) {
|
||||
circle.strokeWidth = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
import com.mapbox.mapboxgl.views.MapView;
|
||||
|
||||
/**
|
||||
* A tooltip view
|
||||
*/
|
||||
public class InfoWindow {
|
||||
|
||||
private Marker boundMarker;
|
||||
private MapView mMapView;
|
||||
private boolean mIsVisible;
|
||||
protected View mView;
|
||||
|
||||
static int mTitleId = 0;
|
||||
static int mDescriptionId = 0;
|
||||
static int mSubDescriptionId = 0;
|
||||
static int mImageId = 0;
|
||||
|
||||
public InfoWindow(int layoutResId, MapView mapView) {
|
||||
mMapView = mapView;
|
||||
mIsVisible = false;
|
||||
Context context = mapView.getContext();
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mView = inflater.inflate(layoutResId, (ViewGroup) mapView, false);
|
||||
|
||||
if (mTitleId == 0) {
|
||||
setResIds(mapView.getContext());
|
||||
}
|
||||
|
||||
// default behavior: close it when clicking on the tooltip:
|
||||
setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent e) {
|
||||
if (e.getAction() == MotionEvent.ACTION_UP) {
|
||||
close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public InfoWindow(View view, MapView mapView) {
|
||||
mMapView = mapView;
|
||||
mIsVisible = false;
|
||||
ViewGroup parent = (ViewGroup) mapView.getParent();
|
||||
Context context = mapView.getContext();
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mView = view;
|
||||
|
||||
// default behavior: close it when clicking on the tooltip:
|
||||
setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent e) {
|
||||
if (e.getAction() == MotionEvent.ACTION_UP) {
|
||||
close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* open the window at the specified position.
|
||||
*
|
||||
* @param object the graphical object on which is hooked the view
|
||||
* @param position to place the window on the map
|
||||
* @param offsetX (&offsetY) the offset of the view to the position, in pixels.
|
||||
* This allows to offset the view from the object position.
|
||||
* @return this infowindow
|
||||
*/
|
||||
public InfoWindow open(Marker object, LatLng position, int offsetX, int offsetY) {
|
||||
onOpen(object);
|
||||
MapView.LayoutParams lp = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, MapView.LayoutParams.WRAP_CONTENT);
|
||||
mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
||||
|
||||
PointF coords = mMapView.toScreenLocation(position);
|
||||
double y = mMapView.getTopOffsetPixelsForAnnotationSymbol(object.sprite);
|
||||
y = y * mMapView.getScreenDensity();
|
||||
|
||||
// Flip y coordinate as Android view origin is upper left corner
|
||||
coords.y = mMapView.getHeight() - coords.y;
|
||||
lp.leftMargin = (int) coords.x - (mView.getMeasuredWidth() / 2);
|
||||
// Add y because it's a negative value
|
||||
lp.topMargin = (int) coords.y - mView.getMeasuredHeight() + (int) y;
|
||||
|
||||
close(); //if it was already opened
|
||||
mMapView.addView(mView, lp);
|
||||
mIsVisible = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this InfoWindow if it is visible, otherwise don't do anything.
|
||||
*
|
||||
* @return this info window
|
||||
*/
|
||||
public InfoWindow close() {
|
||||
if (mIsVisible) {
|
||||
mIsVisible = false;
|
||||
((ViewGroup) mView.getParent()).removeView(mView);
|
||||
// this.boundMarker.blur();
|
||||
setBoundMarker(null);
|
||||
onClose();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Android view. This allows to set its content.
|
||||
*
|
||||
* @return the Android view
|
||||
*/
|
||||
public View getView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapView this InfoWindow is bound to
|
||||
*
|
||||
* @return the mapView
|
||||
*/
|
||||
public MapView getMapView() {
|
||||
return mMapView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the view that is displayed when the InfoWindow opens.
|
||||
* This retrieves data from overlayItem and shows it in the tooltip.
|
||||
*
|
||||
* @param overlayItem the tapped overlay item
|
||||
*/
|
||||
public void onOpen(Marker overlayItem) {
|
||||
String title = overlayItem.getTitle();
|
||||
((TextView) mView.findViewById(mTitleId /*R.id.title*/)).setText(title);
|
||||
String snippet = overlayItem.getSnippet();
|
||||
((TextView) mView.findViewById(mDescriptionId /*R.id.description*/)).setText(snippet);
|
||||
|
||||
/*
|
||||
//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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void onClose() {
|
||||
//by default, do nothing
|
||||
}
|
||||
|
||||
public InfoWindow setBoundMarker(Marker aBoundMarker) {
|
||||
this.boundMarker = aBoundMarker;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Marker getBoundMarker() {
|
||||
return boundMarker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a context, set the resource ids for the layout
|
||||
* of the InfoWindow.
|
||||
*
|
||||
* @param 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to override default touch events handling on InfoWindow (ie, close automatically)
|
||||
*
|
||||
* @param listener New View.OnTouchListener to use
|
||||
*/
|
||||
public void setOnTouchListener(View.OnTouchListener listener) {
|
||||
mView.setOnTouchListener(listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
public class InfoWindowTipView extends View {
|
||||
|
||||
private Paint mPaint;
|
||||
private Path mPath;
|
||||
|
||||
public InfoWindowTipView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mPath = new Path();
|
||||
|
||||
this.mPaint = new Paint();
|
||||
this.mPaint.setColor(Color.WHITE);
|
||||
this.mPaint.setAntiAlias(true);
|
||||
this.mPaint.setStrokeWidth(0.0f);
|
||||
this.mPaint.setStyle(Paint.Style.FILL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
int height = getMeasuredHeight();
|
||||
int width = getMeasuredWidth();
|
||||
|
||||
mPath.rewind();
|
||||
mPath.moveTo((width / 2) - height, 0);
|
||||
mPath.lineTo((width / 2) + height, 0);
|
||||
mPath.lineTo((width / 2), height);
|
||||
mPath.lineTo((width / 2) - height, 0);
|
||||
canvas.drawPath(mPath, this.mPaint);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.view.View;
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
import com.mapbox.mapboxgl.views.R;
|
||||
|
||||
public class Marker extends Annotation {
|
||||
|
||||
float anchorU;
|
||||
float anchorV;
|
||||
boolean draggable;
|
||||
boolean flat;
|
||||
float infoWindowAnchorU;
|
||||
float infoWindowAnchorV;
|
||||
LatLng position;
|
||||
float rotation;
|
||||
String snippet;
|
||||
String sprite = "default_marker";
|
||||
String title;
|
||||
private InfoWindow infoWindow = null;
|
||||
|
||||
private boolean infoWindowShown = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Marker() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* If two markers have the same LatLng, they are equal.
|
||||
*
|
||||
* @param other object
|
||||
* @return boolean - do they have the same LatLng
|
||||
*/
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Marker)) return false;
|
||||
double lat = position.getLatitude();
|
||||
double lng = position.getLongitude();
|
||||
LatLng otherPosition = ((Marker)other).getPosition();
|
||||
double otherLat = otherPosition.getLatitude();
|
||||
double otherLng = otherPosition.getLongitude();
|
||||
return (lat == otherLat && otherLng == lng);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
public Point getAnchor() {
|
||||
return new Point((int)anchorU, (int)anchorV);
|
||||
}
|
||||
|
||||
public float getAnchorU() {
|
||||
return anchorU;
|
||||
}
|
||||
|
||||
public float getAnchorV() {
|
||||
return anchorV;
|
||||
}
|
||||
|
||||
public LatLng getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return snippet;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void hideInfoWindow() {
|
||||
infoWindow.close();
|
||||
infoWindowShown = false;
|
||||
}
|
||||
|
||||
public boolean isDraggable() {
|
||||
return draggable;
|
||||
}
|
||||
|
||||
public boolean isFlat() {
|
||||
return flat;
|
||||
}
|
||||
|
||||
public boolean isInfoWindowShown () {
|
||||
return infoWindowShown;
|
||||
}
|
||||
|
||||
public void setAnchor(float u, float v) {
|
||||
this.anchorU = u;
|
||||
this.anchorV = v;
|
||||
}
|
||||
|
||||
public void setDraggable(boolean draggable) {
|
||||
this.draggable = draggable;
|
||||
}
|
||||
|
||||
public void setFlat(boolean flat) {
|
||||
this.flat = flat;
|
||||
}
|
||||
|
||||
public void setInfoWindowAnchor(float u, float v) {
|
||||
infoWindowAnchorU = u;
|
||||
infoWindowAnchorV = v;
|
||||
}
|
||||
|
||||
public void setPosition(LatLng latlng) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public void setRotation(float rotation) {
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public void setSnippet(String snippet) {
|
||||
this.snippet = snippet;
|
||||
}
|
||||
|
||||
/**
|
||||
* You can specify the name of a sprite to get a marker other than the default marker.
|
||||
* This name can be found in the sprite json file:
|
||||
*
|
||||
* https://github.com/mapbox/mapbox-gl-styles/blob/mb-pages/sprites/mapbox-streets.json
|
||||
*
|
||||
* @param sprite
|
||||
*/
|
||||
public void setSprite(String sprite) {
|
||||
this.sprite = sprite;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void showInfoWindow() {
|
||||
|
||||
if (!isVisible() || mapView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
getInfoWindow().open(this, getPosition(), (int) anchorU, (int) anchorV);
|
||||
getInfoWindow().setBoundMarker(this);
|
||||
infoWindowShown = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to set a custom OnTouchListener for the InfoWindow.
|
||||
* By default the InfoWindow will close on touch.
|
||||
* @param listener Custom OnTouchListener
|
||||
*/
|
||||
public void setInfoWindowOnTouchListener(View.OnTouchListener listener) {
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
getInfoWindow().setOnTouchListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Common internal InfoWindow initialization method
|
||||
* @return InfoWindow for Marker
|
||||
*/
|
||||
private InfoWindow getInfoWindow() {
|
||||
if (infoWindow == null) {
|
||||
infoWindow = new InfoWindow(R.layout.infowindow, mapView);
|
||||
}
|
||||
return infoWindow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
super.setVisible(visible);
|
||||
if (!visible && infoWindowShown) {
|
||||
hideInfoWindow();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Method in Google Maps Android API
|
||||
// public int hashCode()
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// void setIcon(BitmapDescriptor icon) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
public class MarkerOptions extends AnnotationOptions {
|
||||
|
||||
public MarkerOptions() {
|
||||
annotation = new Marker();
|
||||
}
|
||||
|
||||
public MarkerOptions anchor(float u, float v) {
|
||||
((Marker)annotation).anchorU = u;
|
||||
((Marker)annotation).anchorV = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions draggable(boolean draggable) {
|
||||
((Marker)annotation).draggable = draggable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions flat(boolean flat) {
|
||||
((Marker)annotation).flat = flat;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getAnchorU() {
|
||||
return ((Marker)annotation).anchorU;
|
||||
}
|
||||
|
||||
public float getAnchorV() {
|
||||
return ((Marker)annotation).anchorV;
|
||||
}
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// public BitmapDescriptor getIcon () {
|
||||
//
|
||||
// }
|
||||
|
||||
public float getInfoWindowAnchorU() {
|
||||
return ((Marker)annotation).infoWindowAnchorU;
|
||||
}
|
||||
|
||||
public float getInfoWindowAnchorV() {
|
||||
return ((Marker)annotation).infoWindowAnchorV;
|
||||
}
|
||||
|
||||
public Marker getMarker() {
|
||||
return (Marker)annotation;
|
||||
}
|
||||
|
||||
public LatLng getPosition() {
|
||||
return ((Marker)annotation).position;
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return ((Marker)annotation).rotation;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return ((Marker)annotation).snippet;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return ((Marker)annotation).title;
|
||||
}
|
||||
|
||||
public MarkerOptions infoWindowAnchor(float u, float v) {
|
||||
((Marker)annotation).infoWindowAnchorU = u;
|
||||
((Marker)annotation).infoWindowAnchorV = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isDraggable() {
|
||||
return ((Marker)annotation).draggable;
|
||||
}
|
||||
|
||||
public boolean isFlat() {
|
||||
return ((Marker)annotation).flat;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return ((Marker)annotation).visible;
|
||||
}
|
||||
|
||||
public MarkerOptions position(LatLng position) {
|
||||
((Marker)annotation).position = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions rotation(float rotation) {
|
||||
((Marker)annotation).rotation = rotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions snippet(String snippet) {
|
||||
((Marker)annotation).snippet = snippet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions sprite(String sprite) {
|
||||
((Marker)annotation).sprite = sprite;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions title(String title) {
|
||||
((Marker)annotation).title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions visible(boolean visible) {
|
||||
annotation.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// public MarkerOptions icon(BitmapDescriptor icon) {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// public void writeToParcel (Parcel out, int flags)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MultiPoint extends Annotation {
|
||||
|
||||
List<LatLng> points;
|
||||
|
||||
public MultiPoint() {
|
||||
super();
|
||||
points = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the points.
|
||||
*
|
||||
* @return points - as a copy
|
||||
*/
|
||||
public List<LatLng> getPoints() {
|
||||
return new ArrayList<>(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the points of this polyline. This method will take a copy
|
||||
* of the points, so further mutations to points will have no effect
|
||||
* on this polyline.
|
||||
*
|
||||
* @param points
|
||||
*/
|
||||
void setPoints(List<LatLng> points) {
|
||||
this.points = new ArrayList<>(points);
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implement hashCode of Google Maps Android API
|
||||
// public int hashCode() {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement isGeodesic of Google Maps Android API
|
||||
// public boolean isGeodesic() {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement setGeodesic of Google Maps Android API
|
||||
// public void setGeodesic(boolean geodesic) {
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MultiPointOptions extends AnnotationOptions {
|
||||
|
||||
public MultiPointOptions() {}
|
||||
|
||||
public List<LatLng> getPoints() {
|
||||
// the getter gives us a copy, which is the safe thing to do...
|
||||
return ((MultiPoint)annotation).getPoints();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Polygon extends MultiPoint {
|
||||
|
||||
int fillColor = Color.BLACK; // default fillColor is black
|
||||
float strokeAlpha = 1;
|
||||
int strokeColor = Color.BLACK; // default strokeColor is black
|
||||
float strokeWidth = 10; // As specified by Google API Docs (in pixels)
|
||||
|
||||
List<List<LatLng>> holes;
|
||||
|
||||
public Polygon() {
|
||||
super();
|
||||
holes = new ArrayList<>();
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
public List<List<LatLng>> getHoles () {
|
||||
return holes;
|
||||
}
|
||||
|
||||
public int getStrokeColor() {
|
||||
return strokeColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public float getStrokeWidth() {
|
||||
return strokeWidth;
|
||||
}
|
||||
|
||||
public void setFillAlpha(float alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public void setFillColor(int color) {
|
||||
fillColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the holes of this polygon. This method will take a copy of the holes,
|
||||
* so further mutations to holes parameter will have no effect on this polygon.
|
||||
*
|
||||
* @param holes
|
||||
*/
|
||||
public void setHoles(List<? extends List<LatLng>> holes) {
|
||||
this.holes = new ArrayList<>();
|
||||
for (List<LatLng> hole : holes) {
|
||||
this.holes.add(new ArrayList<>(hole));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha (opacity) of the stroke
|
||||
*
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
*/
|
||||
public void setStrokeAlpha(float alpha) {
|
||||
strokeAlpha = alpha;
|
||||
}
|
||||
|
||||
public void setStrokeColor(int color) {
|
||||
strokeColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public void setStrokeWidth(float width) {
|
||||
strokeWidth = width;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implement equals of Google Maps Android API
|
||||
// public boolean equals (Object other) {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement hashCode of Google Maps Android API
|
||||
// public int hashCode () {
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PolygonOptions extends MultiPointOptions {
|
||||
|
||||
public PolygonOptions() {
|
||||
annotation = new Polygon();
|
||||
}
|
||||
|
||||
public PolygonOptions add(LatLng point) {
|
||||
((MultiPoint)annotation).points.add(point);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolygonOptions add(LatLng... points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolygonOptions addAll(Iterable<LatLng> points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1729
|
||||
*
|
||||
* @param points - an iterable (list) of points for cutting a hole
|
||||
* @return PolygonOptions - the options object
|
||||
*/
|
||||
public PolygonOptions addHole (Iterable<LatLng> points) {
|
||||
List<LatLng> hole = new ArrayList<>();
|
||||
for (LatLng point : points) {
|
||||
hole.add(point);
|
||||
}
|
||||
((Polygon)annotation).holes.add(hole);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the polygon.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
* @return PolygonOptions - the options object
|
||||
*/
|
||||
public PolygonOptions fillColor(int color) {
|
||||
((Polygon)annotation).fillColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return ((Polygon)annotation).fillColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1729
|
||||
*
|
||||
* @return a list of lists of points for cutting holes
|
||||
*/
|
||||
public List<List<LatLng>> getHoles() {
|
||||
return ((Polygon)annotation).holes;
|
||||
}
|
||||
|
||||
public Polygon getPolygon() {
|
||||
return ((Polygon)annotation);
|
||||
}
|
||||
|
||||
public int getStrokeColor() {
|
||||
return ((Polygon)annotation).strokeColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
*
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public float getStrokeWidth() {
|
||||
return ((Polygon)annotation).strokeWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the stroke of the polygon.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
* @return PolygonOptions - the options object
|
||||
*/
|
||||
public PolygonOptions strokeColor(int color) {
|
||||
((Polygon)annotation).strokeColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
*
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public PolygonOptions strokeWidth(float width) {
|
||||
((Polygon)annotation).strokeWidth = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolygonOptions visible(boolean visible) {
|
||||
annotation.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: Implement writeToParcel of Google Maps Android API
|
||||
// public void writeToParcel(Parcel out, int flags) {
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Polyline extends MultiPoint {
|
||||
|
||||
int color = Color.BLACK; // default color is black
|
||||
float width = 10; // As specified by Google API Docs (in pixels)
|
||||
|
||||
public Polyline() {
|
||||
super();
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the color of the polyline.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
*/
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the width of the polyline.
|
||||
*
|
||||
* @param width in pixels
|
||||
* @return
|
||||
*/
|
||||
public void setWidth(float width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
// TODO: Implement equals of Google Maps Android API
|
||||
// public boolean equals(Object other) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PolylineOptions extends MultiPointOptions {
|
||||
|
||||
public PolylineOptions() {
|
||||
annotation = new Polyline();
|
||||
}
|
||||
|
||||
public PolylineOptions add(LatLng point) {
|
||||
((MultiPoint)annotation).points.add(point);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolylineOptions add(LatLng... points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolylineOptions addAll(Iterable<LatLng> points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the polyline.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
*/
|
||||
public PolylineOptions color(int color) {
|
||||
((Polyline)annotation).color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return ((Polyline)annotation).color;
|
||||
}
|
||||
|
||||
public Polyline getPolyline() {
|
||||
return ((Polyline)annotation);
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return ((Polyline)annotation).width;
|
||||
}
|
||||
|
||||
public PolylineOptions visible(boolean visible) {
|
||||
annotation.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the width of the polyline.
|
||||
*
|
||||
* @param width in pixels
|
||||
* @return
|
||||
*/
|
||||
public PolylineOptions width(float width) {
|
||||
((Polyline)annotation).width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: Implement writeToParcel of Google Maps Android API
|
||||
// public void writeToParcel(Parcel out, int flags) {
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -119,15 +119,7 @@ public final class BoundingBox implements Parcelable, Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuffer().append("N:")
|
||||
.append(this.mLatNorth)
|
||||
.append("; E:")
|
||||
.append(this.mLonEast)
|
||||
.append("; S:")
|
||||
.append(this.mLatSouth)
|
||||
.append("; W:")
|
||||
.append(this.mLonWest)
|
||||
.toString();
|
||||
return "N:" + this.mLatNorth + "; E:" + this.mLonEast + "; S:" + this.mLatSouth + "; W:" + this.mLonWest;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,17 +156,8 @@ public final class BoundingBox implements Parcelable, Serializable {
|
||||
*/
|
||||
public boolean equals(final BoundingBox other) {
|
||||
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
return other != null && (other == this || mLatNorth == other.getLatNorth() && mLatSouth == other.getLatSouth() && mLonEast == other.getLonEast() && mLonWest == other.getLonWest());
|
||||
|
||||
return mLatNorth == other.getLatNorth()
|
||||
&& mLatSouth == other.getLatSouth()
|
||||
&& mLonEast == other.getLonEast()
|
||||
&& mLonWest == other.getLonWest();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -97,18 +97,8 @@ public class LatLng implements ILatLng, Parcelable, Serializable {
|
||||
|
||||
LatLng latLng = (LatLng) o;
|
||||
|
||||
if (Double.compare(latLng.altitude, altitude) != 0) {
|
||||
return false;
|
||||
}
|
||||
return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 && Double.compare(latLng.longitude, longitude) == 0;
|
||||
|
||||
if (Double.compare(latLng.latitude, latitude) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (Double.compare(latLng.longitude, longitude) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,11 +56,8 @@ public class LatLngZoom extends LatLng implements Parcelable, Serializable {
|
||||
|
||||
LatLngZoom that = (LatLngZoom) o;
|
||||
|
||||
if (Double.compare(that.zoom, zoom) != 0) {
|
||||
return false;
|
||||
}
|
||||
return Double.compare(that.zoom, zoom) == 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,14 +56,8 @@ public class ProjectedMeters implements IProjectedMeters, Parcelable, Serializab
|
||||
|
||||
ProjectedMeters projectedMeters = (ProjectedMeters) o;
|
||||
|
||||
if (Double.compare(projectedMeters.easting, easting) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (Double.compare(projectedMeters.northing, northing) != 0) {
|
||||
return false;
|
||||
}
|
||||
return Double.compare(projectedMeters.easting, easting) == 0 && Double.compare(projectedMeters.northing, northing) == 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.mapbox.mapboxgl.http;
|
||||
|
||||
import com.mapbox.mapboxgl.constants.MapboxConstants;
|
||||
import com.squareup.okhttp.Call;
|
||||
import com.squareup.okhttp.Callback;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
class HTTPContext {
|
||||
|
||||
private static final int CONNECTION_ERROR = 0;
|
||||
private static final int TEMPORARY_ERROR = 1;
|
||||
private static final int PERMANENT_ERROR = 2;
|
||||
|
||||
private static HTTPContext mInstance = null;
|
||||
|
||||
private OkHttpClient mClient;
|
||||
|
||||
private HTTPContext() {
|
||||
super();
|
||||
mClient = new OkHttpClient();
|
||||
}
|
||||
|
||||
public static HTTPContext getInstance() {
|
||||
if (mInstance == null) {
|
||||
mInstance = new HTTPContext();
|
||||
}
|
||||
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
public HTTPRequest createRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) {
|
||||
return new HTTPRequest(nativePtr, resourceUrl, userAgent, etag, modified);
|
||||
}
|
||||
|
||||
public class HTTPRequest implements Callback {
|
||||
private long mNativePtr = 0;
|
||||
|
||||
private Call mCall;
|
||||
private Request mRequest;
|
||||
|
||||
private native void nativeOnFailure(long nativePtr, int type, String message);
|
||||
private native void nativeOnResponse(long nativePtr, int code, String message, String etag, String modified, String cacheControl, String expires, byte[] body);
|
||||
|
||||
private HTTPRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) {
|
||||
mNativePtr = nativePtr;
|
||||
Request.Builder builder = new Request.Builder().url(resourceUrl).tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)).addHeader("User-Agent", userAgent);
|
||||
if (etag.length() > 0) {
|
||||
builder = builder.addHeader("If-None-Match", etag);
|
||||
} else if (modified.length() > 0) {
|
||||
builder = builder.addHeader("If-Modified-Since", modified);
|
||||
}
|
||||
mRequest = builder.build();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mCall = HTTPContext.getInstance().mClient.newCall(mRequest);
|
||||
mCall.enqueue(this);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
mCall.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
int type = PERMANENT_ERROR;
|
||||
if ((e instanceof UnknownHostException) || (e instanceof SocketException) || (e instanceof ProtocolException) || (e instanceof SSLException)) {
|
||||
type = CONNECTION_ERROR;
|
||||
} else if ((e instanceof InterruptedIOException)) {
|
||||
type = TEMPORARY_ERROR;
|
||||
}
|
||||
nativeOnFailure(mNativePtr, type, e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) throws IOException {
|
||||
byte[] body;
|
||||
try {
|
||||
body = response.body().bytes();
|
||||
} catch (IOException e) {
|
||||
onFailure(mRequest, e);
|
||||
return;
|
||||
} finally {
|
||||
response.body().close();
|
||||
}
|
||||
|
||||
nativeOnResponse(mNativePtr, response.code(), response.message(), response.header("ETag"), response.header("Last-Modified"), response.header("Cache-Control"), response.header("Expires"), body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.mapbox.mapboxgl.util;
|
||||
|
||||
import com.mapbox.mapboxgl.constants.MapboxConstants;
|
||||
import com.squareup.okhttp.Callback;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
|
||||
public class JavaFileSource {
|
||||
|
||||
private static JavaFileSource instance = null;
|
||||
|
||||
// Single reference to OkHttp for performance gains
|
||||
private OkHttpClient client;
|
||||
|
||||
/**
|
||||
* Private Constructor to support Singleton pattern
|
||||
*/
|
||||
private JavaFileSource() {
|
||||
super();
|
||||
client = new OkHttpClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance of JavaFileSource
|
||||
* @return Reference to the Singleton Instance of JavaFileSource
|
||||
*/
|
||||
public static JavaFileSource getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new JavaFileSource();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP Request
|
||||
* @param resourceUrl URL to resource
|
||||
* @param callback Callback class
|
||||
*/
|
||||
public void request(final String resourceUrl, final Callback callback) {
|
||||
Request request = new Request.Builder().url(resourceUrl).tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)).build();
|
||||
client.newCall(request).enqueue(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to cancel HTTP Request made
|
||||
* @param resourceUrl URL of request to cancel
|
||||
*/
|
||||
public void cancel(final String resourceUrl) {
|
||||
client.cancel(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE));
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,14 @@ package com.mapbox.mapboxgl.views;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.Surface;
|
||||
import android.util.Log;
|
||||
|
||||
import com.mapbox.mapboxgl.annotations.Marker;
|
||||
import com.mapbox.mapboxgl.annotations.Polygon;
|
||||
import com.mapbox.mapboxgl.annotations.Polyline;
|
||||
import com.mapbox.mapboxgl.geometry.BoundingBox;
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
import com.mapbox.mapboxgl.geometry.LatLngZoom;
|
||||
import com.mapbox.mapboxgl.geometry.ProjectedMeters;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// Class that wraps the native methods for convenience
|
||||
@@ -39,11 +41,19 @@ class NativeMapView {
|
||||
// Constructors
|
||||
//
|
||||
|
||||
public NativeMapView(MapView mapView, String cachePath, String dataPath, String apkPath) {
|
||||
public NativeMapView(MapView mapView, String cachePath, String dataPath, String apkPath, float pixelRatio, int availableProcessors, long totalMemory) {
|
||||
if (availableProcessors < 0) {
|
||||
throw new IllegalArgumentException("availableProcessors cannot be negative.");
|
||||
}
|
||||
|
||||
if (totalMemory < 0) {
|
||||
throw new IllegalArgumentException("totalMemory cannot be negative.");
|
||||
}
|
||||
|
||||
mMapView = mapView;
|
||||
|
||||
// Create the NativeMapView
|
||||
mNativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath);
|
||||
mNativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -90,8 +100,7 @@ class NativeMapView {
|
||||
nativeOnInvalidate(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resize(int width, int height, float ratio, int fbWidth,
|
||||
int fbHeight) {
|
||||
public void resizeView(int width, int height) {
|
||||
if (width < 0) {
|
||||
throw new IllegalArgumentException("width cannot be negative.");
|
||||
}
|
||||
@@ -100,6 +109,19 @@ class NativeMapView {
|
||||
throw new IllegalArgumentException("height cannot be negative.");
|
||||
}
|
||||
|
||||
if (width > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"width cannot be greater than 65535.");
|
||||
}
|
||||
|
||||
if (height > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"height cannot be greater than 65535.");
|
||||
}
|
||||
nativeViewResize(mNativeMapViewPtr, width, height);
|
||||
}
|
||||
|
||||
public void resizeFramebuffer(int fbWidth, int fbHeight) {
|
||||
if (fbWidth < 0) {
|
||||
throw new IllegalArgumentException("fbWidth cannot be negative.");
|
||||
}
|
||||
@@ -117,7 +139,7 @@ class NativeMapView {
|
||||
throw new IllegalArgumentException(
|
||||
"fbHeight cannot be greater than 65535.");
|
||||
}
|
||||
nativeResize(mNativeMapViewPtr, width, height, ratio, fbWidth, fbHeight);
|
||||
nativeFramebufferResize(mNativeMapViewPtr, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
public void addClass(String clazz) {
|
||||
@@ -151,7 +173,7 @@ class NativeMapView {
|
||||
public void setDefaultTransitionDuration(long milliseconds) {
|
||||
if (milliseconds < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"durationMilliseconds cannot be negative.");
|
||||
"milliseconds cannot be negative.");
|
||||
}
|
||||
|
||||
nativeSetDefaultTransitionDuration(mNativeMapViewPtr,
|
||||
@@ -163,7 +185,7 @@ class NativeMapView {
|
||||
}
|
||||
|
||||
public void setStyleJson(String newStyleJson) {
|
||||
setStyleJson(newStyleJson, "");
|
||||
setStyleJson(newStyleJson, "");
|
||||
}
|
||||
|
||||
public void setStyleJson(String newStyleJson, String base) {
|
||||
@@ -186,6 +208,10 @@ class NativeMapView {
|
||||
nativeCancelTransitions(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setGestureInProgress(boolean inProgress) {
|
||||
nativeSetGestureInProgress(mNativeMapViewPtr, inProgress);
|
||||
}
|
||||
|
||||
public void moveBy(double dx, double dy) {
|
||||
moveBy(dx, dy, 0);
|
||||
}
|
||||
@@ -303,6 +329,42 @@ class NativeMapView {
|
||||
nativeResetNorth(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public long addMarker(Marker marker) {
|
||||
return nativeAddMarker(mNativeMapViewPtr, marker);
|
||||
}
|
||||
|
||||
public long addPolyline(Polyline polyline) {
|
||||
return nativeAddPolyline(mNativeMapViewPtr, polyline);
|
||||
}
|
||||
|
||||
public long addPolygon(Polygon polygon) {
|
||||
return nativeAddPolygon(mNativeMapViewPtr, polygon);
|
||||
}
|
||||
|
||||
public long[] addPolygons(List<Polygon> polygon) {
|
||||
return nativeAddPolygons(mNativeMapViewPtr, polygon);
|
||||
}
|
||||
|
||||
public void removeAnnotation(long id) {
|
||||
nativeRemoveAnnotation(mNativeMapViewPtr, id);
|
||||
}
|
||||
|
||||
public void removeAnnotations(long[] ids) {
|
||||
nativeRemoveAnnotations(mNativeMapViewPtr, ids);
|
||||
}
|
||||
|
||||
public long[] getAnnotationsInBounds(BoundingBox bbox) {
|
||||
return nativeGetAnnotationsInBounds(mNativeMapViewPtr, bbox);
|
||||
}
|
||||
|
||||
public void setSprite(String symbol, int width, int height, float scale, byte[] pixels) {
|
||||
nativeSetSprite(mNativeMapViewPtr, symbol, width, height, scale, pixels);
|
||||
}
|
||||
|
||||
public void onLowMemory() {
|
||||
nativeOnLowMemory(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
nativeSetDebug(mNativeMapViewPtr, debug);
|
||||
}
|
||||
@@ -315,11 +377,27 @@ class NativeMapView {
|
||||
return nativeGetDebug(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setCollisionDebug(boolean debug) {
|
||||
nativeSetCollisionDebug(mNativeMapViewPtr, debug);
|
||||
}
|
||||
|
||||
public void toggleCollisionDebug() {
|
||||
nativeToggleCollisionDebug(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public boolean getCollisionDebug() {
|
||||
return nativeGetCollisionDebug(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public boolean isFullyLoaded() {
|
||||
return nativeIsFullyLoaded(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setReachability(boolean status) {
|
||||
nativeSetReachability(mNativeMapViewPtr, status);
|
||||
}
|
||||
|
||||
//public void getWorldBoundsMeters();
|
||||
//public void ();
|
||||
|
||||
//public void getWorldBoundsLatLng();
|
||||
|
||||
@@ -343,6 +421,10 @@ class NativeMapView {
|
||||
return nativeLatLngForPixel(mNativeMapViewPtr, pixel);
|
||||
}
|
||||
|
||||
public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) {
|
||||
return nativeGetTopOffsetPixelsForAnnotationSymbol(mNativeMapViewPtr, symbolName);
|
||||
}
|
||||
|
||||
//
|
||||
// Callbacks
|
||||
//
|
||||
@@ -351,8 +433,8 @@ class NativeMapView {
|
||||
mMapView.onInvalidate();
|
||||
}
|
||||
|
||||
protected void onMapChanged() {
|
||||
mMapView.onMapChanged();
|
||||
protected void onMapChanged(int rawChange) {
|
||||
mMapView.onMapChanged(rawChange);
|
||||
}
|
||||
|
||||
protected void onFpsChanged(double fps) {
|
||||
@@ -370,7 +452,7 @@ class NativeMapView {
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
private native long nativeCreate(String cachePath, String dataPath, String apkPath);
|
||||
private native long nativeCreate(String cachePath, String dataPath, String apkPath, float pixelRatio, int availableProcessors, long totalMemory);
|
||||
|
||||
private native void nativeDestroy(long nativeMapViewPtr);
|
||||
|
||||
@@ -395,8 +477,9 @@ class NativeMapView {
|
||||
|
||||
private native void nativeOnInvalidate(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResize(long nativeMapViewPtr, int width,
|
||||
int height, float ratio, int fbWidth, int fbHeight);
|
||||
private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
|
||||
|
||||
private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight);
|
||||
|
||||
private native void nativeAddClass(long nativeMapViewPtr, String clazz);
|
||||
|
||||
@@ -427,6 +510,8 @@ class NativeMapView {
|
||||
|
||||
private native void nativeCancelTransitions(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress);
|
||||
|
||||
private native void nativeMoveBy(long nativeMapViewPtr, double dx,
|
||||
double dy, long duration);
|
||||
|
||||
@@ -474,12 +559,39 @@ class NativeMapView {
|
||||
|
||||
private native void nativeResetNorth(long nativeMapViewPtr);
|
||||
|
||||
private native long nativeAddMarker(long nativeMapViewPtr, Marker marker);
|
||||
|
||||
private native long nativeAddPolyline(long nativeMapViewPtr, Polyline polyline);
|
||||
|
||||
private native long nativeAddPolygon(long mNativeMapViewPtr, Polygon polygon);
|
||||
|
||||
private native long[] nativeAddPolygons(long mNativeMapViewPtr, List<Polygon> polygon);
|
||||
|
||||
private native void nativeRemoveAnnotation(long nativeMapViewPtr, long id);
|
||||
|
||||
private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id);
|
||||
|
||||
private native long[] nativeGetAnnotationsInBounds(long mNativeMapViewPtr, BoundingBox bbox);
|
||||
|
||||
private native void nativeSetSprite(long nativeMapViewPtr, String symbol,
|
||||
int width, int height, float scale, byte[] pixels);
|
||||
|
||||
private native void nativeOnLowMemory(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetDebug(long nativeMapViewPtr, boolean debug);
|
||||
|
||||
private native void nativeToggleDebug(long nativeMapViewPtr);
|
||||
|
||||
private native boolean nativeGetDebug(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetCollisionDebug(long nativeMapViewPtr, boolean debug);
|
||||
|
||||
private native void nativeToggleCollisionDebug(long nativeMapViewPtr);
|
||||
|
||||
private native boolean nativeGetCollisionDebug(long nativeMapViewPtr);
|
||||
|
||||
private native boolean nativeIsFullyLoaded(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetReachability(long nativeMapViewPtr, boolean status);
|
||||
|
||||
//private native void nativeGetWorldBoundsMeters(long nativeMapViewPtr);
|
||||
@@ -495,4 +607,6 @@ class NativeMapView {
|
||||
private native PointF nativePixelForLatLng(long nativeMapViewPtr, LatLng latLng);
|
||||
|
||||
private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, PointF pixel);
|
||||
|
||||
private native double nativeGetTopOffsetPixelsForAnnotationSymbol(long nativeMapViewPtr, String symbolName);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item
|
||||
android:color="?attr/colorPrimaryDark"
|
||||
android:state_pressed="true"/>
|
||||
<item
|
||||
android:color="?attr/colorPrimary" />
|
||||
</selector>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 730 B |
|
After Width: | Height: | Size: 836 B |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/ic_info_blue_pressed" />
|
||||
<item android:drawable="@drawable/ic_info_blue_normal" />
|
||||
</selector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:textColor="@android:color/white"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall" />
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:background="@color/white"
|
||||
android:padding="5dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/infowindow_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="18sp"
|
||||
android:maxEms="17"
|
||||
android:layout_gravity="left"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/infoWindowTitle"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/infowindow_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="14sp"
|
||||
android:maxEms="17"
|
||||
android:text="@string/infoWindowDescription"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/infowindow_subdescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="12sp"
|
||||
android:maxEms="17"
|
||||
android:text="@string/infoWindowAddress"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.mapbox.mapboxgl.annotations.InfoWindowTipView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="10dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="attribution_names">
|
||||
<item>© Mapbox</item>
|
||||
<item>© OpenStreetMap</item>
|
||||
<item>Improve this map</item>
|
||||
</array>
|
||||
<array name="attribution_links" formatted="false" translatable="false">
|
||||
<item>https://www.mapbox.com/about/maps/</item>
|
||||
<item>http://www.openstreetmap.org/about/</item>
|
||||
<item>https://www.mapbox.com/map-feedback/#/%1$f/%2$f/%3$d</item>
|
||||
</array>
|
||||
</resources>
|
||||
@@ -1,23 +1,77 @@
|
||||
<resources>
|
||||
<attr name="centerLongitude" format="float" />
|
||||
<attr name="centerLatitude" format="float" />
|
||||
<attr name="zoomLevel" format="float" />
|
||||
<attr name="direction" format="float" />
|
||||
<attr name="zoomEnabled" format="boolean" />
|
||||
<attr name="scrollEnabled" format="boolean" />
|
||||
<attr name="rotateEnabled" format="boolean" />
|
||||
<attr name="debugActive" format="boolean" />
|
||||
<attr name="styleUrl" format="string" />
|
||||
|
||||
<declare-styleable name="MapView">
|
||||
<attr name="centerLongitude" />
|
||||
<attr name="centerLatitude" />
|
||||
<attr name="zoomLevel" />
|
||||
<attr name="direction" />
|
||||
<attr name="zoomEnabled" />
|
||||
<attr name="scrollEnabled" />
|
||||
<attr name="rotateEnabled" />
|
||||
<attr name="debugActive" />
|
||||
<attr name="styleUrl" />
|
||||
<attr name="centerLongitude" format="float" />
|
||||
<attr name="centerLatitude" format="float" />
|
||||
<attr name="zoomLevel" format="float" />
|
||||
<attr name="direction" format="float" />
|
||||
<attr name="zoomEnabled" format="boolean" />
|
||||
<attr name="scrollEnabled" format="boolean" />
|
||||
<attr name="rotateEnabled" format="boolean" />
|
||||
<attr name="debugActive" format="boolean" />
|
||||
<attr name="styleUrl" format="string" />
|
||||
<attr name="accessToken" format="string"/>
|
||||
<attr name="styleClasses" format="string"/>
|
||||
<attr name="myLocationEnabled" format="boolean" />
|
||||
<attr name="compassEnabled" format="boolean" />
|
||||
<attr name="compassGravity">
|
||||
<flag name="top" value="0x30" />
|
||||
<flag name="bottom" value="0x50" />
|
||||
<flag name="left" value="0x03" />
|
||||
<flag name="right" value="0x05" />
|
||||
<flag name="center_vertical" value="0x10" />
|
||||
<flag name="fill_vertical" value="0x70" />
|
||||
<flag name="center_horizontal" value="0x01" />
|
||||
<flag name="fill_horizontal" value="0x07" />
|
||||
<flag name="center" value="0x11" />
|
||||
<flag name="fill" value="0x77" />
|
||||
<flag name="clip_vertical" value="0x80" />
|
||||
<flag name="clip_horizontal" value="0x08" />
|
||||
<flag name="start" value="0x00800003" />
|
||||
<flag name="end" value="0x00800005" />
|
||||
</attr>
|
||||
<attr name="compassMarginLeft" format="dimension"/>
|
||||
<attr name="compassMarginTop" format="dimension"/>
|
||||
<attr name="compassMarginRight" format="dimension"/>
|
||||
<attr name="compassMarginBottom" format="dimension"/>
|
||||
<attr name="logoGravity">
|
||||
<flag name="top" value="0x30" />
|
||||
<flag name="bottom" value="0x50" />
|
||||
<flag name="left" value="0x03" />
|
||||
<flag name="right" value="0x05" />
|
||||
<flag name="center_vertical" value="0x10" />
|
||||
<flag name="fill_vertical" value="0x70" />
|
||||
<flag name="center_horizontal" value="0x01" />
|
||||
<flag name="fill_horizontal" value="0x07" />
|
||||
<flag name="center" value="0x11" />
|
||||
<flag name="fill" value="0x77" />
|
||||
<flag name="clip_vertical" value="0x80" />
|
||||
<flag name="clip_horizontal" value="0x08" />
|
||||
<flag name="start" value="0x00800003" />
|
||||
<flag name="end" value="0x00800005" />
|
||||
</attr>
|
||||
<attr name="logoMarginLeft" format="dimension"/>
|
||||
<attr name="logoMarginTop" format="dimension"/>
|
||||
<attr name="logoMarginRight" format="dimension"/>
|
||||
<attr name="logoMarginBottom" format="dimension"/>
|
||||
<attr name="attributionGravity">
|
||||
<flag name="top" value="0x30" />
|
||||
<flag name="bottom" value="0x50" />
|
||||
<flag name="left" value="0x03" />
|
||||
<flag name="right" value="0x05" />
|
||||
<flag name="center_vertical" value="0x10" />
|
||||
<flag name="fill_vertical" value="0x70" />
|
||||
<flag name="center_horizontal" value="0x01" />
|
||||
<flag name="fill_horizontal" value="0x07" />
|
||||
<flag name="center" value="0x11" />
|
||||
<flag name="fill" value="0x77" />
|
||||
<flag name="clip_vertical" value="0x80" />
|
||||
<flag name="clip_horizontal" value="0x08" />
|
||||
<flag name="start" value="0x00800003" />
|
||||
<flag name="end" value="0x00800005" />
|
||||
</attr>
|
||||
<attr name="attributionMarginLeft" format="dimension"/>
|
||||
<attr name="attributionMarginTop" format="dimension"/>
|
||||
<attr name="attributionMarginRight" format="dimension"/>
|
||||
<attr name="attributionMarginBottom" format="dimension"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="black">#000000</color>
|
||||
<color name="mapbox_blue">#1E8CAB</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="compassContentDescription">Map compass. Click to reset the map rotation to North.</string>
|
||||
<string name="attributionsIconContentDescription">Attribution icon. Click to show attribution dialog.</string>
|
||||
<string name="attributionsDialogTitle">Mapbox Android SDK</string>
|
||||
<string name="mapboxIconContentDescription">Mapbox logo.</string>
|
||||
<string name="infoWindowTitle">Title</string>
|
||||
<string name="infoWindowDescription">Description</string>
|
||||
<string name="infoWindowAddress">Address</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AttributionAlertDialogStyle" parent="Theme.AppCompat.Dialog.Alert">
|
||||
<item name="android:textColorPrimary">@android:color/white</item>
|
||||
<item name="android:background">@color/mapbox_blue</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -1,15 +1,23 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0'
|
||||
classpath 'io.fabric.tools:gradle:1.+'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'android-sdk-manager'
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'io.fabric'
|
||||
|
||||
repositories {
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
}
|
||||
|
||||
apply plugin: 'checkstyle'
|
||||
|
||||
task accessToken {
|
||||
@@ -30,8 +38,8 @@ gradle.projectsEvaluated {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 22
|
||||
buildToolsVersion "22.0.1"
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@@ -39,8 +47,8 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.mapbox.mapboxgl.testapp"
|
||||
minSdkVersion 8
|
||||
targetSdkVersion 22
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 23
|
||||
versionCode 4
|
||||
versionName "0.1.3"
|
||||
|
||||
@@ -69,7 +77,7 @@ android {
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,10 +86,13 @@ dependencies {
|
||||
compile(project(':MapboxGLAndroidSDK')) {
|
||||
transitive = true
|
||||
}
|
||||
compile 'com.android.support:support-annotations:22.2.0'
|
||||
compile 'com.android.support:support-v4:22.2.0'
|
||||
compile 'com.android.support:appcompat-v7:22.2.0'
|
||||
compile 'com.mapzen.android:lost:1.0.0'
|
||||
compile 'com.android.support:support-annotations:23.0.1'
|
||||
compile 'com.android.support:support-v4:23.0.1'
|
||||
compile 'com.android.support:appcompat-v7:23.0.1'
|
||||
compile 'com.android.support:design:23.0.1'
|
||||
compile('com.crashlytics.sdk.android:crashlytics:2.5.1@aar') {
|
||||
transitive = true;
|
||||
}
|
||||
|
||||
// Testing dependencies
|
||||
androidTestCompile 'com.android.support.test:runner:0.3'
|
||||
|
||||
1
android/java/MapboxGLAndroidSDKTestApp/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1 @@
|
||||
# Proguard configuration is handeld in the SDK
|
||||
@@ -2,15 +2,12 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.mapbox.mapboxgl.testapp">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:icon="@drawable/icon_burned"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:supportsRtl="true">
|
||||
<activity
|
||||
android:name="com.mapbox.mapboxgl.testapp.MainActivity"
|
||||
@@ -20,6 +17,12 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data
|
||||
android:name="io.fabric.ApiKey"
|
||||
android:value="9724157045ff7d083492c6d9ae03e60e8609d461" />
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"LineString","coordinates":[[-121.3714599609375,38.64583568648869],[-121.48681640624999,38.64047263931154],[-121.53076171875,38.61579745317875],[-121.56509399414061,38.57823196583313],[-121.75186157226561,38.533127435052776],[-121.97021484374999,38.35350340353833],[-122.08007812499999,38.24680876017446],[-122.16796875,38.19718009396176],[-122.23800659179686,38.09457899232253],[-122.27371215820312,38.01455819225337],[-122.33551025390625,37.94094845586459],[-122.27371215820312,37.81846319511331],[-122.4151611328125,37.7652868250379]]}}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-122.28813171386719,38.617406963286136],[-122.26959228515624,38.6833657775237],[-122.18238830566406,38.55568323796419],[-122.10617065429688,38.51378825951165],[-122.11509704589845,38.50465406475561],[-122.18307495117188,38.542795073979015],[-122.19955444335938,38.496593518947556],[-122.28813171386719,38.617406963286136]]]}}]}
|
||||
@@ -1,81 +1,73 @@
|
||||
package com.mapbox.mapboxgl.testapp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PointF;
|
||||
import android.hardware.GeomagneticField;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import android.widget.Toast;
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.mapbox.mapboxgl.annotations.Marker;
|
||||
import com.mapbox.mapboxgl.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxgl.annotations.PolygonOptions;
|
||||
import com.mapbox.mapboxgl.annotations.PolylineOptions;
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
import com.mapbox.mapboxgl.views.MapView;
|
||||
import com.mapzen.android.lost.api.LocationListener;
|
||||
import com.mapzen.android.lost.api.LocationRequest;
|
||||
import com.mapzen.android.lost.api.LocationServices;
|
||||
import com.mapzen.android.lost.api.LostApiClient;
|
||||
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MainActivity extends ActionBarActivity {
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "MainActivity";
|
||||
|
||||
//
|
||||
// Static members
|
||||
//
|
||||
|
||||
// Used for saving instance state
|
||||
private static final String STATE_IS_GPS_ON = "isGpsOn";
|
||||
private static final String STATE_IS_ANNOTATIONS_ON = "isAnnotationsOn";
|
||||
private static final String STATE_SELECTED_STYLE = "selectedStyle";
|
||||
|
||||
// Used for permissions requests
|
||||
private static final int PERMISSIONS_LOCATION = 0;
|
||||
|
||||
//
|
||||
// Instance members
|
||||
//
|
||||
|
||||
// Used for the UI
|
||||
private MapFragment mMapFragment;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private MapView mMapView;
|
||||
private TextView mFpsTextView;
|
||||
private ImageView mCompassView;
|
||||
private FrameLayout mMapFrameLayout;
|
||||
private float mDensity;
|
||||
private Spinner mClassSpinner;
|
||||
private ArrayAdapter mOutdoorsClassAdapter;
|
||||
private ArrayAdapter mSatelliteClassAdapter;
|
||||
private int mSelectedStyle = R.id.actionStyleMapboxStreets;
|
||||
NavigationView mNavigationView;
|
||||
|
||||
// Used for GPS
|
||||
private boolean mIsGpsOn = false;
|
||||
private LostApiClient mLocationClient;
|
||||
private GpsListener mGpsListener;
|
||||
private LocationRequest mLocationRequest;
|
||||
private ImageView mGpsMarker;
|
||||
private Location mGpsLocation;
|
||||
private MenuItem mGpsMenuItem;
|
||||
private FloatingActionButton mLocationFAB;
|
||||
|
||||
// Used for compass
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mSensorAccelerometer;
|
||||
private Sensor mSensorMagneticField;
|
||||
private CompassListener mCompassListener;
|
||||
private float[] mValuesAccelerometer = new float[3];
|
||||
private float[] mValuesMagneticField = new float[3];
|
||||
private float[] mMatrixR = new float[9];
|
||||
private float[] mMatrixI = new float[9];
|
||||
private float[] mMatrixValues = new float[3];
|
||||
private float mCompassBearing;
|
||||
private boolean mCompassValid = false;
|
||||
// Used for Annotations
|
||||
private boolean mIsAnnotationsOn = false;
|
||||
|
||||
//
|
||||
// Lifecycle events
|
||||
@@ -85,62 +77,112 @@ public class MainActivity extends ActionBarActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mIsGpsOn = savedInstanceState.getBoolean(STATE_IS_GPS_ON, false);
|
||||
}
|
||||
|
||||
mDensity = getResources().getDisplayMetrics().density;
|
||||
Fabric.with(this, new Crashlytics());
|
||||
|
||||
// Load the layout
|
||||
setContentView(R.layout.activity_main);
|
||||
mMapFragment = (MapFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_map);
|
||||
mMapFragment.getMap().setOnFpsChangedListener(new MyOnFpsChangedListener());
|
||||
mMapFragment.getMap().setOnMapChangedListener(new MyOnMapChangedListener());
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
final ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setHomeAsUpIndicator(R.drawable.ic_menu);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
|
||||
mNavigationView = (NavigationView) findViewById(R.id.nav_view);
|
||||
if (mNavigationView != null) {
|
||||
setupDrawerContent(mNavigationView);
|
||||
}
|
||||
|
||||
mMapView = (MapView) findViewById(R.id.mainMapView);
|
||||
// Load the access token
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.token)));
|
||||
String line = reader.readLine();
|
||||
mMapView.setAccessToken(line);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error loading access token from token.txt: " + e.toString());
|
||||
}
|
||||
|
||||
mMapView.onCreate(savedInstanceState);
|
||||
mMapView.setOnFpsChangedListener(new MyOnFpsChangedListener());
|
||||
|
||||
final GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
|
||||
public void onLongPress(final MotionEvent e) {
|
||||
float x = e.getX();
|
||||
float y = e.getY();
|
||||
|
||||
// flip y direction vertically to match core GL
|
||||
y = mMapView.getHeight() - y;
|
||||
|
||||
LatLng position = mMapView.fromScreenLocation(new PointF(x, y));
|
||||
|
||||
mMapView.addMarker(new MarkerOptions()
|
||||
.position(position)
|
||||
.title("Dropped Pin")
|
||||
.snippet(new DecimalFormat("#.#####").format(position.getLatitude()) + ", " +
|
||||
new DecimalFormat("#.#####").format(position.getLongitude()))
|
||||
.sprite("default_marker"));
|
||||
}
|
||||
});
|
||||
|
||||
mMapView.setOnTouchListener(new View.OnTouchListener() {
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
mFpsTextView = (TextView) findViewById(R.id.view_fps);
|
||||
mFpsTextView.setText("");
|
||||
|
||||
mCompassView = (ImageView) findViewById(R.id.view_compass);
|
||||
mCompassView.setOnClickListener(new CompassOnClickListener());
|
||||
mLocationFAB = (FloatingActionButton)findViewById(R.id.locationFAB);
|
||||
mLocationFAB.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Toggle GPS position updates
|
||||
toggleGps(!mMapView.isMyLocationEnabled());
|
||||
if (mMapView.isMyLocationEnabled()) {
|
||||
Location location = mMapView.getMyLocation();
|
||||
if (location != null) {
|
||||
mMapView.setZoomLevel(8);
|
||||
mMapView.setCenterCoordinate(new LatLng(location));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mGpsMarker = new ImageView(getApplicationContext());
|
||||
mGpsMarker.setVisibility(View.INVISIBLE);
|
||||
mGpsMarker.setImageResource(R.drawable.location_marker);
|
||||
mGpsMarker.setLayoutParams(new FrameLayout.LayoutParams((int) (27.0f * mDensity), (int) (27.0f * mDensity)));
|
||||
mGpsMarker.requestLayout();
|
||||
// Restore saved state
|
||||
if (savedInstanceState != null) {
|
||||
mIsAnnotationsOn = savedInstanceState.getBoolean(STATE_IS_ANNOTATIONS_ON);
|
||||
mSelectedStyle = savedInstanceState.getInt(STATE_SELECTED_STYLE);
|
||||
}
|
||||
|
||||
mMapFrameLayout = (FrameLayout) findViewById(R.id.layout_map);
|
||||
mMapFrameLayout.addView(mGpsMarker);
|
||||
// Add a toolbar as the action bar
|
||||
Toolbar mainToolbar = (Toolbar) findViewById(R.id.toolbar_main);
|
||||
setSupportActionBar(mainToolbar);
|
||||
getSupportActionBar().setDisplayShowTitleEnabled(false);
|
||||
// Set default UI state
|
||||
mNavigationView.getMenu().findItem(R.id.action_compass).setChecked(mMapView.isCompassEnabled());
|
||||
mNavigationView.getMenu().findItem(R.id.action_debug).setChecked(mMapView.isDebugActive());
|
||||
mNavigationView.getMenu().findItem(R.id.action_markers).setChecked(mIsAnnotationsOn);
|
||||
changeMapStyle(mSelectedStyle);
|
||||
toggleGps(mMapView.isMyLocationEnabled());
|
||||
}
|
||||
|
||||
// Add the spinner to select map styles
|
||||
Spinner styleSpinner = (Spinner) findViewById(R.id.spinner_style);
|
||||
ArrayAdapter styleAdapter = ArrayAdapter.createFromResource(getSupportActionBar().getThemedContext(),
|
||||
R.array.style_list, android.R.layout.simple_spinner_dropdown_item);
|
||||
styleSpinner.setAdapter(styleAdapter);
|
||||
styleSpinner.setOnItemSelectedListener(new StyleSpinnerListener());
|
||||
/**
|
||||
* Dispatch onStart() to all fragments. Ensure any created loaders are
|
||||
* now started.
|
||||
*/
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
mMapView.onStart();
|
||||
}
|
||||
|
||||
// Add the spinner to select class styles
|
||||
mClassSpinner = (Spinner) findViewById(R.id.spinner_class);
|
||||
mOutdoorsClassAdapter = ArrayAdapter.createFromResource(getSupportActionBar().getThemedContext(),
|
||||
R.array.outdoors_class_list, android.R.layout.simple_spinner_dropdown_item);
|
||||
|
||||
// Prepare for GPS
|
||||
mLocationClient = new LostApiClient.Builder(this).build();
|
||||
mLocationRequest = LocationRequest.create()
|
||||
.setInterval(1000)
|
||||
.setSmallestDisplacement(1)
|
||||
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
|
||||
mGpsListener = new GpsListener();
|
||||
|
||||
mSensorManager = (SensorManager) getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
|
||||
mSensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
mSensorMagneticField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
|
||||
mCompassListener = new CompassListener();
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
mMapView.onStop();
|
||||
}
|
||||
|
||||
// Called when our app goes into the background
|
||||
@@ -148,16 +190,21 @@ public class MainActivity extends ActionBarActivity {
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
// Cancel GPS
|
||||
toggleGps(false);
|
||||
mMapView.onPause();
|
||||
}
|
||||
|
||||
// Called when our app comes into the foreground
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// Restart GPS
|
||||
toggleGps(true);
|
||||
|
||||
mMapView.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mMapView.onDestroy();
|
||||
}
|
||||
|
||||
// Called when we need to save instance state
|
||||
@@ -165,53 +212,139 @@ public class MainActivity extends ActionBarActivity {
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
outState.putBoolean(STATE_IS_GPS_ON, mIsGpsOn);
|
||||
mMapView.onSaveInstanceState(outState);
|
||||
outState.putBoolean(STATE_IS_ANNOTATIONS_ON, mIsAnnotationsOn);
|
||||
outState.putInt(STATE_SELECTED_STYLE, mSelectedStyle);
|
||||
}
|
||||
|
||||
// Called when the system is running low on memory
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
|
||||
mMapView.onLowMemory();
|
||||
}
|
||||
|
||||
//
|
||||
// Other events
|
||||
//
|
||||
|
||||
// Adds items to the action bar menu
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_main, menu);
|
||||
mGpsMenuItem = menu.findItem(R.id.action_gps);
|
||||
if (mIsGpsOn) {
|
||||
mGpsMenuItem.setIcon(R.drawable.ic_action_location_found);
|
||||
} else {
|
||||
mGpsMenuItem.setIcon(R.drawable.ic_action_location_searching);
|
||||
}
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
// Called when pressing action bar items
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_gps:
|
||||
// Toggle GPS position updates
|
||||
toggleGps(!mIsGpsOn);
|
||||
updateMap();
|
||||
case android.R.id.home:
|
||||
mDrawerLayout.openDrawer(GravityCompat.START);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PERMISSIONS_LOCATION: {
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
enableGps();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDrawerContent(NavigationView navigationView) {
|
||||
navigationView.setNavigationItemSelectedListener(
|
||||
new NavigationView.OnNavigationItemSelectedListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem menuItem) {
|
||||
mDrawerLayout.closeDrawers();
|
||||
|
||||
// Respond To Selection
|
||||
switch (menuItem.getItemId()) {
|
||||
|
||||
case R.id.action_debug:
|
||||
// Toggle debug mode
|
||||
mMapView.toggleDebug();
|
||||
toggleFpsCounter(mMapView.isDebugActive());
|
||||
menuItem.setChecked(mMapView.isDebugActive());
|
||||
return true;
|
||||
|
||||
case R.id.action_markers:
|
||||
// Toggle markers
|
||||
toggleAnnotations(!mIsAnnotationsOn);
|
||||
menuItem.setChecked(mIsAnnotationsOn);
|
||||
return true;
|
||||
|
||||
case R.id.action_compass:
|
||||
// Toggle compass
|
||||
mMapView.setCompassEnabled(!mMapView.isCompassEnabled());
|
||||
menuItem.setChecked(mMapView.isCompassEnabled());
|
||||
return true;
|
||||
|
||||
/*
|
||||
case R.id.followNone:
|
||||
mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.NONE);
|
||||
return true;
|
||||
|
||||
case R.id.followFollow:
|
||||
mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.FOLLOW);
|
||||
return true;
|
||||
|
||||
case R.id.followBearing:
|
||||
mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.FOLLOW_BEARING);
|
||||
return true;
|
||||
*/
|
||||
default:
|
||||
return changeMapStyle(menuItem.getItemId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void toggleFpsCounter(boolean enableFps) {
|
||||
// Show the FPS counter
|
||||
if (enableFps) {
|
||||
mFpsTextView.setVisibility(View.VISIBLE);
|
||||
mFpsTextView.setText(getResources().getString(R.string.label_fps));
|
||||
} else {
|
||||
mFpsTextView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean changeMapStyle(int id) {
|
||||
switch (id) {
|
||||
case R.id.actionStyleMapboxStreets:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLMapboxStreets));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
case R.id.action_debug:
|
||||
// Toggle debug mode
|
||||
mMapFragment.getMap().toggleDebug();
|
||||
case R.id.actionStyleEmerald:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLEmerald));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
// Show the FPS counter
|
||||
if (mMapFragment.getMap().isDebugActive()) {
|
||||
mFpsTextView.setVisibility(View.VISIBLE);
|
||||
mFpsTextView.setText(getResources().getString(R.string.label_fps));
|
||||
} else {
|
||||
mFpsTextView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
case R.id.actionStyleLight:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLLight));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
case R.id.actionStyleDark:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLDark));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
case R.id.actionStyleSatellite:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLSatellite));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,228 +353,105 @@ public class MainActivity extends ActionBarActivity {
|
||||
* @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
|
||||
*/
|
||||
private void toggleGps(boolean enableGps) {
|
||||
|
||||
if (enableGps) {
|
||||
if (!mIsGpsOn) {
|
||||
mIsGpsOn = true;
|
||||
if (mGpsMenuItem != null) {
|
||||
mGpsMenuItem.setIcon(R.drawable.ic_action_location_found);
|
||||
}
|
||||
mGpsLocation = null;
|
||||
mLocationClient.connect();
|
||||
updateLocation(LocationServices.FusedLocationApi.getLastLocation());
|
||||
LocationServices.FusedLocationApi.requestLocationUpdates(mLocationRequest, new GpsListener());
|
||||
mSensorManager.registerListener(mCompassListener, mSensorAccelerometer, SensorManager.SENSOR_DELAY_UI);
|
||||
mSensorManager.registerListener(mCompassListener, mSensorMagneticField, SensorManager.SENSOR_DELAY_UI);
|
||||
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
|
||||
(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED))
|
||||
{
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
|
||||
} else {
|
||||
enableGps();
|
||||
}
|
||||
} else {
|
||||
if (mIsGpsOn) {
|
||||
mIsGpsOn = false;
|
||||
if (mGpsMenuItem != null) {
|
||||
mGpsMenuItem.setIcon(R.drawable.ic_action_location_searching);
|
||||
}
|
||||
LocationServices.FusedLocationApi.removeLocationUpdates(mGpsListener);
|
||||
mLocationClient.disconnect();
|
||||
mSensorManager.unregisterListener(mCompassListener, mSensorAccelerometer);
|
||||
mSensorManager.unregisterListener(mCompassListener, mSensorMagneticField);
|
||||
mGpsLocation = null;
|
||||
mMapView.setMyLocationEnabled(false);
|
||||
mLocationFAB.setColorFilter(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
private void enableGps() {
|
||||
mMapView.setMyLocationEnabled(true);
|
||||
mLocationFAB.setColorFilter(ContextCompat.getColor(this, R.color.primary));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable / Disable Annotations.
|
||||
*
|
||||
* @param enableAnnotations True to display, False to hide
|
||||
*/
|
||||
private void toggleAnnotations(boolean enableAnnotations) {
|
||||
if (enableAnnotations) {
|
||||
if (!mIsAnnotationsOn) {
|
||||
mIsAnnotationsOn = true;
|
||||
addMarkers();
|
||||
addPolyline();
|
||||
addPolygon();
|
||||
mMapView.setZoomLevel(7);
|
||||
mMapView.setCenterCoordinate(new LatLng(38.11727, -122.22839));
|
||||
}
|
||||
} else {
|
||||
if (mIsAnnotationsOn) {
|
||||
mIsAnnotationsOn = false;
|
||||
removeAnnotations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This class forwards location updates to updateLocation()
|
||||
private class GpsListener implements LocationListener {
|
||||
private void addMarkers() {
|
||||
LatLng backLot = new LatLng(38.649441, -121.369064);
|
||||
final Marker marker = mMapView.addMarker(new MarkerOptions()
|
||||
.position(backLot)
|
||||
.title("Back Lot")
|
||||
.snippet("The back lot behind my house"));
|
||||
marker.setInfoWindowOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
Toast.makeText(getApplicationContext(), "Custom Info Touch Listener!!", Toast.LENGTH_SHORT).show();
|
||||
marker.hideInfoWindow();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
updateLocation(location);
|
||||
LatLng cheeseRoom = new LatLng(38.531577,-122.010646);
|
||||
mMapView.addMarker(new MarkerOptions()
|
||||
.position(cheeseRoom)
|
||||
.sprite("dog-park-15")
|
||||
.title("Cheese Room")
|
||||
.snippet("The only air conditioned room on the property!"));
|
||||
}
|
||||
|
||||
private void addPolyline() {
|
||||
try {
|
||||
String geojsonStr = Util.loadStringFromAssets(this, "small_line.geojson");
|
||||
LatLng[] latLngs = Util.parseGeoJSONCoordinates(geojsonStr);
|
||||
MapView map = mMapView;
|
||||
map.addPolyline(new PolylineOptions()
|
||||
.add(latLngs)
|
||||
.width(2)
|
||||
.color(Color.RED));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error adding Polyline: "+ e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// This class handles sensor updates to calculate compass bearing
|
||||
private class CompassListener implements SensorEventListener {
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
switch (event.sensor.getType()) {
|
||||
case Sensor.TYPE_ACCELEROMETER:
|
||||
System.arraycopy(event.values, 0, mValuesAccelerometer, 0, 3);
|
||||
break;
|
||||
case Sensor.TYPE_MAGNETIC_FIELD:
|
||||
System.arraycopy(event.values, 0, mValuesMagneticField, 0, 3);
|
||||
break;
|
||||
}
|
||||
|
||||
boolean valid = SensorManager.getRotationMatrix(mMatrixR, mMatrixI,
|
||||
mValuesAccelerometer,
|
||||
mValuesMagneticField);
|
||||
|
||||
if (valid) {
|
||||
SensorManager.getOrientation(mMatrixR, mMatrixValues);
|
||||
//mAzimuthRadians.putValue(mMatrixValues[0]);
|
||||
//mAzimuth = Math.toDegrees(mAzimuthRadians.getAverage());
|
||||
|
||||
if (mGpsLocation != null) {
|
||||
GeomagneticField geomagneticField = new GeomagneticField(
|
||||
(float) mGpsLocation.getLatitude(),
|
||||
(float) mGpsLocation.getLongitude(),
|
||||
(float) mGpsLocation.getAltitude(),
|
||||
System.currentTimeMillis());
|
||||
mCompassBearing = (float) Math.toDegrees(mMatrixValues[0]) + geomagneticField.getDeclination();
|
||||
mCompassValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
updateMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO: ignore unreliable stuff
|
||||
private void addPolygon() {
|
||||
try {
|
||||
String geojsonStr = Util.loadStringFromAssets(this, "small_poly.geojson");
|
||||
LatLng[] latLngs = Util.parseGeoJSONCoordinates(geojsonStr);
|
||||
MapView map = mMapView;
|
||||
ArrayList<PolygonOptions> opts = new ArrayList<>();
|
||||
opts.add(new PolygonOptions()
|
||||
.add(latLngs)
|
||||
.strokeColor(Color.MAGENTA)
|
||||
.fillColor(Color.BLUE));
|
||||
map.addPolygons(opts).get(0);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error adding Polygon: "+ e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Handles location updates from GPS
|
||||
private void updateLocation(Location location) {
|
||||
if (location != null) {
|
||||
mGpsLocation = location;
|
||||
}
|
||||
|
||||
updateMap();
|
||||
}
|
||||
|
||||
// This class handles style change events
|
||||
private class StyleSpinnerListener implements AdapterView.OnItemSelectedListener {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
switch (position) {
|
||||
|
||||
// Mapbox Streets
|
||||
case 0:
|
||||
mMapFragment.getMap().setStyleUrl("asset://styles/mapbox-streets-v7.json");
|
||||
mMapFragment.getMap().removeAllClasses();
|
||||
mClassSpinner.setVisibility(View.INVISIBLE);
|
||||
mClassSpinner.setAdapter(null);
|
||||
mClassSpinner.setOnItemSelectedListener(null);
|
||||
break;
|
||||
|
||||
// Emerald
|
||||
case 1:
|
||||
mMapFragment.getMap().setStyleUrl("asset://styles/emerald-v7.json");
|
||||
mMapFragment.getMap().removeAllClasses();
|
||||
mClassSpinner.setVisibility(View.INVISIBLE);
|
||||
mClassSpinner.setAdapter(null);
|
||||
mClassSpinner.setOnItemSelectedListener(null);
|
||||
break;
|
||||
|
||||
// Light
|
||||
case 2:
|
||||
mMapFragment.getMap().setStyleUrl("asset://styles/light-v7.json");
|
||||
mMapFragment.getMap().removeAllClasses();
|
||||
mClassSpinner.setVisibility(View.INVISIBLE);
|
||||
mClassSpinner.setAdapter(null);
|
||||
mClassSpinner.setOnItemSelectedListener(null);
|
||||
break;
|
||||
|
||||
// Dark
|
||||
case 3:
|
||||
mMapFragment.getMap().setStyleUrl("asset://styles/dark-v7.json");
|
||||
mMapFragment.getMap().removeAllClasses();
|
||||
mClassSpinner.setVisibility(View.INVISIBLE);
|
||||
mClassSpinner.setAdapter(null);
|
||||
mClassSpinner.setOnItemSelectedListener(null);
|
||||
break;
|
||||
|
||||
// Outdoors
|
||||
case 4:
|
||||
mMapFragment.getMap().setStyleUrl("asset://styles/outdoors-v7.json");
|
||||
mMapFragment.getMap().removeAllClasses();
|
||||
mClassSpinner.setVisibility(View.VISIBLE);
|
||||
mClassSpinner.setAdapter(mOutdoorsClassAdapter);
|
||||
mClassSpinner.setOnItemSelectedListener(new OutdoorClassSpinnerListener());
|
||||
break;
|
||||
|
||||
default:
|
||||
onNothingSelected(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
mMapFragment.getMap().setStyleUrl("");
|
||||
}
|
||||
}
|
||||
|
||||
// This class handles outdoor class change events
|
||||
private class OutdoorClassSpinnerListener implements AdapterView.OnItemSelectedListener {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
ArrayList<String> classes = new ArrayList<>(1);
|
||||
|
||||
switch (position) {
|
||||
// Day
|
||||
case 0:
|
||||
classes.add("day");
|
||||
mMapFragment.getMap().setClasses(classes);
|
||||
break;
|
||||
|
||||
// Night
|
||||
case 1:
|
||||
classes.add("night");
|
||||
mMapFragment.getMap().setClasses(classes);
|
||||
break;
|
||||
|
||||
default:
|
||||
onNothingSelected(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
mMapFragment.getMap().removeAllClasses();
|
||||
}
|
||||
}
|
||||
|
||||
// This class handles satellite class change events
|
||||
private class SatelliteClassSpinnerListener implements AdapterView.OnItemSelectedListener {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
ArrayList<String> classes = new ArrayList<>(2);
|
||||
|
||||
switch (position) {
|
||||
// Labels + Contours
|
||||
case 0:
|
||||
classes.add("labels");
|
||||
classes.add("contours");
|
||||
mMapFragment.getMap().setClasses(classes);
|
||||
break;
|
||||
|
||||
// Labels Only
|
||||
case 1:
|
||||
classes.add("labels");
|
||||
mMapFragment.getMap().setClasses(classes);
|
||||
break;
|
||||
|
||||
// No Labels
|
||||
case 2:
|
||||
mMapFragment.getMap().setClasses(classes);
|
||||
break;
|
||||
|
||||
default:
|
||||
onNothingSelected(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
mMapFragment.getMap().removeAllClasses();
|
||||
}
|
||||
private void removeAnnotations() {
|
||||
mMapView.removeAnnotations();
|
||||
}
|
||||
|
||||
// Called when FPS changes
|
||||
@@ -453,62 +463,4 @@ public class MainActivity extends ActionBarActivity {
|
||||
}
|
||||
}
|
||||
|
||||
// Rotates an ImageView - does not work if the ImageView has padding, use margins
|
||||
private void rotateImageView(ImageView imageView, float angle) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.setScale((float) imageView.getWidth() / (float) imageView.getDrawable().getIntrinsicWidth(), (float) imageView.getHeight() / (float) imageView.getDrawable().getIntrinsicHeight());
|
||||
matrix.postRotate(angle, (float) imageView.getWidth() / 2.0f, (float) imageView.getHeight() / 2.0f);
|
||||
imageView.setImageMatrix(matrix);
|
||||
imageView.setScaleType(ImageView.ScaleType.MATRIX);
|
||||
}
|
||||
|
||||
// Updates the UI to match the current map's position
|
||||
private void updateMap() {
|
||||
rotateImageView(mCompassView, (float) mMapFragment.getMap().getDirection());
|
||||
|
||||
if (mGpsLocation != null) {
|
||||
mGpsMarker.setVisibility(View.VISIBLE);
|
||||
LatLng coordinate = new LatLng(mGpsLocation);
|
||||
PointF screenLocation = mMapFragment.getMap().toScreenLocation(coordinate);
|
||||
|
||||
if (mGpsLocation.hasBearing() || mCompassValid) {
|
||||
mGpsMarker.setImageResource(R.drawable.direction_arrow);
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) (54.0f * mDensity), (int) (54.0f * mDensity));
|
||||
lp.leftMargin = (int) ((screenLocation.x - 54.0f / 2.0f) * mDensity);
|
||||
lp.topMargin = mMapFrameLayout.getHeight() - (int) ((screenLocation.y + 54.0f / 2.0f) * mDensity);
|
||||
mGpsMarker.setLayoutParams(lp);
|
||||
float bearing = mGpsLocation.hasBearing() ? mGpsLocation.getBearing() : mCompassBearing;
|
||||
rotateImageView(mGpsMarker, bearing);
|
||||
mGpsMarker.requestLayout();
|
||||
} else {
|
||||
mGpsMarker.setImageResource(R.drawable.location_marker);
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) (27.0f * mDensity), (int) (27.0f * mDensity));
|
||||
lp.leftMargin = (int) ((screenLocation.x - 27.0f / 2.0f) * mDensity);
|
||||
lp.topMargin = mMapFrameLayout.getHeight() - (int) ((screenLocation.y + 27.0f / 2.0f) * mDensity);
|
||||
mGpsMarker.setLayoutParams(lp);
|
||||
rotateImageView(mGpsMarker, 0.0f);
|
||||
mGpsMarker.requestLayout();
|
||||
}
|
||||
} else {
|
||||
mGpsMarker.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when map state changes
|
||||
private class MyOnMapChangedListener implements MapView.OnMapChangedListener {
|
||||
|
||||
@Override
|
||||
public void onMapChanged() {
|
||||
updateMap();
|
||||
}
|
||||
}
|
||||
|
||||
// Called when someone presses the compass
|
||||
private class CompassOnClickListener implements View.OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
mMapFragment.getMap().resetNorth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,6 @@ import android.view.ViewGroup;
|
||||
|
||||
import com.mapbox.mapboxgl.views.MapView;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class MapFragment extends Fragment {
|
||||
|
||||
//
|
||||
@@ -42,15 +38,6 @@ public class MapFragment extends Fragment {
|
||||
// Create the map
|
||||
mMap = (MapView) inflater.inflate(R.layout.fragment_main, container, true);
|
||||
|
||||
// Load the access token
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(getActivity().getApplicationContext().getResources().openRawResource(R.raw.token)));
|
||||
String line = reader.readLine();
|
||||
mMap.setAccessToken(line);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Need to pass on any saved state to the map
|
||||
mMap.onCreate(savedInstanceState);
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.mapbox.mapboxgl.testapp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class Util {
|
||||
|
||||
public static String loadStringFromAssets(final Context context, final String fileName) throws IOException {
|
||||
if (TextUtils.isEmpty(fileName)) {
|
||||
throw new NullPointerException("No GeoJSON File Name passed in.");
|
||||
}
|
||||
InputStream is = context.getAssets().open(fileName);
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||
return readAll(rd);
|
||||
}
|
||||
|
||||
public static LatLng[] parseGeoJSONCoordinates(String geojsonStr) throws JSONException {
|
||||
JSONObject jsonObject = new JSONObject(geojsonStr);
|
||||
JSONArray features = jsonObject.getJSONArray("features");
|
||||
JSONObject feature = features.getJSONObject(0);
|
||||
JSONObject geometry = feature.getJSONObject("geometry");
|
||||
String type = geometry.getString("type");
|
||||
JSONArray coordinates;
|
||||
if (type.equals("Polygon")) {
|
||||
coordinates = geometry.getJSONArray("coordinates").getJSONArray(0);
|
||||
} else {
|
||||
coordinates = geometry.getJSONArray("coordinates");
|
||||
}
|
||||
int len = coordinates.length();
|
||||
LatLng[] latLngs = new LatLng[coordinates.length()];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
JSONArray coord = coordinates.getJSONArray(i);
|
||||
double lng = coord.getDouble(0);
|
||||
double lat = coord.getDouble(1);
|
||||
latLngs[i] = new LatLng(lat, lng);
|
||||
}
|
||||
return latLngs;
|
||||
}
|
||||
|
||||
private static String readAll(Reader rd) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int cp;
|
||||
while ((cp = rd.read()) != -1) {
|
||||
sb.append((char) cp);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 683 B |
|
Before Width: | Height: | Size: 722 B |
|
Before Width: | Height: | Size: 641 B |
|
After Width: | Height: | Size: 116 B |
|
After Width: | Height: | Size: 549 B |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 465 B |
|
Before Width: | Height: | Size: 484 B |
|
Before Width: | Height: | Size: 482 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 860 B |
|
Before Width: | Height: | Size: 994 B |
|
Before Width: | Height: | Size: 854 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 660 B |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 976 B |
|
Before Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -1,58 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
<android.support.v4.widget.DrawerLayout
|
||||
android:id="@+id/drawer_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar_main"
|
||||
android:layout_height="wrap_content"
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_style"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_class"
|
||||
android:visibility="invisible"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</android.support.v7.widget.Toolbar>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/layout_map"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<fragment
|
||||
android:name="com.mapbox.mapboxgl.testapp.MapFragment"
|
||||
android:id="@+id/fragment_map"
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="${packageName}.${activityClass}"
|
||||
tools:layout="@layout/fragment_main" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/view_compass"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="end|top"
|
||||
android:layout_margin="10dp"
|
||||
android:contentDescription="@string/compass_desc"
|
||||
android:src="@drawable/compass"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/view_fps"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="@string/label_fps"
|
||||
android:layout_margin="10dp" />
|
||||
android:background="@color/primary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
<FrameLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/toolbar">
|
||||
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.mapbox.mapboxgl.views.MapView
|
||||
android:id="@+id/mainMapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/view_fps"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:text="@string/label_fps"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/locationFAB"
|
||||
android:src="@drawable/ic_my_location_black_24dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:backgroundTint="@color/white"
|
||||
/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<android.support.design.widget.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true"
|
||||
app:menu="@menu/menu_drawer"/>
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
|
||||