Merge remote-tracking branch 'mapbox/master' into 2317-espresso

Conflicts:
	android/java/MapboxGLAndroidSDKTestApp/build.gradle
This commit is contained in:
Antonio Zugaldia
2015-09-14 17:24:59 -04:00
517 changed files with 16656 additions and 7038 deletions

View File

@@ -18,3 +18,6 @@ local.properties
# Token file
MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt
# Twitter Fabric / Crashlytics
fabric.properties

View File

@@ -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'
}
}
}

View File

@@ -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

View 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** {
*;
}

View File

@@ -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" />

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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) {
//
// }
}

View File

@@ -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)
}

View File

@@ -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) {
//
// }
}

View File

@@ -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();
}
}

View File

@@ -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 () {
//
// }
}

View File

@@ -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) {
//
// }
}

View File

@@ -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) {
//
// }
}

View File

@@ -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) {
//
// }
}

View File

@@ -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();
}
/**

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="attribution_names">
<item>&#169; Mapbox</item>
<item>&#169; 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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'

View File

@@ -0,0 +1 @@
# Proguard configuration is handeld in the SDK

View File

@@ -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>

View File

@@ -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]]}}]}

View File

@@ -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]]]}}]}

View File

@@ -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();
}
}
}

View File

@@ -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);

View File

@@ -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();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -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>

Some files were not shown because too many files have changed in this diff Show More