diff options
author | Julian Rex <julian.rex@mapbox.com> | 2018-03-05 21:40:16 -0500 |
---|---|---|
committer | Julian Rex <julian.rex@mapbox.com> | 2018-03-05 21:40:16 -0500 |
commit | bcf3567a4f138e5d7fca71a7b3f683fa2db67589 (patch) | |
tree | 45d5dc80dc853dfb25c7eac8a8ff7a20fb17dadc | |
parent | 9fa27497059f9c08144e49a411bd735efb680fb4 (diff) | |
parent | 1785a98e4f6f4571cfd8fdc5518c0bc2c0921268 (diff) | |
download | qtlocation-mapboxgl-bcf3567a4f138e5d7fca71a7b3f683fa2db67589.tar.gz |
Merge branch 'release-boba' into jrex-9790-offscreen-annotation
199 files changed, 3747 insertions, 8666 deletions
diff --git a/.gitmodules b/.gitmodules index 422fc3930e..e5be61a921 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,7 @@ [submodule "mapbox-gl-js"] path = mapbox-gl-js url = https://github.com/mapbox/mapbox-gl-js.git +[submodule "platform/ios/vendor/mapbox-events-ios"] + path = platform/ios/vendor/mapbox-events-ios + url = https://github.com/mapbox/mapbox-events-ios.git + branch = boundsj-add-namespace-header diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index f24482e301..a915ffed69 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -456,6 +456,7 @@ set(MBGL_CORE_FILES include/mbgl/style/expression/interpolate.hpp include/mbgl/style/expression/is_constant.hpp include/mbgl/style/expression/is_expression.hpp + include/mbgl/style/expression/length.hpp include/mbgl/style/expression/let.hpp include/mbgl/style/expression/literal.hpp include/mbgl/style/expression/match.hpp @@ -478,6 +479,7 @@ set(MBGL_CORE_FILES src/mbgl/style/expression/interpolate.cpp src/mbgl/style/expression/is_constant.cpp src/mbgl/style/expression/is_expression.cpp + src/mbgl/style/expression/length.cpp src/mbgl/style/expression/let.cpp src/mbgl/style/expression/literal.cpp src/mbgl/style/expression/match.cpp diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake index 3d82899538..f087c32511 100644 --- a/cmake/mbgl.cmake +++ b/cmake/mbgl.cmake @@ -110,7 +110,7 @@ endfunction() if(MBGL_PLATFORM STREQUAL "ios") execute_process( - COMMAND git submodule update --init platform/ios/vendor/SMCalloutView platform/ios/uitest/KIF platform/ios/uitest/OHHTTPStubs + COMMAND git submodule update --init platform/ios/vendor/mapbox-events-ios platform/ios/uitest/KIF platform/ios/uitest/OHHTTPStubs WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") endif() diff --git a/include/mbgl/style/conversion/data_driven_property_value.hpp b/include/mbgl/style/conversion/data_driven_property_value.hpp index 8880d28fb1..5f4395f35a 100644 --- a/include/mbgl/style/conversion/data_driven_property_value.hpp +++ b/include/mbgl/style/conversion/data_driven_property_value.hpp @@ -8,6 +8,8 @@ #include <mbgl/style/expression/is_expression.hpp> #include <mbgl/style/expression/is_constant.hpp> #include <mbgl/style/expression/find_zoom_curve.hpp> +#include <mbgl/style/expression/literal.hpp> +#include <mbgl/style/expression/value.hpp> #include <unordered_set> @@ -32,12 +34,25 @@ struct Converter<DataDrivenPropertyValue<T>> { return {}; } - if (isFeatureConstant(**expression)) { + bool featureConstant = isFeatureConstant(**expression); + bool zoomConstant = isZoomConstant(**expression); + + if (featureConstant && !zoomConstant) { return DataDrivenPropertyValue<T>(CameraFunction<T>(std::move(*expression))); - } else if (isZoomConstant(**expression)) { + } else if (!featureConstant && zoomConstant) { return DataDrivenPropertyValue<T>(SourceFunction<T>(std::move(*expression))); - } else { + } else if (!featureConstant && !zoomConstant) { return DataDrivenPropertyValue<T>(CompositeFunction<T>(std::move(*expression))); + } else { + // If an expression is neither zoom- nor feature-dependent, it + // should have been reduced to a Literal when it was parsed. + auto literal = dynamic_cast<Literal*>(expression->get()); + assert(literal); + optional<T> constant = fromExpressionValue<T>(literal->getValue()); + if (!constant) { + return {}; + } + return DataDrivenPropertyValue<T>(*constant); } } else if (!isObject(value)) { optional<T> constant = convert<T>(value, error); diff --git a/include/mbgl/style/expression/array_assertion.hpp b/include/mbgl/style/expression/array_assertion.hpp index 7f36f8aac2..af153611ff 100644 --- a/include/mbgl/style/expression/array_assertion.hpp +++ b/include/mbgl/style/expression/array_assertion.hpp @@ -33,6 +33,9 @@ public: std::vector<optional<Value>> possibleOutputs() const override { return input->possibleOutputs(); } + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "array"; } private: std::unique_ptr<Expression> input; diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp index 43ea73f2ba..d1e919b10f 100644 --- a/include/mbgl/style/expression/assertion.hpp +++ b/include/mbgl/style/expression/assertion.hpp @@ -26,6 +26,8 @@ public: bool operator==(const Expression& e) const override; std::vector<optional<Value>> possibleOutputs() const override; + + std::string getOperator() const override; private: std::vector<std::unique_ptr<Expression>> inputs; diff --git a/include/mbgl/style/expression/at.hpp b/include/mbgl/style/expression/at.hpp index 27fccc761f..1e6f1c7dd2 100644 --- a/include/mbgl/style/expression/at.hpp +++ b/include/mbgl/style/expression/at.hpp @@ -31,6 +31,8 @@ public: std::vector<optional<Value>> possibleOutputs() const override { return { nullopt }; } + + std::string getOperator() const override { return "at"; } private: std::unique_ptr<Expression> index; diff --git a/include/mbgl/style/expression/boolean_operator.hpp b/include/mbgl/style/expression/boolean_operator.hpp index 115a096665..6d0f85756a 100644 --- a/include/mbgl/style/expression/boolean_operator.hpp +++ b/include/mbgl/style/expression/boolean_operator.hpp @@ -23,6 +23,7 @@ public: bool operator==(const Expression& e) const override; std::vector<optional<Value>> possibleOutputs() const override; + std::string getOperator() const override { return "any"; } private: std::vector<std::unique_ptr<Expression>> inputs; }; @@ -41,6 +42,7 @@ public: bool operator==(const Expression& e) const override; std::vector<optional<Value>> possibleOutputs() const override; + std::string getOperator() const override { return "all"; } private: std::vector<std::unique_ptr<Expression>> inputs; }; diff --git a/include/mbgl/style/expression/case.hpp b/include/mbgl/style/expression/case.hpp index e61a55fc6d..667ca53712 100644 --- a/include/mbgl/style/expression/case.hpp +++ b/include/mbgl/style/expression/case.hpp @@ -28,6 +28,7 @@ public: std::vector<optional<Value>> possibleOutputs() const override; + std::string getOperator() const override { return "case"; } private: std::vector<Branch> branches; std::unique_ptr<Expression> otherwise; diff --git a/include/mbgl/style/expression/coalesce.hpp b/include/mbgl/style/expression/coalesce.hpp index 52d9498cbd..a858bef695 100644 --- a/include/mbgl/style/expression/coalesce.hpp +++ b/include/mbgl/style/expression/coalesce.hpp @@ -38,6 +38,7 @@ public: return args.at(i).get(); } + std::string getOperator() const override { return "coalesce"; } private: Args args; }; diff --git a/include/mbgl/style/expression/coercion.hpp b/include/mbgl/style/expression/coercion.hpp index 40d2490186..d83bd6dfa7 100644 --- a/include/mbgl/style/expression/coercion.hpp +++ b/include/mbgl/style/expression/coercion.hpp @@ -28,6 +28,7 @@ public: std::vector<optional<Value>> possibleOutputs() const override; + std::string getOperator() const override; private: EvaluationResult (*coerceSingleValue) (const Value& v); std::vector<std::unique_ptr<Expression>> inputs; diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp index 8b74027578..6baaae862f 100644 --- a/include/mbgl/style/expression/compound_expression.hpp +++ b/include/mbgl/style/expression/compound_expression.hpp @@ -40,14 +40,16 @@ namespace detail { // each CompoundExpression definition's type::Type data from the type of its // "evaluate" function. struct SignatureBase { - SignatureBase(type::Type result_, variant<std::vector<type::Type>, VarargsType> params_) : + SignatureBase(type::Type result_, variant<std::vector<type::Type>, VarargsType> params_, std::string name_) : result(std::move(result_)), - params(std::move(params_)) + params(std::move(params_)), + name(std::move(name_)) {} virtual ~SignatureBase() = default; - virtual std::unique_ptr<Expression> makeExpression(const std::string& name, std::vector<std::unique_ptr<Expression>>) const = 0; + virtual std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>>) const = 0; type::Type result; variant<std::vector<type::Type>, VarargsType> params; + std::string name; }; } // namespace detail @@ -111,6 +113,10 @@ public: } return false; } + + std::string getOperator() const override { + return signature.name; + } private: Signature signature; @@ -128,8 +134,7 @@ struct CompoundExpressionRegistry { ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); -ParseResult createCompoundExpression(const std::string& name, - const CompoundExpressionRegistry::Definition& definition, +ParseResult createCompoundExpression(const CompoundExpressionRegistry::Definition& definition, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx); diff --git a/include/mbgl/style/expression/equals.hpp b/include/mbgl/style/expression/equals.hpp index 80550bd59d..54df890a68 100644 --- a/include/mbgl/style/expression/equals.hpp +++ b/include/mbgl/style/expression/equals.hpp @@ -21,6 +21,7 @@ public: EvaluationResult evaluate(const EvaluationContext&) const override; std::vector<optional<Value>> possibleOutputs() const override; + std::string getOperator() const override { return negate ? "!=" : "=="; } private: std::unique_ptr<Expression> lhs; std::unique_ptr<Expression> rhs; diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index cf9fa0cb21..c41ac0b5f1 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -135,6 +135,17 @@ public: * complete set of outputs is statically undecidable. */ virtual std::vector<optional<Value>> possibleOutputs() const = 0; + + virtual mbgl::Value serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + eachChild([&](const Expression &child) { + serialized.emplace_back(child.serialize()); + }); + return serialized; + }; + + virtual std::string getOperator() const = 0; protected: template <typename T> diff --git a/include/mbgl/style/expression/interpolate.hpp b/include/mbgl/style/expression/interpolate.hpp index dbed74b4cd..cc744ac7b7 100644 --- a/include/mbgl/style/expression/interpolate.hpp +++ b/include/mbgl/style/expression/interpolate.hpp @@ -185,6 +185,9 @@ public: } return false; } + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "interpolate"; } }; } // namespace expression diff --git a/include/mbgl/style/expression/length.hpp b/include/mbgl/style/expression/length.hpp new file mode 100644 index 0000000000..1d754f1932 --- /dev/null +++ b/include/mbgl/style/expression/length.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/expression/parsing_context.hpp> + +#include <memory> +#include <vector> + +namespace mbgl { +namespace style { +namespace expression { + +class Length : public Expression { +public: + Length(std::unique_ptr<Expression> input); + + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); + + EvaluationResult evaluate(const EvaluationContext& params) const override; + void eachChild(const std::function<void(const Expression&)>& visit) const override; + bool operator==(const Expression& e) const override; + std::vector<optional<Value>> possibleOutputs() const override; + std::string getOperator() const override { return "length"; } + +private: + std::unique_ptr<Expression> input; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/let.hpp b/include/mbgl/style/expression/let.hpp index 6829ded9b8..75d2adda62 100644 --- a/include/mbgl/style/expression/let.hpp +++ b/include/mbgl/style/expression/let.hpp @@ -39,6 +39,8 @@ public: return result.get(); } + mbgl::Value serialize() const override; + std::string getOperator() const override { return "let"; } private: Bindings bindings; std::unique_ptr<Expression> result; @@ -66,6 +68,8 @@ public: std::vector<optional<Value>> possibleOutputs() const override; + mbgl::Value serialize() const override; + std::string getOperator() const override { return "var"; } private: std::string name; std::shared_ptr<Expression> value; diff --git a/include/mbgl/style/expression/literal.hpp b/include/mbgl/style/expression/literal.hpp index 82983d78af..a00c468efc 100644 --- a/include/mbgl/style/expression/literal.hpp +++ b/include/mbgl/style/expression/literal.hpp @@ -12,8 +12,16 @@ namespace expression { class Literal : public Expression { public: - Literal(Value value_) : Expression(typeOf(value_)), value(value_) {} - Literal(type::Array type_, std::vector<Value> value_) : Expression(type_), value(value_) {} + Literal(Value value_) + : Expression(typeOf(value_)) + , value(value_) + {} + + Literal(type::Array type_, std::vector<Value> value_) + : Expression(type_) + , value(value_) + {} + EvaluationResult evaluate(const EvaluationContext&) const override { return value; } @@ -32,7 +40,13 @@ public: std::vector<optional<Value>> possibleOutputs() const override { return {{ value }}; } + + Value getValue() const { + return value; + } + mbgl::Value serialize() const override; + std::string getOperator() const override { return "literal"; } private: Value value; }; diff --git a/include/mbgl/style/expression/match.hpp b/include/mbgl/style/expression/match.hpp index 682d784b0f..3775e38067 100644 --- a/include/mbgl/style/expression/match.hpp +++ b/include/mbgl/style/expression/match.hpp @@ -32,7 +32,9 @@ public: bool operator==(const Expression& e) const override; std::vector<optional<Value>> possibleOutputs() const override; - + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "match"; } private: std::unique_ptr<Expression> input; Branches branches; diff --git a/include/mbgl/style/expression/step.hpp b/include/mbgl/style/expression/step.hpp index 6bf42e20f1..2f9524a53c 100644 --- a/include/mbgl/style/expression/step.hpp +++ b/include/mbgl/style/expression/step.hpp @@ -38,6 +38,8 @@ public: static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); + mbgl::Value serialize() const override; + std::string getOperator() const override { return "step"; } private: const std::unique_ptr<Expression> input; const std::map<double, std::unique_ptr<Expression>> stops; diff --git a/include/mbgl/style/expression/value.hpp b/include/mbgl/style/expression/value.hpp index be5be64752..7839ff2ca7 100644 --- a/include/mbgl/style/expression/value.hpp +++ b/include/mbgl/style/expression/value.hpp @@ -110,6 +110,7 @@ struct ValueConverter<float> { template<> struct ValueConverter<mbgl::Value> { static Value toExpressionValue(const mbgl::Value& value); + static mbgl::Value fromExpressionValue(const Value& value); }; template <typename T, std::size_t N> diff --git a/include/mbgl/style/function/convert.hpp b/include/mbgl/style/function/convert.hpp index 8e544d3ad5..401a81d52e 100644 --- a/include/mbgl/style/function/convert.hpp +++ b/include/mbgl/style/function/convert.hpp @@ -49,6 +49,7 @@ public: return {}; } + std::string getOperator() const override { return "error"; } private: std::string message; }; diff --git a/package.json b/package.json index 4ff4b32735..977cd2b09c 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "license": "BSD-2-Clause", "dependencies": { - "nan": "^2.6.2", + "nan": "~2.8", "node-pre-gyp": "^0.6.37", "npm-run-all": "^4.0.2" }, diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index fa9b1d29cc..60d3dc6b70 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,10 +2,29 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. -## master - - - HeatmapLayer [#11046](https://github.com/mapbox/mapbox-gl-native/pull/11046) - +## 6.0.0-beta.3 - March 2, 2018 + - Added missing local reference deletes [#11243](https://github.com/mapbox/mapbox-gl-native/pull/11243), [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) + - Remove obsolete camera api [#11201](https://github.com/mapbox/mapbox-gl-native/pull/11201) + - Fix UTF-8 encoding, add missing package-info.java files [#11261](https://github.com/mapbox/mapbox-gl-native/pull/11261) + - Rework expression api [#11210](https://github.com/mapbox/mapbox-gl-native/pull/11210) + - LatLngBounds fixes [#11333](https://github.com/mapbox/mapbox-gl-native/pull/11333), [#11307](https://github.com/mapbox/mapbox-gl-native/pull/11307), [#11308](https://github.com/mapbox/mapbox-gl-native/pull/11308), [#11309](https://github.com/mapbox/mapbox-gl-native/pull/11309), [#11226](https://github.com/mapbox/mapbox-gl-native/pull/11226) + - New gestures library [#11221](https://github.com/mapbox/mapbox-gl-native/pull/11221) + - Expose ImageSource coordinates setter [#11262](https://github.com/mapbox/mapbox-gl-native/pull/11262) + - Add heatmap color property [#11220](https://github.com/mapbox/mapbox-gl-native/pull/11220) + - Add support for mapzen terrarium raster-dem encoding [#11339](https://github.com/mapbox/mapbox-gl-native/pull/11339) + +## 5.5.0 - March 1, 2018 + - TileJSON Bounds allows values inclusive of world extents [#11178](https://github.com/mapbox/mapbox-gl-native/pull/11178) + - LatLngBounds returned by VisibleRegion when map is rotated [#11226](https://github.com/mapbox/mapbox-gl-native/pull/11226) + - Custom Layer fixes & black list VAO on mali t720 [#11239](https://github.com/mapbox/mapbox-gl-native/pull/11239) + - Check if Activity isn't finishing before showing dialog [#11244](https://github.com/mapbox/mapbox-gl-native/pull/11244) + - Decouple MapPadding from overlain views [#11258](https://github.com/mapbox/mapbox-gl-native/pull/11258) + - Don't disable zoom button controller zooming with gesture disabled zoom [#11259](https://github.com/mapbox/mapbox-gl-native/pull/11259) + - Expose ImageSource coordinates setter [#11262](https://github.com/mapbox/mapbox-gl-native/pull/11262) + - Add missing DeleteLocalRefs [#11272](https://github.com/mapbox/mapbox-gl-native/pull/11272) + - Continue loading style even if we mutate it [#11294](https://github.com/mapbox/mapbox-gl-native/pull/11294) + - Update telemetry version for OkHttp [#11338](https://github.com/mapbox/mapbox-gl-native/pull/11338) + ## 6.0.0-beta.2 - February 13, 2018 - Deprecate LocationEngine [#11185](https://github.com/mapbox/mapbox-gl-native/pull/11185) - Remove LOST from SDK [11186](https://github.com/mapbox/mapbox-gl-native/pull/11186) diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 173b4fa7f8..94b816c1ab 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -3,6 +3,7 @@ apply plugin: 'com.android.library' dependencies { api dependenciesList.mapboxAndroidTelemetry api dependenciesList.mapboxJavaGeoJSON + api dependenciesList.mapboxAndroidGestures implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 implementation dependenciesList.timber diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java deleted file mode 100644 index b7bcb925a1..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.view.MotionEvent; - -/** - * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie - * (code.almeros.com) - * <p> - * All rights reserved. - * <p> - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * <p> - * 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. - * <p> - * 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 context; - protected boolean gestureInProgress; - - protected MotionEvent prevEvent; - protected MotionEvent currEvent; - - protected float currPressure; - protected float prevPressure; - protected long timeDelta; - - /** - * 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) { - this.context = 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 {@code true} as handled - */ - public boolean onTouchEvent(MotionEvent event) { - final int actionCode = event.getAction() & MotionEvent.ACTION_MASK; - if (!gestureInProgress) { - 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 gestureInProgress) 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 - * gestureInProgress). - * - * @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 = prevEvent; - - // Reset currEvent - if (currEvent != null) { - currEvent.recycle(); - currEvent = null; - } - currEvent = MotionEvent.obtain(curr); - - // Delta time - timeDelta = curr.getEventTime() - prev.getEventTime(); - - // Pressure - currPressure = curr.getPressure(curr.getActionIndex()); - prevPressure = prev.getPressure(prev.getActionIndex()); - } - - protected void resetState() { - if (prevEvent != null) { - prevEvent.recycle(); - prevEvent = null; - } - if (currEvent != null) { - currEvent.recycle(); - currEvent = null; - } - gestureInProgress = 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 gestureInProgress; - } - - /** - * 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 timeDelta; - } - - /** - * Return the event time of the current GestureDetector event being - * processed. - * - * @return Current GestureDetector event time in milliseconds. - */ - public long getEventTime() { - return currEvent.getEventTime(); - } - -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java deleted file mode 100644 index bc7dda6159..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.graphics.PointF; -import android.view.MotionEvent; - -/** - * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie - * (code.almeros.com) - * <p> - * All rights reserved. - * <p> - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * <p> - * 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. - * <p> - * 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 listener; - - private PointF focusExternal = new PointF(); - private PointF focusDeltaExternal = new PointF(); - - public MoveGestureDetector(Context context, OnMoveGestureListener listener) { - super(context); - this.listener = listener; - } - - @Override - protected void handleStartProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_DOWN: - resetState(); // In case we missed an UP/CANCEL event - - prevEvent = MotionEvent.obtain(event); - timeDelta = 0; - - updateStateByEvent(event); - break; - - case MotionEvent.ACTION_MOVE: - gestureInProgress = listener.onMoveBegin(this); - break; - } - } - - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - listener.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 (currPressure / prevPressure > PRESSURE_THRESHOLD) { - final boolean updatePrevious = listener.onMove(this); - if (updatePrevious) { - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(event); - } - } - break; - } - } - - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); - - final MotionEvent prev = prevEvent; - - // Focus intenal - PointF currFocusInternal = determineFocalPoint(curr); - PointF prevFocusInternal = determineFocalPoint(prev); - - // Focus external - // - Prevent skipping of focus delta when a finger is added or removed - boolean skipNextMoveEvent = prev.getPointerCount() != curr - .getPointerCount(); - focusDeltaExternal = skipNextMoveEvent ? FOCUS_DELTA_ZERO - : new PointF(currFocusInternal.x - prevFocusInternal.x, - currFocusInternal.y - prevFocusInternal.y); - - // - Don't directly use mFocusInternal (or skipping will occur). Add - // unskipped delta values to focusExternal instead. - focusExternal.x += focusDeltaExternal.x; - focusExternal.y += focusDeltaExternal.y; - } - - /** - * Determine (multi)finger focal point (a.k.a. center point between all - * fingers) - * - * @param motionEvent a {@link MotionEvent} object. - * @return PointF focal point - */ - private PointF determineFocalPoint(MotionEvent motionEvent) { - // Number of fingers on screen - final int pCount = motionEvent.getPointerCount(); - float x = 0.0f; - float y = 0.0f; - - for (int i = 0; i < pCount; i++) { - x += motionEvent.getX(i); - y += motionEvent.getY(i); - } - - return new PointF(x / pCount, y / pCount); - } - - public float getFocusX() { - return focusExternal.x; - } - - public float getFocusY() { - return focusExternal.y; - } - - public PointF getFocusDelta() { - return focusDeltaExternal; - } - -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java deleted file mode 100644 index 8c111a68df..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java +++ /dev/null @@ -1,180 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.view.MotionEvent; - -/** - * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie - * (code.almeros.com) - * <p> - * All rights reserved. - * <p> - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * <p> - * 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. - * <p> - * 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 listener; - private boolean sloppyGesture; - - public RotateGestureDetector(Context context, - OnRotateGestureListener listener) { - super(context); - this.listener = 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 - prevEvent = MotionEvent.obtain(event); - timeDelta = 0; - - updateStateByEvent(event); - - // See if we have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start gesture now - gestureInProgress = listener.onRotateBegin(this); - } - break; - - case MotionEvent.ACTION_MOVE: - if (!sloppyGesture) { - break; - } - - // See if we still have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start normal gesture now - gestureInProgress = listener.onRotateBegin(this); - } - - break; - - case MotionEvent.ACTION_POINTER_UP: - if (!sloppyGesture) { - break; - } - - break; - } - } - - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_UP: - // Gesture ended but - updateStateByEvent(event); - - if (!sloppyGesture) { - listener.onRotateEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_CANCEL: - if (!sloppyGesture) { - listener.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 (currPressure / prevPressure > PRESSURE_THRESHOLD) { - final boolean updatePrevious = listener.onRotate(this); - if (updatePrevious) { - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(event); - } - } - break; - } - } - - @Override - protected void resetState() { - super.resetState(); - sloppyGesture = 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(prevFingerDiffY, prevFingerDiffX) - - Math.atan2(currFingerDiffY, currFingerDiffX); - return (float) (diffRadians * 180.0 / Math.PI); - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java deleted file mode 100644 index 9396578e48..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java +++ /dev/null @@ -1,214 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.view.MotionEvent; - -/** - * @author Robert Nordan (robert.nordan@norkart.no) - * <p> - * Copyright (c) 2013, Norkart AS - * <p> - * All rights reserved. - * <p> - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * <p> - * 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. - * <p> - * 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 prevAverageY; - private float currAverageY; - - private final OnShoveGestureListener listener; - private boolean sloppyGesture; - - public ShoveGestureDetector(Context context, OnShoveGestureListener listener) { - super(context); - this.listener = 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 - prevEvent = MotionEvent.obtain(event); - timeDelta = 0; - - updateStateByEvent(event); - - // See if we have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start gesture now - gestureInProgress = listener.onShoveBegin(this); - } - break; - - case MotionEvent.ACTION_MOVE: - if (!sloppyGesture) { - break; - } - - // See if we still have a sloppy gesture - sloppyGesture = isSloppyGesture(event); - if (!sloppyGesture) { - // No, start normal gesture now - gestureInProgress = listener.onShoveBegin(this); - } - - break; - - case MotionEvent.ACTION_POINTER_UP: - if (!sloppyGesture) { - break; - } - - break; - } - } - - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_UP: - // Gesture ended but - updateStateByEvent(event); - - if (!sloppyGesture) { - listener.onShoveEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_CANCEL: - if (!sloppyGesture) { - listener.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 (currPressure / prevPressure > PRESSURE_THRESHOLD - && Math.abs(getShovePixelsDelta()) > 0.5f) { - final boolean updatePrevious = listener.onShove(this); - if (updatePrevious) { - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(event); - } - } - break; - } - } - - @Override - protected void resetState() { - super.resetState(); - sloppyGesture = false; - prevAverageY = 0.0f; - currAverageY = 0.0f; - } - - @Override - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); - - final MotionEvent prev = prevEvent; - float py0 = prev.getY(0); - float py1 = prev.getY(1); - prevAverageY = (py0 + py1) / 2.0f; - - float cy0 = curr.getY(0); - float cy1 = curr.getY(1); - currAverageY = (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(currFingerDiffY, currFingerDiffX)); - // 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 currAverageY - prevAverageY; - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java deleted file mode 100644 index db492b6556..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.almeros.android.multitouch.gesturedetectors; - -import android.content.Context; -import android.graphics.PointF; -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) - * <p> - * All rights reserved. - * <p> - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * <p> - * 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. - * <p> - * 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 edgeSlop; - - protected float prevFingerDiffX; - protected float prevFingerDiffY; - protected float currFingerDiffX; - protected float currFingerDiffY; - - private float currLen; - private float prevLen; - - private PointF focus; - - public TwoFingerGestureDetector(Context context) { - super(context); - - ViewConfiguration config = ViewConfiguration.get(context); - - edgeSlop = 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 = prevEvent; - - currLen = -1; - prevLen = -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; - prevFingerDiffX = pvx; - prevFingerDiffY = 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; - currFingerDiffX = cvx; - currFingerDiffY = cvy; - focus = determineFocalPoint(curr); - } - - /** - * Return the current distance between the two pointers forming the gesture - * in progress. - * - * @return Distance between pointers in pixels. - */ - public float getCurrentSpan() { - if (currLen == -1) { - final float cvx = currFingerDiffX; - final float cvy = currFingerDiffY; - currLen = (float) Math.sqrt(cvx * cvx + cvy * cvy); - } - return currLen; - } - - /** - * Return the previous distance between the two pointers forming the gesture - * in progress. - * - * @return Previous distance between pointers in pixels. - */ - public float getPreviousSpan() { - if (prevLen == -1) { - final float pvx = prevFingerDiffX; - final float pvy = prevFingerDiffY; - prevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy); - } - return prevLen; - } - - /** - * MotionEvent has no getRawX(int) method; simulate it pending future API - * approval. - * - * @param event Motion Event - * @param pointerIndex Pointer Index - * @return Raw x value or 0 - */ - protected static float getRawX(MotionEvent event, int pointerIndex) { - float offset = event.getRawX() - event.getX(); - if (pointerIndex < event.getPointerCount()) { - return event.getX(pointerIndex) + offset; - } - return 0.0f; - } - - /** - * MotionEvent has no getRawY(int) method; simulate it pending future API - * approval. - * - * @param event Motion Event - * @param pointerIndex Pointer Index - * @return Raw y value or 0 - */ - protected static float getRawY(MotionEvent event, int pointerIndex) { - float offset = event.getRawY() - event.getY(); - if (pointerIndex < event.getPointerCount()) { - return event.getY(pointerIndex) + offset; - } - return 0.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 Motion Event - * @return {@code true} if is sloppy gesture, {@code false} if not - */ - protected boolean isSloppyGesture(MotionEvent event) { - // As orientation can change, query the metrics in touch down - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - float rightSlopEdge = metrics.widthPixels - edgeSlop; - float bottomSlopEdge = metrics.heightPixels - edgeSlop; - - final float edgeSlop = this.edgeSlop; - - 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 > rightSlopEdge - || y0 > bottomSlopEdge; - boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlopEdge - || y1 > bottomSlopEdge; - - if (p0sloppy && p1sloppy) { - return true; - } else if (p0sloppy) { - return true; - } else if (p1sloppy) { - return true; - } - return false; - } - - /** - * Determine (multi)finger focal point (a.k.a. center point between all - * fingers) - * - * @param motionEvent Motion Event - * @return PointF focal point - */ - public static PointF determineFocalPoint(MotionEvent motionEvent) { - // Number of fingers on screen - final int pCount = motionEvent.getPointerCount(); - float x = 0.0f; - float y = 0.0f; - - for (int i = 0; i < pCount; i++) { - x += motionEvent.getX(i); - y += motionEvent.getY(i); - } - - return new PointF(x / pCount, y / pCount); - } - - public float getFocusX() { - return focus.x; - } - - public float getFocusY() { - return focus.y; - } - -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/package-info.java deleted file mode 100644 index cff2f086dc..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Do not use this package. Internal use only. - */ -package com.almeros.android.multitouch.gesturedetectors; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index e963993ae3..b3dcf87c7e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -8,9 +8,6 @@ import android.support.annotation.NonNull; import android.support.annotation.UiThread; import android.text.TextUtils; -import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEnginePriority; -import com.mapbox.android.core.location.LocationEngineProvider; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; import com.mapbox.mapboxsdk.maps.Events; @@ -32,7 +29,6 @@ public final class Mapbox { private Context context; private String accessToken; private Boolean connected; - private LocationEngine locationEngine; /** * Get an instance of Mapbox. @@ -48,22 +44,18 @@ public final class Mapbox { public static synchronized Mapbox getInstance(@NonNull Context context, @NonNull String accessToken) { if (INSTANCE == null) { Context appContext = context.getApplicationContext(); - LocationEngineProvider locationEngineProvider = new LocationEngineProvider(context); - LocationEngine locationEngine = locationEngineProvider.obtainBestLocationEngineAvailable(); - INSTANCE = new Mapbox(appContext, accessToken, locationEngine); - locationEngine.setPriority(LocationEnginePriority.NO_POWER); + INSTANCE = new Mapbox(appContext, accessToken); - Events.initiliaze(); + Events.initialize(); ConnectivityReceiver.instance(appContext); } return INSTANCE; } - Mapbox(@NonNull Context context, @NonNull String accessToken, LocationEngine locationEngine) { + Mapbox(@NonNull Context context, @NonNull String accessToken) { this.context = context; this.accessToken = accessToken; - this.locationEngine = locationEngine; } /** @@ -136,16 +128,4 @@ public final class Mapbox { NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return (activeNetwork != null && activeNetwork.isConnected()); } - - /** - * Returns the location engine used by the SDK. - * - * @return the location engine configured - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. - */ - @Deprecated - public static LocationEngine getLocationEngine() { - return INSTANCE.locationEngine; - } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/package-info.java new file mode 100644 index 0000000000..57d840af52 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Attribution API classes. + */ +package com.mapbox.mapboxsdk.attribution; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java index 50e33f4f9f..8ef0d5b523 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java @@ -148,6 +148,26 @@ public final class CameraUpdateFactory { return new ZoomUpdate(ZoomUpdate.ZOOM_TO, zoom); } + /** + * Returns a CameraUpdate that moves the camera viewpoint to a particular bearing. + * + * @param bearing Bearing to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate bearingTo(double bearing) { + return new CameraPositionUpdate(bearing, null, -1, -1); + } + + /** + * Returns a CameraUpdate that moves the camera viewpoint to a particular tilt. + * + * @param tilt Tilt to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate tiltTo(double tilt) { + return new CameraPositionUpdate(-1, null, tilt, -1); + } + // // CameraUpdate types // diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java index 1a7544d33a..7a17e500ca 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java @@ -37,6 +37,20 @@ public class GeometryConstants { public static final double MIN_LATITUDE = -90; /** + * This constant represents the latitude span when representing a geolocation. + * + * @since 6.0.0 + */ + public static final double LATITUDE_SPAN = 180; + + /** + * This constant represents the longitude span when representing a geolocation. + * + * @since 6.0.0 + */ + public static final double LONGITUDE_SPAN = 360; + + /** * This constant represents the highest latitude value available to represent a geolocation. * * @since 6.0.0 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 60362dd2e9..6f263e4635 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -48,6 +48,31 @@ public class MapboxConstants { public static final long VELOCITY_THRESHOLD_IGNORE_FLING = 1000; /** + * Value by which the default rotation threshold will be increased when scaling + */ + public static final float ROTATION_THRESHOLD_INCREASE_WHEN_SCALING = 25f; + + /** + * Time within which user needs to lift fingers for velocity animation to start. + */ + public static final long SCHEDULED_ANIMATION_TIMEOUT = 150L; + + /** + * Minimum angular velocity for rotation animation + */ + public static final float MINIMUM_ANGULAR_VELOCITY = 1.5f; + + /** + * Maximum angular velocity for rotation animation + */ + public static final float MAXIMUM_ANGULAR_VELOCITY = 20f; + + /** + * Factor to calculate tilt change based on pixel change during shove gesture. + */ + public static final float SHOVE_PIXEL_CHANGE_FACTOR = 0.1f; + + /** * The currently supported minimum zoom level. */ public static final float MINIMUM_ZOOM = 0.0f; @@ -78,14 +103,14 @@ public class MapboxConstants { public static final double MINIMUM_DIRECTION = 0; /** - * The currently used minimun scale factor to clamp to when a quick zoom gesture occurs + * The currently used minimum scale factor to clamp to when a quick zoom gesture occurs */ public static final float MINIMUM_SCALE_FACTOR_CLAMP = 0.00f; /** * The currently used maximum scale factor to clamp to when a quick zoom gesture occurs */ - public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.45f; + public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.15f; /** * Fragment Argument Key for MapboxMapOptions diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java deleted file mode 100644 index c042b00577..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.mapbox.mapboxsdk.constants; - -import android.support.annotation.IntDef; - -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * MyBearingTracking exposes different types of bearing tracking modes. - * <p> - * These modes visualise the user direction by extracting the direction from either sensor or location data. - * </p> - * <p> - * Required to enable showing the user location first through {@link MapboxMap#setMyLocationEnabled(boolean)}. - * </p> - * - * @see com.mapbox.mapboxsdk.maps.TrackingSettings#setMyBearingTrackingMode(int) - * @see MyLocationView#setMyBearingTrackingMode(int) - */ -public class MyBearingTracking { - - @IntDef( {NONE, COMPASS, GPS, GPS_NORTH_FACING}) - @Retention(RetentionPolicy.SOURCE) - public @interface Mode { - } - - /** - * Bearing tracking is disabled - */ - public static final int NONE = 0x00000000; - - /** - * Tracking the bearing of the user based on sensor data - */ - public static final int COMPASS = 0x00000004; - - /** - * Tracking the bearing of the user based on GPS data - */ - public static final int GPS = 0x00000008; - - /** - * Tracking the bearing of the user based on GPS data, but camera always faces north direction - */ - public static final int GPS_NORTH_FACING = 0x0000000B; - -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java deleted file mode 100644 index 1283283fa5..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.mapbox.mapboxsdk.constants; - -import android.support.annotation.IntDef; - -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.TrackingSettings; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * MyLocationTracking exposes types of location tracking modes. - * * <p> - * This allows tracking the user location on screen by updating the camera position when a location update occurs. - * </p> - * <p> - * Required to enable showing the user location first through {@link MapboxMap#setMyLocationEnabled(boolean)}. - * </p> - * - * @see MapboxMap#setMyLocationEnabled(boolean) - * @see TrackingSettings#setMyLocationTrackingMode(int) - */ -public class MyLocationTracking { - - @IntDef( {TRACKING_NONE, TRACKING_FOLLOW}) - @Retention(RetentionPolicy.SOURCE) - public @interface Mode { - } - - /** - * Tracking the location of the user is disabled. - */ - public static final int TRACKING_NONE = 0x00000000; - - /** - * Tracking the location of the user. {@link MapView} will reposition to center of {@link MyLocationView} - */ - public static final int TRACKING_FOLLOW = 0x00000004; - -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index cf647224ae..fb12a76b55 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -29,6 +29,10 @@ public class LatLngBounds implements Parcelable { * Construct a new LatLngBounds based on its corners, given in NESW * order. * + * If eastern longitude is smaller than the western one, bounds will include antimeridian. + * For example, if the NE point is (10, -170) and the SW point is (-10, 170), then bounds will span over 20 degrees + * and cross the antimeridian. + * * @param northLatitude Northern Latitude * @param eastLongitude Eastern Longitude * @param southLatitude Southern Latitude @@ -48,10 +52,9 @@ public class LatLngBounds implements Parcelable { * @return the bounds representing the world */ public static LatLngBounds world() { - return new LatLngBounds.Builder() - .include(new LatLng(GeometryConstants.MAX_LATITUDE, GeometryConstants.MAX_LONGITUDE)) - .include(new LatLng(GeometryConstants.MIN_LATITUDE, GeometryConstants.MIN_LONGITUDE)) - .build(); + return LatLngBounds.from( + GeometryConstants.MAX_LATITUDE, GeometryConstants.MAX_LONGITUDE, + GeometryConstants.MIN_LATITUDE, GeometryConstants.MIN_LONGITUDE); } /** @@ -61,8 +64,21 @@ public class LatLngBounds implements Parcelable { * @return LatLng center of this LatLngBounds */ public LatLng getCenter() { - return new LatLng((this.latitudeNorth + this.latitudeSouth) / 2, - (this.longitudeEast + this.longitudeWest) / 2); + double latCenter = (this.latitudeNorth + this.latitudeSouth) / 2.0; + double longCenter; + + if (this.longitudeEast > this.longitudeWest) { + longCenter = (this.longitudeEast + this.longitudeWest) / 2; + } else { + double halfSpan = (GeometryConstants.LONGITUDE_SPAN + this.longitudeEast - this.longitudeWest) / 2.0; + longCenter = this.longitudeWest + halfSpan; + if (longCenter >= GeometryConstants.MAX_LONGITUDE) { + longCenter = this.longitudeEast - halfSpan; + } + return new LatLng(latCenter, longCenter); + } + + return new LatLng(latCenter, longCenter); } /** @@ -163,10 +179,26 @@ public class LatLngBounds implements Parcelable { * @return Span distance */ public double getLongitudeSpan() { - return Math.abs(this.longitudeEast - this.longitudeWest); + double longSpan = Math.abs(this.longitudeEast - this.longitudeWest); + if (this.longitudeEast > this.longitudeWest) { + return longSpan; + } + + // shortest span contains antimeridian + return GeometryConstants.LONGITUDE_SPAN - longSpan; } + static double getLongitudeSpan(final double longEast, final double longWest) { + double longSpan = Math.abs(longEast - longWest); + if (longEast > longWest) { + return longSpan; + } + + // shortest span contains antimeridian + return GeometryConstants.LONGITUDE_SPAN - longSpan; + } + /** * Validate if LatLngBounds is empty, determined if absolute distance is * @@ -196,21 +228,44 @@ public class LatLngBounds implements Parcelable { */ static LatLngBounds fromLatLngs(final List<? extends ILatLng> latLngs) { double minLat = GeometryConstants.MAX_LATITUDE; - double minLon = GeometryConstants.MAX_LONGITUDE; double maxLat = GeometryConstants.MIN_LATITUDE; - double maxLon = GeometryConstants.MIN_LONGITUDE; + + double eastLon = latLngs.get(0).getLongitude(); + double westLon = latLngs.get(1).getLongitude(); + double lonSpan = Math.abs(eastLon - westLon); + if (lonSpan < GeometryConstants.LONGITUDE_SPAN / 2) { + if (eastLon < westLon) { + double temp = eastLon; + eastLon = westLon; + westLon = temp; + } + } else { + lonSpan = GeometryConstants.LONGITUDE_SPAN - lonSpan; + if (westLon < eastLon) { + double temp = eastLon; + eastLon = westLon; + westLon = temp; + } + } for (final ILatLng gp : latLngs) { final double latitude = gp.getLatitude(); - final double longitude = gp.getLongitude(); - minLat = Math.min(minLat, latitude); - minLon = Math.min(minLon, longitude); maxLat = Math.max(maxLat, latitude); - maxLon = Math.max(maxLon, longitude); + + final double longitude = gp.getLongitude(); + if (!containsLongitude(eastLon, westLon, longitude)) { + final double eastSpan = getLongitudeSpan(longitude, westLon); + final double westSpan = getLongitudeSpan(eastLon, longitude); + if (eastSpan <= westSpan) { + eastLon = longitude; + } else { + westLon = longitude; + } + } } - return new LatLngBounds(maxLat, maxLon, minLat, minLon); + return new LatLngBounds(maxLat, eastLon, minLat, westLon); } /** @@ -228,6 +283,8 @@ public class LatLngBounds implements Parcelable { * This values of latNorth and latSouth should be in the range of [-90, 90], * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, * otherwise IllegalArgumentException will be thrown. + * latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown. + * * <p> * This method doesn't recalculate most east or most west boundaries. * Note that lonEast and lonWest will be wrapped to be in the range of [-180, 180], @@ -257,6 +314,10 @@ public class LatLngBounds implements Parcelable { throw new IllegalArgumentException("latitude must be between -90 and 90"); } + if (latNorth < latSouth) { + throw new IllegalArgumentException("LatSouth cannot be less than latNorth"); + } + lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); @@ -322,6 +383,24 @@ public class LatLngBounds implements Parcelable { return false; } + + private boolean containsLatitude(final double latitude) { + return (latitude <= this.latitudeNorth) + && (latitude >= this.latitudeSouth); + } + + private boolean containsLongitude(final double longitude) { + return containsLongitude(this.longitudeEast, this.longitudeWest, longitude); + } + + static boolean containsLongitude(final double eastLon, final double westLon, final double longitude) { + if (eastLon > westLon) { + return (longitude <= eastLon) + && (longitude >= westLon); + } + return (longitude < eastLon) || (longitude > westLon); + } + /** * Determines whether this LatLngBounds contains a point. * @@ -329,12 +408,8 @@ public class LatLngBounds implements Parcelable { * @return true, if the point is contained within the bounds */ public boolean contains(final ILatLng latLng) { - final double latitude = latLng.getLatitude(); - final double longitude = latLng.getLongitude(); - return ((latitude <= this.latitudeNorth) - && (latitude >= this.latitudeSouth)) - && ((longitude <= this.longitudeEast) - && (longitude >= this.longitudeWest)); + return containsLatitude(latLng.getLatitude()) + && containsLongitude(latLng.getLongitude()); } /** @@ -344,7 +419,8 @@ public class LatLngBounds implements Parcelable { * @return true, if the bounds is contained within the bounds */ public boolean contains(final LatLngBounds other) { - return contains(other.getNorthEast()) && contains(other.getSouthWest()); + return contains(other.getNorthEast()) + && contains(other.getSouthWest()); } /** @@ -368,10 +444,21 @@ public class LatLngBounds implements Parcelable { * @return BoundingBox */ public LatLngBounds union(final double latNorth, final double lonEast, final double latSouth, final double lonWest) { - return new LatLngBounds((this.latitudeNorth < latNorth) ? latNorth : this.latitudeNorth, - (this.longitudeEast < lonEast) ? lonEast : this.longitudeEast, - (this.latitudeSouth > latSouth) ? latSouth : this.latitudeSouth, - (this.longitudeWest > lonWest) ? lonWest : this.longitudeWest); + double north = (this.latitudeNorth < latNorth) ? latNorth : this.latitudeNorth; + double south = (this.latitudeSouth > latSouth) ? latSouth : this.latitudeSouth; + + if (LatLngSpan.getLongitudeSpan(lonEast, this.longitudeWest) + < LatLngSpan.getLongitudeSpan(this.longitudeEast, lonWest)) { + return new LatLngBounds(north, + lonEast, + south, + this.longitudeWest); + } + + return new LatLngBounds(north, + this.longitudeEast, + south, + lonWest); } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java index 322c7dfb74..133949f743 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java @@ -4,6 +4,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.constants.GeometryConstants; + /** * A geographical span defined by its latitude and longitude span. */ @@ -136,4 +138,20 @@ public class LatLngSpan implements Parcelable { result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } + + /** + * Get the absolute distance, in degrees, between the west and + * east boundaries of this LatLngBounds + * + * @return Span distance + */ + static double getLongitudeSpan(double east, double west) { + double longSpan = Math.abs(east - west); + if (east > west) { + return longSpan; + } + + // shortest span contains antimeridian + return GeometryConstants.LONGITUDE_SPAN - longSpan; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java index 2bcbd5ce40..5ccd6bd795 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.maps; +import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.Context; @@ -48,7 +49,17 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt @Override public void onClick(View view) { attributionSet = new AttributionBuilder(mapboxMap).build(); - showAttributionDialog(getAttributionTitles()); + + boolean isActivityFinishing = false; + if (context instanceof Activity) { + isActivityFinishing = ((Activity) context).isFinishing(); + } + + // check is hosting activity isn't finishing + // https://github.com/mapbox/mapbox-gl-native/issues/11238 + if (!isActivityFinishing) { + showAttributionDialog(getAttributionTitles()); + } } protected void showAttributionDialog(String[] attributionTitles) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Events.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Events.java index a4f6b233cf..7ba592f121 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Events.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Events.java @@ -26,7 +26,7 @@ public class Events { } } - public static void initiliaze() { + public static void initialize() { obtainTelemetry(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 8047e19809..17ade7b5fa 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -5,26 +5,31 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.PointF; +import android.os.Handler; import android.support.annotation.Nullable; -import android.support.v4.view.GestureDetectorCompat; -import android.support.v4.view.ScaleGestureDetectorCompat; -import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.view.InputDevice; import android.view.MotionEvent; -import android.view.ScaleGestureDetector; -import android.view.VelocityTracker; -import android.view.ViewConfiguration; - -import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector; -import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector; -import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector; +import android.view.animation.DecelerateInterpolator; + +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.MultiFingerTapGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; import com.mapbox.android.telemetry.Event; import com.mapbox.android.telemetry.MapEventFactory; import com.mapbox.android.telemetry.MapState; +import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.utils.MathUtils; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_ANIMATION; @@ -32,24 +37,15 @@ import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.RE /** * Manages gestures events on a MapView. - * <p> - * Relies on gesture detection code in almeros.android.multitouch.gesturedetectors. - * </p> */ final class MapGestureDetector { private final Transform transform; private final Projection projection; private final UiSettings uiSettings; - private final TrackingSettings trackingSettings; private final AnnotationManager annotationManager; private final CameraChangeDispatcher cameraChangeDispatcher; - private GestureDetectorCompat gestureDetector; - private ScaleGestureDetector scaleGestureDetector; - private RotateGestureDetector rotateGestureDetector; - private ShoveGestureDetector shoveGestureDetector; - // deprecated map touch API private MapboxMap.OnMapClickListener onMapClickListener; private MapboxMap.OnMapLongClickListener onMapLongClickListener; @@ -69,43 +65,73 @@ final class MapGestureDetector { private final CopyOnWriteArrayList<MapboxMap.OnScrollListener> onScrollListenerList = new CopyOnWriteArrayList<>(); - private PointF focalPoint; + private final CopyOnWriteArrayList<MapboxMap.OnMoveListener> onMoveListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList<MapboxMap.OnRotateListener> onRotateListenerList + = new CopyOnWriteArrayList<>(); + + private final CopyOnWriteArrayList<MapboxMap.OnScaleListener> onScaleListenerList + = new CopyOnWriteArrayList<>(); - private boolean twoTap; - private boolean quickZoom; - private boolean tiltGestureOccurred; - private boolean scrollGestureOccurred; + private final CopyOnWriteArrayList<MapboxMap.OnShoveListener> onShoveListenerList + = new CopyOnWriteArrayList<>(); - private boolean scaleGestureOccurred; - private boolean recentScaleGestureOccurred; - private long scaleBeginTime; + /** + * User-set focal point. + */ + private PointF focalPoint; + + private AndroidGesturesManager gesturesManager; + private boolean executeDoubleTap; - private boolean scaleAnimating; - private boolean rotateAnimating; + private Animator scaleAnimator; + private Animator rotateAnimator; + private final List<Animator> scheduledAnimators = new ArrayList<>(); - private VelocityTracker velocityTracker; - private boolean wasZoomingIn; - private boolean wasClockwiseRotating; - private boolean rotateGestureOccurred; + /** + * Cancels scheduled velocity animations if user doesn't lift fingers within + * {@link MapboxConstants#SCHEDULED_ANIMATION_TIMEOUT} + */ + private Handler animationsTimeoutHandler = new Handler(); MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings, - TrackingSettings trackingSettings, AnnotationManager annotationManager, - CameraChangeDispatcher cameraChangeDispatcher) { + AnnotationManager annotationManager, CameraChangeDispatcher cameraChangeDispatcher) { this.annotationManager = annotationManager; this.transform = transform; this.projection = projection; this.uiSettings = uiSettings; - this.trackingSettings = trackingSettings; this.cameraChangeDispatcher = cameraChangeDispatcher; - // Touch gesture detectors + // Checking for context != null for testing purposes if (context != null) { - gestureDetector = new GestureDetectorCompat(context, new GestureListener()); - gestureDetector.setIsLongpressEnabled(true); - scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener()); - ScaleGestureDetectorCompat.setQuickScaleEnabled(scaleGestureDetector, true); - rotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener()); - shoveGestureDetector = new ShoveGestureDetector(context, new ShoveGestureListener()); + gesturesManager = new AndroidGesturesManager(context); + + Set<Integer> shoveScaleSet = new HashSet<>(); + shoveScaleSet.add(AndroidGesturesManager.GESTURE_TYPE_SHOVE); + shoveScaleSet.add(AndroidGesturesManager.GESTURE_TYPE_SCALE); + + Set<Integer> shoveRotateSet = new HashSet<>(); + shoveRotateSet.add(AndroidGesturesManager.GESTURE_TYPE_SHOVE); + shoveRotateSet.add(AndroidGesturesManager.GESTURE_TYPE_ROTATE); + + Set<Integer> ScaleLongPressSet = new HashSet<>(); + ScaleLongPressSet.add(AndroidGesturesManager.GESTURE_TYPE_SCALE); + ScaleLongPressSet.add(AndroidGesturesManager.GESTURE_TYPE_LONG_PRESS); + + gesturesManager.setMutuallyExclusiveGestures(shoveScaleSet, shoveRotateSet, ScaleLongPressSet); + + gesturesManager.setStandardGestureListener(new StandardGestureListener()); + gesturesManager.setMoveGestureListener(new MoveGestureListener()); + gesturesManager.setStandardScaleGestureListener(new ScaleGestureListener( + context.getResources().getDimension(R.dimen.mapbox_minimum_scale_velocity) + )); + gesturesManager.setRotateGestureListener(new RotateGestureListener( + context.getResources().getDimension(R.dimen.mapbox_minimum_scale_span_when_rotating), + context.getResources().getDimension(R.dimen.mapbox_minimum_angular_velocity) + )); + gesturesManager.setShoveGestureListener(new ShoveGestureListener()); + gesturesManager.setMultiFingerTapGestureListener(new TapGestureListener()); } } @@ -132,8 +158,9 @@ final class MapGestureDetector { /** * Get the current active gesture focal point. * <p> - * This could be either the user provided focal point in {@link UiSettings#setFocalPoint(PointF)} or the focal point - * defined as a result of {@link TrackingSettings#setMyLocationEnabled(boolean)}. + * This could be either the user provided focal point in + * {@link UiSettings#setFocalPoint(PointF)}or <code>null</code>. + * If it's <code>null</code>, gestures will use focal pointed returned by the detector. * </p> * * @return the current active gesture focal point. @@ -149,118 +176,81 @@ final class MapGestureDetector { * Forwards event to the related gesture detectors. * </p> * - * @param event the MotionEvent + * @param motionEvent the MotionEvent * @return True if touch event is handled */ - boolean onTouchEvent(MotionEvent event) { - // framework can return null motion events in edge cases #9432 - if (event == null) { + boolean onTouchEvent(MotionEvent motionEvent) { + // Framework can return null motion events in edge cases #9432 + if (motionEvent == null) { return false; } // Check and ignore non touch or left clicks - if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + if ((motionEvent.getButtonState() != 0) && (motionEvent.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { return false; } - // Check two finger gestures first - scaleGestureDetector.onTouchEvent(event); - rotateGestureDetector.onTouchEvent(event); - shoveGestureDetector.onTouchEvent(event); + boolean result = gesturesManager.onTouchEvent(motionEvent); - // Handle two finger tap - switch (event.getActionMasked()) { + switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: - if (velocityTracker == null) { - velocityTracker = VelocityTracker.obtain(); - } else { - velocityTracker.clear(); - } - velocityTracker.addMovement(event); - // First pointer down, reset scaleGestureOccurred, used to avoid triggering a fling after a scale gesture #7666 - recentScaleGestureOccurred = false; + cancelAnimators(); transform.setGestureInProgress(true); break; + case MotionEvent.ACTION_UP: + transform.setGestureInProgress(false); - case MotionEvent.ACTION_POINTER_DOWN: - // Second pointer down - twoTap = event.getPointerCount() == 2 - && uiSettings.isZoomGesturesEnabled(); - if (twoTap) { - // Confirmed 2nd Finger Down - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(event.getX(), event.getY())); - MapState twoFingerTap = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - twoFingerTap.setGesture(Events.TWO_FINGER_TAP); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, twoFingerTap)); - } + // Start all awaiting velocity animations + animationsTimeoutHandler.removeCallbacksAndMessages(null); + for (Animator animator : scheduledAnimators) { + animator.start(); } + scheduledAnimators.clear(); break; - case MotionEvent.ACTION_POINTER_UP: - // Second pointer up + case MotionEvent.ACTION_CANCEL: + scheduledAnimators.clear(); + transform.setGestureInProgress(false); break; + } - case MotionEvent.ACTION_UP: - // First pointer up - long tapInterval = event.getEventTime() - event.getDownTime(); - boolean isTap = tapInterval <= ViewConfiguration.getTapTimeout(); - boolean inProgress = rotateGestureDetector.isInProgress() - || scaleGestureDetector.isInProgress() - || shoveGestureDetector.isInProgress(); - - if (twoTap && isTap && !inProgress) { - if (focalPoint != null) { - transform.zoom(false, focalPoint); - } else { - PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); - transform.zoom(false, focalPoint); - } - twoTap = false; - return true; - } + return result; + } - // Scroll / Pan Has Stopped - if (scrollGestureOccurred) { - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(event.getX(), event.getY())); - MapState dragend = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_DRAGEND, dragend)); - } - scrollGestureOccurred = false; + void cancelAnimators() { + animationsTimeoutHandler.removeCallbacksAndMessages(null); + scheduledAnimators.clear(); - if (!scaleAnimating && !rotateAnimating) { - cameraChangeDispatcher.onCameraIdle(); - } - } + cancelAnimator(scaleAnimator); + cancelAnimator(rotateAnimator); + } - twoTap = false; - transform.setGestureInProgress(false); - if (velocityTracker != null) { - velocityTracker.recycle(); - } - velocityTracker = null; - break; + private void cancelAnimator(Animator animator) { + if (animator != null && animator.isStarted()) { + animator.cancel(); + } + } - case MotionEvent.ACTION_CANCEL: - twoTap = false; - transform.setGestureInProgress(false); - if (velocityTracker != null) { - velocityTracker.recycle(); - } - velocityTracker = null; - break; - case MotionEvent.ACTION_MOVE: - if (velocityTracker != null) { - velocityTracker.addMovement(event); - velocityTracker.computeCurrentVelocity(1000); - } - break; + /** + * Posted on main thread with {@link #animationsTimeoutHandler}. Cancels all scheduled animators if needed. + */ + private Runnable cancelAnimatorsRunnable = new Runnable() { + @Override + public void run() { + cancelAnimators(); } + }; - return gestureDetector.onTouchEvent(event); + /** + * Schedules a velocity animator to be executed when user lift fingers, + * unless canceled by the {@link #cancelAnimatorsRunnable}. + * + * @param animator animator ot be scheduled + */ + private void scheduleAnimator(Animator animator) { + scheduledAnimators.add(animator); + animationsTimeoutHandler.removeCallbacksAndMessages(null); + animationsTimeoutHandler.postDelayed(cancelAnimatorsRunnable, MapboxConstants.SCHEDULED_ANIMATION_TIMEOUT); } /** @@ -269,7 +259,7 @@ final class MapGestureDetector { * Examples of such events are mouse scroll events, mouse moves, joystick & trackpad. * </p> * - * @param event The MotionEvent occured + * @param event The MotionEvent occurred * @return True is the event is handled */ boolean onGenericMotionEvent(MotionEvent event) { @@ -291,7 +281,7 @@ final class MapGestureDetector { float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); // Scale the map by the appropriate power of two factor - transform.zoomBy(scrollDist, event.getX(), event.getY()); + transform.zoomBy(scrollDist, new PointF(event.getX(), event.getY())); return true; @@ -305,61 +295,14 @@ final class MapGestureDetector { return false; } - /** - * Responsible for handling one finger gestures. - */ - private class GestureListener extends android.view.GestureDetector.SimpleOnGestureListener { - + private final class StandardGestureListener extends StandardGestureDetector.SimpleStandardOnGestureListener { @Override - public boolean onDown(MotionEvent event) { - return true; - } - - @Override - public boolean onDoubleTapEvent(MotionEvent e) { - if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled()) { - return false; - } - - switch (e.getAction()) { - case MotionEvent.ACTION_DOWN: - break; - case MotionEvent.ACTION_MOVE: - break; - case MotionEvent.ACTION_UP: - if (quickZoom) { - cameraChangeDispatcher.onCameraIdle(); - quickZoom = false; - break; - } - - // notify camera change listener - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - - // Single finger double tap - if (focalPoint != null) { - // User provided focal point - transform.zoom(true, focalPoint); - } else { - // Zoom in on gesture - transform.zoom(true, new PointF(e.getX(), e.getY())); - } - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(e.getX(), e.getY())); - MapState doubleTap = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - doubleTap.setGesture(Events.DOUBLE_TAP); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, doubleTap)); - } - break; - } - + public boolean onDown(MotionEvent motionEvent) { return true; } @Override public boolean onSingleTapUp(MotionEvent motionEvent) { - // Cancel any animation transform.cancelTransitions(); return true; } @@ -378,31 +321,54 @@ final class MapGestureDetector { notifyOnMapClickListeners(tapPoint); } - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(motionEvent.getX(), motionEvent.getY())); - MapState singleTap = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - singleTap.setGesture(Events.SINGLE_TAP); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, singleTap)); - } + sendTelemetryEvent(Events.SINGLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); return true; } @Override - public void onLongPress(MotionEvent motionEvent) { - PointF longClickPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + public boolean onDoubleTapEvent(MotionEvent motionEvent) { + int action = motionEvent.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN) { + executeDoubleTap = true; + } + if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) { + if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled() || !executeDoubleTap) { + return false; + } - if (!quickZoom) { - notifyOnMapLongClickListeners(longClickPoint); + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + PointF zoomFocalPoint; + // Single finger double tap + if (focalPoint != null) { + // User provided focal point + zoomFocalPoint = focalPoint; + } else { + // Zoom in on gesture + zoomFocalPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + } + + zoomInAnimated(zoomFocalPoint, false); + + sendTelemetryEvent(Events.DOUBLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); + + return true; } + return super.onDoubleTapEvent(motionEvent); + } + + @Override + public void onLongPress(MotionEvent motionEvent) { + PointF longClickPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + notifyOnMapLongClickListeners(longClickPoint); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if ((!trackingSettings.isScrollGestureCurrentlyEnabled()) || recentScaleGestureOccurred) { + if ((!uiSettings.isScrollGesturesEnabled())) { // don't allow a fling is scroll is disabled - // and ignore when a scale gesture has occurred return false; } @@ -415,11 +381,7 @@ final class MapGestureDetector { return false; } - trackingSettings.resetTrackingModesIfRequired(true, false, false); - - // cancel any animation transform.cancelTransitions(); - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); // tilt results in a bigger translation, limiting input for #5281 @@ -435,501 +397,581 @@ final class MapGestureDetector { transform.moveBy(offsetX, offsetY, animationTime); notifyOnFlingListeners(); + return true; } + } - // Called for drags + private final class MoveGestureListener extends MoveGestureDetector.SimpleOnMoveGestureListener { @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + public boolean onMoveBegin(MoveGestureDetector detector) { + if (!uiSettings.isScrollGesturesEnabled()) { return false; } - if (tiltGestureOccurred) { - return false; - } + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - if (!scrollGestureOccurred) { - scrollGestureOccurred = true; + sendTelemetryEvent(Events.PAN, detector.getFocalPoint()); - // Cancel any animation - if (!scaleGestureOccurred) { - transform.cancelTransitions(); - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - } + notifyOnMoveBeginListeners(detector); - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(e1.getX(), e1.getY())); - MapState pan = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - pan.setGesture(Events.PAN); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, pan)); - } - } + return true; + } - // reset tracking if needed - trackingSettings.resetTrackingModesIfRequired(true, false, false); + @Override + public boolean onMove(MoveGestureDetector detector, float distanceX, float distanceY) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); // Scroll the map transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); notifyOnScrollListeners(); + notifyOnMoveListeners(detector); return true; } - } - void notifyOnMapClickListeners(PointF tapPoint) { - // deprecated API - if (onMapClickListener != null) { - onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint)); - } - - // new API - for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) { - listener.onMapClick(projection.fromScreenLocation(tapPoint)); + @Override + public void onMoveEnd(MoveGestureDetector detector, float velocityX, float velocityY) { + cameraChangeDispatcher.onCameraIdle(); + notifyOnMoveEndListeners(detector); } } - void notifyOnMapLongClickListeners(PointF longClickPoint) { - // deprecated API - if (onMapLongClickListener != null) { - onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); - } + private final class ScaleGestureListener extends StandardScaleGestureDetector.SimpleStandardOnScaleGestureListener { - // new API - for (MapboxMap.OnMapLongClickListener listener : onMapLongClickListenerList) { - listener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); - } - } + private final float minimumVelocity; - void notifyOnFlingListeners() { - // deprecated API - if (onFlingListener != null) { - onFlingListener.onFling(); - } + private PointF scaleFocalPoint; + private boolean quickZoom; - // new API - for (MapboxMap.OnFlingListener listener : onFlingListenerList) { - listener.onFling(); + ScaleGestureListener(float minimumVelocity) { + this.minimumVelocity = minimumVelocity; } - } - void notifyOnScrollListeners() { - //deprecated API - if (onScrollListener != null) { - onScrollListener.onScroll(); - } + @Override + public boolean onScaleBegin(StandardScaleGestureDetector detector) { + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } - // new API - for (MapboxMap.OnScrollListener listener : onScrollListenerList) { - listener.onScroll(); - } - } + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - /** - * Responsible for handling two finger gestures and double-tap drag gestures. - */ - private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + quickZoom = detector.getPointersCount() == 1; + if (quickZoom) { + // when quickzoom, dismiss double tap and disable move gesture + executeDoubleTap = false; + gesturesManager.getMoveGestureDetector().setEnabled(false); + } - private static final int ANIMATION_TIME_MULTIPLIER = 77; - private static final double ZOOM_DISTANCE_DIVIDER = 5; + // increase rotate angle threshold when scale is detected first + gesturesManager.getRotateGestureDetector().setAngleThreshold( + gesturesManager.getRotateGestureDetector().getDefaultAngleThreshold() + + MapboxConstants.ROTATION_THRESHOLD_INCREASE_WHEN_SCALING + ); - private float scaleFactor = 1.0f; - private PointF scalePointBegin; + // setting focalPoint in #onScaleBegin() as well, because #onScale() might not get called before #onScaleEnd() + setScaleFocalPoint(detector); + + sendTelemetryEvent(Events.PINCH, scaleFocalPoint); + + notifyOnScaleBeginListeners(detector); + + return true; + } - // Called when two fingers first touch the screen @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { - if (!uiSettings.isZoomGesturesEnabled()) { - return false; - } + public boolean onScale(StandardScaleGestureDetector detector) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + setScaleFocalPoint(detector); + + float scaleFactor = detector.getScaleFactor(); + double zoomBy = getNewZoom(scaleFactor, quickZoom); + transform.zoomBy(zoomBy, scaleFocalPoint); + + notifyOnScaleListeners(detector); - recentScaleGestureOccurred = true; - scalePointBegin = new PointF(detector.getFocusX(), detector.getFocusY()); - scaleBeginTime = detector.getEventTime(); - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(detector.getFocusX(), detector.getFocusY())); - MapState pinch = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - pinch.setGesture(Events.PINCH); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, pinch)); - } return true; } - // Called each time a finger moves - // Called for pinch zooms and quickzooms/quickscales @Override - public boolean onScale(ScaleGestureDetector detector) { - if (!uiSettings.isZoomGesturesEnabled()) { - return super.onScale(detector); - } + public void onScaleEnd(StandardScaleGestureDetector detector, float velocityX, float velocityY) { + cameraChangeDispatcher.onCameraIdle(); - wasZoomingIn = (Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2)) > 0; - if (tiltGestureOccurred) { - return false; + if (quickZoom) { + //if quickzoom, re-enabling move gesture detector + gesturesManager.getMoveGestureDetector().setEnabled(true); } - // Ignore short touches in case it is a tap - // Also ignore small scales - long time = detector.getEventTime(); - long interval = time - scaleBeginTime; - if (!scaleGestureOccurred && (interval <= ViewConfiguration.getTapTimeout())) { - return false; - } + // resetting default angle threshold + gesturesManager.getRotateGestureDetector().setAngleThreshold( + gesturesManager.getRotateGestureDetector().getDefaultAngleThreshold() + ); - // If scale is large enough ignore a tap - scaleFactor *= detector.getScaleFactor(); - if ((scaleFactor > 1.1f) || (scaleFactor < 0.9f)) { - // notify camera change listener - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - scaleGestureOccurred = true; + float velocityXY = Math.abs(velocityX) + Math.abs(velocityY); + if (velocityXY > minimumVelocity) { + double zoomAddition = calculateScale(velocityXY, detector.isScalingOut()); + double currentZoom = transform.getRawZoom(); + long animationTime = (long) (Math.abs(zoomAddition) * 1000 / 4); + scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, scaleFocalPoint, animationTime); + scheduleAnimator(scaleAnimator); } - if (!scaleGestureOccurred) { - return false; + notifyOnScaleEndListeners(detector); + } + + private void setScaleFocalPoint(StandardScaleGestureDetector detector) { + if (focalPoint != null) { + // around user provided focal point + scaleFocalPoint = focalPoint; + } else if (quickZoom) { + // around center + scaleFocalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + } else { + // around gesture + scaleFocalPoint = detector.getFocalPoint(); } + } - // Gesture is a quickzoom if there aren't two fingers - if (!quickZoom && !twoTap) { - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + private double calculateScale(double velocityXY, boolean isScalingOut) { + double zoomAddition = (float) Math.log(velocityXY / 1000 + 1); + if (isScalingOut) { + zoomAddition = -zoomAddition; } - quickZoom = !twoTap; + return zoomAddition; + } - // make an assumption here; if the zoom center is specified by the gesture, it's NOT going - // to be in the center of the map. Therefore the zoom will translate the map center, so tracking - // should be disabled. - trackingSettings.resetTrackingModesIfRequired(!quickZoom, false, false); - // Scale the map - if (focalPoint != null) { - // arround user provided focal point - transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2), focalPoint.x, focalPoint.y); - } else if (quickZoom) { - cameraChangeDispatcher.onCameraMove(); + private double getNewZoom(float scaleFactor, boolean quickZoom) { + double zoomBy = Math.log(scaleFactor) / Math.log(Math.PI / 2); + if (quickZoom) { // clamp scale factors we feed to core #7514 - float scaleFactor = detector.getScaleFactor(); - // around center map - double zoomBy = Math.log(scaleFactor) / Math.log(Math.PI / 2); boolean negative = zoomBy < 0; zoomBy = MathUtils.clamp(Math.abs(zoomBy), MapboxConstants.MINIMUM_SCALE_FACTOR_CLAMP, MapboxConstants.MAXIMUM_SCALE_FACTOR_CLAMP); - transform.zoomBy(negative ? -zoomBy : zoomBy, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - recentScaleGestureOccurred = true; - } else { - // around gesture - transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2), - scalePointBegin.x, scalePointBegin.y); + return negative ? -zoomBy : zoomBy; } - return true; + return zoomBy; + } + } + + private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { + private PointF rotateFocalPoint; + private final float minimumScaleSpanWhenRotating; + private final float minimumAngularVelocity; + + RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity) { + this.minimumScaleSpanWhenRotating = minimumScaleSpanWhenRotating; + this.minimumAngularVelocity = minimumAngularVelocity; } - // Called when fingers leave screen @Override - public void onScaleEnd(final ScaleGestureDetector detector) { - if (velocityTracker == null) { - return; + public boolean onRotateBegin(RotateGestureDetector detector) { + if (!uiSettings.isRotateGesturesEnabled()) { + return false; } - if (rotateGestureOccurred || quickZoom) { - reset(); + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + // when rotation starts, interrupting scale and increasing the threshold + // to make rotation without scaling easier + gesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold(minimumScaleSpanWhenRotating); + gesturesManager.getStandardScaleGestureDetector().interrupt(); + + // setting in #onRotateBegin() as well, because #onRotate() might not get called before #onRotateEnd() + setRotateFocalPoint(detector); + + sendTelemetryEvent(Events.ROTATION, rotateFocalPoint); + + notifyOnRotateBeginListeners(detector); + + return true; + } + + @Override + public boolean onRotate(RotateGestureDetector detector, float rotationDegreesSinceLast, + float rotationDegreesSinceFirst) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + + setRotateFocalPoint(detector); + + // Calculate map bearing value + double bearing = transform.getRawBearing() + rotationDegreesSinceLast; + + // Rotate the map + transform.setBearing(bearing, rotateFocalPoint.x, rotateFocalPoint.y); + + notifyOnRotateListeners(detector); + + return true; + } + + @Override + public void onRotateEnd(RotateGestureDetector detector, float velocityX, float velocityY, float angularVelocity) { + cameraChangeDispatcher.onCameraIdle(); + + // resetting default scale threshold values + gesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold( + gesturesManager.getStandardScaleGestureDetector().getDefaultSpanSinceStartThreshold()); + + if (Math.abs(angularVelocity) < minimumAngularVelocity) { return; } - double velocityXY = Math.abs(velocityTracker.getYVelocity()) + Math.abs(velocityTracker.getXVelocity()); - if (velocityXY > MapboxConstants.VELOCITY_THRESHOLD_IGNORE_FLING / 2) { - scaleAnimating = true; - double zoomAddition = calculateScale(velocityXY); - double currentZoom = transform.getRawZoom(); - long animationTime = (long) (Math.log(velocityXY) * ANIMATION_TIME_MULTIPLIER); - createScaleAnimator(currentZoom, zoomAddition, animationTime).start(); - } else if (!scaleAnimating) { - reset(); + boolean negative = angularVelocity < 0; + angularVelocity = (float) Math.pow(angularVelocity, 2); + angularVelocity = MathUtils.clamp( + angularVelocity, MapboxConstants.MINIMUM_ANGULAR_VELOCITY, MapboxConstants.MAXIMUM_ANGULAR_VELOCITY); + + long animationTime = (long) (Math.log(angularVelocity + 1) * 500); + + if (negative) { + angularVelocity = -angularVelocity; } - } - private void reset() { - scaleAnimating = false; - scaleGestureOccurred = false; - scaleBeginTime = 0; - scaleFactor = 1.0f; - cameraChangeDispatcher.onCameraIdle(); + rotateAnimator = createRotateAnimator(angularVelocity, animationTime); + scheduleAnimator(rotateAnimator); + + notifyOnRotateEndListeners(detector); } - private double calculateScale(double velocityXY) { - double zoomAddition = (float) (Math.log(velocityXY) / ZOOM_DISTANCE_DIVIDER); - if (!wasZoomingIn) { - zoomAddition = -zoomAddition; + private void setRotateFocalPoint(RotateGestureDetector detector) { + if (focalPoint != null) { + // User provided focal point + rotateFocalPoint = focalPoint; + } else { + // around gesture + rotateFocalPoint = detector.getFocalPoint(); } - return zoomAddition; } - private Animator createScaleAnimator(double currentZoom, double zoomAddition, long animationTime) { - ValueAnimator animator = ValueAnimator.ofFloat((float) currentZoom, (float) (currentZoom + zoomAddition)); + private Animator createRotateAnimator(float angularVelocity, long animationTime) { + ValueAnimator animator = ValueAnimator.ofFloat(angularVelocity, 0f); animator.setDuration(animationTime); - animator.setInterpolator(new FastOutSlowInInterpolator()); + animator.setInterpolator(new DecelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override public void onAnimationUpdate(ValueAnimator animation) { - transform.setZoom((Float) animation.getAnimatedValue(), scalePointBegin, 0, true); + transform.setBearing( + transform.getRawBearing() + (float) animation.getAnimatedValue(), + rotateFocalPoint.x, rotateFocalPoint.y, + 0L + ); } }); + animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { + transform.cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(REASON_API_ANIMATION); } @Override public void onAnimationCancel(Animator animation) { - reset(); + cameraChangeDispatcher.onCameraIdle(); } @Override public void onAnimationEnd(Animator animation) { - reset(); + cameraChangeDispatcher.onCameraIdle(); } }); + return animator; } } - /** - * Responsible for handling rotation gestures. - */ - private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { - - private static final float ROTATE_INVOKE_ANGLE = 15.30f; - private static final float ROTATE_LIMITATION_ANGLE = 3.35f; - private static final float ROTATE_LIMITATION_DURATION = ROTATE_LIMITATION_ANGLE * 1.85f; - - private long beginTime = 0; - private boolean started = false; - - // Called when two fingers first touch the screen + private final class ShoveGestureListener extends ShoveGestureDetector.SimpleOnShoveGestureListener { @Override - public boolean onRotateBegin(RotateGestureDetector detector) { - if (!trackingSettings.isRotateGestureCurrentlyEnabled()) { + public boolean onShoveBegin(ShoveGestureDetector detector) { + if (!uiSettings.isTiltGesturesEnabled()) { return false; } - // notify camera change listener + transform.cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - beginTime = detector.getEventTime(); + sendTelemetryEvent(Events.PITCH, detector.getFocalPoint()); + + // disabling move gesture during shove + gesturesManager.getMoveGestureDetector().setEnabled(false); + + notifyOnShoveBeginListeners(detector); + return true; } - // Called each time one of the two fingers moves - // Called for rotation @Override - public boolean onRotate(RotateGestureDetector detector) { - if (!trackingSettings.isRotateGestureCurrentlyEnabled() || tiltGestureOccurred) { - return false; - } + public boolean onShove(ShoveGestureDetector detector, float deltaPixelsSinceLast, float deltaPixelsSinceStart) { + // dispatching start even once more if another detector ended, and this one didn't + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); - // If rotate is large enough ignore a tap - // Also is zoom already started, don't rotate - float angle = detector.getRotationDegreesDelta(); - if (Math.abs(angle) >= ROTATE_INVOKE_ANGLE) { - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(detector.getFocusX(), detector.getFocusY())); - MapState rotation = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - rotation.setGesture(Events.ROTATION); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, rotation)); - } - started = true; - } + // Get tilt value (scale and clamp) + double pitch = transform.getTilt(); + pitch -= MapboxConstants.SHOVE_PIXEL_CHANGE_FACTOR * deltaPixelsSinceLast; + pitch = MathUtils.clamp(pitch, MapboxConstants.MINIMUM_TILT, MapboxConstants.MAXIMUM_TILT); - if (!started) { - return false; - } + // Tilt the map + transform.setTilt(pitch); - wasClockwiseRotating = detector.getRotationDegreesDelta() > 0; - if (scaleBeginTime != 0) { - rotateGestureOccurred = true; - } + notifyOnShoveListeners(detector); - // rotation constitutes translation of anything except the center of - // rotation, so cancel both location and bearing tracking if required - trackingSettings.resetTrackingModesIfRequired(true, true, false); + return true; + } - // Calculate map bearing value - double bearing = transform.getRawBearing() + angle; + @Override + public void onShoveEnd(ShoveGestureDetector detector, float velocityX, float velocityY) { + cameraChangeDispatcher.onCameraIdle(); - // Rotate the map + // re-enabling move gesture + gesturesManager.getMoveGestureDetector().setEnabled(true); + + notifyOnShoveEndListeners(detector); + } + } + + private final class TapGestureListener implements MultiFingerTapGestureDetector.OnMultiFingerTapGestureListener { + @Override + public boolean onMultiFingerTap(MultiFingerTapGestureDetector detector, int pointersCount) { + if (!uiSettings.isZoomGesturesEnabled() || pointersCount != 2) { + return false; + } + + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); + + PointF zoomFocalPoint; + // Single finger double tap if (focalPoint != null) { // User provided focal point - transform.setBearing(bearing, focalPoint.x, focalPoint.y); + zoomFocalPoint = focalPoint; } else { - // around gesture - transform.setBearing(bearing, detector.getFocusX(), detector.getFocusY()); + // Zoom in on gesture + zoomFocalPoint = detector.getFocalPoint(); } + + zoomOutAnimated(zoomFocalPoint, false); + return true; } + } - // Called when the fingers leave the screen - @Override - public void onRotateEnd(RotateGestureDetector detector) { - long interval = detector.getEventTime() - beginTime; - if ((!started && (interval <= ViewConfiguration.getTapTimeout())) || scaleAnimating || interval > 500) { - reset(); - return; + private Animator createScaleAnimator(double currentZoom, double zoomAddition, PointF animationFocalPoint, + long animationTime) { + ValueAnimator animator = ValueAnimator.ofFloat((float) currentZoom, (float) (currentZoom + zoomAddition)); + animator.setDuration(animationTime); + animator.setInterpolator(new DecelerateInterpolator()); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + transform.setZoom((Float) animation.getAnimatedValue(), animationFocalPoint); } + }); - double angularVelocity = calculateVelocityVector(detector); - if (Math.abs(angularVelocity) > 0.001 && rotateGestureOccurred && !rotateAnimating) { - animateRotateVelocity(); - } else if (!rotateAnimating) { - reset(); + animator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationStart(Animator animation) { + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_ANIMATION); } - } - private void reset() { - beginTime = 0; - started = false; - rotateAnimating = false; - rotateGestureOccurred = false; + @Override + public void onAnimationCancel(Animator animation) { + transform.cancelTransitions(); + } - if (!twoTap) { + @Override + public void onAnimationEnd(Animator animation) { cameraChangeDispatcher.onCameraIdle(); } + }); + return animator; + } + + /** + * Zoom in by 1. + * + * @param zoomFocalPoint focal point of zoom animation + * @param runImmediately if true, animation will be started right away, otherwise it will wait until + * {@link MotionEvent#ACTION_UP} is registered. + */ + void zoomInAnimated(PointF zoomFocalPoint, boolean runImmediately) { + zoomAnimated(true, zoomFocalPoint, runImmediately); + } + + /** + * Zoom out by 1. + * + * @param zoomFocalPoint focal point of zoom animation + * @param runImmediately if true, animation will be started right away, otherwise it will wait until + * {@link MotionEvent#ACTION_UP} is registered. + */ + void zoomOutAnimated(PointF zoomFocalPoint, boolean runImmediately) { + zoomAnimated(false, zoomFocalPoint, runImmediately); + } + + private void zoomAnimated(boolean zoomIn, PointF zoomFocalPoint, boolean runImmediately) { + //canceling here as well, because when using a button it will not be canceled automatically by onDown() + cancelAnimator(scaleAnimator); + + double currentZoom = transform.getRawZoom(); + scaleAnimator = createScaleAnimator( + currentZoom, + zoomIn ? 1 : -1, + zoomFocalPoint, + MapboxConstants.ANIMATION_DURATION); + if (runImmediately) { + scaleAnimator.start(); + } else { + scheduleAnimator(scaleAnimator); } + } - private void animateRotateVelocity() { - rotateAnimating = true; - double currentRotation = transform.getRawBearing(); - double rotateAdditionDegrees = calculateVelocityInDegrees(); - createAnimator(currentRotation, rotateAdditionDegrees).start(); + private void sendTelemetryEvent(String eventType, PointF focalPoint) { + if (isZoomValid(transform)) { + MapEventFactory mapEventFactory = new MapEventFactory(); + LatLng latLng = projection.fromScreenLocation(focalPoint); + MapState state = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); + state.setGesture(eventType); + Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, state)); } + } - private double calculateVelocityVector(RotateGestureDetector detector) { - return ((detector.getFocusX() * velocityTracker.getYVelocity()) - + (detector.getFocusY() * velocityTracker.getXVelocity())) - / (Math.pow(detector.getFocusX(), 2) + Math.pow(detector.getFocusY(), 2)); + private boolean isZoomValid(Transform transform) { + if (transform == null) { + return false; } + double mapZoom = transform.getZoom(); + return mapZoom >= MapboxConstants.MINIMUM_ZOOM && mapZoom <= MapboxConstants.MAXIMUM_ZOOM; + } - private double calculateVelocityInDegrees() { - double angleRadians = Math.atan2(velocityTracker.getXVelocity(), velocityTracker.getYVelocity()); - double angle = angleRadians / (Math.PI / 180); - if (angle <= 0) { - angle += 360; - } + void notifyOnMapClickListeners(PointF tapPoint) { + // deprecated API + if (onMapClickListener != null) { + onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint)); + } - // limit the angle - angle = angle / ROTATE_LIMITATION_ANGLE; + // new API + for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) { + listener.onMapClick(projection.fromScreenLocation(tapPoint)); + } + } - // correct direction - if (!wasClockwiseRotating) { - angle = -angle; - } + void notifyOnMapLongClickListeners(PointF longClickPoint) { + // deprecated API + if (onMapLongClickListener != null) { + onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); + } - return angle; + // new API + for (MapboxMap.OnMapLongClickListener listener : onMapLongClickListenerList) { + listener.onMapLongClick(projection.fromScreenLocation(longClickPoint)); } + } - private Animator createAnimator(double currentRotation, double rotateAdditionDegrees) { - ValueAnimator animator = ValueAnimator.ofFloat( - (float) currentRotation, - (float) (currentRotation + rotateAdditionDegrees) - ); - animator.setDuration((long) (Math.abs(rotateAdditionDegrees) * ROTATE_LIMITATION_DURATION)); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - transform.setBearing((Float) animation.getAnimatedValue()); - } - }); - animator.addListener(new AnimatorListenerAdapter() { + void notifyOnFlingListeners() { + // deprecated API + if (onFlingListener != null) { + onFlingListener.onFling(); + } - @Override - public void onAnimationStart(Animator animation) { - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_ANIMATION); - } + // new API + for (MapboxMap.OnFlingListener listener : onFlingListenerList) { + listener.onFling(); + } + } - @Override - public void onAnimationCancel(Animator animation) { - reset(); - } + void notifyOnScrollListeners() { + //deprecated API + if (onScrollListener != null) { + onScrollListener.onScroll(); + } - @Override - public void onAnimationEnd(Animator animation) { - reset(); - } - }); - return animator; + // new API + for (MapboxMap.OnScrollListener listener : onScrollListenerList) { + listener.onScroll(); } } - /** - * Responsible for handling 2 finger shove gestures. - */ - private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener { + void notifyOnMoveBeginListeners(MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMoveBegin(detector); + } + } - private long beginTime = 0; - private float totalDelta = 0.0f; + void notifyOnMoveListeners(MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMove(detector); + } + } - @Override - public boolean onShoveBegin(ShoveGestureDetector detector) { - if (!uiSettings.isTiltGesturesEnabled()) { - return false; - } + void notifyOnMoveEndListeners(MoveGestureDetector detector) { + for (MapboxMap.OnMoveListener listener : onMoveListenerList) { + listener.onMoveEnd(detector); + } + } - // notify camera change listener - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - return true; + void notifyOnRotateBeginListeners(RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotateBegin(detector); } + } - @Override - public void onShoveEnd(ShoveGestureDetector detector) { - beginTime = 0; - totalDelta = 0.0f; - tiltGestureOccurred = false; + void notifyOnRotateListeners(RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotate(detector); } + } - @Override - public boolean onShove(ShoveGestureDetector detector) { - if (!uiSettings.isTiltGesturesEnabled()) { - return false; - } + void notifyOnRotateEndListeners(RotateGestureDetector detector) { + for (MapboxMap.OnRotateListener listener : onRotateListenerList) { + listener.onRotateEnd(detector); + } + } - // Ignore short touches in case it is a tap - // Also ignore small tilt - long time = detector.getEventTime(); - long interval = time - beginTime; - if (!tiltGestureOccurred && (interval <= ViewConfiguration.getTapTimeout())) { - return false; - } + void notifyOnScaleBeginListeners(StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScaleBegin(detector); + } + } - // If tilt is large enough ignore a tap - // Also if zoom already started, don't tilt - totalDelta += detector.getShovePixelsDelta(); - if (!tiltGestureOccurred && ((totalDelta > 10.0f) || (totalDelta < -10.0f))) { - tiltGestureOccurred = true; - beginTime = detector.getEventTime(); - if (isZoomValid(transform)) { - MapEventFactory mapEventFactory = new MapEventFactory(); - LatLng latLng = projection.fromScreenLocation(new PointF(detector.getFocusX(), detector.getFocusY())); - MapState pitch = new MapState(latLng.getLatitude(), latLng.getLongitude(), transform.getZoom()); - pitch.setGesture(Events.PITCH); - Events.obtainTelemetry().push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, pitch)); - } - } + void notifyOnScaleListeners(StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScale(detector); + } + } - if (!tiltGestureOccurred) { - return false; - } + void notifyOnScaleEndListeners(StandardScaleGestureDetector detector) { + for (MapboxMap.OnScaleListener listener : onScaleListenerList) { + listener.onScaleEnd(detector); + } + } - // Get tilt value (scale and clamp) - double pitch = transform.getTilt(); - pitch -= 0.1 * detector.getShovePixelsDelta(); - pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch)); + void notifyOnShoveBeginListeners(ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShoveBegin(detector); + } + } - // Tilt the map - transform.setTilt(pitch); - return true; + void notifyOnShoveListeners(ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShove(detector); + } + } + + void notifyOnShoveEndListeners(ShoveGestureDetector detector) { + for (MapboxMap.OnShoveListener listener : onShoveListenerList) { + listener.onShoveEnd(detector); } } @@ -981,14 +1023,43 @@ final class MapGestureDetector { onScrollListenerList.remove(onScrollListener); } - private boolean isZoomValid(Transform transform) { - if (transform == null) { - return false; - } - double mapZoom = transform.getZoom(); - if (mapZoom < MapboxConstants.MINIMUM_ZOOM || mapZoom > MapboxConstants.MAXIMUM_ZOOM) { - return false; - } - return true; + void addOnMoveListener(MapboxMap.OnMoveListener listener) { + onMoveListenerList.add(listener); + } + + void removeOnMoveListener(MapboxMap.OnMoveListener listener) { + onMoveListenerList.remove(listener); + } + + void addOnRotateListener(MapboxMap.OnRotateListener listener) { + onRotateListenerList.add(listener); + } + + void removeOnRotateListener(MapboxMap.OnRotateListener listener) { + onRotateListenerList.remove(listener); + } + + void addOnScaleListener(MapboxMap.OnScaleListener listener) { + onScaleListenerList.add(listener); + } + + void removeOnScaleListener(MapboxMap.OnScaleListener listener) { + onScaleListenerList.remove(listener); + } + + void addShoveListener(MapboxMap.OnShoveListener listener) { + onShoveListenerList.add(listener); + } + + void removeShoveListener(MapboxMap.OnShoveListener listener) { + onShoveListenerList.remove(listener); + } + + AndroidGesturesManager getGesturesManager() { + return gesturesManager; + } + + void setGesturesManager(AndroidGesturesManager gesturesManager) { + this.gesturesManager = gesturesManager; } -} +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java index d1f01a30f7..08110ff326 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java @@ -13,24 +13,22 @@ import android.view.ViewConfiguration; * <p> * <ul> * <li> Uses {@link Transform} to change the map state</li> - * <li> Uses {@link TrackingSettings} to verify validity of the current tracking mode.</li> * <li> Uses {@link UiSettings} to verify validity of user restricted movement.</li> * </ul> * <p> */ final class MapKeyListener { - private final TrackingSettings trackingSettings; private final Transform transform; private final UiSettings uiSettings; + private final MapGestureDetector mapGestureDetector; private TrackballLongPressTimeOut currentTrackballLongPressTimeOut; - MapKeyListener(@NonNull Transform transform, @NonNull TrackingSettings trackingSettings, - @NonNull UiSettings uiSettings) { + MapKeyListener(Transform transform, UiSettings uiSettings, MapGestureDetector mapGestureDetector) { this.transform = transform; - this.trackingSettings = trackingSettings; this.uiSettings = uiSettings; + this.mapGestureDetector = mapGestureDetector; } /** @@ -55,7 +53,7 @@ final class MapKeyListener { return true; case KeyEvent.KEYCODE_DPAD_LEFT: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + if (!uiSettings.isScrollGesturesEnabled()) { return false; } @@ -67,7 +65,7 @@ final class MapKeyListener { return true; case KeyEvent.KEYCODE_DPAD_RIGHT: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + if (!uiSettings.isScrollGesturesEnabled()) { return false; } @@ -79,7 +77,7 @@ final class MapKeyListener { return true; case KeyEvent.KEYCODE_DPAD_UP: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + if (!uiSettings.isScrollGesturesEnabled()) { return false; } @@ -91,7 +89,7 @@ final class MapKeyListener { return true; case KeyEvent.KEYCODE_DPAD_DOWN: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + if (!uiSettings.isScrollGesturesEnabled()) { return false; } @@ -128,7 +126,7 @@ final class MapKeyListener { // Zoom out PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(false, focalPoint); + mapGestureDetector.zoomOutAnimated(focalPoint, true); return true; default: @@ -164,7 +162,7 @@ final class MapKeyListener { // Zoom in PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(true, focalPoint); + mapGestureDetector.zoomInAnimated(focalPoint, true); return true; } @@ -183,7 +181,7 @@ final class MapKeyListener { switch (event.getActionMasked()) { // The trackball was rotated case MotionEvent.ACTION_MOVE: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + if (!uiSettings.isScrollGesturesEnabled()) { return false; } @@ -219,7 +217,7 @@ final class MapKeyListener { if (currentTrackballLongPressTimeOut != null) { // Zoom in PointF focalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(true, focalPoint); + mapGestureDetector.zoomInAnimated(focalPoint, true); } return true; @@ -261,7 +259,7 @@ final class MapKeyListener { if (!cancelled) { // Zoom out PointF pointF = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - transform.zoom(false, pointF); + mapGestureDetector.zoomOutAnimated(pointF, true); // Ensure the up action is not run currentTrackballLongPressTimeOut = null; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index cf70300c6e..4f5ce2c926 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -23,6 +23,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ZoomButtonsController; +import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.android.telemetry.AppUserTurnstile; import com.mapbox.android.telemetry.Event; import com.mapbox.android.telemetry.MapEventFactory; @@ -37,13 +38,9 @@ import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer; import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer; import com.mapbox.mapboxsdk.maps.widgets.CompassView; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; import com.mapbox.mapboxsdk.storage.FileSource; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -52,6 +49,9 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + import timber.log.Timber; import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION; @@ -81,7 +81,6 @@ public class MapView extends FrameLayout { private boolean destroyed; private boolean hasSurface; - private MyLocationView myLocationView; private CompassView compassView; private PointF focalPoint; private ImageView attrView; @@ -129,7 +128,6 @@ public class MapView extends FrameLayout { // inflate view View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this); compassView = (CompassView) view.findViewById(R.id.compassView); - myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView); attrView = (ImageView) view.findViewById(R.id.attributionView); logoView = (ImageView) view.findViewById(R.id.logoView); @@ -149,10 +147,7 @@ public class MapView extends FrameLayout { focalPointInvalidator.addListener(createFocalPointChangeListener()); // callback for registering touch listeners - RegisterTouchListener registerTouchListener = new RegisterTouchListener(); - - // callback for zooming in the camera - CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator(); + GesturesManagerInteractionListener registerTouchListener = new GesturesManagerInteractionListener(); // callback for camera change events final CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher(); @@ -160,10 +155,6 @@ public class MapView extends FrameLayout { // setup components for MapboxMap creation Projection proj = new Projection(nativeMapView); UiSettings uiSettings = new UiSettings(proj, focalPointInvalidator, compassView, attrView, logoView); - TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointInvalidator, - zoomInvalidator); - MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, - focalPointInvalidator); LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>(); MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer)); IconManager iconManager = new IconManager(nativeMapView); @@ -174,30 +165,28 @@ public class MapView extends FrameLayout { ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(nativeMapView, annotationsArray); AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray, markerViewManager, iconManager, annotations, markers, polygons, polylines, shapeAnnotations); - Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings, + Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), cameraChangeDispatcher); - mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj, - registerTouchListener, annotationManager, cameraChangeDispatcher); - focalPointInvalidator.addListener(mapboxMap.createFocalPointChangeListener()); + mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, proj, registerTouchListener, + annotationManager, cameraChangeDispatcher); mapCallback.attachMapboxMap(mapboxMap); // user input - mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings, + mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, annotationManager, cameraChangeDispatcher); - mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings); + mapKeyListener = new MapKeyListener(transform, uiSettings, mapGestureDetector); // overlain zoom buttons mapZoomButtonController = new MapZoomButtonController(new ZoomButtonsController(this)); - MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform, - cameraChangeDispatcher, getWidth(), getHeight()); + MapZoomControllerListener zoomListener = new MapZoomControllerListener( + mapGestureDetector, cameraChangeDispatcher, getWidth(), getHeight()); mapZoomButtonController.bind(uiSettings, zoomListener); compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraChangeDispatcher)); compassView.setOnClickListener(createCompassClickListener(cameraChangeDispatcher)); // inject widgets with MapboxMap - myLocationView.setMapboxMap(mapboxMap); attrView.setOnClickListener(new AttributionClickListener(context, mapboxMap)); // Ensure this view is interactable @@ -390,6 +379,7 @@ public class MapView extends FrameLayout { public void onStop() { if (mapboxMap != null) { // map was destroyed before it was started + mapGestureDetector.cancelAnimators(); mapboxMap.onStop(); } @@ -923,7 +913,7 @@ public class MapView extends FrameLayout { } } - private class RegisterTouchListener implements MapboxMap.OnRegisterTouchListener { + private class GesturesManagerInteractionListener implements MapboxMap.OnGesturesManagerInteractionListener { @Override public void onSetMapClickListener(MapboxMap.OnMapClickListener listener) { @@ -984,22 +974,68 @@ public class MapView extends FrameLayout { public void onRemoveFlingListener(MapboxMap.OnFlingListener listener) { mapGestureDetector.removeOnFlingListener(listener); } + + @Override + public void onAddMoveListener(MapboxMap.OnMoveListener listener) { + mapGestureDetector.addOnMoveListener(listener); + } + + @Override + public void onRemoveMoveListener(MapboxMap.OnMoveListener listener) { + mapGestureDetector.removeOnMoveListener(listener); + } + + @Override + public void onAddRotateListener(MapboxMap.OnRotateListener listener) { + mapGestureDetector.addOnRotateListener(listener); + } + + @Override + public void onRemoveRotateListener(MapboxMap.OnRotateListener listener) { + mapGestureDetector.removeOnRotateListener(listener); + } + + @Override + public void onAddScaleListener(MapboxMap.OnScaleListener listener) { + mapGestureDetector.addOnScaleListener(listener); + } + + @Override + public void onRemoveScaleListener(MapboxMap.OnScaleListener listener) { + mapGestureDetector.removeOnScaleListener(listener); + } + + @Override + public void onAddShoveListener(MapboxMap.OnShoveListener listener) { + mapGestureDetector.addShoveListener(listener); + } + + @Override + public void onRemoveShoveListener(MapboxMap.OnShoveListener listener) { + mapGestureDetector.removeShoveListener(listener); + } + + @Override + public AndroidGesturesManager getGesturesManager() { + return mapGestureDetector.getGesturesManager(); + } + + @Override + public void setGesturesManager(AndroidGesturesManager gesturesManager) { + mapGestureDetector.setGesturesManager(gesturesManager); + } } private static class MapZoomControllerListener implements ZoomButtonsController.OnZoomListener { private final MapGestureDetector mapGestureDetector; - private final UiSettings uiSettings; - private final Transform transform; private final CameraChangeDispatcher cameraChangeDispatcher; private final float mapWidth; private final float mapHeight; - MapZoomControllerListener(MapGestureDetector detector, UiSettings uiSettings, Transform transform, - CameraChangeDispatcher dispatcher, float mapWidth, float mapHeight) { + MapZoomControllerListener(MapGestureDetector detector, CameraChangeDispatcher dispatcher, + float mapWidth, float mapHeight) { this.mapGestureDetector = detector; - this.uiSettings = uiSettings; - this.transform = transform; this.cameraChangeDispatcher = dispatcher; this.mapWidth = mapWidth; this.mapHeight = mapHeight; @@ -1014,39 +1050,18 @@ public class MapView extends FrameLayout { // Called when user pushes a zoom button on the ZoomButtonController @Override public void onZoom(boolean zoomIn) { - if (uiSettings.isZoomGesturesEnabled()) { - cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_ANIMATION); - onZoom(zoomIn, mapGestureDetector.getFocalPoint()); - } + cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_ANIMATION); + onZoom(zoomIn, mapGestureDetector.getFocalPoint()); } private void onZoom(boolean zoomIn, @Nullable PointF focalPoint) { - if (focalPoint != null) { - transform.zoom(zoomIn, focalPoint); - } else { - PointF centerPoint = new PointF(mapWidth / 2, mapHeight / 2); - transform.zoom(zoomIn, centerPoint); + if (focalPoint == null) { + focalPoint = new PointF(mapWidth / 2, mapHeight / 2); } - } - } - - private class CameraZoomInvalidator implements TrackingSettings.CameraZoomInvalidator { - - @Override - public void zoomTo(double zoomLevel) { - Transform transform = mapboxMap.getTransform(); - double currentZoomLevel = transform.getCameraPosition().zoom; - if (currentZoomLevel < zoomLevel) { - setZoom(zoomLevel, mapGestureDetector.getFocalPoint(), transform); - } - } - - private void setZoom(double zoomLevel, @Nullable PointF focalPoint, @NonNull Transform transform) { - if (focalPoint != null) { - transform.setZoom(zoomLevel, focalPoint); + if (zoomIn) { + mapGestureDetector.zoomInAnimated(focalPoint, true); } else { - PointF centerPoint = new PointF(getMeasuredWidth() / 2, getMeasuredHeight() / 2); - transform.setZoom(zoomLevel, centerPoint); + mapGestureDetector.zoomOutAnimated(focalPoint, true); } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 4f2c940ea3..a245c283bd 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -4,7 +4,6 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; -import android.location.Location; import android.os.Bundle; import android.support.annotation.FloatRange; import android.support.annotation.IntRange; @@ -16,6 +15,11 @@ import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; +import com.mapbox.android.gestures.AndroidGesturesManager; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Geometry; import com.mapbox.mapboxsdk.annotations.Annotation; @@ -33,17 +37,13 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdate; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MapboxConstants; -import com.mapbox.mapboxsdk.constants.MyBearingTracking; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import com.mapbox.mapboxsdk.style.layers.Filter; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.light.Light; import com.mapbox.mapboxsdk.style.sources.Source; -import com.mapbox.android.core.location.LocationEngine; import java.lang.reflect.ParameterizedType; import java.util.HashMap; @@ -66,37 +66,30 @@ public final class MapboxMap { private final NativeMapView nativeMapView; private final UiSettings uiSettings; - private final TrackingSettings trackingSettings; private final Projection projection; private final Transform transform; private final AnnotationManager annotationManager; - private final MyLocationViewSettings myLocationViewSettings; private final CameraChangeDispatcher cameraChangeDispatcher; - private final OnRegisterTouchListener onRegisterTouchListener; + private final OnGesturesManagerInteractionListener onGesturesManagerInteractionListener; private MapboxMap.OnFpsChangedListener onFpsChangedListener; - private PointF focalPoint; - MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking, - MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener, - AnnotationManager annotations, CameraChangeDispatcher cameraChangeDispatcher) { + MapboxMap(NativeMapView map, Transform transform, UiSettings ui, Projection projection, + OnGesturesManagerInteractionListener listener, AnnotationManager annotations, + CameraChangeDispatcher cameraChangeDispatcher) { this.nativeMapView = map; this.uiSettings = ui; - this.trackingSettings = tracking; this.projection = projection; - this.myLocationViewSettings = myLocationView; this.annotationManager = annotations.bind(this); this.transform = transform; - this.onRegisterTouchListener = listener; + this.onGesturesManagerInteractionListener = listener; this.cameraChangeDispatcher = cameraChangeDispatcher; } void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) { transform.initialise(this, options); uiSettings.initialise(context, options); - myLocationViewSettings.initialise(options); - trackingSettings.initialise(options); // Map configuration setDebugActive(options.getDebugActive()); @@ -110,7 +103,6 @@ public final class MapboxMap { */ void onStart() { nativeMapView.update(); - trackingSettings.onStart(); if (TextUtils.isEmpty(nativeMapView.getStyleUrl())) { // if user hasn't loaded a Style yet nativeMapView.setStyleUrl(Style.MAPBOX_STREETS); @@ -121,7 +113,6 @@ public final class MapboxMap { * Called when the hosting Activity/Fragment onStop() method is called. */ void onStop() { - trackingSettings.onStop(); } /** @@ -133,9 +124,7 @@ public final class MapboxMap { outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, transform.getCameraPosition()); outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, nativeMapView.getDebug()); outState.putString(MapboxConstants.STATE_STYLE_URL, nativeMapView.getStyleUrl()); - trackingSettings.onSaveInstanceState(outState); uiSettings.onSaveInstanceState(outState); - myLocationViewSettings.onSaveInstanceState(outState); } /** @@ -146,9 +135,7 @@ public final class MapboxMap { void onRestoreInstanceState(Bundle savedInstanceState) { final CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION); - myLocationViewSettings.onRestoreInstanceState(savedInstanceState); uiSettings.onRestoreInstanceState(savedInstanceState); - trackingSettings.onRestoreInstanceState(savedInstanceState); if (cameraPosition != null) { moveCamera(CameraUpdateFactory.newCameraPosition( @@ -187,7 +174,6 @@ public final class MapboxMap { * Called when the region is changing or has changed. */ void onUpdateRegionChange() { - trackingSettings.update(); annotationManager.update(); } @@ -555,38 +541,6 @@ public final class MapboxMap { } // - // TrackingSettings - // - - /** - * Gets the tracking interface settings for the map. - * - * @return the TrackingSettings asssociated with this map - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public TrackingSettings getTrackingSettings() { - return trackingSettings; - } - - // - // MyLocationViewSettings - // - - /** - * Gets the settings of the user location for the map. - * - * @return the MyLocationViewSettings associated with this map - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public MyLocationViewSettings getMyLocationViewSettings() { - return myLocationViewSettings; - } - - // // Projection // @@ -601,7 +555,7 @@ public final class MapboxMap { } // - // + // Light // /** @@ -619,65 +573,6 @@ public final class MapboxMap { // /** - * Moves the center of the screen to a latitude and longitude specified by a LatLng object. This centers the - * camera on the LatLng object. - * <p> - * Note that at low zoom levels, setLatLng is constrained so that the entire viewport shows map data. - * </p> - * - * @param latLng Target location to change to - */ - public void setLatLng(@NonNull LatLng latLng) { - nativeMapView.setLatLng(latLng); - } - - /** - * Moves the camera viewpoint to a particular zoom level. - * - * @param zoom Zoom level to change to - */ - public void setZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double zoom) { - if (focalPoint == null) { - focalPoint = new PointF(nativeMapView.getWidth() / 2, nativeMapView.getHeight() / 2); - } - nativeMapView.setZoom(zoom, focalPoint, 0); - } - - /** - * Moves the center and the zoom of the camera specified by a LatLng object and double zoom. - * <p> - * Note that at low zoom levels, setLatLng is constrained so that the entire viewport shows map data. - * </p> - * - * @param latLng Target location to change to - */ - public void setLatLngZoom(@NonNull LatLng latLng, - @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, - to = MapboxConstants.MAXIMUM_ZOOM) double zoom) { - setZoom(zoom); - setLatLng(latLng); - } - - /** - * Moves the camera viewpoint angle to a particular angle in degrees. - * - * @param tilt Tilt angle to change to - */ - public void setTilt(@FloatRange(from = MapboxConstants.MINIMUM_TILT, to = MapboxConstants.MAXIMUM_TILT) double tilt) { - nativeMapView.setPitch(tilt, 0); - } - - /** - * Moves the camera viewpoint direction to a particular angle in degrees. - * - * @param bearing Direction angle to change to - */ - public void setBearing(@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION) - double bearing) { - nativeMapView.setBearing(bearing); - } - - /** * Cancels ongoing animations. * <p> * This invokes the {@link CancelableCallback} for ongoing camera updates. @@ -804,11 +699,6 @@ public final class MapboxMap { * unless specified within {@link CameraUpdate}. A callback can be used to be notified when * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it * will return the current location of the camera in flight. - * <p> - * Note that this will cancel location tracking mode if enabled. You can change this behaviour by calling - * {@link com.mapbox.mapboxsdk.maps.TrackingSettings#setDismissLocationTrackingOnGesture(boolean)} with false before - * invoking this method and calling it with true in the {@link CancelableCallback#onFinish()}. - * </p> * * @param update The change that should be applied to the camera. * @param durationMs The duration of the animation in milliseconds. This must be strictly @@ -830,11 +720,6 @@ public final class MapboxMap { * unless specified within {@link CameraUpdate}. A callback can be used to be notified when * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it * will return the current location of the camera in flight. - * <p> - * Note that this will cancel location tracking mode if enabled. You can change this behaviour by calling - * {@link com.mapbox.mapboxsdk.maps.TrackingSettings#setDismissLocationTrackingOnGesture(boolean)} with false before - * invoking this method and calling it with true in the {@link CancelableCallback#onFinish()}. - * </p> * * @param update The change that should be applied to the camera. * @param durationMs The duration of the animation in milliseconds. This must be strictly @@ -1670,7 +1555,7 @@ public final class MapboxMap { for (int i = 0; i < padding.length; i++) { padding[i] = mapPadding[i] + padding[i]; } - projection.setContentPadding(padding, myLocationViewSettings.getPadding()); + projection.setContentPadding(padding); // get padded camera position from LatLngBounds CameraPosition cameraPosition = nativeMapView.getCameraForLatLngBounds(latLngBounds); @@ -1694,7 +1579,7 @@ public final class MapboxMap { for (int i = 0; i < padding.length; i++) { padding[i] = mapPadding[i] + padding[i]; } - projection.setContentPadding(padding, myLocationViewSettings.getPadding()); + projection.setContentPadding(padding); // get padded camera position from LatLngBounds CameraPosition cameraPosition = nativeMapView.getCameraForGeometry(geometry, bearing); @@ -1710,13 +1595,13 @@ public final class MapboxMap { /** * <p> - * Sets the distance from the edges of the map view’s frame to the edges of the map - * view’s logical viewport. + * Sets the distance from the edges of the map view's frame to the edges of the map + * view's logical viewport. * </p> * <p> * When the value of this property is equal to {0,0,0,0}, viewport - * properties such as `centerCoordinate` assume a viewport that matches the map - * view’s frame. Otherwise, those properties are inset, excluding part of the + * properties such as 'centerCoordinate' assume a viewport that matches the map + * view's frame. Otherwise, those properties are inset, excluding part of the * frame from the viewport. For instance, if the only the top edge is inset, the * map center is effectively shifted downward. * </p> @@ -1731,7 +1616,7 @@ public final class MapboxMap { } private void setPadding(int[] padding) { - projection.setContentPadding(padding, myLocationViewSettings.getPadding()); + projection.setContentPadding(padding); uiSettings.invalidate(); } @@ -1904,7 +1789,7 @@ public final class MapboxMap { */ @Deprecated public void setOnScrollListener(@Nullable OnScrollListener listener) { - onRegisterTouchListener.onSetScrollListener(listener); + onGesturesManagerInteractionListener.onSetScrollListener(listener); } /** @@ -1914,7 +1799,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void addOnScrollListener(@Nullable OnScrollListener listener) { - onRegisterTouchListener.onAddScrollListener(listener); + onGesturesManagerInteractionListener.onAddScrollListener(listener); } /** @@ -1924,7 +1809,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void removeOnScrollListener(@Nullable OnScrollListener listener) { - onRegisterTouchListener.onRemoveScrollListener(listener); + onGesturesManagerInteractionListener.onRemoveScrollListener(listener); } /** @@ -1936,7 +1821,7 @@ public final class MapboxMap { */ @Deprecated public void setOnFlingListener(@Nullable OnFlingListener listener) { - onRegisterTouchListener.onSetFlingListener(listener); + onGesturesManagerInteractionListener.onSetFlingListener(listener); } /** @@ -1946,7 +1831,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void addOnFlingListener(@Nullable OnFlingListener listener) { - onRegisterTouchListener.onAddFlingListener(listener); + onGesturesManagerInteractionListener.onAddFlingListener(listener); } /** @@ -1956,7 +1841,98 @@ public final class MapboxMap { * To unset the callback, use null. */ public void removeOnFlingListener(@Nullable OnFlingListener listener) { - onRegisterTouchListener.onRemoveFlingListener(listener); + onGesturesManagerInteractionListener.onRemoveFlingListener(listener); + } + + /** + * Adds a callback that's invoked when the map is moved. + * + * @param listener The callback that's invoked when the map is moved. + */ + public void addOnMoveListener(OnMoveListener listener) { + onGesturesManagerInteractionListener.onAddMoveListener(listener); + } + + /** + * Removes a callback that's invoked when the map is moved. + * + * @param listener The callback that's invoked when the map is moved. + */ + public void removeOnMoveListener(OnMoveListener listener) { + onGesturesManagerInteractionListener.onRemoveMoveListener(listener); + } + + /** + * Adds a callback that's invoked when the map is rotated. + * + * @param listener The callback that's invoked when the map is rotated. + */ + public void addOnRotateListener(OnRotateListener listener) { + onGesturesManagerInteractionListener.onAddRotateListener(listener); + } + + /** + * Removes a callback that's invoked when the map is rotated. + * + * @param listener The callback that's invoked when the map is rotated. + */ + public void removeOnRotateListener(OnRotateListener listener) { + onGesturesManagerInteractionListener.onRemoveRotateListener(listener); + } + + /** + * Adds a callback that's invoked when the map is scaled. + * + * @param listener The callback that's invoked when the map is scaled. + */ + public void addOnScaleListener(OnScaleListener listener) { + onGesturesManagerInteractionListener.onAddScaleListener(listener); + } + + /** + * Removes a callback that's invoked when the map is scaled. + * + * @param listener The callback that's invoked when the map is scaled. + */ + public void removeOnScaleListener(OnScaleListener listener) { + onGesturesManagerInteractionListener.onRemoveScaleListener(listener); + } + + /** + * Adds a callback that's invoked when the map is tilted. + * + * @param listener The callback that's invoked when the map is tilted. + */ + public void addOnShoveListener(OnShoveListener listener) { + onGesturesManagerInteractionListener.onAddShoveListener(listener); + } + + /** + * Remove a callback that's invoked when the map is tilted. + * + * @param listener The callback that's invoked when the map is tilted. + */ + public void removeOnShoveListener(OnShoveListener listener) { + onGesturesManagerInteractionListener.onRemoveShoveListener(listener); + } + + /** + * Sets a custom {@link AndroidGesturesManager} to handle {@link android.view.MotionEvent}s registered by the map. + * + * @param androidGesturesManager Gestures manager that interprets gestures based on the motion events. + * @see <a href="https://github.com/mapbox/mapbox-gestures-android">mapbox-gestures-android library</a> + */ + public void setGesturesManager(AndroidGesturesManager androidGesturesManager) { + onGesturesManagerInteractionListener.setGesturesManager(androidGesturesManager); + } + + /** + * Get current {@link AndroidGesturesManager} that handles {@link android.view.MotionEvent}s registered by the map. + * + * @return Current gestures manager. + */ + public AndroidGesturesManager getGesturesManager() { + return onGesturesManagerInteractionListener.getGesturesManager(); } /** @@ -1968,7 +1944,7 @@ public final class MapboxMap { */ @Deprecated public void setOnMapClickListener(@Nullable OnMapClickListener listener) { - onRegisterTouchListener.onSetMapClickListener(listener); + onGesturesManagerInteractionListener.onSetMapClickListener(listener); } /** @@ -1978,7 +1954,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void addOnMapClickListener(@Nullable OnMapClickListener listener) { - onRegisterTouchListener.onAddMapClickListener(listener); + onGesturesManagerInteractionListener.onAddMapClickListener(listener); } /** @@ -1988,7 +1964,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void removeOnMapClickListener(@Nullable OnMapClickListener listener) { - onRegisterTouchListener.onRemoveMapClickListener(listener); + onGesturesManagerInteractionListener.onRemoveMapClickListener(listener); } /** @@ -2000,7 +1976,7 @@ public final class MapboxMap { */ @Deprecated public void setOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { - onRegisterTouchListener.onSetMapLongClickListener(listener); + onGesturesManagerInteractionListener.onSetMapLongClickListener(listener); } /** @@ -2010,7 +1986,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void addOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { - onRegisterTouchListener.onAddMapLongClickListener(listener); + onGesturesManagerInteractionListener.onAddMapLongClickListener(listener); } /** @@ -2020,7 +1996,7 @@ public final class MapboxMap { * To unset the callback, use null. */ public void removeOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { - onRegisterTouchListener.onRemoveMapLongClickListener(listener); + onGesturesManagerInteractionListener.onRemoveMapLongClickListener(listener); } /** @@ -2081,107 +2057,6 @@ public final class MapboxMap { } // - // User location - // - - /** - * Returns the status of the my-location layer. - * - * @return True if the my-location layer is enabled, false otherwise. - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public boolean isMyLocationEnabled() { - return trackingSettings.isMyLocationEnabled(); - } - - /** - * <p> - * Enables or disables the my-location layer. - * While enabled, the my-location layer continuously draws an indication of a user's current - * location and bearing. - * </p> - * In order to use the my-location layer feature you need to request permission for either - * android.Manifest.permission#ACCESS_COARSE_LOCATION or android.Manifest.permission#ACCESS_FINE_LOCATION. - * - * @param enabled True to enable; false to disable. - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public void setMyLocationEnabled(boolean enabled) { - trackingSettings.setMyLocationEnabled(enabled); - } - - /** - * Returns the currently displayed user location, or null if there is no location data available. - * - * @return The currently displayed user location. - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Nullable - @Deprecated - public Location getMyLocation() { - return trackingSettings.getMyLocation(); - } - - /** - * Sets a callback that's invoked when the the My Location view - * (which signifies the user's location) changes location. - * - * @param listener The callback that's invoked when the user clicks on a marker. - * To unset the callback, use null. - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener - listener) { - trackingSettings.setOnMyLocationChangeListener(listener); - } - - /** - * Replaces the location source of the my-location layer. - * - * @param locationSource A {@link LocationEngine} location source to use in the my-location layer. - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public void setLocationSource(@Nullable LocationEngine locationSource) { - trackingSettings.setLocationSource(locationSource); - } - - /** - * Sets a callback that's invoked when the location tracking mode changes. - * - * @param listener The callback that's invoked when the location tracking mode changes. - * To unset the callback, use null. - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public void setOnMyLocationTrackingModeChangeListener( - @Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { - trackingSettings.setOnMyLocationTrackingModeChangeListener(listener); - } - - /** - * Sets a callback that's invoked when the bearing tracking mode changes. - * - * @param listener The callback that's invoked when the bearing tracking mode changes. - * To unset the callback, use null. - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead. - */ - @Deprecated - public void setOnMyBearingTrackingModeChangeListener(@Nullable OnMyBearingTrackingModeChangeListener listener) { - trackingSettings.setOnMyBearingTrackingModeChangeListener(listener); - } - - // // Invalidate // @@ -2250,15 +2125,6 @@ public final class MapboxMap { return nativeMapView.queryRenderedFeatures(coordinates, layerIds, filter); } - FocalPointChangeListener createFocalPointChangeListener() { - return new FocalPointChangeListener() { - @Override - public void onFocalPointChanged(PointF pointF) { - focalPoint = pointF; - } - }; - } - // // Interfaces // @@ -2279,7 +2145,9 @@ public final class MapboxMap { * Interface definition for a callback to be invoked when the map is scrolled. * * @see MapboxMap#setOnScrollListener(OnScrollListener) + * @deprecated Use {@link OnMoveListener} instead. */ + @Deprecated public interface OnScrollListener { /** * Called when the map is scrolled. @@ -2288,6 +2156,58 @@ public final class MapboxMap { } /** + * Interface definition for a callback to be invoked when the map is moved. + * + * @see MapboxMap#addOnMoveListener(OnMoveListener) + */ + public interface OnMoveListener { + void onMoveBegin(MoveGestureDetector detector); + + void onMove(MoveGestureDetector detector); + + void onMoveEnd(MoveGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is rotated. + * + * @see MapboxMap#addOnRotateListener(OnRotateListener) + */ + public interface OnRotateListener { + void onRotateBegin(RotateGestureDetector detector); + + void onRotate(RotateGestureDetector detector); + + void onRotateEnd(RotateGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is scaled. + * + * @see MapboxMap#addOnScaleListener(OnScaleListener) + */ + public interface OnScaleListener { + void onScaleBegin(StandardScaleGestureDetector detector); + + void onScale(StandardScaleGestureDetector detector); + + void onScaleEnd(StandardScaleGestureDetector detector); + } + + /** + * Interface definition for a callback to be invoked when the map is tilted. + * + * @see MapboxMap#addOnShoveListener(OnShoveListener) + */ + public interface OnShoveListener { + void onShoveBegin(ShoveGestureDetector detector); + + void onShove(ShoveGestureDetector detector); + + void onShoveEnd(ShoveGestureDetector detector); + } + + /** * Interface definition for a callback to be invoked when the camera changes position. * * @deprecated Replaced by {@link MapboxMap.OnCameraMoveStartedListener}, {@link MapboxMap.OnCameraMoveListener} and @@ -2389,7 +2309,7 @@ public final class MapboxMap { * Interface definition for a callback to be invoked when a user registers an listener that is * related to touch and click events. */ - interface OnRegisterTouchListener { + interface OnGesturesManagerInteractionListener { void onSetMapClickListener(OnMapClickListener listener); void onAddMapClickListener(OnMapClickListener listener); @@ -2413,6 +2333,26 @@ public final class MapboxMap { void onAddFlingListener(OnFlingListener listener); void onRemoveFlingListener(OnFlingListener listener); + + void onAddMoveListener(OnMoveListener listener); + + void onRemoveMoveListener(OnMoveListener listener); + + void onAddRotateListener(OnRotateListener listener); + + void onRemoveRotateListener(OnRotateListener listener); + + void onAddScaleListener(OnScaleListener listener); + + void onRemoveScaleListener(OnScaleListener listener); + + void onAddShoveListener(OnShoveListener listener); + + void onRemoveShoveListener(OnShoveListener listener); + + AndroidGesturesManager getGesturesManager(); + + void setGesturesManager(AndroidGesturesManager gesturesManager); } /** @@ -2685,51 +2625,6 @@ public final class MapboxMap { } /** - * Interface definition for a callback to be invoked when the the My Location view changes location. - * - * @see MapboxMap#setOnMyLocationChangeListener(OnMyLocationChangeListener) - */ - public interface OnMyLocationChangeListener { - /** - * Called when the location of the My Location view has changed - * (be it latitude/longitude, bearing or accuracy). - * - * @param location The current location of the My Location view The type of map change event. - */ - void onMyLocationChange(@Nullable Location location); - } - - /** - * Interface definition for a callback to be invoked when the the My Location tracking mode changes. - * - * @see TrackingSettings#setMyLocationTrackingMode(int) - */ - public interface OnMyLocationTrackingModeChangeListener { - - /** - * Called when the tracking mode of My Location tracking has changed - * - * @param myLocationTrackingMode the current active location tracking mode - */ - void onMyLocationTrackingModeChange(@MyLocationTracking.Mode int myLocationTrackingMode); - } - - /** - * Interface definition for a callback to be invoked when the the My Location tracking mode changes. - * - * @see TrackingSettings#setMyLocationTrackingMode(int) - */ - public interface OnMyBearingTrackingModeChangeListener { - - /** - * Called when the tracking mode of My Bearing tracking has changed - * - * @param myBearingTrackingMode the current active bearing tracking mode - */ - void onMyBearingTrackingModeChange(@MyBearingTracking.Mode int myBearingTrackingMode); - } - - /** * Interface definition for a callback to be invoked when a task is complete or cancelled. */ public interface CancelableCallback { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 49188a5a98..bb4e2f9212 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -8,10 +8,8 @@ import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.ColorInt; -import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; import android.util.AttributeSet; import android.view.Gravity; @@ -20,7 +18,6 @@ import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.utils.BitmapUtils; -import com.mapbox.mapboxsdk.utils.ColorUtils; import java.util.Arrays; @@ -68,18 +65,6 @@ public class MapboxMapOptions implements Parcelable { private boolean zoomControlsEnabled = false; private boolean doubleTapGesturesEnabled = true; - private boolean myLocationEnabled; - private Drawable myLocationForegroundDrawable; - private Drawable myLocationForegroundBearingDrawable; - private Drawable myLocationBackgroundDrawable; - @ColorInt - private int myLocationForegroundTintColor = UNDEFINED_COLOR; - @ColorInt - private int myLocationBackgroundTintColor = UNDEFINED_COLOR; - private int[] myLocationBackgroundPadding; - private int myLocationAccuracyTintColor; - private int myLocationAccuracyAlpha; - private float myLocationAccuracyThreshold; private boolean prefetchesTiles = true; private boolean zMediaOverlay = false; private String localIdeographFontFamily; @@ -130,30 +115,6 @@ public class MapboxMapOptions implements Parcelable { zoomGesturesEnabled = in.readByte() != 0; doubleTapGesturesEnabled = in.readByte() != 0; - myLocationEnabled = in.readByte() != 0; - - Bitmap foregroundBitmap = in.readParcelable(getClass().getClassLoader()); - if (foregroundBitmap != null) { - myLocationForegroundDrawable = new BitmapDrawable(foregroundBitmap); - } - - Bitmap foregroundBearingBitmap = in.readParcelable(getClass().getClassLoader()); - if (foregroundBearingBitmap != null) { - myLocationForegroundBearingDrawable = new BitmapDrawable(foregroundBearingBitmap); - } - - Bitmap backgroundBitmap = in.readParcelable(getClass().getClassLoader()); - if (backgroundBitmap != null) { - myLocationBackgroundDrawable = new BitmapDrawable(backgroundBitmap); - } - - myLocationForegroundTintColor = in.readInt(); - myLocationBackgroundTintColor = in.readInt(); - myLocationBackgroundPadding = in.createIntArray(); - myLocationAccuracyAlpha = in.readInt(); - myLocationAccuracyTintColor = in.readInt(); - myLocationAccuracyThreshold = in.readFloat(); - style = in.readString(); apiBaseUrl = in.readString(); textureMode = in.readByte() != 0; @@ -247,48 +208,6 @@ public class MapboxMapOptions implements Parcelable { (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginBottom, FOUR_DP * pxlRatio))}); - mapboxMapOptions.locationEnabled(typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_myLocation, false)); - mapboxMapOptions.myLocationForegroundTintColor( - typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationTintColor, UNDEFINED_COLOR)); - mapboxMapOptions.myLocationBackgroundTintColor( - typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationBackgroundTintColor, UNDEFINED_COLOR)); - - Drawable foregroundDrawable = typedArray.getDrawable(R.styleable.mapbox_MapView_mapbox_myLocationDrawable); - if (foregroundDrawable == null) { - foregroundDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_default); - } - - Drawable foregroundBearingDrawable = typedArray.getDrawable( - R.styleable.mapbox_MapView_mapbox_myLocationBearingDrawable); - if (foregroundBearingDrawable == null) { - foregroundBearingDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_bearing); - } - - Drawable backgroundDrawable = typedArray.getDrawable( - R.styleable.mapbox_MapView_mapbox_myLocationBackgroundDrawable); - if (backgroundDrawable == null) { - backgroundDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_bg_shape); - } - - mapboxMapOptions.myLocationForegroundDrawables(foregroundDrawable, foregroundBearingDrawable); - mapboxMapOptions.myLocationBackgroundDrawable(backgroundDrawable); - mapboxMapOptions.myLocationBackgroundPadding(new int[] { - (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_myLocationBackgroundMarginLeft, - 0) * pxlRatio), - (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_myLocationBackgroundMarginTop, - 0) * pxlRatio), - (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_myLocationBackgroundMarginRight, - 0) * pxlRatio), - (int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_myLocationBackgroundMarginBottom, - 0) * pxlRatio) - }); - mapboxMapOptions.myLocationAccuracyAlpha( - typedArray.getInt(R.styleable.mapbox_MapView_mapbox_myLocationAccuracyAlpha, 100)); - mapboxMapOptions.myLocationAccuracyTint( - typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationAccuracyTintColor, - ColorUtils.getPrimaryColor(context))); - mapboxMapOptions.myLocationAccuracyThreshold( - typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_myLocationAccuracyThreshold, 0)); mapboxMapOptions.textureMode( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_renderTextureMode, false)); mapboxMapOptions.translucentTextureSurface( @@ -576,128 +495,6 @@ public class MapboxMapOptions implements Parcelable { } /** - * Specifies if the user location view is enabled for a map view. - * - * @param locationEnabled True and gesture will be enabled - * @return This - */ - public MapboxMapOptions locationEnabled(boolean locationEnabled) { - this.myLocationEnabled = locationEnabled; - return this; - } - - /** - * Set the foreground drawables of the MyLocationView. - * - * @param myLocationForegroundDrawable the drawable to show as foreground without bearing - * @param myLocationBearingDrawable the drawable to show as foreground when bearing is disabled - * @return This - */ - public MapboxMapOptions myLocationForegroundDrawables(Drawable myLocationForegroundDrawable, - Drawable myLocationBearingDrawable) { - this.myLocationForegroundDrawable = myLocationForegroundDrawable; - this.myLocationForegroundBearingDrawable = myLocationBearingDrawable; - return this; - } - - /** - * Set the foreground drawable of the MyLocationView. - * <p> - * The same drawable will be used for both bearing as non bearing modes. - * </p> - * - * @param myLocationForegroundDrawable the drawable to show as foreground - * @return This - */ - public MapboxMapOptions myLocationForegroundDrawable(Drawable myLocationForegroundDrawable) { - this.myLocationForegroundDrawable = myLocationForegroundDrawable; - return this; - } - - /** - * Set the background drawable of MyLocationView. - * <p> - * Padding can be added to provide an offset to the background. - * </p> - * - * @param myLocationBackgroundDrawable the drawable to show as background - * @return This - */ - public MapboxMapOptions myLocationBackgroundDrawable(Drawable myLocationBackgroundDrawable) { - this.myLocationBackgroundDrawable = myLocationBackgroundDrawable; - return this; - } - - /** - * Set the foreground tint color of MyLocationView. - * <p> - * The color will tint both the foreground and the bearing foreground drawable. - * </p> - * - * @param myLocationForegroundTintColor the color to tint the foreground drawable - * @return This - */ - public MapboxMapOptions myLocationForegroundTintColor(@ColorInt int myLocationForegroundTintColor) { - this.myLocationForegroundTintColor = myLocationForegroundTintColor; - return this; - } - - /** - * Set the background tint color of MyLocationView. - * - * @param myLocationBackgroundTintColor the color to tint the background drawable - * @return This - */ - public MapboxMapOptions myLocationBackgroundTintColor(@ColorInt int myLocationBackgroundTintColor) { - this.myLocationBackgroundTintColor = myLocationBackgroundTintColor; - return this; - } - - /** - * Set the MyLocationView padding. - * - * @param myLocationBackgroundPadding the color to tint the background - * @return This - */ - public MapboxMapOptions myLocationBackgroundPadding(int[] myLocationBackgroundPadding) { - this.myLocationBackgroundPadding = myLocationBackgroundPadding; - return this; - } - - /** - * Set the MyLocationView accuracy circle tint color. - * - * @param myLocationAccuracyTintColor the color to tint the accuracy circle - * @return This - */ - public MapboxMapOptions myLocationAccuracyTint(@ColorInt int myLocationAccuracyTintColor) { - this.myLocationAccuracyTintColor = myLocationAccuracyTintColor; - return this; - } - - /** - * Set the MyLocationView accuracy alpha value. - * - * @param alpha the alpha value - * @return This - */ - public MapboxMapOptions myLocationAccuracyAlpha(@IntRange(from = 0, to = 255) int alpha) { - this.myLocationAccuracyAlpha = alpha; - return this; - } - - /** - * Set accuracy circle threshold. Circle won't be displayed if accuracy is below set value. - * - * @param myLocationAccuracyThreshold Value of accuracy (in meters), below which circle won't be displayed - * @return This - */ - public MapboxMapOptions myLocationAccuracyThreshold(float myLocationAccuracyThreshold) { - this.myLocationAccuracyThreshold = myLocationAccuracyThreshold; - return this; - } - - /** * Enable {@link android.view.TextureView} as rendered surface. * <p> * Since the 5.2.0 release we replaced our TextureView with an {@link android.opengl.GLSurfaceView} @@ -734,11 +531,11 @@ public class MapboxMapOptions implements Parcelable { } /** - * Set the font family for generating glyphs locally for ideographs in the ‘CJK Unified Ideographs’ - * and ‘Hangul Syllables’ ranges. - * + * Set the font family for generating glyphs locally for ideographs in the 'CJK Unified Ideographs' + * and 'Hangul Syllables' ranges. + * <p> * The font family argument is passed to {@link android.graphics.Typeface#create(String, int)}. - * Default system fonts are defined in '/system/etc/fonts.xml' + * Default system fonts are defined in '/system/etc/fonts.xml' * * @param fontFamily font family for local ideograph generation. * @return This @@ -985,98 +782,6 @@ public class MapboxMapOptions implements Parcelable { } /** - * Get the current configured user location view state for a map view. - * - * @return True and user location will be shown - */ - public boolean getLocationEnabled() { - return myLocationEnabled; - } - - /** - * Get the current configured MyLocationView foreground drawable. - * - * @return the drawable used as foreground - */ - public Drawable getMyLocationForegroundDrawable() { - return myLocationForegroundDrawable; - } - - /** - * Get the current configured MyLocationView foreground bearing drawable. - * - * @return the drawable used as foreground when bearing is enabled - */ - public Drawable getMyLocationForegroundBearingDrawable() { - return myLocationForegroundBearingDrawable; - } - - /** - * Get the current configured MyLocationView background drawable. - * - * @return the drawable used as background - */ - public Drawable getMyLocationBackgroundDrawable() { - return myLocationBackgroundDrawable; - } - - /** - * Get the current configured MyLocationView foreground tint color. - * - * @return the tint color - */ - @ColorInt - public int getMyLocationForegroundTintColor() { - return myLocationForegroundTintColor; - } - - /** - * Get the current configured MyLocationView background tint color. - * - * @return the tint color - */ - @ColorInt - public int getMyLocationBackgroundTintColor() { - return myLocationBackgroundTintColor; - } - - /** - * Get the current configured MyLocationView background padding. - * - * @return an array describing the padding in a LTRB manner - */ - public int[] getMyLocationBackgroundPadding() { - return myLocationBackgroundPadding; - } - - /** - * Get the current configured MyLocationView accuracy circle color tint value. - * - * @return the tint color - */ - public int getMyLocationAccuracyTintColor() { - return myLocationAccuracyTintColor; - } - - /** - * Get the current configured MyLocationView accuracy circle alpha value. - * - * @return the alpha value - */ - public int getMyLocationAccuracyAlpha() { - return myLocationAccuracyAlpha; - } - - /** - * Returns current accuracy threshold value (in meters). - * - * @return Value of accuracy threshold (in meters), below which circle won't be displayed - */ - public float getMyLocationAccuracyThreshold() { - return myLocationAccuracyThreshold; - } - - /** * Get the current configured debug state for a map view. * * @return True indicates debug is enabled. @@ -1100,7 +805,7 @@ public class MapboxMapOptions implements Parcelable { /** * Returns the font-family for locally overriding generation of glyphs in the - * ‘CJK Unified Ideographs’ and ‘Hangul Syllables’ ranges. + * 'CJK Unified Ideographs' and 'Hangul Syllables' ranges. * * @return Local ideograph font family name. */ @@ -1154,21 +859,6 @@ public class MapboxMapOptions implements Parcelable { dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (doubleTapGesturesEnabled ? 1 : 0)); - dest.writeByte((byte) (myLocationEnabled ? 1 : 0)); - - dest.writeParcelable(myLocationForegroundDrawable != null - ? BitmapUtils.getBitmapFromDrawable(myLocationForegroundDrawable) : null, flags); - dest.writeParcelable(myLocationForegroundBearingDrawable != null - ? BitmapUtils.getBitmapFromDrawable(myLocationForegroundBearingDrawable) : null, flags); - dest.writeParcelable(myLocationBackgroundDrawable != null - ? BitmapUtils.getBitmapFromDrawable(myLocationBackgroundDrawable) : null, flags); - dest.writeInt(myLocationForegroundTintColor); - dest.writeInt(myLocationBackgroundTintColor); - dest.writeIntArray(myLocationBackgroundPadding); - dest.writeInt(myLocationAccuracyAlpha); - dest.writeInt(myLocationAccuracyTintColor); - dest.writeFloat(myLocationAccuracyThreshold); - dest.writeString(style); dest.writeString(apiBaseUrl); dest.writeByte((byte) (textureMode ? 1 : 0)); @@ -1245,24 +935,6 @@ public class MapboxMapOptions implements Parcelable { if (doubleTapGesturesEnabled != options.doubleTapGesturesEnabled) { return false; } - if (myLocationEnabled != options.myLocationEnabled) { - return false; - } - if (myLocationForegroundTintColor != options.myLocationForegroundTintColor) { - return false; - } - if (myLocationBackgroundTintColor != options.myLocationBackgroundTintColor) { - return false; - } - if (myLocationAccuracyTintColor != options.myLocationAccuracyTintColor) { - return false; - } - if (myLocationAccuracyAlpha != options.myLocationAccuracyAlpha) { - return false; - } - if (myLocationAccuracyThreshold != options.myLocationAccuracyThreshold) { - return false; - } if (cameraPosition != null ? !cameraPosition.equals(options.cameraPosition) : options.cameraPosition != null) { return false; } @@ -1275,24 +947,6 @@ public class MapboxMapOptions implements Parcelable { if (!Arrays.equals(attributionMargins, options.attributionMargins)) { return false; } - if (myLocationForegroundDrawable != null - ? !myLocationForegroundDrawable.equals(options.myLocationForegroundDrawable) - : options.myLocationForegroundDrawable != null) { - return false; - } - if (myLocationForegroundBearingDrawable != null - ? !myLocationForegroundBearingDrawable.equals(options.myLocationForegroundBearingDrawable) - : options.myLocationForegroundBearingDrawable != null) { - return false; - } - if (myLocationBackgroundDrawable != null - ? !myLocationBackgroundDrawable.equals(options.myLocationBackgroundDrawable) - : options.myLocationBackgroundDrawable != null) { - return false; - } - if (!Arrays.equals(myLocationBackgroundPadding, options.myLocationBackgroundPadding)) { - return false; - } if (style != null ? !style.equals(options.style) : options.style != null) { return false; } @@ -1340,18 +994,6 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (zoomGesturesEnabled ? 1 : 0); result = 31 * result + (zoomControlsEnabled ? 1 : 0); result = 31 * result + (doubleTapGesturesEnabled ? 1 : 0); - result = 31 * result + (myLocationEnabled ? 1 : 0); - result = 31 * result + (myLocationForegroundDrawable != null ? myLocationForegroundDrawable.hashCode() : 0); - result = 31 * result + (myLocationForegroundBearingDrawable != null - ? myLocationForegroundBearingDrawable.hashCode() : 0); - result = 31 * result + (myLocationBackgroundDrawable != null ? myLocationBackgroundDrawable.hashCode() : 0); - result = 31 * result + myLocationForegroundTintColor; - result = 31 * result + myLocationBackgroundTintColor; - result = 31 * result + Arrays.hashCode(myLocationBackgroundPadding); - result = 31 * result + myLocationAccuracyTintColor; - result = 31 * result + myLocationAccuracyAlpha; - result = 31 * result + (myLocationAccuracyThreshold != +0.0f - ? Float.floatToIntBits(myLocationAccuracyThreshold) : 0); result = 31 * result + (apiBaseUrl != null ? apiBaseUrl.hashCode() : 0); result = 31 * result + (textureMode ? 1 : 0); result = 31 * result + (translucentTextureSurface ? 1 : 0); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java index ae559189ad..f35355533d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java @@ -9,6 +9,9 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; import com.mapbox.mapboxsdk.geometry.VisibleRegion; +import java.util.ArrayList; +import java.util.List; + /** * A projection is used to translate between on screen location and geographic coordinates on * the surface of the Earth. Screen location is in screen pixels (not display pixels) @@ -24,25 +27,17 @@ public class Projection { this.contentPadding = new int[] {0, 0, 0, 0}; } - void setContentPadding(int[] contentPadding, int[] userLocationViewPadding) { + void setContentPadding(int[] contentPadding) { this.contentPadding = contentPadding; - - int[] padding = new int[] { - contentPadding[0] + userLocationViewPadding[0], - contentPadding[1] + userLocationViewPadding[1], - contentPadding[2] + userLocationViewPadding[2], - contentPadding[3] + userLocationViewPadding[3] - }; - - nativeMapView.setContentPadding(padding); + nativeMapView.setContentPadding(contentPadding); } int[] getContentPadding() { return contentPadding; } - public void invalidateContentPadding(int[] userLocationViewPadding) { - setContentPadding(contentPadding, userLocationViewPadding); + public void invalidateContentPadding() { + setContentPadding(contentPadding); } /** @@ -103,14 +98,49 @@ public class Projection { LatLng bottomRight = fromScreenLocation(new PointF(right, bottom)); LatLng bottomLeft = fromScreenLocation(new PointF(left, bottom)); - return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, - new LatLngBounds.Builder() - .include(topRight) - .include(bottomLeft) - .include(bottomRight) - .include(topLeft) - .build() - ); + // Map can be rotated, find correct LatLngBounds that encompasses the visible region (that might be rotated) + List<LatLng> boundsPoints = new ArrayList<>(); + boundsPoints.add(topLeft); + boundsPoints.add(topRight); + boundsPoints.add(bottomRight); + boundsPoints.add(bottomLeft); + + // order so that two most northern point are put first + while ((boundsPoints.get(0).getLatitude() < boundsPoints.get(3).getLatitude()) + || (boundsPoints.get(1).getLatitude() < boundsPoints.get(2).getLatitude())) { + LatLng first = boundsPoints.remove(0); + boundsPoints.add(first); + } + + double north = boundsPoints.get(0).getLatitude(); + if (north < boundsPoints.get(1).getLatitude()) { + north = boundsPoints.get(1).getLatitude(); + } + + double south = boundsPoints.get(2).getLatitude(); + if (south > boundsPoints.get(3).getLatitude()) { + south = boundsPoints.get(3).getLatitude(); + } + + double firstLon = boundsPoints.get(0).getLongitude(); + double secondLon = boundsPoints.get(1).getLongitude(); + double thridLon = boundsPoints.get(2).getLongitude(); + double fourthLon = boundsPoints.get(3).getLongitude(); + + // if it does not go over the date line + if (secondLon > fourthLon && firstLon < thridLon) { + return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, + LatLngBounds.from(north, + secondLon > thridLon ? secondLon : thridLon, + south, + firstLon < fourthLon ? firstLon : fourthLon)); + } else { + return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, + LatLngBounds.from(north, + secondLon < thridLon ? secondLon : thridLon, + south, + firstLon > fourthLon ? firstLon : fourthLon)); + } } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java deleted file mode 100644 index 3743096824..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java +++ /dev/null @@ -1,419 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -import android.location.Location; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; - -import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.constants.MapboxConstants; -import com.mapbox.mapboxsdk.constants.MyBearingTracking; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; -import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; -import com.mapbox.android.core.permissions.PermissionsManager; - -import timber.log.Timber; - -/** - * Settings for the user location and bearing tracking of a MapboxMap. - * - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. - */ -@Deprecated -public final class TrackingSettings { - - private final MyLocationView myLocationView; - private final UiSettings uiSettings; - private final FocalPointChangeListener focalPointChangedListener; - private final CameraZoomInvalidator zoomInvalidator; - private LocationEngine locationSource; - private LocationEngineListener myLocationListener; - private boolean locationChangeAnimationEnabled = true; - private boolean isCustomLocationSource; - - private boolean myLocationEnabled; - private boolean dismissLocationTrackingOnGesture = true; - private boolean dismissBearingTrackingOnGesture = true; - - private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener; - private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener; - - TrackingSettings(@NonNull MyLocationView myLocationView, UiSettings uiSettings, - FocalPointChangeListener focalPointChangedListener, CameraZoomInvalidator zoomInvalidator) { - this.myLocationView = myLocationView; - this.focalPointChangedListener = focalPointChangedListener; - this.uiSettings = uiSettings; - this.zoomInvalidator = zoomInvalidator; - } - - void initialise(MapboxMapOptions options) { - locationSource = Mapbox.getLocationEngine(); - setMyLocationEnabled(options.getLocationEnabled()); - } - - void onSaveInstanceState(Bundle outState) { - outState.putInt(MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, getMyLocationTrackingMode()); - outState.putInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, getMyBearingTrackingMode()); - outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, isDismissLocationTrackingOnGesture()); - outState.putBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, isDismissBearingTrackingOnGesture()); - outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, isMyLocationEnabled()); - outState.putBoolean(MapboxConstants.STATE_LOCATION_CHANGE_ANIMATION_ENABLED, isLocationChangeAnimationEnabled()); - outState.putBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE, isCustomLocationSource()); - } - - void onRestoreInstanceState(Bundle savedInstanceState) { - try { - setMyLocationEnabled( - savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED), - savedInstanceState.getBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE) - ); - } catch (SecurityException ignore) { - // User did not accept location permissions - } - // noinspection ResourceType - setMyLocationTrackingMode(savedInstanceState.getInt( - MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); - // noinspection ResourceType - setMyBearingTrackingMode(savedInstanceState.getInt( - MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); - setDismissLocationTrackingOnGesture(savedInstanceState.getBoolean( - MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true)); - setDismissBearingTrackingOnGesture(savedInstanceState.getBoolean( - MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true)); - setLocationChangeAnimationEnabled(savedInstanceState.getBoolean( - MapboxConstants.STATE_LOCATION_CHANGE_ANIMATION_ENABLED, true)); - } - - /** - * <p> - * Set the current my location tracking mode. - * </p> - * <p> - * Will enable my location if not active. - * </p> - * See {@link MyLocationTracking} for different values. - * - * @param myLocationTrackingMode The location tracking mode to be used. - * @throws SecurityException if no suitable permission is present - * @see MyLocationTracking - */ - @UiThread - public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) { - myLocationView.setLocationChangeAnimationEnabled(isLocationChangeAnimationEnabled()); - myLocationView.setMyLocationTrackingMode(myLocationTrackingMode); - - if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - zoomInvalidator.zoomTo(2.0); - focalPointChangedListener.onFocalPointChanged(myLocationView.getCenter()); - } else { - focalPointChangedListener.onFocalPointChanged(null); - } - - if (onMyLocationTrackingModeChangeListener != null) { - onMyLocationTrackingModeChangeListener.onMyLocationTrackingModeChange(myLocationTrackingMode); - } - } - - /** - * Returns the current user location tracking mode. - * - * @return The current user location tracking mode. - * One of the values from {@link MyLocationTracking.Mode}. - * @see MyLocationTracking.Mode - */ - @UiThread - @MyLocationTracking.Mode - public int getMyLocationTrackingMode() { - return myLocationView.getMyLocationTrackingMode(); - } - - /** - * <p> - * Set the current my bearing tracking mode. - * </p> - * Shows the direction the user is heading. - * <p> - * When location tracking is disabled the direction of {@link MyLocationView} is rotated. When - * location tracking is enabled the {@link MapView} is rotated based on the bearing value. - * </p> - * See {@link MyBearingTracking} for different values. - * - * @param myBearingTrackingMode The bearing tracking mode to be used. - * @throws SecurityException if no suitable permission is present - * @see MyBearingTracking - */ - @UiThread - public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) { - myLocationView.setMyBearingTrackingMode(myBearingTrackingMode); - if (onMyBearingTrackingModeChangeListener != null) { - onMyBearingTrackingModeChangeListener.onMyBearingTrackingModeChange(myBearingTrackingMode); - } - } - - /** - * Returns the current user bearing tracking mode. - * See {@link MyBearingTracking} for possible return values. - * - * @return the current user bearing tracking mode. - * @see MyBearingTracking - */ - @UiThread - @MyBearingTracking.Mode - public int getMyBearingTrackingMode() { - return myLocationView.getMyBearingTrackingMode(); - } - - /** - * Returns if all tracking modes will be dismissed when a gesture occurs. - * - * @return True to indicate that location and bearing tracking will be dismissed. - */ - public boolean isAllDismissTrackingOnGesture() { - return dismissLocationTrackingOnGesture && dismissBearingTrackingOnGesture; - } - - /** - * Set the dismissal of the tracking modes if a gesture occurs. - * - * @param dismissTrackingOnGesture True to dismiss all the tracking modes. - */ - public void setDismissAllTrackingOnGesture(boolean dismissTrackingOnGesture) { - dismissLocationTrackingOnGesture = dismissTrackingOnGesture; - dismissBearingTrackingOnGesture = dismissTrackingOnGesture; - } - - /** - * Set the dismissal of the tracking modes if a gesture occurs. - * - * @param dismissLocationTrackingOnGesture True to dismiss the location tracking mode. - */ - public void setDismissLocationTrackingOnGesture(boolean dismissLocationTrackingOnGesture) { - this.dismissLocationTrackingOnGesture = dismissLocationTrackingOnGesture; - } - - /** - * Returns if the location tracking will be disabled when a gesture occurs - * - * @return True if location tracking will be disabled. - */ - public boolean isDismissLocationTrackingOnGesture() { - return dismissLocationTrackingOnGesture; - } - - /** - * Set the dismissal of the bearing tracking modes if a gesture occurs. - * - * @param dismissBearingTrackingOnGesture True to dimsiss the bearinf tracking mode - */ - public void setDismissBearingTrackingOnGesture(boolean dismissBearingTrackingOnGesture) { - this.dismissBearingTrackingOnGesture = dismissBearingTrackingOnGesture; - } - - /** - * Returns if bearing will disabled when a gesture occurs - * - * @return True if bearing tracking will be disabled - */ - public boolean isDismissBearingTrackingOnGesture() { - return dismissBearingTrackingOnGesture; - } - - /** - * Returns if location tracking is disabled - * - * @return True if location tracking is disabled. - */ - public boolean isLocationTrackingDisabled() { - return myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE; - } - - /** - * Returns if bearing tracking disabled - * - * @return True if bearing tracking is disabled. - */ - public boolean isBearingTrackingDisabled() { - return myLocationView.getMyBearingTrackingMode() == MyBearingTracking.NONE; - } - - /** - * Returns if rotate gesture are currently enabled. - * - * @return True if rotate gestures are currently enabled. - */ - public boolean isRotateGestureCurrentlyEnabled() { - // rotate gestures are recognised if: - // The user settings are enabled AND; - // EITHER bearing tracking is dismissed on gesture OR there is no bearing tracking - return uiSettings.isRotateGesturesEnabled() - && (dismissBearingTrackingOnGesture - || myLocationView.getMyBearingTrackingMode() == MyBearingTracking.NONE - || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); - } - - /** - * Returns if scroll gesture are currently enabled. - * - * @return True if scroll gestures are currently enabled. - */ - public boolean isScrollGestureCurrentlyEnabled() { - return uiSettings.isScrollGesturesEnabled() - && (dismissLocationTrackingOnGesture - || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); - } - - /** - * Returns whether location change animation is applied for {@link MyLocationTracking#TRACKING_FOLLOW}. - * - * @return True if animation is applied, false otherwise. - */ - public boolean isLocationChangeAnimationEnabled() { - return locationChangeAnimationEnabled; - } - - /** - * Set whether location change animation should be applied for {@link MyLocationTracking#TRACKING_FOLLOW}. - * - * @param locationChangeAnimationEnabled True if animation should be applied, false otherwise. - */ - public void setLocationChangeAnimationEnabled(boolean locationChangeAnimationEnabled) { - this.locationChangeAnimationEnabled = locationChangeAnimationEnabled; - - myLocationView.setLocationChangeAnimationEnabled(locationChangeAnimationEnabled); - } - - /** - * Reset the tracking modes as necessary. Location tracking is reset if the map center is changed and not from - * location, bearing tracking if there is a rotation. - * - * @param translate true if translation - * @param rotate true if rotation - * @param isFromLocation true if from location - */ - void resetTrackingModesIfRequired(boolean translate, boolean rotate, boolean isFromLocation) { - // if tracking is on, and we should dismiss tracking with gestures, and this is a scroll action, turn tracking off - if (translate && !isLocationTrackingDisabled() && isDismissLocationTrackingOnGesture() && !isFromLocation) { - setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE); - } - - // reset bearing tracking only on rotate - if (rotate && !isBearingTrackingDisabled() && isDismissBearingTrackingOnGesture()) { - setMyBearingTrackingMode(MyBearingTracking.NONE); - } - } - - /** - * Reset the tracking modes as necessary. Animated camera position changes can reset the underlying tracking modes. - * - * @param currentCameraPosition the current camera position - * @param targetCameraPosition the changed camera position - * @param isFromLocation true if from location - */ - void resetTrackingModesIfRequired(CameraPosition currentCameraPosition, CameraPosition targetCameraPosition, - boolean isFromLocation) { - if (currentCameraPosition.target != null) { - resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false, - isFromLocation); - } - } - - Location getMyLocation() { - return myLocationView.getLocation(); - } - - void setOnMyLocationChangeListener(@Nullable final MapboxMap.OnMyLocationChangeListener listener) { - if (listener != null) { - myLocationListener = new LocationEngineListener() { - @Override - public void onConnected() { - // Nothing - } - - @Override - public void onLocationChanged(Location location) { - if (listener != null) { - listener.onMyLocationChange(location); - } - } - }; - locationSource.addLocationEngineListener(myLocationListener); - } else { - locationSource.removeLocationEngineListener(myLocationListener); - myLocationListener = null; - } - } - - public boolean isCustomLocationSource() { - return isCustomLocationSource; - } - - void setOnMyLocationTrackingModeChangeListener(MapboxMap.OnMyLocationTrackingModeChangeListener listener) { - this.onMyLocationTrackingModeChangeListener = listener; - } - - void setOnMyBearingTrackingModeChangeListener(MapboxMap.OnMyBearingTrackingModeChangeListener listener) { - this.onMyBearingTrackingModeChangeListener = listener; - } - - MyLocationView getMyLocationView() { - return myLocationView; - } - - - boolean isMyLocationEnabled() { - return myLocationEnabled; - } - - void setMyLocationEnabled(boolean locationEnabled) { - setMyLocationEnabled(locationEnabled, isCustomLocationSource()); - } - - private void setMyLocationEnabled(boolean locationEnabled, boolean isCustomLocationSource) { - if (locationEnabled && !PermissionsManager.areLocationPermissionsGranted(myLocationView.getContext())) { - Timber.e("Could not activate user location tracking: " - + "user did not accept the permission or permissions were not requested."); - return; - } - myLocationEnabled = locationEnabled; - this.isCustomLocationSource = isCustomLocationSource; - myLocationView.setEnabled(locationEnabled, isCustomLocationSource); - } - - void setLocationSource(LocationEngine locationSource) { - if (this.locationSource != null && this.locationSource.equals(locationSource)) { - // this source is already active - return; - } - - this.isCustomLocationSource = locationSource != null; - if (locationSource == null) { - locationSource = Mapbox.getLocationEngine(); - } - this.locationSource = locationSource; - myLocationView.setLocationSource(locationSource); - } - - void update() { - if (!myLocationView.isEnabled()) { - return; - } - myLocationView.update(); - } - - void onStart() { - myLocationView.onStart(); - } - - void onStop() { - myLocationView.onStop(); - } - - interface CameraZoomInvalidator { - void zoomTo(double zoomLevel); - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java index 84a601039f..83f853bfc2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -12,7 +12,6 @@ import com.mapbox.mapboxsdk.camera.CameraUpdate; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import timber.log.Timber; @@ -30,8 +29,6 @@ final class Transform implements MapView.OnMapChangedListener { private final NativeMapView mapView; private final MarkerViewManager markerViewManager; - private final TrackingSettings trackingSettings; - private final MyLocationView myLocationView; private final Handler handler = new Handler(); private CameraPosition cameraPosition; @@ -41,12 +38,10 @@ final class Transform implements MapView.OnMapChangedListener { private CameraChangeDispatcher cameraChangeDispatcher; - Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings, + Transform(NativeMapView mapView, MarkerViewManager markerViewManager, CameraChangeDispatcher cameraChangeDispatcher) { this.mapView = mapView; this.markerViewManager = markerViewManager; - this.trackingSettings = trackingSettings; - this.myLocationView = trackingSettings.getMyLocationView(); this.cameraChangeDispatcher = cameraChangeDispatcher; } @@ -73,9 +68,6 @@ final class Transform implements MapView.OnMapChangedListener { @UiThread void updateCameraPosition(@NonNull CameraPosition position) { - if (myLocationView != null) { - myLocationView.setCameraPosition(position); - } markerViewManager.setTilt((float) position.tilt); } @@ -103,7 +95,6 @@ final class Transform implements MapView.OnMapChangedListener { final void moveCamera(MapboxMap mapboxMap, CameraUpdate update, final MapboxMap.CancelableCallback callback) { CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); if (isValidCameraPosition(cameraPosition)) { - trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false); cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION); mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); @@ -125,7 +116,6 @@ final class Transform implements MapView.OnMapChangedListener { final MapboxMap.CancelableCallback callback, boolean isDismissable) { CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); if (isValidCameraPosition(cameraPosition)) { - trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, isDismissable); cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION); @@ -143,7 +133,6 @@ final class Transform implements MapView.OnMapChangedListener { final MapboxMap.CancelableCallback callback) { CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); if (isValidCameraPosition(cameraPosition)) { - trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false); cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION); @@ -205,6 +194,8 @@ final class Transform implements MapView.OnMapChangedListener { // cancel ongoing transitions mapView.cancelTransitions(); + + cameraChangeDispatcher.onCameraIdle(); } @UiThread @@ -235,39 +226,21 @@ final class Transform implements MapView.OnMapChangedListener { return mapView.getZoom(); } - void zoom(boolean zoomIn, @NonNull PointF focalPoint) { - CameraPosition cameraPosition = invalidateCameraPosition(); - if (cameraPosition != null) { - int newZoom = (int) Math.round(cameraPosition.zoom + (zoomIn ? 1 : -1)); - setZoom(newZoom, focalPoint, MapboxConstants.ANIMATION_DURATION, false); - } else { - // we are not transforming, notify about being idle - cameraChangeDispatcher.onCameraIdle(); - } - } - - void zoom(double zoomAddition, @NonNull PointF focalPoint, long duration) { - CameraPosition cameraPosition = invalidateCameraPosition(); - if (cameraPosition != null) { - int newZoom = (int) Math.round(cameraPosition.zoom + zoomAddition); - setZoom(newZoom, focalPoint, duration, false); - } else { - // we are not transforming, notify about being idle - cameraChangeDispatcher.onCameraIdle(); - } + void zoomBy(double zoomAddition, @NonNull PointF focalPoint) { + setZoom(mapView.getZoom() + zoomAddition, focalPoint); } void setZoom(double zoom, @NonNull PointF focalPoint) { - setZoom(zoom, focalPoint, 0, false); + setZoom(zoom, focalPoint, 0); } - void setZoom(double zoom, @NonNull PointF focalPoint, long duration, final boolean isAnimator) { + void setZoom(double zoom, @NonNull PointF focalPoint, long duration) { if (mapView != null) { mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { @Override public void onMapChanged(int change) { if (change == MapView.REGION_DID_CHANGE_ANIMATED) { - if (!isAnimator) { + if (duration > 0) { cameraChangeDispatcher.onCameraIdle(); } mapView.removeOnMapChangedListener(this); @@ -297,23 +270,14 @@ final class Transform implements MapView.OnMapChangedListener { } void setBearing(double bearing) { - if (myLocationView != null) { - myLocationView.setBearing(bearing); - } mapView.setBearing(bearing); } void setBearing(double bearing, float focalX, float focalY) { - if (myLocationView != null) { - myLocationView.setBearing(bearing); - } mapView.setBearing(bearing, focalX, focalY); } void setBearing(double bearing, float focalX, float focalY, long duration) { - if (myLocationView != null) { - myLocationView.setBearing(bearing); - } mapView.setBearing(bearing, focalX, focalY, duration); } @@ -335,9 +299,6 @@ final class Transform implements MapView.OnMapChangedListener { } void setTilt(Double pitch) { - if (myLocationView != null) { - myLocationView.setTilt(pitch); - } markerViewManager.setTilt(pitch.floatValue()); mapView.setPitch(pitch, 0); } @@ -361,10 +322,6 @@ final class Transform implements MapView.OnMapChangedListener { } } - void zoomBy(double z, float x, float y) { - mapView.setZoom(mapView.getZoom() + z, new PointF(x, y), 0); - } - void moveBy(double offsetX, double offsetY, long duration) { if (duration > 0) { mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 12d8dfe85b..2f6110d8b1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -973,12 +973,7 @@ public final class UiSettings { initMargins[3] = bottom; // convert initial margins with padding - int[] contentPadding = projection.getContentPadding(); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); - left += contentPadding[0]; - top += contentPadding[1]; - right += contentPadding[2]; - bottom += contentPadding[3]; layoutParams.setMargins(left, top, right, bottom); // support RTL diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/package-info.java new file mode 100644 index 0000000000..b14b302652 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android EGL API classes. + */ +package com.mapbox.mapboxsdk.maps.renderer.egl; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/package-info.java new file mode 100644 index 0000000000..aefcffef42 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android GLSurfaceView API classes. + */ +package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/package-info.java new file mode 100644 index 0000000000..f5d8021ea1 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Renderer API classes. + */ +package com.mapbox.mapboxsdk.maps.renderer; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/package-info.java new file mode 100644 index 0000000000..d3585d41f9 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android TextureView API classes. + */ +package com.mapbox.mapboxsdk.maps.renderer.textureview; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java deleted file mode 100644 index 3f37da99d5..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ /dev/null @@ -1,1104 +0,0 @@ -package com.mapbox.mapboxsdk.maps.widgets; - -import android.animation.ValueAnimator; -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Camera; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.PointF; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -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.os.Parcelable; -import android.os.SystemClock; -import android.support.annotation.ColorInt; -import android.support.annotation.FloatRange; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; - -import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.MyBearingTracking; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.Projection; -import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; -import com.mapbox.android.core.location.LocationEnginePriority; - -import java.lang.ref.WeakReference; - -import timber.log.Timber; - -/** - * UI element overlaid on a map to show the user's location. - * <p> - * Use {@link MyLocationViewSettings} to manipulate the state of this view. - * </p> - * - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. - */ -@Deprecated -public class MyLocationView extends View { - - private static final int UNDEFINED_TINT_COLOR = -1; - private MyLocationBehavior myLocationBehavior; - private MapboxMap mapboxMap; - - private Projection projection; - private float[] projectedCoordinate = new float[2]; - private float projectedX; - private float projectedY; - - private float contentPaddingX; - private float contentPaddingY; - - private LatLng latLng; - private Location location; - private LocationEngine locationEngine; - private long locationUpdateTimestamp; - private float previousDirection; - - private float accuracy; - private Paint accuracyPaint; - private float accuracyThreshold; - - private ValueAnimator locationChangeAnimator; - private ValueAnimator accuracyAnimator; - private ValueAnimator directionAnimator; - private boolean locationChangeAnimationEnabled = true; - - private ValueAnimator.AnimatorUpdateListener invalidateSelfOnUpdateListener = - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - invalidate(); - } - }; - - private Drawable foregroundDrawable; - private Drawable foregroundBearingDrawable; - private Drawable backgroundDrawable; - - private Rect foregroundBounds; - private Rect backgroundBounds; - - private int backgroundOffsetLeft; - private int backgroundOffsetTop; - private int backgroundOffsetRight; - private int backgroundOffsetBottom; - - private Matrix matrix; - private Camera camera; - private PointF screenLocation; - - // camera vars - private double tilt; - private double bearing; - private float magneticHeading; - - // Controls the compass update rate in milliseconds - private static final int COMPASS_UPDATE_RATE_MS = 500; - - @MyLocationTracking.Mode - private int myLocationTrackingMode; - - @MyBearingTracking.Mode - private int myBearingTrackingMode; - - private GpsLocationListener userLocationListener; - private CompassListener compassListener; - - public MyLocationView(Context context) { - super(context); - init(context); - } - - public MyLocationView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - public MyLocationView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context); - } - - private void init(Context context) { - if (isInEditMode()) { - return; - } - - setEnabled(false); - - // setup LayoutParams - ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - setLayoutParams(lp); - - matrix = new Matrix(); - camera = new Camera(); - camera.setLocation(0, 0, -1000); - accuracyPaint = new Paint(); - - myLocationBehavior = new MyLocationBehaviorFactory().getBehavioralModel(MyLocationTracking.TRACKING_NONE); - compassListener = new CompassListener(context); - } - - @Deprecated - public void init(LocationEngine locationSource) { - this.locationEngine = locationSource; - } - - /** - * Set the foreground drawable, for internal use only. - * - * @param defaultDrawable The drawable shown when showing this view - * @param bearingDrawable The drawable shown when tracking of bearing is enabled - */ - public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bearingDrawable) { - if (defaultDrawable == null) { - return; - } - - if (bearingDrawable == null) { - // if user only provided one resource - // use same for bearing mode - bearingDrawable = defaultDrawable.getConstantState().newDrawable(); - } - - if (backgroundDrawable == null) { - // if the user didn't provide a background resource we will use the foreground resource instead, - // we need to create a new drawable to handle tinting correctly - backgroundDrawable = defaultDrawable.getConstantState().newDrawable(); - } - - if (defaultDrawable.getIntrinsicWidth() != bearingDrawable.getIntrinsicWidth() - || defaultDrawable.getIntrinsicHeight() != bearingDrawable.getIntrinsicHeight()) { - throw new RuntimeException("The dimensions from location and bearing drawables should be match"); - } - - foregroundDrawable = defaultDrawable; - foregroundBearingDrawable = bearingDrawable; - - invalidateBounds(); - } - - /** - * Set the foreground drawable tint, for internal use only. - * - * @param color The color to tint the drawable with - */ - public final void setForegroundDrawableTint(@ColorInt int color) { - applyDrawableTint(foregroundDrawable, color); - applyDrawableTint(foregroundBearingDrawable, color); - invalidate(); - } - - /** - * Set the shadow drawable, for internal use only. - * - * @param drawable The drawable shown as shadow - */ - public final void setShadowDrawable(Drawable drawable) { - setShadowDrawable(drawable, 0, 0, 0, 0); - } - - /** - * Set the shadow drawable with some additional offset. - * - * @param drawable The drawable shown as shadow - * @param left The left offset margin - * @param top The top offset margin - * @param right The right offset margin - * @param bottom The bottom offset margin - */ - public final void setShadowDrawable(Drawable drawable, int left, int top, int right, int bottom) { - if (drawable != null) { - backgroundDrawable = drawable; - } - - backgroundOffsetLeft = left; - backgroundOffsetTop = top; - backgroundOffsetRight = right; - backgroundOffsetBottom = bottom; - - invalidateBounds(); - } - - /** - * Set the shadow drawable tint color, for internal use only. - * - * @param color The tint color to apply - */ - public final void setShadowDrawableTint(@ColorInt int color) { - if (backgroundDrawable == null) { - return; - } - applyDrawableTint(backgroundDrawable, color); - invalidate(); - } - - /** - * Set the accuracy tint color, for internal use only. - * - * @param color The tint color to apply - */ - public final void setAccuracyTint(@ColorInt int color) { - int alpha = accuracyPaint.getAlpha(); - accuracyPaint.setColor(color); - accuracyPaint.setAlpha(alpha); - invalidate(); - } - - /** - * Set the accuracy alpha value, for internal use only. - * - * @param alpha The alpha accuracy value to apply - */ - public final void setAccuracyAlpha(@IntRange(from = 0, to = 255) int alpha) { - accuracyPaint.setAlpha(alpha); - invalidate(); - } - - private void invalidateBounds() { - if (backgroundDrawable == null || foregroundDrawable == null || foregroundBearingDrawable == null) { - return; - } - - int backgroundWidth = backgroundDrawable.getIntrinsicWidth(); - int backgroundHeight = backgroundDrawable.getIntrinsicHeight(); - int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight; - int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom; - backgroundBounds = new Rect(-backgroundWidth / 2 + horizontalOffset, - -backgroundHeight / 2 + verticalOffset, backgroundWidth / 2 + horizontalOffset, backgroundHeight / 2 - + verticalOffset); - backgroundDrawable.setBounds(backgroundBounds); - - int foregroundWidth = foregroundDrawable.getIntrinsicWidth(); - int foregroundHeight = foregroundDrawable.getIntrinsicHeight(); - foregroundBounds = new Rect(-foregroundWidth / 2, -foregroundHeight / 2, foregroundWidth / 2, foregroundHeight / 2); - foregroundDrawable.setBounds(foregroundBounds); - foregroundBearingDrawable.setBounds(foregroundBounds); - - // invoke a new draw - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null - || screenLocation == null) { - // Not ready yet - return; - } - - final PointF pointF = screenLocation; - float metersPerPixel = (float) projection.getMetersPerPixelAtLatitude(location.getLatitude()); - float accuracyPixels = (Float) accuracyAnimator.getAnimatedValue() / metersPerPixel; - - // reset - matrix.reset(); - projectedCoordinate[0] = 0; - projectedCoordinate[1] = 0; - - // put camera in position - camera.save(); - camera.rotate((float) tilt, 0, 0); - camera.getMatrix(matrix); - - if (myBearingTrackingMode != MyBearingTracking.NONE && directionAnimator != null) { - matrix.preRotate((Float) directionAnimator.getAnimatedValue()); - } - - matrix.preTranslate(0, contentPaddingY); - matrix.postTranslate(pointF.x, pointF.y - contentPaddingY); - - // concat our matrix on canvas - canvas.concat(matrix); - - // calculate focal point - matrix.mapPoints(projectedCoordinate); - projectedX = pointF.x - projectedCoordinate[0]; - projectedY = pointF.y - projectedCoordinate[1]; - - // restore orientation from camera - camera.restore(); - - // draw circle - canvas.drawCircle(0, 0, accuracyPixels, accuracyPaint); - - // draw shadow - if (backgroundDrawable != null) { - backgroundDrawable.draw(canvas); - } - - // draw foreground - if (myBearingTrackingMode == MyBearingTracking.NONE) { - if (foregroundDrawable != null) { - foregroundDrawable.draw(canvas); - } - } else if (foregroundBearingDrawable != null && foregroundBounds != null) { - if (myBearingTrackingMode == MyBearingTracking.GPS - || myBearingTrackingMode == MyBearingTracking.GPS_NORTH_FACING - || compassListener.isSensorAvailable()) { - foregroundBearingDrawable.draw(canvas); - } else { - // We are tracking MyBearingTracking.COMPASS, but sensor is not available. - foregroundDrawable.draw(canvas); - } - } - } - - /** - * Set the tilt value, for internal use only. - * - * @param tilt The tilt to apply - */ - public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) { - this.tilt = tilt; - invalidate(); - } - - /** - * Set the bearing value, for internal use only. - * - * @param bearing The bearing to apply - */ - public void setBearing(double bearing) { - this.bearing = bearing; - if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - if (myBearingTrackingMode == MyBearingTracking.GPS - || myBearingTrackingMode == MyBearingTracking.GPS_NORTH_FACING) { - if (location != null) { - setCompass(location.getBearing() - bearing); - } - } else if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) { - setCompass(magneticHeading - bearing); - } - } - } - - /** - * Set the bearing and tilt from a camera position, for internal use only. - * - * @param position The camera position to extract bearing and tilt from - */ - public void setCameraPosition(CameraPosition position) { - if (position != null) { - setBearing(position.bearing); - setTilt(position.tilt); - } - } - - /** - * Called when the hosting activity is starting, for internal use only. - */ - public void onStart() { - if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) { - compassListener.onResume(); - } - if (isEnabled()) { - toggleGps(true); - } - } - - /** - * Called when the hosting activity is stopping, for internal use only. - */ - public void onStop() { - compassListener.onPause(); - toggleGps(false); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - // cleanup to prevent memory leaks - if (locationChangeAnimator != null) { - locationChangeAnimator.cancel(); - locationChangeAnimator = null; - } - - if (accuracyAnimator != null) { - accuracyAnimator.cancel(); - accuracyAnimator = null; - } - - if (directionAnimator != null) { - directionAnimator.cancel(); - directionAnimator = null; - } - - if (userLocationListener != null) { - locationEngine.removeLocationEngineListener(userLocationListener); - locationEngine = null; - userLocationListener = null; - } - } - - /** - * Update current locationstate. - */ - public void update() { - if (isEnabled()) { - myLocationBehavior.invalidate(); - } else { - setVisibility(View.INVISIBLE); - } - } - - // TODO refactor MapboxMap out - public void setMapboxMap(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - this.projection = mapboxMap.getProjection(); - } - - /** - * Set the enabled state, for internal use only. - * - * @param enabled The value to set the state to - */ - @Override - public void setEnabled(boolean enabled) { - setEnabled(enabled, false); - } - - /** - * Set the enabled state, for internal use only. - * - * @param enabled The value to set the state to - * @param isCustomLocationEngine Flag handling for handling user provided custom location engine - */ - public void setEnabled(boolean enabled, boolean isCustomLocationEngine) { - super.setEnabled(enabled); - setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); - toggleGps(enabled, isCustomLocationEngine); - } - - /** - * Save the view instance state, for internal use only. - * - * @return the marshaled representation of the view state - */ - @Override - protected Parcelable onSaveInstanceState() { - Bundle bundle = new Bundle(); - bundle.putParcelable("superState", super.onSaveInstanceState()); - bundle.putDouble("tilt", tilt); - return bundle; - } - - /** - * Restore the view instance state, for internal use only. - * - * @param state the marshalled representation of the state to restore - */ - @Override - public void onRestoreInstanceState(Parcelable state) { - if (state instanceof Bundle) { - Bundle bundle = (Bundle) state; - tilt = bundle.getDouble("tilt"); - state = bundle.getParcelable("superState"); - } - super.onRestoreInstanceState(state); - } - - private void toggleGps(boolean enableGps) { - toggleGps(enableGps, mapboxMap != null - && mapboxMap.getTrackingSettings().isCustomLocationSource()); - } - - /** - * Enabled / Disable GPS location updates along with updating the UI, for internal use only. - * - * @param enableGps true if GPS is to be enabled, false if GPS is to be disabled - */ - private void toggleGps(boolean enableGps, boolean isCustomLocationEngine) { - if (enableGps) { - if (locationEngine == null) { - if (!isCustomLocationEngine) { - locationEngine = Mapbox.getLocationEngine(); - } else { - return; - } - } - - if (userLocationListener == null) { - userLocationListener = new GpsLocationListener(this, locationEngine); - } - - locationEngine.addLocationEngineListener(userLocationListener); - locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY); - locationEngine.activate(); - } else { - if (locationEngine == null) { - return; - } - // Disable location and user dot - location = null; - locationEngine.removeLocationEngineListener(userLocationListener); - locationEngine.removeLocationUpdates(); - locationEngine.deactivate(); - restoreLocationEngine(); - } - } - - /** - * Get the current location. - * - * @return the current location - */ - public Location getLocation() { - return location; - } - - /** - * Set the current location, for internal use only. - * - * @param location The current location - */ - public void setLocation(Location location) { - if (location == null) { - this.location = null; - return; - } - - this.location = location; - myLocationBehavior.updateLatLng(location); - - if (mapboxMap != null && (myBearingTrackingMode == MyBearingTracking.GPS - || myBearingTrackingMode == MyBearingTracking.GPS_NORTH_FACING) - && myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - setBearing(mapboxMap.getCameraPosition().bearing); - } - } - - /** - * Set location change animation enabled, for internal use only. - * - * @param locationChangeAnimationEnabled True if location changes are animated - */ - public void setLocationChangeAnimationEnabled(boolean locationChangeAnimationEnabled) { - this.locationChangeAnimationEnabled = locationChangeAnimationEnabled; - } - - /** - * Set accuracy circle threshold. Circle won't be displayed if accuracy is below set value. - * For internal use only. - * - * @param accuracyThreshold Value below which circle won't be displayed - */ - public void setAccuracyThreshold(float accuracyThreshold) { - this.accuracyThreshold = accuracyThreshold; - } - - /** - * Set the bearing tracking mode, for internal use only. - * - * @param myBearingTrackingMode The bearing tracking mode - */ - public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) { - this.myBearingTrackingMode = myBearingTrackingMode; - if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) { - compassListener.onResume(); - } else { - compassListener.onPause(); - if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW - && myBearingTrackingMode == MyBearingTracking.GPS) { - // always face north - setCompass(0); - } else { - myLocationBehavior.invalidate(); - } - } - invalidate(); - } - - /** - * Set the location tracking mode, for internla use only. - * - * @param myLocationTrackingMode The location tracking mode - */ - public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) { - MyLocationBehaviorFactory factory = new MyLocationBehaviorFactory(); - myLocationBehavior = factory.getBehavioralModel(myLocationTrackingMode); - - if (location != null) { - if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - // center map directly - mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(location))); - } else { - // do not use interpolated location from tracking mode - latLng = null; - } - myLocationBehavior.updateLatLng(location); - } - - this.myLocationTrackingMode = myLocationTrackingMode; - invalidate(); - } - - /** - * Get the location tracking mode, for internal use only. - * - * @return The location tracking mode - */ - @MyLocationTracking.Mode - public int getMyLocationTrackingMode() { - return myLocationTrackingMode; - } - - - /** - * Get the bearing tracking mode, for internal use only. - * - * @return the bearing tracking mode - */ - @MyBearingTracking.Mode - public int getMyBearingTrackingMode() { - return myBearingTrackingMode; - } - - /** - * Set the compass bearing value, for internal use only. - * - * @param bearing The compas bearing value - */ - private void setCompass(double bearing) { - setCompass(bearing, 0 /* no animation */); - } - - private void setCompass(double bearing, long duration) { - float oldDir = previousDirection; - if (directionAnimator != null) { - oldDir = (Float) directionAnimator.getAnimatedValue(); - directionAnimator.end(); - directionAnimator = null; - } - - float newDir = (float) bearing; - float diff = oldDir - newDir; - if (diff > 180.0f) { - newDir += 360.0f; - } else if (diff < -180.0f) { - newDir -= 360.f; - } - previousDirection = newDir; - - directionAnimator = ValueAnimator.ofFloat(oldDir, newDir); - directionAnimator.setDuration(duration); - directionAnimator.addUpdateListener(invalidateSelfOnUpdateListener); - directionAnimator.start(); - } - - /** - * Get the center of this view in screen coordinates. - * - * @return the center of the view - */ - public PointF getCenter() { - return new PointF(getCenterX(), getCenterY()); - } - - /** - * Get the x value of the center of this view. - * - * @return the x value of the center of the view - */ - private float getCenterX() { - return (getX() + getMeasuredWidth()) / 2 + contentPaddingX - projectedX; - } - - /** - * Get the y value of the center of this view. - * - * @return the y value of the center of the view - */ - private float getCenterY() { - return (getY() + getMeasuredHeight()) / 2 + contentPaddingY - projectedY; - } - - public void setContentPadding(int[] padding) { - contentPaddingX = (padding[0] - padding[2]) / 2; - contentPaddingY = (padding[1] - padding[3]) / 2; - } - - /** - * Set the location source from which location updates are received, for internal use only. - * - * @param locationEngine The location engine to receive updates from - */ - public void setLocationSource(LocationEngine locationEngine) { - toggleGps(false); - this.locationEngine = locationEngine; - this.userLocationListener = null; - setEnabled(isEnabled(), locationEngine != null); - } - - private void applyDrawableTint(Drawable drawable, @ColorInt int color) { - if (color == UNDEFINED_TINT_COLOR) { - removeTintColorFilter(drawable); - } else { - applyTintColorFilter(drawable, color); - } - } - - private void removeTintColorFilter(Drawable drawable) { - if (drawable != null) { - drawable.mutate().setColorFilter(null); - } - } - - private void applyTintColorFilter(Drawable drawable, @ColorInt int color) { - if (drawable != null) { - drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - } - - private void restoreLocationEngine() { - locationEngine.setPriority(LocationEnginePriority.LOW_POWER); - locationEngine.activate(); - } - - private static class GpsLocationListener implements LocationEngineListener { - - private WeakReference<MyLocationView> userLocationView; - private WeakReference<LocationEngine> locationSource; - - GpsLocationListener(MyLocationView myLocationView, LocationEngine locationEngine) { - userLocationView = new WeakReference<>(myLocationView); - locationSource = new WeakReference<>(locationEngine); - } - - @SuppressLint("MissingPermission") - @Override - public void onConnected() { - MyLocationView locationView = userLocationView.get(); - LocationEngine locationEngine = locationSource.get(); - if (locationView != null && locationEngine != null) { - Location lastKnownLocation = locationEngine.getLastLocation(); - if (lastKnownLocation != null) { - locationView.setLocation(lastKnownLocation); - } - locationEngine.requestLocationUpdates(); - } - } - - /** - * Callback method for receiving location updates from LocationServices. - * - * @param location The new Location data - */ - @Override - public void onLocationChanged(Location location) { - MyLocationView locationView = userLocationView.get(); - if (locationView != null) { - locationView.setLocation(location); - } - } - } - - private class CompassListener implements SensorEventListener { - - private final SensorManager sensorManager; - - private Sensor rotationVectorSensor; - private float[] matrix = new float[9]; - private float[] rotationVectorValue; - private float[] truncatedRotationVectorValue = new float[4]; - - private float[] orientation = new float[3]; - private boolean reportMissingSensor = true; - // Compass data - private long compassUpdateNextTimestamp = 0; - - CompassListener(Context context) { - sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - rotationVectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); - } - - public void onResume() { - sensorManager.registerListener(this, rotationVectorSensor, SensorManager.SENSOR_DELAY_GAME); - } - - public void onPause() { - sensorManager.unregisterListener(this, rotationVectorSensor); - } - - public boolean isSensorAvailable() { - if (rotationVectorSensor == null && reportMissingSensor) { - reportMissingSensor = false; - Timber.e("Sensor.TYPE_ROTATION_VECTOR is missing from this device. Unable to use MyBearingTracking.COMPASS."); - } - return rotationVectorSensor != null; - } - - @Override - public void onSensorChanged(SensorEvent event) { - - // check when the last time the compass was updated, return if too soon. - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime < compassUpdateNextTimestamp) { - return; - } - - if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { - rotationVectorValue = getRotationVectorFromSensorEvent(event); - SensorManager.getRotationMatrixFromVector(matrix, rotationVectorValue); - SensorManager.getOrientation(matrix, orientation); - - magneticHeading = (float) Math.toDegrees(SensorManager.getOrientation(matrix, orientation)[0]); - if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - // Change the user location view orientation to reflect the device orientation - rotateCamera(magneticHeading); - setCompass(0, COMPASS_UPDATE_RATE_MS); - } else { - // Change compass direction - setCompass(magneticHeading - bearing, COMPASS_UPDATE_RATE_MS); - } - - compassUpdateNextTimestamp = currentTime + COMPASS_UPDATE_RATE_MS; - } - } - - /** - * Pulls out the rotation vector from a SensorEvent, with a maximum length - * vector of four elements to avoid potential compatibility issues. - * - * @param event the sensor event - * @return the events rotation vector, potentially truncated - */ - @NonNull - float[] getRotationVectorFromSensorEvent(@NonNull SensorEvent event) { - if (event.values.length > 4) { - // On some Samsung devices SensorManager.getRotationMatrixFromVector - // appears to throw an exception if rotation vector has length > 4. - // For the purposes of this class the first 4 values of the - // rotation vector are sufficient (see crbug.com/335298 for details). - // Only affects Android 4.3 - System.arraycopy(event.values, 0, truncatedRotationVectorValue, 0, 4); - return truncatedRotationVectorValue; - } else { - return event.values; - } - } - - private void rotateCamera(float rotation) { - CameraPosition.Builder builder = new CameraPosition.Builder(); - builder.bearing(rotation); - mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), COMPASS_UPDATE_RATE_MS, - false /*linear interpolator*/, null); - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - - } - - private class MarkerCoordinateAnimatorListener implements ValueAnimator.AnimatorUpdateListener { - - private MyLocationBehavior behavior; - private double fromLat; - private double fromLng; - private double toLat; - private double toLng; - - private MarkerCoordinateAnimatorListener(MyLocationBehavior myLocationBehavior, LatLng from, LatLng to) { - behavior = myLocationBehavior; - fromLat = from.getLatitude(); - fromLng = from.getLongitude(); - toLat = to.getLatitude(); - toLng = to.getLongitude(); - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float frac = animation.getAnimatedFraction(); - double latitude = fromLat + (toLat - fromLat) * frac; - double longitude = fromLng + (toLng - fromLng) * frac; - behavior.updateLatLng(latitude, longitude); - update(); - } - } - - private class MyLocationBehaviorFactory { - - MyLocationBehavior getBehavioralModel(@MyLocationTracking.Mode int mode) { - if (mode == MyLocationTracking.TRACKING_NONE) { - return new MyLocationShowBehavior(); - } else { - return new MyLocationTrackingBehavior(); - } - } - } - - private abstract class MyLocationBehavior { - - MyLocationBehavior() { - if (latLng != null) { - locationUpdateTimestamp = SystemClock.elapsedRealtime(); - } - } - - void updateLatLng(@NonNull Location newLocation) { - location = newLocation; - } - - void updateLatLng(double lat, double lon) { - if (latLng != null) { - latLng.setLatitude(lat); - latLng.setLongitude(lon); - } - } - - void updateAccuracy(@NonNull Location location) { - if (accuracyAnimator != null && accuracyAnimator.isRunning()) { - // use current accuracy as a starting point - accuracy = (Float) accuracyAnimator.getAnimatedValue(); - accuracyAnimator.end(); - } - - float newAccuracy = location.getAccuracy() >= accuracyThreshold ? location.getAccuracy() : 0f; - accuracyAnimator = ValueAnimator.ofFloat(accuracy, newAccuracy); - accuracyAnimator.setDuration(750); - accuracyAnimator.start(); - accuracy = newAccuracy; - } - - abstract void invalidate(); - } - - private class MyLocationTrackingBehavior extends MyLocationBehavior { - - @Override - void updateLatLng(@NonNull Location location) { - super.updateLatLng(location); - if (latLng == null) { - // first location fix - latLng = new LatLng(location); - locationUpdateTimestamp = SystemClock.elapsedRealtime(); - } - - // updateLatLng timestamp - float previousUpdateTimeStamp = locationUpdateTimestamp; - locationUpdateTimestamp = SystemClock.elapsedRealtime(); - - // calculate animation duration - int animationDuration; - if (previousUpdateTimeStamp == 0) { - animationDuration = 0; - } else { - animationDuration = (int) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.1f) - /*make animation slightly longer*/; - } - - // calculate interpolated location - latLng = new LatLng(location); - CameraPosition.Builder builder = new CameraPosition.Builder().target(latLng); - - // add direction - if (myBearingTrackingMode == MyBearingTracking.GPS) { - if (location.hasBearing()) { - builder.bearing(location.getBearing()); - } - setCompass(0, COMPASS_UPDATE_RATE_MS); - } - - if (myBearingTrackingMode == MyBearingTracking.GPS_NORTH_FACING) { - builder.bearing(0); - if (location.hasBearing()) { - setCompass(location.getBearing(), COMPASS_UPDATE_RATE_MS); - } - } - - // accuracy - updateAccuracy(location); - - if (locationChangeAnimationEnabled && animationDuration > 0) { - // ease to new camera position with a linear interpolator - mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), animationDuration, false, null, - true); - } else { - mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(builder.build())); - } - } - - @Override - void invalidate() { - int[] mapPadding = mapboxMap.getPadding(); - float x = (getWidth() + mapPadding[0] - mapPadding[2]) / 2 + contentPaddingX; - float y = (getHeight() - mapPadding[3] + mapPadding[1]) / 2 + contentPaddingY; - screenLocation = new PointF(x, y); - MyLocationView.this.invalidate(); - } - } - - private class MyLocationShowBehavior extends MyLocationBehavior { - - @Override - void updateLatLng(@NonNull final Location location) { - super.updateLatLng(location); - if (latLng == null) { - // first location update - latLng = new LatLng(location); - locationUpdateTimestamp = SystemClock.elapsedRealtime(); - } - - // update LatLng location - LatLng newLocation = new LatLng(location); - - // update LatLng accuracy - updateAccuracy(location); - - // calculate updateLatLng time + add some extra offset to improve animation - long previousUpdateTimeStamp = locationUpdateTimestamp; - locationUpdateTimestamp = SystemClock.elapsedRealtime(); - long locationUpdateDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.2f); - - // animate changes - if (locationChangeAnimator != null) { - locationChangeAnimator.end(); - locationChangeAnimator = null; - } - - locationChangeAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); - if (locationChangeAnimationEnabled) { - locationChangeAnimator.setDuration(locationUpdateDuration); - } else { - locationChangeAnimator.setDuration(0); - } - locationChangeAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener(this, - latLng, newLocation - )); - locationChangeAnimator.start(); - latLng = newLocation; - } - - @Override - void invalidate() { - if (latLng != null) { - screenLocation = projection.toScreenLocation(latLng); - } - MyLocationView.this.invalidate(); - } - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java deleted file mode 100644 index ec7c53e1d0..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java +++ /dev/null @@ -1,389 +0,0 @@ -package com.mapbox.mapboxsdk.maps.widgets; - -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.ColorInt; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; - -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.constants.MapboxConstants; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.maps.FocalPointChangeListener; -import com.mapbox.mapboxsdk.maps.MapboxMapOptions; -import com.mapbox.mapboxsdk.maps.Projection; -import com.mapbox.mapboxsdk.utils.BitmapUtils; - -/** - * Settings to configure the visual appearance of the MyLocationView. - * - * @deprecated use location layer plugin from - * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. - */ -@Deprecated -public class MyLocationViewSettings { - - private Projection projection; - private MyLocationView myLocationView; - private FocalPointChangeListener focalPointChangeListener; - - // - // State - // - - private boolean enabled; - - // - // Foreground - // - - private Drawable foregroundDrawable; - private Drawable foregroundBearingDrawable; - - @ColorInt - private int foregroundTintColor; - - // - // Background - // - - private Drawable backgroundDrawable; - private int[] backgroundOffset = new int[4]; - - @ColorInt - private int backgroundTintColor; - - // - // Accuracy - // - - private int accuracyAlpha; - private float accuracyThreshold = 0f; - - @ColorInt - private int accuracyTintColor; - - // - // Padding - // - - private int[] padding = new int[4]; - - /** - * Creates an instance of MyLocationViewSettings - * <p> - * - * @param myLocationView the MyLocationView to apply the settings to - * @param projection the MapView projection - * @param focalPointChangedListener the interface to be invoked when focal points changes - * @see MyLocationView - */ - public MyLocationViewSettings(MyLocationView myLocationView, Projection projection, FocalPointChangeListener - focalPointChangedListener) { - this.myLocationView = myLocationView; - this.projection = projection; - this.focalPointChangeListener = focalPointChangedListener; - } - - /** - * Initialise this with MapboxMapOptions. - * - * @param options the options to initialise this class from - */ - public void initialise(@NonNull MapboxMapOptions options) { - CameraPosition position = options.getCamera(); - if (position != null && !position.equals(CameraPosition.DEFAULT)) { - setTilt(position.tilt); - } - setForegroundDrawable(options.getMyLocationForegroundDrawable(), options.getMyLocationForegroundBearingDrawable()); - setForegroundTintColor(options.getMyLocationForegroundTintColor()); - setBackgroundDrawable(options.getMyLocationBackgroundDrawable(), options.getMyLocationBackgroundPadding()); - setBackgroundTintColor(options.getMyLocationBackgroundTintColor()); - setAccuracyAlpha(options.getMyLocationAccuracyAlpha()); - setAccuracyTintColor(options.getMyLocationAccuracyTintColor()); - setAccuracyThreshold(options.getMyLocationAccuracyThreshold()); - } - - public void onSaveInstanceState(Bundle outState) { - outState.putBoolean(MapboxConstants.STATE_LOCATION_VIEW_ENABLED, isEnabled()); - outState.putByteArray( - MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_DRAWABLE, - BitmapUtils.getByteArrayFromDrawable(getForegroundDrawable()) - ); - outState.putByteArray( - MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_BEARING_DRAWABLE, - BitmapUtils.getByteArrayFromDrawable(getForegroundBearingDrawable()) - ); - outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_TINT_COLOR, getForegroundTintColor()); - outState.putByteArray( - MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_DRAWABLE, - BitmapUtils.getByteArrayFromDrawable(getBackgroundDrawable()) - ); - outState.putIntArray(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_OFFSET, getBackgroundOffset()); - outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_TINT_COLOR, getBackgroundTintColor()); - outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_ALPHA, getAccuracyAlpha()); - outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_TINT_COLOR, getAccuracyTintColor()); - outState.putFloat(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_THRESHOLD, getAccuracyThreshold()); - outState.putIntArray(MapboxConstants.STATE_LOCATION_VIEW_PADDING, getPadding()); - } - - public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { - setEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_LOCATION_VIEW_ENABLED)); - setForegroundDrawable( - BitmapUtils.getDrawableFromByteArray( - myLocationView.getContext(), - savedInstanceState.getByteArray(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_DRAWABLE) - ), - BitmapUtils.getDrawableFromByteArray( - myLocationView.getContext(), - savedInstanceState.getByteArray(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_BEARING_DRAWABLE) - ) - ); - setForegroundTintColor(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_TINT_COLOR)); - setBackgroundDrawable( - BitmapUtils.getDrawableFromByteArray( - myLocationView.getContext(), - savedInstanceState.getByteArray(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_DRAWABLE) - ), - savedInstanceState.getIntArray(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_OFFSET) - ); - setBackgroundTintColor(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_TINT_COLOR)); - setAccuracyAlpha(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_ALPHA)); - setAccuracyTintColor(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_TINT_COLOR)); - setAccuracyThreshold(savedInstanceState.getFloat(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_THRESHOLD)); - setPadding(savedInstanceState.getIntArray(MapboxConstants.STATE_LOCATION_VIEW_PADDING)); - } - - /** - * Returns if the MyLocationView is enabled - * - * @return true if MyLocationView is enabled, - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Set the enabled state of MyLocationView - * - * @param enabled true shows the MyLocationView on the map - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - myLocationView.setEnabled(enabled); - } - - /** - * Set the foreground drawable of the MyLocationView - * <p> - * The foreground drawable is the image visible on screen - * </p> - * It's linked with the foreground tint color - * - * @param foregroundDrawable the drawable to show as foreground without bearing - * @param foregroundBearingDrawable the drawable to show as foreground when bearing is enabled - */ - public void setForegroundDrawable(Drawable foregroundDrawable, Drawable foregroundBearingDrawable) { - this.foregroundDrawable = foregroundDrawable; - this.foregroundBearingDrawable = foregroundBearingDrawable; - myLocationView.setForegroundDrawables(foregroundDrawable, foregroundBearingDrawable); - myLocationView.setForegroundDrawableTint(foregroundTintColor); - } - - /** - * Get the foreground drawable when bearing is disabled. - * - * @return the drawable used as foreground - */ - public Drawable getForegroundDrawable() { - return foregroundDrawable; - } - - /** - * Get the foreground drawable when bearing is enabled. - * - * @return the bearing drawable used as foreground - */ - public Drawable getForegroundBearingDrawable() { - return foregroundBearingDrawable; - } - - /** - * Set the foreground tint color. - * <p> - * The color will tint both the foreground and the bearing foreground drawable. - * </p> - * - * @param foregroundTintColor the color to tint the foreground drawable or -1 (undefined color) to remove the - * existing foreground tint color - */ - public void setForegroundTintColor(@ColorInt int foregroundTintColor) { - this.foregroundTintColor = foregroundTintColor; - myLocationView.setForegroundDrawableTint(foregroundTintColor); - } - - /** - * Get the foreground tint color. - * - * @return the foreground tint color - */ - public int getForegroundTintColor() { - return foregroundTintColor; - } - - /** - * Set the background drawable of MyLocationView - * <p> - * Padding can be added to provide an offset to the background - * </p> - * It's linked with the background tint color - * - * @param backgroundDrawable the drawable to show as background - * @param padding the padding added to the background - */ - public void setBackgroundDrawable(Drawable backgroundDrawable, int[] padding) { - this.backgroundDrawable = backgroundDrawable; - this.backgroundOffset = padding; - if (padding != null && padding.length == 4) { - myLocationView.setShadowDrawable(backgroundDrawable, padding[0], padding[1], padding[2], padding[3]); - } else { - myLocationView.setShadowDrawable(backgroundDrawable); - } - myLocationView.setShadowDrawableTint(backgroundTintColor); - } - - /** - * Get the background drawable of MyLocationView. - * - * @return the drawable used as background - */ - public Drawable getBackgroundDrawable() { - return backgroundDrawable; - } - - /** - * Set the background tint color. - * - * @param backgroundTintColor the color to tint the background drawable or -1 (undefined color) to remove the - * existing background tint color - */ - public void setBackgroundTintColor(@ColorInt int backgroundTintColor) { - this.backgroundTintColor = backgroundTintColor; - myLocationView.setShadowDrawableTint(backgroundTintColor); - } - - /** - * Get the background tint color. - * - * @return the background tint color - */ - public int getBackgroundTintColor() { - return backgroundTintColor; - } - - /** - * Get the background offset. - * - * @return the background offset - */ - public int[] getBackgroundOffset() { - return backgroundOffset; - } - - /** - * Set the MyLocationView padding. - * - * @param left the padding left of MyLocationView - * @param top the padding top of MyLocationView - * @param right the padding right of MyLocationView - * @param bottom the padding bottom of MyLocaionView - */ - public void setPadding(int left, int top, int right, int bottom) { - padding = new int[] {left, top, right, bottom}; - setPadding(padding); - } - - private void setPadding(int[] padding) { - myLocationView.setContentPadding(padding); - projection.invalidateContentPadding(padding); - invalidateFocalPointForTracking(myLocationView); - } - - /** - * Get the MyLocationView padding. - * - * @return an array describing the padding in a LTRB manner - */ - public int[] getPadding() { - return padding; - } - - /** - * Get the alpha value of the accuracy circle of MyLocationView - * - * @return the alpha value - */ - public int getAccuracyAlpha() { - return accuracyAlpha; - } - - /** - * Set the alpha value of the accuracy circle of MyLocationView - * - * @param accuracyAlpha the alpha value to set - */ - public void setAccuracyAlpha(@IntRange(from = 0, to = 255) int accuracyAlpha) { - this.accuracyAlpha = accuracyAlpha; - myLocationView.setAccuracyAlpha(accuracyAlpha); - } - - /** - * Get the accuracy tint color of MyLocationView. - * - * @return the tint color used for accuracy - */ - public int getAccuracyTintColor() { - return accuracyTintColor; - } - - /** - * Set the accuracy tint color of MyLocationView. - * - * @param accuracyTintColor the accuracy tint color - */ - public void setAccuracyTintColor(@ColorInt int accuracyTintColor) { - this.accuracyTintColor = accuracyTintColor; - myLocationView.setAccuracyTint(accuracyTintColor); - } - - /** - * Returns current accuracy threshold value (in meters). - * - * @return Value of accuracy threshold (in meters), below which circle won't be displayed - */ - public float getAccuracyThreshold() { - return accuracyThreshold; - } - - /** - * Set accuracy circle threshold. Circle won't be displayed if accuracy is below set value. - * - * @param accuracyThreshold Value of accuracy (in meters), below which circle won't be displayed - */ - public void setAccuracyThreshold(float accuracyThreshold) { - this.accuracyThreshold = accuracyThreshold; - myLocationView.setAccuracyThreshold(accuracyThreshold); - } - - public void setTilt(double tilt) { - myLocationView.setTilt(tilt); - } - - private void invalidateFocalPointForTracking(MyLocationView myLocationView) { - if (!(myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE)) { - focalPointChangeListener.onFocalPointChanged(myLocationView.getCenter()); - } else { - focalPointChangeListener.onFocalPointChanged(null); - } - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java index 2a32f0bdd6..ea9a066df7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java @@ -10,12 +10,12 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds; * An offline region defined by a style URL, geographic bounding box, zoom range, and * device pixel ratio. * <p> - * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom. + * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom. * <p> - * maxZoom may be ∞, in which case for each tile source, the region will include + * maxZoom may be ∞, in which case for each tile source, the region will include * tiles from minZoom up to the maximum zoom level provided by that source. * <p> - * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0. + * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0. */ public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefinition, Parcelable { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index 1c59bb468e..0895096f6e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -82,7 +82,7 @@ public class MapSnapshotter { * MapSnapshotter options */ public static class Options { - private int pixelRatio = 1; + private float pixelRatio = 1; private int width; private int height; private String styleUrl = Style.MAPBOX_STREETS; @@ -95,6 +95,9 @@ public class MapSnapshotter { * @param height the height of the image */ public Options(int width, int height) { + if (width == 0 || height == 0) { + throw new IllegalArgumentException("Unable to create a snapshot with width or height set to 0"); + } this.width = width; this.height = height; } @@ -122,7 +125,7 @@ public class MapSnapshotter { * @param pixelRatio the pixel ratio to use (default: 1) * @return the mutated {@link Options} */ - public Options withPixelRatio(int pixelRatio) { + public Options withPixelRatio(float pixelRatio) { this.pixelRatio = pixelRatio; return this; } @@ -164,7 +167,7 @@ public class MapSnapshotter { /** * @return the pixel ratio */ - public int getPixelRatio() { + public float getPixelRatio() { return pixelRatio; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/package-info.java new file mode 100644 index 0000000000..f1ce247ba8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Snapshotter API classes. + */ +package com.mapbox.mapboxsdk.snapshotter; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index 0f76f590c2..f336f7330d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -46,10 +46,8 @@ import java.util.List; * Such composite expressions allows a layer's appearance to be determined by * a combination of the zoom level and individual feature properties. * </p> - * - * @param <T> the type of the expression */ -public class Expression<T> { +public class Expression { private final String operator; private final Expression[] arguments; @@ -68,161 +66,19 @@ public class Expression<T> { * @param operator the expression operator * @param arguments expressions input */ - @SafeVarargs public Expression(@NonNull String operator, @Nullable Expression... arguments) { this.operator = operator; this.arguments = arguments; } /** - * Converts the expression to Object array representation. - * <p> - * The output will later be converted to a JSON Object array. - * </p> - * - * @return the converted object array expression - */ - @NonNull - public Object[] toArray() { - List<Object> array = new ArrayList<>(); - array.add(operator); - if (arguments != null) { - for (Expression argument : arguments) { - if (argument instanceof Expression.ExpressionLiteral) { - array.add(toValue((ExpressionLiteral) argument)); - } else { - array.add(argument.toArray()); - } - } - } - return array.toArray(); - } - - /** - * Converts the expression value to an Object. - * - * @param expressionValue the expression value to convert - * @return the converted object expression - */ - private Object toValue(ExpressionLiteral expressionValue) { - Object value = expressionValue.toValue(); - if (value instanceof Expression.Color) { - return ((Expression.Color) value).convertColor(); - } else if (value instanceof Expression.ExpressionLiteral) { - return toValue((ExpressionLiteral) value); - } else if (value instanceof Expression) { - return ((Expression) value).toArray(); - } - return value; - } - - /** - * ExpressionLiteral wraps an object to be used as a literal in an expression. - * <p> - * ExpressionLiteral is created with {@link #literal(Number)}, {@link #literal(boolean)}, - * {@link #literal(String)} and {@link #literal(Object)}. - * </p> - * - * @param <T> - */ - private static class ExpressionLiteral<T> extends Expression<T> { - - protected T object; - - /** - * Create an ExpressionValue wrapper. - * - * @param object the object to be wrapped - */ - ExpressionLiteral(@NonNull T object) { - this.object = object; - } - - /** - * Get the wrapped object. - * - * @return the wrapped object - */ - Object toValue() { - return object; - } - } - - // - // Types - // - - /** - * Expression interpolator type. - * <p> - * Is used for first parameter of {@link #interpolate(Expression, Expression, Stop...)}. - * </p> - */ - public static class Interpolator { - } - - /** - * Expression color type. - */ - public static class Color { - - private int color; - - /** - * Creates a color color type from a color int. - * - * @param color the int color - */ - public Color(@ColorInt int color) { - this.color = color; - } - - /** - * Converts the int color to rgba(d, d, d, d) string representation - * - * @return - */ - public String convertColor() { - return PropertyFactory.colorToRgbaString(color); - } - } - - /** - * Expression array type. - */ - public static class Array { - } - - /** - * Expression stop type. - * <p> - * Can be used for {@link #stop(Object, Object)} as part of varargs parameter in - * {@link #step(Number, Expression, Stop...)} or {@link #interpolate(Expression, Expression, Stop...)}. - * </p> - */ - public static class Stop { - - private Object value; - private Object output; - - public Stop(Object value, Object output) { - this.value = value; - this.output = output; - } - } - - // - // Literals - // - - /** * Create a literal number expression. * * @param number the number * @return the expression */ - public static Expression<Number> literal(@NonNull Number number) { - return new ExpressionLiteral<>(number); + public static Expression literal(@NonNull Number number) { + return new ExpressionLiteral(number); } /** @@ -231,8 +87,8 @@ public class Expression<T> { * @param string the string * @return the expression */ - public static Expression<String> literal(@NonNull String string) { - return new ExpressionLiteral<>(string); + public static Expression literal(@NonNull String string) { + return new ExpressionLiteral(string); } /** @@ -241,32 +97,32 @@ public class Expression<T> { * @param bool the boolean * @return the expression */ - public static Expression<Boolean> literal(boolean bool) { - return new ExpressionLiteral<>(bool); + public static Expression literal(boolean bool) { + return new ExpressionLiteral(bool); } + // + // Types + // + /** * Create a literal object expression. * * @param object the object * @return the expression */ - public static Expression<Object> literal(@NonNull Object object) { - return new ExpressionLiteral<>(object); + public static Expression literal(@NonNull Object object) { + return new ExpressionLiteral(object); } - // - // Color - // - /** * Expression literal utility method to convert a color int to an color expression * * @param color the int color * @return the color expression */ - public static Expression<Color> color(@ColorInt int color) { - return new ExpressionLiteral<>(new Color(color)); + public static Expression color(@ColorInt int color) { + return new ExpressionLiteral(new Color(color)); } /** @@ -282,9 +138,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-rgb">Style specification</a> */ - public static Expression<Color> rgb(@NonNull Expression<Number> red, @NonNull Expression<Number> green, - @NonNull Expression<Number> blue) { - return new Expression<>("rgb", red, green, blue); + public static Expression rgb(@NonNull Expression red, @NonNull Expression green, @NonNull Expression blue) { + return new Expression("rgb", red, green, blue); } /** @@ -300,10 +155,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-rgb">Style specification</a> */ - public static Expression<Color> rgb(@NonNull Number red, @NonNull Number green, @NonNull Number blue) { + public static Expression rgb(@NonNull Number red, @NonNull Number green, @NonNull Number blue) { return rgb(literal(red), literal(green), literal(blue)); } + // + // Literals + // + /** * Creates a color value from red, green, blue components, which must range between 0 and 255, * and an alpha component which must range between 0 and 1. @@ -318,9 +177,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-rgba">Style specification</a> */ - public static Expression<Color> rgba(@NonNull Expression<Number> red, @NonNull Expression<Number> green, - @NonNull Expression<Number> blue, @NonNull Expression<Number> alpha) { - return new Expression<>("rgba", red, green, blue, alpha); + public static Expression rgba(@NonNull Expression red, @NonNull Expression green, + @NonNull Expression blue, @NonNull Expression alpha) { + return new Expression("rgba", red, green, blue, alpha); } /** @@ -337,7 +196,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-rgba">Style specification</a> */ - public static Expression<Color> rgba(@NonNull Number red, @NonNull Number green, @NonNull Number blue, @NonNull Number alpha) { + public static Expression rgba(@NonNull Number red, @NonNull Number green, @NonNull Number blue, @NonNull Number alpha) { return rgba(literal(red), literal(green), literal(blue), literal(alpha)); } @@ -348,14 +207,10 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-to-rgba">Style specification</a> */ - public static Expression<Array> toRgba(@NonNull Expression<Color> expression) { - return new Expression<>("to-rgba", expression); + public static Expression toRgba(@NonNull Expression expression) { + return new Expression("to-rgba", expression); } - // - // Decision - // - /** * Returns true if the input values are equal, false otherwise. * The inputs must be numbers, strings, or booleans, and both of the same type. @@ -365,10 +220,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a> */ - public static Expression<Boolean> eq(@NonNull Expression compareOne, @NonNull Expression compareTwo) { - return new Expression<>("==", compareOne, compareTwo); + public static Expression eq(@NonNull Expression compareOne, @NonNull Expression compareTwo) { + return new Expression("==", compareOne, compareTwo); } + // + // Color + // + /** * Returns true if the input values are equal, false otherwise. * @@ -377,7 +236,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a> */ - public static Expression<Boolean> eq(boolean compareOne, boolean compareTwo) { + public static Expression eq(boolean compareOne, boolean compareTwo) { return eq(literal(compareOne), literal(compareTwo)); } @@ -389,7 +248,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a> */ - public static Expression<Boolean> eq(@NonNull String compareOne, @NonNull String compareTwo) { + public static Expression eq(@NonNull String compareOne, @NonNull String compareTwo) { return eq(literal(compareOne), literal(compareTwo)); } @@ -401,7 +260,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a> */ - public static Expression<Boolean> eq(@NonNull Number compareOne, @NonNull Number compareTwo) { + public static Expression eq(@NonNull Number compareOne, @NonNull Number compareTwo) { return eq(literal(compareOne), literal(compareTwo)); } @@ -414,8 +273,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a> */ - public static Expression<Boolean> neq(@NonNull Expression compareOne, @NonNull Expression compareTwo) { - return new Expression<>("!=", compareOne, compareTwo); + public static Expression neq(@NonNull Expression compareOne, @NonNull Expression compareTwo) { + return new Expression("!=", compareOne, compareTwo); } /** @@ -426,8 +285,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a> */ - public static Expression<Boolean> neq(boolean compareOne, boolean compareTwo) { - return new Expression<>("!=", literal(compareOne), literal(compareTwo)); + public static Expression neq(boolean compareOne, boolean compareTwo) { + return new Expression("!=", literal(compareOne), literal(compareTwo)); } /** @@ -438,10 +297,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a> */ - public static Expression<Boolean> neq(@NonNull String compareOne, @NonNull String compareTwo) { - return new Expression<>("!=", literal(compareOne), literal(compareTwo)); + public static Expression neq(@NonNull String compareOne, @NonNull String compareTwo) { + return new Expression("!=", literal(compareOne), literal(compareTwo)); } + // + // Decision + // + /** * Returns `true` if the input values are not equal, `false` otherwise. * @@ -450,8 +313,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a> */ - public static Expression<Boolean> neq(@NonNull Number compareOne, @NonNull Number compareTwo) { - return new Expression<>("!=", literal(compareOne), literal(compareTwo)); + public static Expression neq(@NonNull Number compareOne, @NonNull Number compareTwo) { + return new Expression("!=", literal(compareOne), literal(compareTwo)); } /** @@ -463,8 +326,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions->">Style specification</a> */ - public static Expression<Boolean> gt(@NonNull Expression compareOne, @NonNull Expression compareTwo) { - return new Expression<>(">", compareOne, compareTwo); + public static Expression gt(@NonNull Expression compareOne, @NonNull Expression compareTwo) { + return new Expression(">", compareOne, compareTwo); } /** @@ -475,8 +338,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions->">Style specification</a> */ - public static Expression<Boolean> gt(@NonNull Number compareOne, @NonNull Number compareTwo) { - return new Expression<>(">", literal(compareOne), literal(compareTwo)); + public static Expression gt(@NonNull Number compareOne, @NonNull Number compareTwo) { + return new Expression(">", literal(compareOne), literal(compareTwo)); } /** @@ -487,8 +350,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions->">Style specification</a> */ - public static Expression<Boolean> gt(@NonNull String compareOne, @NonNull String compareTwo) { - return new Expression<>(">", literal(compareOne), literal(compareTwo)); + public static Expression gt(@NonNull String compareOne, @NonNull String compareTwo) { + return new Expression(">", literal(compareOne), literal(compareTwo)); } /** @@ -500,8 +363,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-<">Style specification</a> */ - public static Expression<Boolean> lt(@NonNull Expression compareOne, @NonNull Expression compareTwo) { - return new Expression<>("<", compareOne, compareTwo); + public static Expression lt(@NonNull Expression compareOne, @NonNull Expression compareTwo) { + return new Expression("<", compareOne, compareTwo); } /** @@ -512,8 +375,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-<">Style specification</a> */ - public static Expression<Boolean> lt(@NonNull Number compareOne, @NonNull Number compareTwo) { - return new Expression<>("<", literal(compareOne), literal(compareTwo)); + public static Expression lt(@NonNull Number compareOne, @NonNull Number compareTwo) { + return new Expression("<", literal(compareOne), literal(compareTwo)); } /** @@ -524,8 +387,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-<">Style specification</a> */ - public static Expression<Boolean> lt(@NonNull String compareOne, @NonNull String compareTwo) { - return new Expression<>("<", literal(compareOne), literal(compareTwo)); + public static Expression lt(@NonNull String compareOne, @NonNull String compareTwo) { + return new Expression("<", literal(compareOne), literal(compareTwo)); } /** @@ -537,8 +400,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions->=">Style specification</a> */ - public static Expression<Boolean> gte(@NonNull Expression compareOne, @NonNull Expression compareTwo) { - return new Expression<>(">=", compareOne, compareTwo); + public static Expression gte(@NonNull Expression compareOne, @NonNull Expression compareTwo) { + return new Expression(">=", compareOne, compareTwo); } /** @@ -549,8 +412,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions->=">Style specification</a> */ - public static Expression<Boolean> gte(@NonNull Number compareOne, @NonNull Number compareTwo) { - return new Expression<>(">=", literal(compareOne), literal(compareTwo)); + public static Expression gte(@NonNull Number compareOne, @NonNull Number compareTwo) { + return new Expression(">=", literal(compareOne), literal(compareTwo)); } /** @@ -561,8 +424,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions->=">Style specification</a> */ - public static Expression<Boolean> gte(@NonNull String compareOne, @NonNull String compareTwo) { - return new Expression<>(">=", literal(compareOne), literal(compareTwo)); + public static Expression gte(@NonNull String compareOne, @NonNull String compareTwo) { + return new Expression(">=", literal(compareOne), literal(compareTwo)); } /** @@ -574,8 +437,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-<=">Style specification</a> */ - public static Expression<Boolean> lte(@NonNull Expression compareOne, @NonNull Expression compareTwo) { - return new Expression<>("<=", compareOne, compareTwo); + public static Expression lte(@NonNull Expression compareOne, @NonNull Expression compareTwo) { + return new Expression("<=", compareOne, compareTwo); } /** @@ -586,8 +449,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-<=">Style specification</a> */ - public static Expression<Boolean> lte(@NonNull Number compareOne, @NonNull Number compareTwo) { - return new Expression<>("<=", literal(compareOne), literal(compareTwo)); + public static Expression lte(@NonNull Number compareOne, @NonNull Number compareTwo) { + return new Expression("<=", literal(compareOne), literal(compareTwo)); } /** @@ -598,8 +461,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-<=">Style specification</a> */ - public static Expression<Boolean> lte(@NonNull String compareOne, @NonNull String compareTwo) { - return new Expression<>("<=", literal(compareOne), literal(compareTwo)); + public static Expression lte(@NonNull String compareOne, @NonNull String compareTwo) { + return new Expression("<=", literal(compareOne), literal(compareTwo)); } /** @@ -614,9 +477,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-all">Style specification</a> */ - @SafeVarargs - public static Expression<Boolean> all(@NonNull Expression<Boolean>... input) { - return new Expression<>("all", input); + + public static Expression all(@NonNull Expression... input) { + return new Expression("all", input); } /** @@ -631,9 +494,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-any">Style specification</a> */ - @SafeVarargs - public static Expression<Boolean> any(@NonNull Expression<Boolean>... input) { - return new Expression<>("any", input); + + public static Expression any(@NonNull Expression... input) { + return new Expression("any", input); } /** @@ -643,8 +506,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!">Style specification</a> */ - public static Expression<Boolean> not(@NonNull Expression<Boolean> input) { - return new Expression<>("!", input); + public static Expression not(@NonNull Expression input) { + return new Expression("!", input); } /** @@ -654,7 +517,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!">Style specification</a> */ - public static Expression<Boolean> not(boolean input) { + public static Expression not(boolean input) { return not(literal(input)); } @@ -669,7 +532,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-case">Style specification</a> */ - @SafeVarargs + public static Expression switchCase(@NonNull @Size(min = 1) Expression... input) { return new Expression("case", input); } @@ -716,10 +579,6 @@ public class Expression<T> { return new Expression("coalesce", input); } - // - // FeatureData - // - /** * Gets the feature properties object. * <p> @@ -729,8 +588,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-properties">Style specification</a> */ - public static Expression<Object> properties() { - return new Expression<>("properties"); + public static Expression properties() { + return new Expression("properties"); } /** @@ -739,8 +598,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-geometry-types">Style specification</a> */ - public static Expression<String> geometryType() { - return new Expression<>("geometry-type"); + public static Expression geometryType() { + return new Expression("geometry-type"); } /** @@ -749,14 +608,10 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-id">Style specification</a> */ - public static Expression<Number> id() { - return new Expression<>("id"); + public static Expression id() { + return new Expression("id"); } - // - // Heatmap - // - /** * Gets the kernel density estimation of a pixel in a heatmap layer, * which is a relative measure of how many data points are crowded around a particular pixel. @@ -765,14 +620,10 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-heatmap-density">Style specification</a> */ - public static Expression<Number> heatmapDensity() { - return new Expression<>("heatmap-density"); + public static Expression heatmapDensity() { + return new Expression("heatmap-density"); } - // - // Lookup - // - /** * Retrieves an item from an array. * @@ -781,8 +632,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-at">Style specification</a> */ - public static Expression<Object> at(@NonNull Expression<Number> number, @NonNull Expression expression) { - return new Expression<>("at", number, expression); + public static Expression at(@NonNull Expression number, @NonNull Expression expression) { + return new Expression("at", number, expression); } /** @@ -793,7 +644,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-at">Style specification</a> */ - public static Expression<Object> at(@NonNull Number number, @NonNull Expression expression) { + public static Expression at(@NonNull Number number, @NonNull Expression expression) { return at(literal(number), expression); } @@ -806,10 +657,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-get">Style specification</a> */ - public static Expression get(@NonNull Expression<String> input) { - return new Expression<>("get", input); + public static Expression get(@NonNull Expression input) { + return new Expression("get", input); } + // + // FeatureData + // + /** * Retrieves a property value from the current feature's properties, * or from another object if a second argument is provided. @@ -832,8 +687,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-get">Style specification</a> */ - public static Expression<Object> get(@NonNull Expression<String> key, @NonNull Expression<Object> object) { - return new Expression<>("get", key, object); + public static Expression get(@NonNull Expression key, @NonNull Expression object) { + return new Expression("get", key, object); } /** @@ -845,10 +700,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-get">Style specification</a> */ - public static Expression<Object> get(@NonNull String key, @NonNull Expression<Object> object) { + public static Expression get(@NonNull String key, @NonNull Expression object) { return get(literal(key), object); } + // + // Heatmap + // + /** * Tests for the presence of an property value in the current feature's properties. * @@ -856,10 +715,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-has">Style specification</a> */ - public static Expression<Boolean> has(@NonNull Expression<String> key) { - return new Expression<>("has", key); + public static Expression has(@NonNull Expression key) { + return new Expression("has", key); } + // + // Lookup + // + /** * Tests for the presence of an property value in the current feature's properties. * @@ -867,7 +730,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-has">Style specification</a> */ - public static Expression<Boolean> has(@NonNull String key) { + public static Expression has(@NonNull String key) { return has(literal(key)); } @@ -879,8 +742,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-has">Style specification</a> */ - public static Expression<Boolean> has(@NonNull Expression<String> key, @NonNull Expression<Object> object) { - return new Expression<>("has", key, object); + public static Expression has(@NonNull Expression key, @NonNull Expression object) { + return new Expression("has", key, object); } /** @@ -891,7 +754,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-has">Style specification</a> */ - public static Expression<Boolean> has(@NonNull String key, @NonNull Expression<Object> object) { + public static Expression has(@NonNull String key, @NonNull Expression object) { return has(literal(key), object); } @@ -902,8 +765,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-lenght">Style specification</a> */ - public static Expression<Number> length(@NonNull Expression<?> expression) { - return new Expression<>("length", expression); + public static Expression length(@NonNull Expression expression) { + return new Expression("length", expression); } /** @@ -913,22 +776,18 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-lenght">Style specification</a> */ - public static Expression<Number> length(@NonNull String input) { + public static Expression length(@NonNull String input) { return length(literal(input)); } - // - // Math - // - /** * Returns mathematical constant ln(2). * * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-ln2">Style specification</a> */ - public static Expression<Number> ln2() { - return new Expression<>("ln2"); + public static Expression ln2() { + return new Expression("ln2"); } /** @@ -937,8 +796,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-pi">Style specification</a> */ - public static Expression<Number> pi() { - return new Expression<>("pi"); + public static Expression pi() { + return new Expression("pi"); } /** @@ -947,8 +806,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-e">Style specification</a> */ - public static Expression<Number> e() { - return new Expression<>("e"); + public static Expression e() { + return new Expression("e"); } /** @@ -958,9 +817,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-+">Style specification</a> */ - @SafeVarargs - public static Expression<Number> sum(@Size(min = 2) Expression<Number>... numbers) { - return new Expression<>("+", numbers); + + public static Expression sum(@Size(min = 2) Expression... numbers) { + return new Expression("+", numbers); } /** @@ -970,9 +829,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-+">Style specification</a> */ - @SuppressWarnings("unchecked") - public static Expression<Number> sum(@Size(min = 2) Number... numbers) { - Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length]; + + public static Expression sum(@Size(min = 2) Number... numbers) { + Expression[] numberExpression = new Expression[numbers.length]; for (int i = 0; i < numbers.length; i++) { numberExpression[i] = literal(numbers[i]); } @@ -986,9 +845,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-*">Style specification</a> */ - @SafeVarargs - public static Expression<Number> product(@Size(min = 2) Expression<Number>... numbers) { - return new Expression<>("*", numbers); + + public static Expression product(@Size(min = 2) Expression... numbers) { + return new Expression("*", numbers); } /** @@ -998,15 +857,19 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-*">Style specification</a> */ - @SuppressWarnings("unchecked") - public static Expression<Number> product(@Size(min = 2) Number... numbers) { - Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length]; + + public static Expression product(@Size(min = 2) Number... numbers) { + Expression[] numberExpression = new Expression[numbers.length]; for (int i = 0; i < numbers.length; i++) { numberExpression[i] = literal(numbers[i]); } return product(numberExpression); } + // + // Math + // + /** * Returns the result of subtracting a number from 0. * @@ -1014,8 +877,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions--">Style specification</a> */ - public static Expression<Number> subtract(@NonNull Expression<Number> number) { - return new Expression<>("-", number); + public static Expression subtract(@NonNull Expression number) { + return new Expression("-", number); } /** @@ -1025,7 +888,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions--">Style specification</a> */ - public static Expression<Number> subtract(@NonNull Number number) { + public static Expression subtract(@NonNull Number number) { return subtract(literal(number)); } @@ -1037,8 +900,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions--">Style specification</a> */ - public static Expression<Number> subtract(@NonNull Expression<Number> first, @NonNull Expression<Number> second) { - return new Expression<>("-", first, second); + public static Expression subtract(@NonNull Expression first, @NonNull Expression second) { + return new Expression("-", first, second); } /** @@ -1049,7 +912,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions--">Style specification</a> */ - public static Expression<Number> subtract(@NonNull Number first, @NonNull Number second) { + public static Expression subtract(@NonNull Number first, @NonNull Number second) { return subtract(literal(first), literal(second)); } @@ -1061,9 +924,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-/">Style specification</a> */ - @SuppressWarnings("unchecked") - public static Expression<Number> division(@NonNull Expression<Number> first, @NonNull Expression<Number> second) { - return new Expression<>("/", first, second); + public static Expression division(@NonNull Expression first, @NonNull Expression second) { + return new Expression("/", first, second); } /** @@ -1074,8 +936,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-/">Style specification</a> */ - @SuppressWarnings("unchecked") - public static Expression<Number> division(@NonNull Number first, @NonNull Number second) { + public static Expression division(@NonNull Number first, @NonNull Number second) { return division(literal(first), literal(second)); } @@ -1087,8 +948,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%">Style specification</a> */ - public static Expression<Number> mod(@NonNull Expression<Number> first, @NonNull Expression<Number> second) { - return new Expression<>("%", first, second); + public static Expression mod(@NonNull Expression first, @NonNull Expression second) { + return new Expression("%", first, second); } /** @@ -1099,7 +960,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%">Style specification</a> */ - public static Expression<Number> mod(@NonNull Number first, @NonNull Number second) { + public static Expression mod(@NonNull Number first, @NonNull Number second) { return mod(literal(first), literal(second)); } @@ -1111,8 +972,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-^">Style specification</a> */ - public static Expression<Number> pow(@NonNull Expression<Number> first, @NonNull Expression<Number> second) { - return new Expression<>("^", first, second); + public static Expression pow(@NonNull Expression first, @NonNull Expression second) { + return new Expression("^", first, second); } /** @@ -1123,7 +984,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-^">Style specification</a> */ - public static Expression<Number> pow(@NonNull Number first, @NonNull Number second) { + public static Expression pow(@NonNull Number first, @NonNull Number second) { return pow(literal(first), literal(second)); } @@ -1134,8 +995,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-sqrt">Style specification</a> */ - public static Expression<Number> sqrt(@NonNull Expression<Number> number) { - return new Expression<>("sqrt", number); + public static Expression sqrt(@NonNull Expression number) { + return new Expression("sqrt", number); } /** @@ -1145,7 +1006,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-sqrt">Style specification</a> */ - public static Expression<Number> sqrt(@NonNull Number number) { + public static Expression sqrt(@NonNull Number number) { return sqrt(literal(number)); } @@ -1156,8 +1017,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-log10">Style specification</a> */ - public static Expression<Number> log10(@NonNull Expression<Number> number) { - return new Expression<>("log10", number); + public static Expression log10(@NonNull Expression number) { + return new Expression("log10", number); } /** @@ -1167,7 +1028,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-log10">Style specification</a> */ - public static Expression<Number> log10(@NonNull Number number) { + public static Expression log10(@NonNull Number number) { return log10(literal(number)); } @@ -1178,8 +1039,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-ln">Style specification</a> */ - public static Expression<Number> ln(Expression<Number> number) { - return new Expression<>("ln", number); + public static Expression ln(Expression number) { + return new Expression("ln", number); } /** @@ -1189,7 +1050,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-ln">Style specification</a> */ - public static Expression<Number> ln(Number number) { + public static Expression ln(Number number) { return ln(literal(number)); } @@ -1200,8 +1061,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-log2">Style specification</a> */ - public static Expression<Number> log2(@NonNull Expression<Number> number) { - return new Expression<>("log2", number); + public static Expression log2(@NonNull Expression number) { + return new Expression("log2", number); } /** @@ -1211,7 +1072,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-log2">Style specification</a> */ - public static Expression<Number> log2(@NonNull Number number) { + public static Expression log2(@NonNull Number number) { return log2(literal(number)); } @@ -1222,8 +1083,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-sin">Style specification</a> */ - public static Expression<Number> sin(@NonNull Expression<Number> number) { - return new Expression<>("sin", number); + public static Expression sin(@NonNull Expression number) { + return new Expression("sin", number); } /** @@ -1233,7 +1094,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-sin">Style specification</a> */ - public static Expression<Number> sin(@NonNull Number number) { + public static Expression sin(@NonNull Number number) { return sin(literal(number)); } @@ -1244,8 +1105,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-cos">Style specification</a> */ - public static Expression<Number> cos(@NonNull Expression<Number> number) { - return new Expression<>("cos", number); + public static Expression cos(@NonNull Expression number) { + return new Expression("cos", number); } /** @@ -1255,8 +1116,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-cos">Style specification</a> */ - public static Expression<Number> cos(@NonNull Number number) { - return new Expression<>("cos", literal(number)); + public static Expression cos(@NonNull Number number) { + return new Expression("cos", literal(number)); } /** @@ -1266,8 +1127,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-tan">Style specification</a> */ - public static Expression<Number> tan(@NonNull Expression<Number> number) { - return new Expression<>("tan", number); + public static Expression tan(@NonNull Expression number) { + return new Expression("tan", number); } /** @@ -1277,8 +1138,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-tan">Style specification</a> */ - public static Expression<Number> tan(@NonNull Number number) { - return new Expression<>("tan", literal(number)); + public static Expression tan(@NonNull Number number) { + return new Expression("tan", literal(number)); } /** @@ -1288,8 +1149,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-asin">Style specification</a> */ - public static Expression<Number> asin(@NonNull Expression<Number> number) { - return new Expression<>("asin", number); + public static Expression asin(@NonNull Expression number) { + return new Expression("asin", number); } /** @@ -1299,7 +1160,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-asin">Style specification</a> */ - public static Expression<Number> asin(@NonNull Number number) { + public static Expression asin(@NonNull Number number) { return asin(literal(number)); } @@ -1310,8 +1171,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-acos">Style specification</a> */ - public static Expression<Number> acos(@NonNull Expression<Number> number) { - return new Expression<>("acos", number); + public static Expression acos(@NonNull Expression number) { + return new Expression("acos", number); } /** @@ -1321,7 +1182,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-acos">Style specification</a> */ - public static Expression<Number> acos(@NonNull Number number) { + public static Expression acos(@NonNull Number number) { return acos(literal(number)); } @@ -1332,7 +1193,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-atan">Style specification</a> */ - public static Expression<Number> atan(@NonNull Expression<Number> number) { + public static Expression atan(@NonNull Expression number) { return new Expression("atan", number); } @@ -1343,7 +1204,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-atan">Style specification</a> */ - public static Expression<Number> atan(@NonNull Number number) { + public static Expression atan(@NonNull Number number) { return atan(literal(number)); } @@ -1354,9 +1215,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-min">Style specification</a> */ - @SafeVarargs - public static Expression<Number> min(@Size(min = 1) Expression<Number>... numbers) { - return new Expression<>("min", numbers); + + public static Expression min(@Size(min = 1) Expression... numbers) { + return new Expression("min", numbers); } /** @@ -1366,9 +1227,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-min">Style specification</a> */ - @SuppressWarnings("unchecked") - public static Expression<Number> min(@Size(min = 1) Number... numbers) { - Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length]; + + public static Expression min(@Size(min = 1) Number... numbers) { + Expression[] numberExpression = new Expression[numbers.length]; for (int i = 0; i < numbers.length; i++) { numberExpression[i] = literal(numbers[i]); } @@ -1382,9 +1243,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-max">Style specification</a> */ - @SafeVarargs - public static Expression<Number> max(@Size(min = 1) Expression<Number>... numbers) { - return new Expression<>("max", numbers); + + public static Expression max(@Size(min = 1) Expression... numbers) { + return new Expression("max", numbers); } /** @@ -1394,19 +1255,15 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-max">Style specification</a> */ - @SuppressWarnings("unchecked") - public static Expression<Number> max(@Size(min = 1) Number... numbers) { - Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length]; + + public static Expression max(@Size(min = 1) Number... numbers) { + Expression[] numberExpression = new Expression[numbers.length]; for (int i = 0; i < numbers.length; i++) { numberExpression[i] = literal(numbers[i]); } return max(numberExpression); } - // - // String - // - /** * Returns the input string converted to uppercase. * <p> @@ -1418,8 +1275,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-upcase">Style specification</a> */ - public static Expression<String> upcase(@NonNull Expression<String> string) { - return new Expression<>("upcase", string); + public static Expression upcase(@NonNull Expression string) { + return new Expression("upcase", string); } /** @@ -1433,7 +1290,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-upcase">Style specification</a> */ - public static Expression<String> upcase(@NonNull String string) { + public static Expression upcase(@NonNull String string) { return upcase(literal(string)); } @@ -1448,8 +1305,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-downcase">Style specification</a> */ - public static Expression<String> downcase(@NonNull Expression<String> input) { - return new Expression<>("downcase", input); + public static Expression downcase(@NonNull Expression input) { + return new Expression("downcase", input); } /** @@ -1463,7 +1320,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-downcase">Style specification</a> */ - public static Expression<String> downcase(@NonNull String input) { + public static Expression downcase(@NonNull String input) { return downcase(literal(input)); } @@ -1474,9 +1331,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-concat">Style specification</a> */ - @SafeVarargs - public static Expression<String> concat(@NonNull Expression<String>... input) { - return new Expression<>("concat", input); + + public static Expression concat(@NonNull Expression... input) { + return new Expression("concat", input); } /** @@ -1486,19 +1343,15 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-concat">Style specification</a> */ - @SuppressWarnings("unchecked") - public static Expression<String> concat(@NonNull String... input) { - Expression<String>[] stringExpression = (Expression<String>[]) new Expression<?>[input.length]; + + public static Expression concat(@NonNull String... input) { + Expression[] stringExpression = new Expression[input.length]; for (int i = 0; i < input.length; i++) { stringExpression[i] = literal(input[i]); } return concat(stringExpression); } - // - // Types - // - /** * Asserts that the input is an array (optionally with a specific item type and length). * If, when the input expression is evaluated, it is not of the asserted type, @@ -1508,10 +1361,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-array">Style specification</a> */ - public static Expression<Boolean> array(@NonNull Expression input) { - return new Expression<>("array", input); + public static Expression array(@NonNull Expression input) { + return new Expression("array", input); } + // + // String + // + /** * Returns a string describing the type of the given value. * @@ -1519,8 +1376,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-typeof">Style specification</a> */ - public static Expression<String> typeOf(@NonNull Expression input) { - return new Expression<>("typeof", input); + public static Expression typeOf(@NonNull Expression input) { + return new Expression("typeof", input); } /** @@ -1532,8 +1389,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-string">Style specification</a> */ - public static Expression<Boolean> string(@NonNull Expression input) { - return new Expression<>("string", input); + public static Expression string(@NonNull Expression input) { + return new Expression("string", input); } /** @@ -1545,8 +1402,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-number">Style specification</a> */ - public static Expression<Boolean> number(@NonNull Expression input) { - return new Expression<>("number", input); + public static Expression number(@NonNull Expression input) { + return new Expression("number", input); } /** @@ -1558,8 +1415,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-boolean">Style specification</a> */ - public static Expression<Boolean> bool(@NonNull Expression input) { - return new Expression<>("boolean", input); + public static Expression bool(@NonNull Expression input) { + return new Expression("boolean", input); } /** @@ -1569,8 +1426,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-object">Style specification</a> */ - public static Expression<Boolean> object(@NonNull Expression input) { - return new Expression<>("object", input); + public static Expression object(@NonNull Expression input) { + return new Expression("object", input); } /** @@ -1587,10 +1444,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-to-string">Style specification</a> */ - public static Expression<String> toString(@NonNull Expression input) { - return new Expression<>("to-string", input); + public static Expression toString(@NonNull Expression input) { + return new Expression("to-string", input); } + // + // Types + // + /** * Converts the input value to a number, if possible. * If the input is null or false, the result is 0. @@ -1603,8 +1464,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-to-number">Style specification</a> */ - public static Expression<Number> toNumber(@NonNull Expression input) { - return new Expression<>("to-number", input); + public static Expression toNumber(@NonNull Expression input) { + return new Expression("to-number", input); } /** @@ -1615,8 +1476,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-to-boolean">Style specification</a> */ - public static Expression<Boolean> toBool(@NonNull Expression input) { - return new Expression<>("to-boolean", input); + public static Expression toBool(@NonNull Expression input) { + return new Expression("to-boolean", input); } /** @@ -1628,14 +1489,10 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-to-color">Style specification</a> */ - public static Expression<Color> toColor(@NonNull Expression input) { - return new Expression<>("to-color", input); + public static Expression toColor(@NonNull Expression input) { + return new Expression("to-color", input); } - // - // Variable binding - // - /** * Binds input to named variables, * which can then be referenced in the result expression using {@link #var(String)} or {@link #var(Expression)}. @@ -1644,9 +1501,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-let">Style specification</a> */ - @SafeVarargs + public static Expression let(@Size(min = 1) Expression... input) { - return new Expression<>("let", input); + return new Expression("let", input); } /** @@ -1656,8 +1513,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-var">Style specification</a> */ - public static Expression<Object> var(@NonNull Expression<String> expression) { - return new Expression<>("var", expression); + public static Expression var(@NonNull Expression expression) { + return new Expression("var", expression); } /** @@ -1671,10 +1528,6 @@ public class Expression<T> { return var(literal(variableName)); } - // - // Zoom - // - /** * Gets the current zoom level. * <p> @@ -1685,18 +1538,14 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-zoom">Style specification</a> */ - public static Expression<Number> zoom() { - return new Expression<>("zoom"); + public static Expression zoom() { + return new Expression("zoom"); } - // - // Ramps, scales, curves - // - /** * Produces a stop value to be used as part of the step expression. * - * @param stop the stop input + * @param stop the stop input * @param value the stop output * @return the stop */ @@ -1716,7 +1565,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-step">Style specification</a> */ - @SafeVarargs + public static Expression step(@NonNull Number input, @NonNull Expression expression, Expression... stops) { return step(literal(input), expression, stops); } @@ -1733,11 +1582,15 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-step">Style specification</a> */ - @SafeVarargs - public static Expression step(@NonNull Expression<Number> input, @NonNull Expression expression, Expression... stops) { + + public static Expression step(@NonNull Expression input, @NonNull Expression expression, Expression... stops) { return new Expression("step", join(new Expression[] {input, expression}, stops)); } + // + // Variable binding + // + /** * Produces discrete, stepped results by evaluating a piecewise-constant function defined by pairs of * input and output values (\"stops\"). The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`). @@ -1750,7 +1603,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-step">Style specification</a> */ - @SafeVarargs + public static Expression step(@NonNull Number input, @NonNull Expression expression, Stop... stops) { Expression[] expressions = new Expression[stops.length * 2]; for (int i = 0; i < stops.length; i++) { @@ -1772,8 +1625,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-step">Style specification</a> */ - @SafeVarargs - public static Expression step(@NonNull Expression<Number> input, @NonNull Expression expression, Stop... stops) { + + public static Expression step(@NonNull Expression input, @NonNull Expression expression, Stop... stops) { Expression[] expressions = new Expression[stops.length * 2]; for (int i = 0; i < stops.length; i++) { expressions[i * 2] = literal(stops[i].value); @@ -1794,12 +1647,16 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> */ - @SafeVarargs - public static Expression interpolate(@NonNull Expression<Interpolator> interpolation, - @NonNull Expression<Number> number, Expression... stops) { + + public static Expression interpolate(@NonNull Interpolator interpolation, + @NonNull Expression number, Expression... stops) { return new Expression("interpolate", join(new Expression[] {interpolation, number}, stops)); } + // + // Zoom + // + /** * Produces continuous, smooth results by interpolating between pairs of input and output values (\"stops\"). * The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`). @@ -1812,9 +1669,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> */ - @SafeVarargs - public static Expression interpolate(@NonNull Expression<Interpolator> interpolation, - @NonNull Expression<Number> number, Stop... stops) { + + public static Expression interpolate(@NonNull Interpolator interpolation, + @NonNull Expression number, Stop... stops) { Expression[] expressions = new Expression[stops.length * 2]; for (int i = 0; i < stops.length; i++) { expressions[i * 2] = literal(stops[i].value); @@ -1823,14 +1680,18 @@ public class Expression<T> { return interpolate(interpolation, number, expressions); } + // + // Ramps, scales, curves + // + /** * interpolates linearly between the pair of stops just less than and just greater than the input. * * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> */ - public static Expression<Interpolator> linear() { - return new Expression<>("linear"); + public static Interpolator linear() { + return new Interpolator("linear"); } /** @@ -1843,7 +1704,7 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> */ - public static Expression<Interpolator> exponential(@NonNull Number base) { + public static Interpolator exponential(@NonNull Number base) { return exponential(literal(base)); } @@ -1857,8 +1718,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> */ - public static Expression<Interpolator> exponential(@NonNull Expression<Number> expression) { - return new Expression<>("exponential", expression); + public static Interpolator exponential(@NonNull Expression expression) { + return new Interpolator("exponential", expression); } /** @@ -1871,9 +1732,9 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> */ - public static Expression<Interpolator> cubicBezier(@NonNull Expression<Number> x1, @NonNull Expression<Number> y1, - @NonNull Expression<Number> x2, @NonNull Expression<Number> y2) { - return new Expression<>("cubic-bezier", x1, y1, x2, y2); + public static Interpolator cubicBezier(@NonNull Expression x1, @NonNull Expression y1, + @NonNull Expression x2, @NonNull Expression y2) { + return new Interpolator("cubic-bezier", x1, y1, x2, y2); } /** @@ -1886,8 +1747,8 @@ public class Expression<T> { * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> */ - public static Expression<Interpolator> cubicBezier(@NonNull Number x1, @NonNull Number y1, - @NonNull Number x2, @NonNull Number y2) { + public static Interpolator cubicBezier(@NonNull Number x1, @NonNull Number y1, + @NonNull Number x2, @NonNull Number y2) { return cubicBezier(literal(x1), literal(y1), literal(x2), literal(y2)); } @@ -1908,6 +1769,47 @@ public class Expression<T> { return output; } + /** + * Converts the expression to Object array representation. + * <p> + * The output will later be converted to a JSON Object array. + * </p> + * + * @return the converted object array expression + */ + @NonNull + public Object[] toArray() { + List<Object> array = new ArrayList<>(); + array.add(operator); + if (arguments != null) { + for (Expression argument : arguments) { + if (argument instanceof Expression.ExpressionLiteral) { + array.add(toValue((ExpressionLiteral) argument)); + } else { + array.add(argument.toArray()); + } + } + } + return array.toArray(); + } + + /** + * Converts the expression value to an Object. + * + * @param expressionValue the expression value to convert + * @return the converted object expression + */ + private Object toValue(ExpressionLiteral expressionValue) { + Object value = expressionValue.toValue(); + if (value instanceof Expression.Color) { + return ((Expression.Color) value).convertColor(); + } else if (value instanceof Expression.ExpressionLiteral) { + return toValue((ExpressionLiteral) value); + } else if (value instanceof Expression) { + return ((Expression) value).toArray(); + } + return value; + } /** * Returns a string representation of the object that matches the definition set in the style specification. @@ -1919,7 +1821,7 @@ public class Expression<T> { StringBuilder builder = new StringBuilder(); builder.append("[\"").append(operator).append("\""); if (arguments != null) { - for (Expression argument : arguments) { + for (Object argument : arguments) { builder.append(", "); if (argument instanceof ExpressionLiteral) { builder.append(((ExpressionLiteral) argument).toValue()); @@ -1931,4 +1833,97 @@ public class Expression<T> { builder.append("]"); return builder.toString(); } + + /** + * ExpressionLiteral wraps an object to be used as a literal in an expression. + * <p> + * ExpressionLiteral is created with {@link #literal(Number)}, {@link #literal(boolean)}, + * {@link #literal(String)} and {@link #literal(Object)}. + * </p> + */ + private static class ExpressionLiteral extends Expression { + + protected Object literal; + + /** + * Create an ExpressionValue wrapper. + * + * @param object the object to be wrapped + */ + ExpressionLiteral(@NonNull Object object) { + this.literal = object; + } + + /** + * Get the wrapped object. + * + * @return the wrapped object + */ + Object toValue() { + return literal; + } + } + + /** + * Expression interpolator type. + * <p> + * Is used for first parameter of {@link #interpolate(Interpolator, Expression, Stop...)}. + * </p> + */ + public static class Interpolator extends Expression { + + Interpolator(@NonNull String operator, @Nullable Expression... arguments) { + super(operator, arguments); + } + } + + /** + * Expression color type. + */ + public static class Color { + + private int color; + + /** + * Creates a color color type from a color int. + * + * @param color the int color + */ + public Color(@ColorInt int color) { + this.color = color; + } + + /** + * Converts the int color to rgba(d, d, d, d) string representation + * + * @return + */ + public String convertColor() { + return PropertyFactory.colorToRgbaString(color); + } + } + + /** + * Expression array type. + */ + public static class Array { + } + + /** + * Expression stop type. + * <p> + * Can be used for {@link #stop(Object, Object)} as part of varargs parameter in + * {@link #step(Number, Expression, Stop...)} or {@link #interpolate(Interpolator, Expression, Stop...)}. + * </p> + */ + public static class Stop { + + private Object value; + private Object output; + + public Stop(Object value, Object output) { + this.value = value; + this.output = output; + } + } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/package-info.java new file mode 100644 index 0000000000..ee2b96fa61 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Expression API classes. + */ +package com.mapbox.mapboxsdk.style.expressions; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java index bb87fe8a39..74c68cf574 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java @@ -11,7 +11,7 @@ import com.mapbox.mapboxsdk.style.functions.stops.Stops; /** * Camera function. Functions that take camera properties as input (zoom for now) * <p> - * Zoom functions allow the appearance of a map feature to change with map’s zoom level. + * Zoom functions allow the appearance of a map feature to change with map's zoom level. * Zoom functions can be used to create the illusion of depth and control data density. * Each stop is an array with two elements: the first is a zoom level and the second is * a function output value. diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java index e7bb52ebb3..80ff4198fc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java @@ -32,7 +32,7 @@ public class Function<I, O> { /** * Create an exponential {@link CameraFunction} * <p> - * Zoom functions allow the appearance of a map feature to change with map’s zoom. + * Zoom functions allow the appearance of a map feature to change with map's zoom. * Zoom functions can be used to create the illusion of depth and control data density. * Each stop is an array with two elements, the first is a zoom and the second is a function output value. * @@ -53,7 +53,7 @@ public class Function<I, O> { /** * Create an interval {@link CameraFunction} * <p> - * Zoom functions allow the appearance of a map feature to change with map’s zoom. + * Zoom functions allow the appearance of a map feature to change with map’s zoom. * Zoom functions can be used to create the illusion of depth and control data density. * Each stop is an array with two elements, the first is a zoom and the second is a function output value. * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java index 6b8fd65def..bfc663449f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java @@ -168,6 +168,32 @@ public class HeatmapLayer extends Layer { } /** + * Get the HeatmapColor property + * + * @return property wrapper value around String + */ + @SuppressWarnings("unchecked") + public PropertyValue<String> getHeatmapColor() { + return (PropertyValue<String>) new PropertyValue("heatmap-color", nativeGetHeatmapColor()); + } + + /** + * Defines the color of each pixel based on its density value in a heatmap. Should be an expression that uses `["heatmap-density"]` as input. + * + * @return int representation of a rgba string color + * @throws RuntimeException thrown if property isn't a value + */ + @ColorInt + public int getHeatmapColorAsInt() { + PropertyValue<String> value = getHeatmapColor(); + if (value.isValue()) { + return rgbaToColor(value.getValue()); + } else { + throw new RuntimeException("heatmap-color was set as a Function"); + } + } + + /** * Get the HeatmapOpacity property * * @return property wrapper value around Float @@ -209,6 +235,8 @@ public class HeatmapLayer extends Layer { private native void nativeSetHeatmapIntensityTransition(long duration, long delay); + private native Object nativeGetHeatmapColor(); + private native Object nativeGetHeatmapOpacity(); private native TransitionOptions nativeGetHeatmapOpacityTransition(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index 18ee05e63b..43f5be98cb 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -1615,6 +1615,36 @@ public class PropertyFactory { } /** + * Defines the color of each pixel based on its density value in a heatmap. Should be an expression that uses `["heatmap-density"]` as input. + * + * @param value a int color value + * @return property wrapper around String color + */ + public static PropertyValue<String> heatmapColor(@ColorInt int value) { + return new PaintPropertyValue<>("heatmap-color", colorToRgbaString(value)); + } + + /** + * Defines the color of each pixel based on its density value in a heatmap. Should be an expression that uses `["heatmap-density"]` as input. + * + * @param value a String value + * @return property wrapper around String + */ + public static PropertyValue<String> heatmapColor(String value) { + return new PaintPropertyValue<>("heatmap-color", value); + } + + /** + * Defines the color of each pixel based on its density value in a heatmap. Should be an expression that uses `["heatmap-density"]` as input. + * + * @param expression an expression statement + * @return property wrapper around an expression statement + */ + public static PropertyValue<Expression> heatmapColor(Expression expression) { + return new PaintPropertyValue<>("heatmap-color", expression); + } + + /** * The global opacity at which the heatmap layer will be drawn. * * @param value a Float value diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java index 8f23e7d01e..7df48001cc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java @@ -48,7 +48,7 @@ public class Light { } /** - * Set the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below). + * Set the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below). * * @param position of the light */ @@ -57,7 +57,7 @@ public class Light { } /** - * Get the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below). + * Get the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below). * * @return position as Position */ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java index cd6218d3e2..00f8486a1c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java @@ -5,11 +5,11 @@ package com.mapbox.mapboxsdk.style.light; * <p> * The position is constructed out of a radial coordinate, an azimuthal angle and a polar angle. * where the radial coordinate indicates the distance from the center of the base of an object to its light, the - * azimuthal angle indicates the position of the light relative to 0° (0° when + * azimuthal angle indicates the position of the light relative to 0° (0° when * {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to viewport corresponds to the top of the - * viewport, or 0° when {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to map corresponds to due + * viewport, or 0° when {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to map corresponds to due * north, and degrees proceed clockwise), and polar indicates the height of the light - * (from 0°, directly above, to 180°, directly below). + * (from 0°, directly above, to 180°, directly below). */ public class Position { @@ -21,7 +21,7 @@ public class Position { * Creates a Position from a radial coordinate, an azimuthal angle and a polar angle. * * @param radialCoordinate the distance from the center of the base of an object to its light - * @param azimuthalAngle the position of the light relative to 0° + * @param azimuthalAngle the position of the light relative to 0° * @param polarAngle the height of the light */ public Position(float radialCoordinate, float azimuthalAngle, float polarAngle) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java index 84e5e96fa4..b7679b5a16 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java @@ -124,6 +124,15 @@ public class ImageSource extends Source { return nativeGetUrl(); } + /** + * Updates the latitude and longitude of the four corners of the image + * + * @param latLngQuad latitude and longitude of the four corners of the image + */ + public void setCoordinates(LatLngQuad latLngQuad) { + nativeSetCoordinates(latLngQuad); + } + protected native void initialize(String layerId, LatLngQuad payload); protected native void nativeSetUrl(String url); @@ -132,6 +141,8 @@ public class ImageSource extends Source { protected native void nativeSetImage(Bitmap bitmap); + protected native void nativeSetCoordinates(LatLngQuad latLngQuad); + @Override protected native void finalize() throws Throwable; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java index 54e4e5f5d3..25df2d91e7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java @@ -9,6 +9,7 @@ import java.util.Map; /** * Tile set, allows using TileJson specification as source. + * Note that `encoding` is only relevant to `raster-dem` sources, and is not supported in the TileJson spec. * * @see <a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">The tileset specification</a> */ @@ -28,6 +29,7 @@ public class TileSet { private Float maxZoom; private Float[] bounds; private Float[] center; + private String encoding; /** * @param tilejson A semver.org style version number. Describes the version of the TileJSON spec that is implemented @@ -246,6 +248,20 @@ public class TileSet { this.bounds = bounds; } + public String getEncoding() { + return encoding; + } + + /** + * Default: "mapbox". The encoding formula for a raster-dem tileset. + * Supported values are "mapbox" and "terrarium". + * + * @param encoding the String encoding formula to set + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + public Float[] getCenter() { return center; } @@ -313,6 +329,10 @@ public class TileSet { if (center != null) { result.put("center", center); } + if (encoding != null) { + result.put("encoding", encoding); + } + return result; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/package-info.java new file mode 100644 index 0000000000..52c7014bce --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains the Mapbox Maps Android Text API classes. + */ +package com.mapbox.mapboxsdk.text; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java index 007880acd1..08d39d6b3b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java @@ -1,11 +1,8 @@ package com.mapbox.mapboxsdk.utils; import android.content.Context; -import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.v4.content.ContextCompat; -import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; @@ -45,25 +42,6 @@ public class MapFragmentUtils { // load default options options = MapboxMapOptions.createFromAttributes(context, null); } - options = loadDefaultMyLocationViewDrawables(context, options); - return options; - } - - private static MapboxMapOptions loadDefaultMyLocationViewDrawables(Context context, MapboxMapOptions options) { - Drawable foregroundDrawable = options.getMyLocationForegroundDrawable(); - Drawable foregroundBearingDrawable = options.getMyLocationForegroundBearingDrawable(); - if (foregroundDrawable == null || foregroundBearingDrawable == null) { - if (foregroundDrawable == null) { - foregroundDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_default); - } - if (foregroundBearingDrawable == null) { - foregroundBearingDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_bearing); - } - options.myLocationForegroundDrawables(foregroundDrawable, foregroundBearingDrawable); - } - if (options.getMyLocationBackgroundDrawable() == null) { - options.myLocationBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_bg_shape)); - } return options; } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml index 29ff49f47e..8dd4a858df 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml @@ -8,12 +8,6 @@ android:background="@android:color/transparent" android:contentDescription="@null"/> - <com.mapbox.mapboxsdk.maps.widgets.MyLocationView - android:id="@+id/userLocationView" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:contentDescription="@string/mapbox_myLocationViewContentDescription"/> - <com.mapbox.mapboxsdk.maps.widgets.CompassView android:id="@+id/compassView" android:layout_width="wrap_content" diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml index 1c6a265587..00fc05cf6d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml @@ -6,4 +6,13 @@ <dimen name="mapbox_eight_dp">8dp</dimen> <dimen name="mapbox_ninety_two_dp">92dp</dimen> <dimen name="mapbox_my_locationview_outer_circle">18dp</dimen> + + <!--Minimum scale velocity required to start animation--> + <dimen name="mapbox_minimum_scale_velocity">150dp</dimen> + + <!--Minimum scale span delta required to execute scale gesture when rotating--> + <dimen name="mapbox_minimum_scale_span_when_rotating">100dp</dimen> + + <!--Minimum angular velocity required to start rotation animation--> + <dimen name="mapbox_minimum_angular_velocity">0.025dp</dimen> </resources> diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java index d9e3ae427d..6ee5c157b9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java @@ -5,7 +5,6 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; -import com.mapbox.android.core.location.LocationEngine; import org.junit.Before; import org.junit.Test; @@ -25,13 +24,11 @@ public class MapboxTest { private Context context; private Context appContext; - private LocationEngine locationSource; @Before public void before() { context = mock(Context.class); appContext = mock(Context.class); - locationSource = mock(LocationEngine.class); when(context.getApplicationContext()).thenReturn(appContext); } @@ -83,7 +80,7 @@ public class MapboxTest { } private void injectMapboxSingleton(String accessToken) { - Mapbox mapbox = new Mapbox(appContext, accessToken, locationSource); + Mapbox mapbox = new Mapbox(appContext, accessToken); try { Field field = Mapbox.class.getDeclaredField("INSTANCE"); field.setAccessible(true); diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index e6c1fdd0cf..940fde1257 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -71,6 +71,82 @@ public class LatLngBoundsTest { } @Test + public void dateLineSpanBuilder1() { + latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, -170)) + .include(new LatLng(-10, 170)) + .build(); + + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 20), + latLngSpan); + } + + @Test + public void dateLineSpanBuilder2() { + latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(-10, -170)) + .include(new LatLng(10, 170)) + .build(); + + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 20), + latLngSpan); + } + + @Test + public void dateLineSpanFrom1() { + latLngBounds = LatLngBounds.from(10, -170, -10, 170); + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 20), + latLngSpan); + } + + @Test + public void dateLineSpanFrom2() { + latLngBounds = LatLngBounds.from(10, 170, -10, -170); + LatLngSpan latLngSpan = latLngBounds.getSpan(); + assertEquals("LatLngSpan should be shortest distance", new LatLngSpan(20, 340), + latLngSpan); + } + + @Test + public void nearDateLineCenter1() { + latLngBounds = LatLngBounds.from(10, -175, -10, 165); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 175), center); + } + + @Test + public void nearDateLineCenter2() { + latLngBounds = LatLngBounds.from(10, -165, -10, 175); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, -175), center); + } + + @Test + public void nearDateLineCenter3() { + latLngBounds = LatLngBounds.from(10, -170, -10, 170); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, -180), center); + } + + @Test + public void nearDateLineCenter4() { + latLngBounds = LatLngBounds.from(10, -180, -10, 0); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 90), center); + } + + @Test + public void nearDateLineCenter5() { + latLngBounds = LatLngBounds.from(10, 180, -10, 0); + LatLng center = latLngBounds.getCenter(); + assertEquals("Center should match", new LatLng(0, 90), center); + } + + + @Test public void center() { LatLng center = latLngBounds.getCenter(); assertEquals("Center should match", new LatLng(1, 1), center); @@ -121,6 +197,46 @@ public class LatLngBoundsTest { } @Test + public void includesOverDateline1() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, -170)) + .include(new LatLng(-10, -175)) + .include(new LatLng(0, 170)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + + @Test + public void includesOverDateline2() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(-10, 175)) + .include(new LatLng(0, -170)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + + @Test + public void includesOverDateline3() { + + LatLngBounds latLngBounds = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(-10, -170)) + .include(new LatLng(0, -180)) + .include(new LatLng(5, 180)) + .build(); + + assertEquals("LatLngSpan should be the same", + new LatLngSpan(20, 20), latLngBounds.getSpan()); + } + + @Test public void containsNot() { assertFalse("LatLng should not be included", latLngBounds.contains(new LatLng(3, 1))); } @@ -131,6 +247,21 @@ public class LatLngBoundsTest { } @Test + public void worldSpan() { + assertEquals("LatLngBounds world span should be 180, 360", + GeometryConstants.LATITUDE_SPAN, LatLngBounds.world().getLatitudeSpan(), DELTA); + assertEquals("LatLngBounds world span should be 180, 360", + GeometryConstants.LONGITUDE_SPAN, LatLngBounds.world().getLongitudeSpan(), DELTA); + } + + @Test + public void emptySpan() { + LatLngBounds latLngBounds = LatLngBounds.from(GeometryConstants.MIN_LATITUDE, GeometryConstants.MAX_LONGITUDE, + GeometryConstants.MIN_LATITUDE, GeometryConstants.MAX_LONGITUDE); + assertTrue("LatLngBounds empty span", latLngBounds.isEmptySpan()); + } + + @Test public void containsBounds() { LatLngBounds inner = new LatLngBounds.Builder() .include(new LatLng(-5, -5)) @@ -207,6 +338,27 @@ public class LatLngBoundsTest { } @Test + public void unionOverDateLine() { + LatLngBounds latLngBounds1 = new LatLngBounds.Builder() + .include(new LatLng(10, 170)) + .include(new LatLng(0, 160)) + .build(); + + LatLngBounds latLngBounds2 = new LatLngBounds.Builder() + .include(new LatLng(0, -170)) + .include(new LatLng(-10, -160)) + .build(); + + assertEquals("outer union should match", + latLngBounds1.union(latLngBounds2), + new LatLngBounds.Builder() + .include(new LatLng(10, 160)) + .include(new LatLng(-10, -160)) + .build()); + } + + + @Test public void northWest() { double minLat = 5; double minLon = 6; @@ -365,4 +517,11 @@ public class LatLngBoundsTest { exception.expectMessage("longitude must not be infinite"); LatLngBounds.from(20, 20, 0, Double.POSITIVE_INFINITY); } + + @Test + public void testConstructorCheckLatSouthGreaterLatNorth() { + exception.expect(IllegalArgumentException.class); + exception.expectMessage("LatSouth cannot be less than latNorth"); + LatLngBounds.from(0, 20, 20, 0); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java index eeb00355bd..5de55f47c9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java @@ -2,8 +2,13 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.PointF; +import com.mapbox.android.gestures.MoveGestureDetector; +import com.mapbox.android.gestures.RotateGestureDetector; +import com.mapbox.android.gestures.ShoveGestureDetector; +import com.mapbox.android.gestures.StandardScaleGestureDetector; import com.mapbox.mapboxsdk.geometry.LatLng; +import org.junit.Before; import org.junit.Test; import static org.mockito.Mockito.mock; @@ -13,16 +18,23 @@ import static org.mockito.Mockito.when; public class MapTouchListenersTest { - @Test - public void onMapClickListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); + private MapGestureDetector mapGestureDetector; + private LatLng latLng; + private PointF pointF; + + @Before + public void setUp() throws Exception { + latLng = new LatLng(); + pointF = new PointF(); Projection projection = mock(Projection.class); when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); + mapGestureDetector = new MapGestureDetector(null, + null, projection, null, null, null); + } + @Test + public void onMapClickListenerTest() throws Exception { MapboxMap.OnMapClickListener listener = mock(MapboxMap.OnMapClickListener.class); mapGestureDetector.addOnMapClickListener(listener); mapGestureDetector.notifyOnMapClickListeners(pointF); @@ -35,14 +47,6 @@ public class MapTouchListenersTest { @Test public void onMapLongClickListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); - - Projection projection = mock(Projection.class); - when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); - MapboxMap.OnMapLongClickListener listener = mock(MapboxMap.OnMapLongClickListener.class); mapGestureDetector.addOnMapLongClickListener(listener); mapGestureDetector.notifyOnMapLongClickListeners(pointF); @@ -55,14 +59,6 @@ public class MapTouchListenersTest { @Test public void onFlingListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); - - Projection projection = mock(Projection.class); - when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); - MapboxMap.OnFlingListener listener = mock(MapboxMap.OnFlingListener.class); mapGestureDetector.addOnFlingListener(listener); mapGestureDetector.notifyOnFlingListeners(); @@ -75,14 +71,6 @@ public class MapTouchListenersTest { @Test public void onScrollListenerTest() throws Exception { - LatLng latLng = new LatLng(); - PointF pointF = new PointF(); - - Projection projection = mock(Projection.class); - when(projection.fromScreenLocation(pointF)).thenReturn(latLng); - MapGestureDetector mapGestureDetector = new MapGestureDetector(null, - null, projection, null, null, null, null); - MapboxMap.OnScrollListener listener = mock(MapboxMap.OnScrollListener.class); mapGestureDetector.addOnScrollListener(listener); mapGestureDetector.notifyOnScrollListeners(); @@ -92,4 +80,88 @@ public class MapTouchListenersTest { mapGestureDetector.notifyOnScrollListeners(); verify(listener, times(1)).onScroll(); } + + @Test + public void onMoveListenerTest() throws Exception { + MapboxMap.OnMoveListener listener = mock(MapboxMap.OnMoveListener.class); + MoveGestureDetector detector = mock(MoveGestureDetector.class); + mapGestureDetector.addOnMoveListener(listener); + mapGestureDetector.notifyOnMoveBeginListeners(detector); + mapGestureDetector.notifyOnMoveListeners(detector); + mapGestureDetector.notifyOnMoveEndListeners(detector); + verify(listener, times(1)).onMoveBegin(detector); + verify(listener, times(1)).onMove(detector); + verify(listener, times(1)).onMoveEnd(detector); + + mapGestureDetector.removeOnMoveListener(listener); + mapGestureDetector.notifyOnMoveBeginListeners(detector); + mapGestureDetector.notifyOnMoveListeners(detector); + mapGestureDetector.notifyOnMoveEndListeners(detector); + verify(listener, times(1)).onMoveBegin(detector); + verify(listener, times(1)).onMove(detector); + verify(listener, times(1)).onMoveEnd(detector); + } + + @Test + public void onRotateListenerTest() throws Exception { + MapboxMap.OnRotateListener listener = mock(MapboxMap.OnRotateListener.class); + RotateGestureDetector detector = mock(RotateGestureDetector.class); + mapGestureDetector.addOnRotateListener(listener); + mapGestureDetector.notifyOnRotateBeginListeners(detector); + mapGestureDetector.notifyOnRotateListeners(detector); + mapGestureDetector.notifyOnRotateEndListeners(detector); + verify(listener, times(1)).onRotateBegin(detector); + verify(listener, times(1)).onRotate(detector); + verify(listener, times(1)).onRotateEnd(detector); + + mapGestureDetector.removeOnRotateListener(listener); + mapGestureDetector.notifyOnRotateBeginListeners(detector); + mapGestureDetector.notifyOnRotateListeners(detector); + mapGestureDetector.notifyOnRotateEndListeners(detector); + verify(listener, times(1)).onRotateBegin(detector); + verify(listener, times(1)).onRotate(detector); + verify(listener, times(1)).onRotateEnd(detector); + } + + @Test + public void onScaleListenerTest() throws Exception { + MapboxMap.OnScaleListener listener = mock(MapboxMap.OnScaleListener.class); + StandardScaleGestureDetector detector = mock(StandardScaleGestureDetector.class); + mapGestureDetector.addOnScaleListener(listener); + mapGestureDetector.notifyOnScaleBeginListeners(detector); + mapGestureDetector.notifyOnScaleListeners(detector); + mapGestureDetector.notifyOnScaleEndListeners(detector); + verify(listener, times(1)).onScaleBegin(detector); + verify(listener, times(1)).onScale(detector); + verify(listener, times(1)).onScaleEnd(detector); + + mapGestureDetector.removeOnScaleListener(listener); + mapGestureDetector.notifyOnScaleBeginListeners(detector); + mapGestureDetector.notifyOnScaleListeners(detector); + mapGestureDetector.notifyOnScaleEndListeners(detector); + verify(listener, times(1)).onScaleBegin(detector); + verify(listener, times(1)).onScale(detector); + verify(listener, times(1)).onScaleEnd(detector); + } + + @Test + public void onShoveListenerTest() throws Exception { + MapboxMap.OnShoveListener listener = mock(MapboxMap.OnShoveListener.class); + ShoveGestureDetector detector = mock(ShoveGestureDetector.class); + mapGestureDetector.addShoveListener(listener); + mapGestureDetector.notifyOnShoveBeginListeners(detector); + mapGestureDetector.notifyOnShoveListeners(detector); + mapGestureDetector.notifyOnShoveEndListeners(detector); + verify(listener, times(1)).onShoveBegin(detector); + verify(listener, times(1)).onShove(detector); + verify(listener, times(1)).onShoveEnd(detector); + + mapGestureDetector.removeShoveListener(listener); + mapGestureDetector.notifyOnShoveBeginListeners(detector); + mapGestureDetector.notifyOnShoveListeners(detector); + mapGestureDetector.notifyOnShoveEndListeners(detector); + verify(listener, times(1)).onShoveBegin(detector); + verify(listener, times(1)).onShove(detector); + verify(listener, times(1)).onShoveEnd(detector); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java index 65bdff41ab..9dd0ca9285 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -119,13 +119,6 @@ public class MapboxMapOptionsTest { } @Test - public void testLocationEnabled() { - assertFalse(new MapboxMapOptions().getLocationEnabled()); - assertTrue(new MapboxMapOptions().locationEnabled(true).getLocationEnabled()); - assertFalse(new MapboxMapOptions().locationEnabled(false).getLocationEnabled()); - } - - @Test public void testTiltGesturesEnabled() { assertTrue(new MapboxMapOptions().getTiltGesturesEnabled()); assertTrue(new MapboxMapOptions().tiltGesturesEnabled(true).getTiltGesturesEnabled()); @@ -176,18 +169,6 @@ public class MapboxMapOptionsTest { } @Test - public void testMyLocationForegroundTint() { - assertEquals(Color.BLUE, new MapboxMapOptions() - .myLocationForegroundTintColor(Color.BLUE).getMyLocationForegroundTintColor()); - } - - @Test - public void testMyLocationBackgroundTint() { - assertEquals(Color.BLUE, new MapboxMapOptions() - .myLocationBackgroundTintColor(Color.BLUE).getMyLocationBackgroundTintColor()); - } - - @Test public void testPrefetchesTiles() { // Default value assertTrue(new MapboxMapOptions().getPrefetchesTiles()); diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java index 5e9f94db28..9a323a1d75 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -2,7 +2,6 @@ package com.mapbox.mapboxsdk.maps; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import org.junit.After; import org.junit.Before; @@ -20,10 +19,8 @@ public class MapboxMapTest { mapboxMap = new MapboxMap(mock(NativeMapView.class), mock(Transform.class), mock(UiSettings.class), - mock(TrackingSettings.class), - mock(MyLocationViewSettings.class), mock(Projection.class), - mock(MapboxMap.OnRegisterTouchListener.class), + mock(MapboxMap.OnGesturesManagerInteractionListener.class), mock(AnnotationManager.class), mock(CameraChangeDispatcher.class)); } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java deleted file mode 100644 index de5f364a5b..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -import android.Manifest; -import android.content.Context; -import android.content.pm.PackageManager; -import android.graphics.PointF; - -import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class TrackingSettingsTest { - - @InjectMocks - MyLocationView myLocationView = mock(MyLocationView.class); - - @InjectMocks - UiSettings uiSettings = mock(UiSettings.class); - - @InjectMocks - FocalPointChangeListener focalPointChangeListener = mock(FocalPointChangeListener.class); - - @InjectMocks - TrackingSettings.CameraZoomInvalidator zoomInvalidator = mock(TrackingSettings.CameraZoomInvalidator.class); - - private TrackingSettings trackingSettings; - - @Before - public void beforeTest() { - trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointChangeListener, zoomInvalidator); - } - - @Test - public void testSanity() { - assertNotNull("trackingsettings should not be null", trackingSettings); - } - - @Test - public void testDismissTrackingModesOnGesture() { - trackingSettings.setDismissAllTrackingOnGesture(false); - assertFalse("DismissTrackingOnGesture should be false", trackingSettings.isAllDismissTrackingOnGesture()); - } - - @Test - public void testValidateGesturesForTrackingModes() { - trackingSettings.setDismissAllTrackingOnGesture(false); - trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - assertFalse("DismissTrackingOnGesture should be false", trackingSettings.isAllDismissTrackingOnGesture()); - } - - @Test - public void testMyLocationEnabled() { - // setup mock context to provide accepted location permission - Context context = mock(Context.class); - when(myLocationView.getContext()).thenReturn(context); - when(context.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), anyInt(), - anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); - - assertFalse("Location should be disabled by default.", trackingSettings.isMyLocationEnabled()); - trackingSettings.setMyLocationEnabled(true); - assertTrue("Location should be enabled", trackingSettings.isMyLocationEnabled()); - } - - @Test - public void testCameraZoomTo2forTracking() { - trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - verify(zoomInvalidator, atLeast(1)).zoomTo(2.0); - } - - @Test - public void testFocalPointChangeForTracking() { - final float centerX = 32.3f; - final float centerY = 46.3f; - final PointF pointF = new PointF(centerX, centerY); - when(myLocationView.getCenter()).thenReturn(pointF); - - trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - verify(focalPointChangeListener, atLeast(1)).onFocalPointChanged(pointF); - } - - @Test - public void testFocalPointChangeForNonTracking() { - trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE); - verify(focalPointChangeListener, atLeast(1)).onFocalPointChanged(null); - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java deleted file mode 100644 index c9ce19dc85..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.mapbox.mapboxsdk.maps.widgets; - -import android.graphics.Color; -import android.graphics.drawable.Drawable; - -import com.mapbox.mapboxsdk.maps.FocalPointChangeListener; -import com.mapbox.mapboxsdk.maps.Projection; -import com.mapbox.mapboxsdk.maps.TrackingSettings; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; - -import java.util.Arrays; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MyLocationViewSettingsTest { - - @InjectMocks - Projection projection = mock(Projection.class); - - @InjectMocks - MyLocationView myLocationView = mock(MyLocationView.class); - - @InjectMocks - TrackingSettings trackingSettings = mock(TrackingSettings.class); - - @InjectMocks - FocalPointChangeListener focalPointChangeListener = mock(FocalPointChangeListener.class); - - private MyLocationViewSettings locationViewSettings; - - @Before - public void beforeTest() { - locationViewSettings = new MyLocationViewSettings(myLocationView, projection, focalPointChangeListener); - } - - @Test - public void testSanity() { - assertNotNull("should not be null", locationViewSettings); - } - - @Test - public void testForegroundDrawables() { - Drawable foregroundDrawable = mock(Drawable.class); - Drawable foregroundBearingDrawable = mock(Drawable.class); - Drawable.ConstantState constantState = mock(Drawable.ConstantState.class); - when(foregroundDrawable.getConstantState()).thenReturn(constantState); - when(constantState.newDrawable()).thenReturn(foregroundDrawable); - locationViewSettings.setForegroundDrawable(foregroundDrawable, foregroundBearingDrawable); - assertEquals("foreground should match", foregroundDrawable, locationViewSettings.getForegroundDrawable()); - assertEquals("foreground bearing should match", foregroundBearingDrawable, - locationViewSettings.getForegroundBearingDrawable()); - } - - @Test - public void testBackgroundDrawable() { - Drawable backgroundDrawable = mock(Drawable.class); - int[] offset = new int[] {1, 2, 3, 4}; - locationViewSettings.setBackgroundDrawable(backgroundDrawable, offset); - assertEquals("foreground should match", backgroundDrawable, locationViewSettings.getBackgroundDrawable()); - assertTrue("offsets should match", Arrays.equals(offset, locationViewSettings.getBackgroundOffset())); - } - - @Test - public void testForegroundTint() { - int color = Color.RED; - locationViewSettings.setForegroundTintColor(Color.RED); - assertEquals("color should match", color, locationViewSettings.getForegroundTintColor()); - } - - @Test - public void testForegroundTransparentTint() { - int color = Color.TRANSPARENT; - locationViewSettings.setForegroundTintColor(Color.TRANSPARENT); - assertEquals("color should match", color, locationViewSettings.getForegroundTintColor()); - } - - @Test - public void testBackgroundTint() { - int color = Color.RED; - locationViewSettings.setBackgroundTintColor(Color.RED); - assertEquals("color should match", color, locationViewSettings.getBackgroundTintColor()); - } - - @Test - public void testBackgroundTransparentTint() { - int color = Color.TRANSPARENT; - locationViewSettings.setBackgroundTintColor(Color.TRANSPARENT); - assertEquals("color should match", color, locationViewSettings.getBackgroundTintColor()); - } - - @Test - public void testEnabled() { - assertFalse("initial state should be false", locationViewSettings.isEnabled()); - locationViewSettings.setEnabled(true); - assertTrue("state should be true", locationViewSettings.isEnabled()); - } -} - diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapViewUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapViewUtils.java deleted file mode 100644 index 38d5297291..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapViewUtils.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -import com.mapbox.mapboxsdk.geometry.LatLng; - -/** - * Utility class to bypass package visibility - */ -public class MapViewUtils { - - public static void setDirection(MapboxMap mapboxMap, float direction) { - mapboxMap.getTransform().setBearing(direction); - } - - public static float getDirection(MapboxMap mapboxMap) { - return (float) mapboxMap.getTransform().getBearing(); - } - - public static void setTilt(MapboxMap mapboxMap, float tilt) { - mapboxMap.getTransform().setTilt((double) tilt); - } - - public static float getTilt(MapboxMap mapboxMap) { - return (float) mapboxMap.getTransform().getTilt(); - } - - public static void setLatLng(MapboxMap mapboxMap, LatLng latLng) { - mapboxMap.getTransform().setCenterCoordinate(latLng); - } - - public static LatLng getLatLng(MapboxMap mapboxMap) { - return mapboxMap.getTransform().getCenterCoordinate(); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java index b4bc118129..38fd8491a8 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -162,16 +162,6 @@ public class MapboxMapTest extends BaseActivityTest { } // - // TrackingSettings - // - - @Test - public void testTrackingSettings() { - validateTestSetup(); - assertNotNull("TrackingSettings should not be null", mapboxMap.getTrackingSettings()); - } - - // // InfoWindow // @@ -204,30 +194,6 @@ public class MapboxMapTest extends BaseActivityTest { } // - // Location - // - - @Test - @Ignore /* disabled due to enabling permissions during test #7177 */ - public void testMyLocationEnabled() { - validateTestSetup(); - onView(withId(R.id.mapView)).perform(new MapboxMapAction((uiController, view) -> { - mapboxMap.setMyLocationEnabled(true); - assertTrue("MyLocationEnabled should be true", mapboxMap.isMyLocationEnabled()); - })); - } - - @Test - @Ignore /* can't create handler inside thread that not called Looper.prepare() */ - public void testMyLocationDisabled() { - validateTestSetup(); - onView(withId(R.id.mapView)).perform(new MapboxMapAction((uiController, view) -> { - mapboxMap.setMyLocationEnabled(false); - assertFalse("MyLocationEnabled should be false", mapboxMap.isMyLocationEnabled()); - })); - } - - // // setters/getters interfaces // diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java deleted file mode 100644 index 883e76653d..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.camera; - -import android.support.test.espresso.Espresso; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; -import android.view.View; - -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapViewUtils; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest; -import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; -import com.mapbox.mapboxsdk.testapp.utils.TestConstants; - -import org.hamcrest.Matcher; -import org.junit.After; -import org.junit.Ignore; -import org.junit.Test; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static org.junit.Assert.assertEquals; - -/** - * Tests camera transformations that aren't part of our public API - */ -public class CameraInternalApiTest extends BaseActivityTest { - - @Override - protected Class getActivityClass() { - return EspressoTestActivity.class; - } - - @Test - @Ignore - public void testBearing() { - validateTestSetup(); - - CameraPosition initialPosition = new - CameraPosition.Builder().target(new LatLng()).zoom(1).bearing(0).tilt(0).build(); - CameraPosition cameraPosition = mapboxMap.getCameraPosition(); - assertEquals("Default camera position should match default", cameraPosition, initialPosition); - - onView(withId(R.id.mapView)).perform(new BearingAction(mapboxMap)); - assertEquals("Bearing should match", 45.1f, MapViewUtils.getDirection(mapboxMap), TestConstants.BEARING_DELTA); - } - - @Test - @Ignore - public void testTilt() { - validateTestSetup(); - - CameraPosition initialPosition = new CameraPosition.Builder().target( - new LatLng()).zoom(1).bearing(0).tilt(0).build(); - CameraPosition cameraPosition = mapboxMap.getCameraPosition(); - assertEquals("Default camera position should match default", cameraPosition, initialPosition); - - onView(withId(R.id.mapView)).perform(new TiltAction(mapboxMap)); - assertEquals("Tilt should match", 40.0f, MapViewUtils.getTilt(mapboxMap), TestConstants.TILT_DELTA); - } - - @Test - @Ignore - public void testLatLng() { - validateTestSetup(); - - CameraPosition initialPosition = new CameraPosition.Builder().target( - new LatLng()).zoom(1).bearing(0).tilt(0).build(); - CameraPosition cameraPosition = mapboxMap.getCameraPosition(); - assertEquals("Default camera position should match default", cameraPosition, initialPosition); - - onView(withId(R.id.mapView)).perform(new LatLngAction(mapboxMap)); - LatLng centerCoordinate = MapViewUtils.getLatLng(mapboxMap); - assertEquals("Latitude should match", 1.1f, centerCoordinate.getLatitude(), TestConstants.LAT_LNG_DELTA); - assertEquals("Longitude should match", 2.2f, centerCoordinate.getLongitude(), TestConstants.LAT_LNG_DELTA); - } - - @After - public void unregisterIdlingResource() { - Espresso.unregisterIdlingResources(idlingResource); - } - - private class BearingAction implements ViewAction { - - private MapboxMap mapboxMap; - - BearingAction(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - } - - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return getClass().getSimpleName(); - } - - @Override - public void perform(UiController uiController, View view) { - MapViewUtils.setDirection(mapboxMap, -45.1f); - } - } - - private class TiltAction implements ViewAction { - - private MapboxMap mapboxMap; - - TiltAction(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - } - - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return getClass().getSimpleName(); - } - - @Override - public void perform(UiController uiController, View view) { - MapViewUtils.setTilt(mapboxMap, 40.0f); - } - } - - private class LatLngAction implements ViewAction { - - private MapboxMap mapboxMap; - - LatLngAction(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - } - - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return getClass().getSimpleName(); - } - - @Override - public void perform(UiController uiController, View view) { - MapViewUtils.setLatLng(mapboxMap, new LatLng(1.1, 2.2)); - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java deleted file mode 100644 index cf58ba50a6..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java +++ /dev/null @@ -1,229 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.maps.widgets; - -import android.annotation.SuppressLint; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; -import android.view.View; - -import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.MyBearingTracking; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; -import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest; -import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.Ignore; -import org.junit.Test; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static org.hamcrest.Matchers.not; - -/** - * Experimental MyLocationView tests, - * requires application to be granted with runtime location permissions. - * <p> - * Tests for enabling and disabling the {@link MyLocationView}. - * Tests for enabling tracking modes and if the correct default images are shown when toggling - * {@link com.mapbox.mapboxsdk.maps.TrackingSettings#setMyLocationTrackingMode(int)} & - * {@link com.mapbox.mapboxsdk.maps.TrackingSettings#setMyBearingTrackingMode(int)}. - * </p> - */ -public class MyLocationViewTest extends BaseActivityTest { - - @Override - protected Class getActivityClass() { - return EspressoTestActivity.class; - } - - @Test - @Ignore // requires runtime permissions, disabled for CI - public void testEnabled() { - validateTestSetup(); - onView(withId(R.id.userLocationView)).check(matches(not(isDisplayed()))); - onView(withId(R.id.mapView)).perform(new ToggleLocationAction(mapboxMap, true)); - onView(withId(R.id.userLocationView)).check(matches(isDisplayed())); - onView(withId(R.id.mapView)).perform(new ToggleLocationAction(mapboxMap, false)); - onView(withId(R.id.userLocationView)).check(matches(not(isDisplayed()))); - } - - @Test - @Ignore - // requires runtime permissions, disabled for CI + issue with android.support.test.espresso.AppNotIdleException: - // Looped for 5049 iterations over 60 SECONDS. - public void testTracking() { - validateTestSetup(); - onView(withId(R.id.userLocationView)).check(matches(not(isDisplayed()))); - onView(withId(R.id.mapView)).perform(new EnableLocationTrackingAction(mapboxMap)); - onView(withId(R.id.userLocationView)).check(matches(isDisplayed())); - onView(withId(R.id.userLocationView)).check(matches(new DrawableMatcher(mapboxMap, - R.drawable.mapbox_mylocation_icon_default, false))); - onView(withId(R.id.mapView)).perform(new EnableCompassBearingTrackingAction(mapboxMap)); - onView(withId(R.id.userLocationView)).check(matches(new DrawableMatcher(mapboxMap, - R.drawable.mapbox_mylocation_icon_bearing, true))); - } - - private class ToggleLocationAction implements ViewAction { - - private MapboxMap mapboxMap; - private boolean isEnabled; - - ToggleLocationAction(MapboxMap map, boolean enable) { - mapboxMap = map; - isEnabled = enable; - } - - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return getClass().getSimpleName(); - } - - @SuppressLint("MissingPermission") - @Override - public void perform(UiController uiController, View view) { - if (isEnabled) { - // move camera above user location - mapboxMap.moveCamera( - CameraUpdateFactory.newCameraPosition( - new CameraPosition.Builder() - .target(new LatLng(Mapbox.getLocationEngine().getLastLocation())) - .build() - ) - ); - } - - // show loction on screen - mapboxMap.setMyLocationEnabled(isEnabled); - } - } - - private class EnableLocationTrackingAction implements ViewAction { - - private MapboxMap mapboxMap; - - EnableLocationTrackingAction(MapboxMap map) { - mapboxMap = map; - } - - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return getClass().getSimpleName(); - } - - @Override - public void perform(UiController uiController, View view) { - mapboxMap.getTrackingSettings().setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - } - } - - private class EnableCompassBearingTrackingAction implements ViewAction { - - private MapboxMap mapboxMap; - - EnableCompassBearingTrackingAction(MapboxMap map) { - mapboxMap = map; - } - - @Override - public Matcher<View> getConstraints() { - return isDisplayed(); - } - - @Override - public String getDescription() { - return getClass().getSimpleName(); - } - - @Override - public void perform(UiController uiController, View view) { - mapboxMap.getTrackingSettings().setMyBearingTrackingMode(MyBearingTracking.COMPASS); - // wait for next compass update cycle - uiController.loopMainThreadForAtLeast(500); - } - } - - private class DrawableMatcher extends TypeSafeMatcher<View> { - - private MapboxMap mapboxMap; - private boolean isBearingDrawable; - private final int expectedId; - - DrawableMatcher(MapboxMap mapboxMap, int expectedId, boolean isBearingDrawable) { - super(MyLocationView.class); - this.mapboxMap = mapboxMap; - this.expectedId = expectedId; - this.isBearingDrawable = isBearingDrawable; - } - - @Override - protected boolean matchesSafely(View target) { - Drawable currentDrawable = isBearingDrawable - ? mapboxMap.getMyLocationViewSettings().getForegroundBearingDrawable() : - mapboxMap.getMyLocationViewSettings().getForegroundDrawable(); - - Resources resources = target.getContext().getResources(); - Drawable expectedDrawable = resources.getDrawable(expectedId); - return areDrawablesIdentical(currentDrawable, expectedDrawable); - } - - @Override - public void describeTo(Description description) { - description.appendText("trying to match MyLocationView drawable to " + expectedId); - } - - boolean areDrawablesIdentical(Drawable drawableA, Drawable drawableB) { - Drawable.ConstantState stateA = drawableA.getConstantState(); - Drawable.ConstantState stateB = drawableB.getConstantState(); - return (stateA != null && stateB != null && stateA.equals(stateB)) - || getBitmap(drawableA).sameAs(getBitmap(drawableB)); - } - - Bitmap getBitmap(Drawable drawable) { - Bitmap result; - if (drawable instanceof BitmapDrawable) { - result = ((BitmapDrawable) drawable).getBitmap(); - } else { - int width = drawable.getIntrinsicWidth(); - int height = drawable.getIntrinsicHeight(); - // Some drawables have no intrinsic width - e.g. solid colours. - if (width <= 0) { - width = 1; - } - if (height <= 0) { - height = 1; - } - - result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(result); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - } - return result; - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs index 206497b860..4e014c4384 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs @@ -123,6 +123,7 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest { } <% } -%> <% for (const property of properties) { -%> +<% if (property.name != 'heatmap-color') { -%> <% if (property.transition) { -%> @Test @@ -456,5 +457,6 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest { } <% } -%> <% } -%> +<% } -%> } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 0b6d2a155d..65d7b34b21 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -2,7 +2,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mapbox.mapboxsdk.testapp"> - <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application @@ -213,62 +212,6 @@ android:value=".activity.FeatureOverviewActivity"/> </activity> <activity - android:name=".activity.userlocation.MyLocationTrackingModeActivity" - android:description="@string/description_user_location_tracking" - android:label="@string/activity_user_tracking_mode" - android:theme="@style/NoActionBar"> - <meta-data - android:name="@string/category" - android:value="@string/category_userlocation"/> - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value=".activity.FeatureOverviewActivity"/> - </activity> - <activity - android:name=".activity.userlocation.MyLocationDrawableActivity" - android:description="@string/description_user_location_customization" - android:label="@string/activity_user_tracking_customization"> - <meta-data - android:name="@string/category" - android:value="@string/category_userlocation"/> - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value=".activity.FeatureOverviewActivity"/> - </activity> - <activity - android:name=".activity.userlocation.MyLocationTintActivity" - android:description="@string/description_user_location_dot_color" - android:label="@string/activity_user_dot_color"> - <meta-data - android:name="@string/category" - android:value="@string/category_userlocation"/> - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value=".activity.FeatureOverviewActivity"/> - </activity> - <activity - android:name=".activity.userlocation.MyLocationToggleActivity" - android:description="@string/description_user_location_toggle" - android:label="@string/activity_user_location_toggle"> - <meta-data - android:name="@string/category" - android:value="@string/category_userlocation"/> - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value=".activity.FeatureOverviewActivity"/> - </activity> - <activity - android:name=".activity.userlocation.CustomLocationEngineActivity" - android:description="@string/description_custom_location_engine" - android:label="@string/activity_custom_location_engine"> - <meta-data - android:name="@string/category" - android:value="@string/category_userlocation"/> - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value=".activity.FeatureOverviewActivity"/> - </activity> - <activity android:name=".activity.annotation.PolygonActivity" android:description="@string/description_polygon" android:label="@string/activity_polygon"> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java index 0ee1f78e0e..c8b15593ec 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java @@ -7,23 +7,17 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; import android.support.annotation.StringRes; -import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.text.TextUtils; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.adapter.FeatureAdapter; import com.mapbox.mapboxsdk.testapp.adapter.FeatureSectionAdapter; import com.mapbox.mapboxsdk.testapp.model.activity.Feature; import com.mapbox.mapboxsdk.testapp.utils.ItemClickSupport; -import com.mapbox.android.core.permissions.PermissionsListener; -import com.mapbox.android.core.permissions.PermissionsManager; import java.util.ArrayList; import java.util.Collections; @@ -39,23 +33,19 @@ import timber.log.Timber; * It uses tags as category and description to order the different entries. * </p> */ -public class FeatureOverviewActivity extends AppCompatActivity implements PermissionsListener { +public class FeatureOverviewActivity extends AppCompatActivity { private static final String KEY_STATE_FEATURES = "featureList"; - private PermissionsManager permissionsManager; private RecyclerView recyclerView; private FeatureSectionAdapter sectionAdapter; private List<Feature> features; - private int locationActivityInList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_feature_overview); - permissionsManager = new PermissionsManager(this); - recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener()); @@ -65,11 +55,6 @@ public class FeatureOverviewActivity extends AppCompatActivity implements Permis if (!sectionAdapter.isSectionHeaderPosition(position)) { int itemPosition = sectionAdapter.getConvertedPosition(position); Feature feature = features.get(itemPosition); - if (feature.isRequiresLocationPermission()) { - if (requestLocationPermission(itemPosition)) { - return; - } - } startFeature(feature); } }); @@ -118,45 +103,6 @@ public class FeatureOverviewActivity extends AppCompatActivity implements Permis startActivity(intent); } - private boolean requestLocationPermission(final int positionInList) { - if (isRuntimePermissionsRequired()) { - locationActivityInList = positionInList; - permissionsManager.requestLocationPermissions(this); - return true; - } - return false; - } - - @Override - public void onExplanationNeeded(List<String> list) { - Snackbar.make( - findViewById(android.R.id.content), - TextUtils.join("", list.toArray()), - Snackbar.LENGTH_SHORT).show(); - } - - @Override - public void onPermissionResult(boolean isPermissionGranted) { - if (isPermissionGranted) { - startFeature(features.get(locationActivityInList)); - } else { - Snackbar.make( - findViewById(android.R.id.content), - "Can't open without accepting the location permission.", - Snackbar.LENGTH_SHORT).show(); - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - private boolean isRuntimePermissionsRequired() { - return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; - } - @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -178,8 +124,7 @@ public class FeatureOverviewActivity extends AppCompatActivity implements Permis String label = getString(info.labelRes); String description = resolveString(info.descriptionRes); String category = resolveMetaData(info.metaData, metaDataKey); - boolean requiresLocationPermission = requiresLocationPermission(label, category); - features.add(new Feature(info.name, label, description, category, requiresLocationPermission)); + features.add(new Feature(info.name, label, description, category)); } } @@ -213,24 +158,6 @@ public class FeatureOverviewActivity extends AppCompatActivity implements Permis } } - private boolean requiresLocationPermission(String name, String category) { - final Resources resources = getResources(); - - List<String> requiresPermissionCategories = new ArrayList<String>() { - { - add(resources.getString(R.string.category_userlocation)); - } - }; - - List<String> requiresPermissionActivities = new ArrayList<String>() { - { - add(resources.getString(R.string.activity_double_map)); - } - }; - - return requiresPermissionCategories.contains(category) || requiresPermissionActivities.contains(name); - } - @Override protected void onPostExecute(List<Feature> features) { super.onPostExecute(features); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java index f25fd6ab27..6277dffe91 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java @@ -115,7 +115,9 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, targetPosition); latLngAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); latLngAnimator.setInterpolator(new FastOutSlowInInterpolator()); - latLngAnimator.addUpdateListener(animation -> mapboxMap.setLatLng((LatLng) animation.getAnimatedValue())); + latLngAnimator.addUpdateListener(animation -> mapboxMap.moveCamera( + CameraUpdateFactory.newLatLng((LatLng) animation.getAnimatedValue())) + ); return latLngAnimator; } @@ -124,7 +126,9 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe zoomAnimator.setDuration((long) (2200 * ANIMATION_DELAY_FACTOR)); zoomAnimator.setStartDelay((long) (600 * ANIMATION_DELAY_FACTOR)); zoomAnimator.setInterpolator(new AnticipateOvershootInterpolator()); - zoomAnimator.addUpdateListener(animation -> mapboxMap.setZoom((Float) animation.getAnimatedValue())); + zoomAnimator.addUpdateListener(animation -> mapboxMap.moveCamera( + CameraUpdateFactory.zoomTo((Float) animation.getAnimatedValue())) + ); return zoomAnimator; } @@ -133,7 +137,9 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe bearingAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); bearingAnimator.setStartDelay((long) (1000 * ANIMATION_DELAY_FACTOR)); bearingAnimator.setInterpolator(new FastOutLinearInInterpolator()); - bearingAnimator.addUpdateListener(animation -> mapboxMap.setBearing((Float) animation.getAnimatedValue())); + bearingAnimator.addUpdateListener(animation -> mapboxMap.moveCamera( + CameraUpdateFactory.bearingTo((Float) animation.getAnimatedValue())) + ); return bearingAnimator; } @@ -141,7 +147,9 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, (float) targetTilt); tiltAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR)); tiltAnimator.setStartDelay((long) (1500 * ANIMATION_DELAY_FACTOR)); - tiltAnimator.addUpdateListener(animation -> mapboxMap.setTilt((Float) animation.getAnimatedValue())); + tiltAnimator.addUpdateListener(animation -> mapboxMap.moveCamera( + CameraUpdateFactory.tiltTo((Float) animation.getAnimatedValue())) + ); return tiltAnimator; } @@ -192,7 +200,9 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe ValueAnimator zoomAnimator = ValueAnimator.ofFloat(11.0f, 16.0f); zoomAnimator.setDuration((long) (duration * ANIMATION_DELAY_FACTOR)); zoomAnimator.setInterpolator(interpolator); - zoomAnimator.addUpdateListener(animation -> mapboxMap.setZoom((Float) animation.getAnimatedValue())); + zoomAnimator.addUpdateListener(animation -> mapboxMap.moveCamera( + CameraUpdateFactory.zoomTo((Float) animation.getAnimatedValue())) + ); return zoomAnimator; } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java index 3b58843e13..a165d9ab9d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/BottomSheetActivity.java @@ -1,7 +1,6 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; import android.content.Context; -import android.location.Location; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -151,10 +150,7 @@ public class BottomSheetActivity extends AppCompatActivity { @Override public void onMapReady(MapboxMap mapboxMap) { - Location location = mapboxMap.getMyLocation(); - if (location != null) { - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 15)); - } + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.760545, -122.436055), 15)); } @Override @@ -207,7 +203,6 @@ public class BottomSheetActivity extends AppCompatActivity { public static BottomSheetFragment newInstance() { BottomSheetFragment mapFragment = new BottomSheetFragment(); MapboxMapOptions mapboxMapOptions = new MapboxMapOptions(); - mapboxMapOptions.locationEnabled(true); mapboxMapOptions.renderSurfaceOnTop(true); mapboxMapOptions.styleUrl(Style.LIGHT); mapFragment.setArguments(MapFragmentUtils.createFragmentArgs(mapboxMapOptions)); @@ -230,10 +225,7 @@ public class BottomSheetActivity extends AppCompatActivity { @Override public void onMapReady(MapboxMap mapboxMap) { - Location location = mapboxMap.getMyLocation(); - if (location != null) { - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 15)); - } + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.760545, -122.436055), 15)); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java index 75b2378ef7..b4dde8d2cd 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java @@ -11,11 +11,9 @@ import android.view.View; import android.view.ViewGroup; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.TrackingSettings; import com.mapbox.mapboxsdk.maps.UiSettings; import com.mapbox.mapboxsdk.testapp.R; @@ -50,14 +48,6 @@ public class DoubleMapActivity extends AppCompatActivity { mapboxMap = map; mapboxMap.setStyleUrl(Style.DARK); mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(18)); - try { - mapboxMap.setMyLocationEnabled(true); - TrackingSettings settings = mapboxMap.getTrackingSettings(); - settings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - } catch (SecurityException securityException) { - // permission is handled in MainActivity - finish(); - } } /** @@ -106,15 +96,6 @@ public class DoubleMapActivity extends AppCompatActivity { uiSettings.setAttributionEnabled(false); uiSettings.setLogoEnabled(false); - try { - mapboxMap.setMyLocationEnabled(true); - TrackingSettings settings = mapboxMap.getTrackingSettings(); - settings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - } catch (SecurityException securityException) { - // permission is handled in MainActivity - getActivity().finish(); - } - mapboxMap.setOnMapClickListener(point -> { // test if we can open 2 activities after each other startActivity(new Intent(mapViewMini.getContext(), DoubleMapActivity.class)); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java index 9a6079b157..d547866239 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java @@ -8,18 +8,13 @@ import android.view.MenuItem; import com.mapbox.mapboxsdk.annotations.MarkerOptions; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.TrackingSettings; import com.mapbox.mapboxsdk.testapp.R; /** * Test activity showcasing using the map padding API. - * <p> - * This activity tests for correct padding around a marker (Bangalore) and correct padding around MyLocationView. - * </p> */ public class MapPaddingActivity extends AppCompatActivity { @@ -96,24 +91,7 @@ public class MapPaddingActivity extends AppCompatActivity { return true; } - private void toggleGps(boolean enable) { - try { - // Enable user location - mapboxMap.setMyLocationEnabled(enable); - - TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); - trackingSettings.setDismissLocationTrackingOnGesture(false); - trackingSettings.setMyLocationTrackingMode( - enable ? MyLocationTracking.TRACKING_FOLLOW : MyLocationTracking.TRACKING_NONE); - } catch (SecurityException securityException) { - // permission not granted is handled in FeatureOverviewActivity - finish(); - } - } - private void moveToBangalore() { - toggleGps(false); - LatLng bangalore = new LatLng(12.9810816, 77.6368034); CameraPosition cameraPosition = new CameraPosition.Builder() .zoom(16) @@ -129,11 +107,6 @@ public class MapPaddingActivity extends AppCompatActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.action_user_tracking: - if (mapboxMap != null) { - toggleGps(true); - } - return true; case R.id.action_bangalore: if (mapboxMap != null) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java index b42734ea67..52509e3297 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/HeatmapLayerActivity.java @@ -16,6 +16,7 @@ import java.net.URL; import timber.log.Timber; import static com.mapbox.mapboxsdk.style.expressions.Expression.get; +import static com.mapbox.mapboxsdk.style.expressions.Expression.heatmapDensity; import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; import static com.mapbox.mapboxsdk.style.expressions.Expression.linear; import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; @@ -28,6 +29,7 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeColor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeWidth; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapColor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapIntensity; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapOpacity; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapRadius; @@ -51,7 +53,6 @@ public class HeatmapLayerActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_heatmaplayer); - mapView = (MapView) findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); mapView.getMapAsync(map -> { @@ -76,11 +77,20 @@ public class HeatmapLayerActivity extends AppCompatActivity { layer.setSourceLayer(HEATMAP_LAYER_SOURCE); layer.setProperties( - // TODO add heatmap color https://github.com/mapbox/mapbox-gl-native/issues/11172 // Color ramp for heatmap. Domain is 0 (low) to 1 (high). // Begin color ramp at 0-stop with a 0-transparancy color // to create a blur-like effect. - //heatmapColor(), + heatmapColor( + interpolate( + linear(), heatmapDensity(), + literal(0), rgba(33, 102, 172, 0), + literal(0.2), rgb(103, 169, 207), + literal(0.4), rgb(209, 229, 240), + literal(0.6), rgb(253, 219, 199), + literal(0.8), rgb(239, 138, 98), + literal(1), rgb(178, 24, 43) + ) + ), // Increase the heatmap weight based on frequency and property magnitude heatmapWeight( diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java deleted file mode 100644 index eec26cc9a7..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.userlocation; - -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AppCompatActivity; -import android.text.TextUtils; - -import com.mapbox.android.core.permissions.PermissionsListener; -import com.mapbox.android.core.permissions.PermissionsManager; - -import java.util.List; - -/** - * Base class for location aware activities. - */ -public abstract class BaseLocationActivity extends AppCompatActivity implements PermissionsListener { - - private PermissionsManager permissionsManager; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - permissionsManager = new PermissionsManager(this); - } - - @UiThread - protected final void toggleGps(boolean enableGps) { - if (enableGps) { - if (!isRuntimePermissionsRequired()) { - permissionsManager.requestLocationPermissions(this); - } else { - enableLocation(true); - } - } else { - enableLocation(false); - } - } - - @Override - public void onExplanationNeeded(List<String> list) { - Snackbar.make( - findViewById(android.R.id.content), - TextUtils.join("", list.toArray()), - Snackbar.LENGTH_SHORT).show(); - } - - @Override - public void onPermissionResult(boolean isPermissionAccepted) { - enableLocation(isPermissionAccepted); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - private boolean isRuntimePermissionsRequired() { - return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; - } - - protected abstract void enableLocation(boolean enabled); -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java deleted file mode 100644 index ff2559089c..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.userlocation; - -import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.view.Menu; -import android.view.MenuItem; - -import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.testapp.R; - -/** - * Test activity showcasing using a custom location engine. - */ -public class CustomLocationEngineActivity extends BaseLocationActivity { - - private MapView mapView; - private MapboxMap mapboxMap; - private FloatingActionButton locationToggleFab; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_custom_location_engine); - - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(map -> { - mapboxMap = map; - mapboxMap.setLocationSource(MockLocationEngine.getInstance()); - }); - - locationToggleFab = (FloatingActionButton) findViewById(R.id.fabLocationToggle); - locationToggleFab.setOnClickListener(view -> { - if (mapboxMap != null) { - enableLocation(!mapboxMap.isMyLocationEnabled()); - } - }); - } - - @Override - protected void enableLocation(boolean enabled) { - mapboxMap.setMyLocationEnabled(enabled); - if (enabled) { - locationToggleFab.setImageResource(R.drawable.ic_location_disabled); - } else { - locationToggleFab.setImageResource(R.drawable.ic_my_location); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_location_engine, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (mapboxMap != null) { - int itemId = item.getItemId(); - if (itemId == R.id.action_id_location_source_lost) { - mapboxMap.setLocationSource(Mapbox.getLocationEngine()); - return true; - } else if (itemId == R.id.action_id_location_source_mock) { - mapboxMap.setLocationSource(MockLocationEngine.getInstance()); - return true; - } else if (itemId == R.id.action_id_location_source_null) { - mapboxMap.setLocationSource(null); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java deleted file mode 100644 index f4fe710de1..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.userlocation; - -import android.animation.AnimatorListenerAdapter; -import android.animation.TypeEvaluator; -import android.animation.ValueAnimator; -import android.location.Location; - -import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; - -import timber.log.Timber; - -/** - * Sample LocationEngine that provides mocked LOCATIONS simulating GPS updates - */ -public class MockLocationEngine extends LocationEngine { - private static MockLocationEngine INSTANCE; - - private final LocationAnimator locationAnimator; - private boolean running; - private static int counter; - - MockLocationEngine(Location start, Location end) { - locationAnimator = new LocationAnimator(start, end, animation -> { - for (LocationEngineListener listener : locationListeners) { - listener.onLocationChanged((Location) animation.getAnimatedValue()); - } - }); - } - - public static synchronized MockLocationEngine getInstance() { - if (INSTANCE == null) { - INSTANCE = new MockLocationEngine( - MockLocationEngine.createLocation(40.416913, -3.703861), - MockLocationEngine.createLocation(39.461643, -0.368041) - ); - } - return INSTANCE; - } - - public static Location createLocation(double latitude, double longitude) { - Location location = new Location(MockLocationEngine.class.getSimpleName()); - location.setLatitude(latitude); - location.setLongitude(longitude); - return location; - } - - @Override - public void activate() { - // "Connection" is immediate here - for (LocationEngineListener listener : locationListeners) { - listener.onConnected(); - } - } - - @Override - public void deactivate() { - } - - @Override - public boolean isConnected() { - return true; // Always connected - } - - @Override - public Location getLastLocation() { - return null; - } - - @Override - public void requestLocationUpdates() { - if (!running) { - locationAnimator.start(); - running = true; - } - } - - @Override - public void removeLocationUpdates() { - if (running) { - locationAnimator.stop(); - running = false; - Timber.e("LOC %s", counter); - } - } - - @Override - public Type obtainType() { - return Type.MOCK; - } - - private static class LocationAnimator extends AnimatorListenerAdapter { - - private static final long DURATION_ANIMATION = 10000; - private final ValueAnimator locationAnimator; - private long animationTime; - - LocationAnimator(Location start, Location end, ValueAnimator.AnimatorUpdateListener listener) { - locationAnimator = ValueAnimator.ofObject(new LocationEvaluator(), start, end); - locationAnimator.setDuration(DURATION_ANIMATION); - locationAnimator.addUpdateListener(listener); - locationAnimator.addListener(this); - } - - void start() { - locationAnimator.start(); - locationAnimator.setCurrentPlayTime(animationTime); - } - - void stop() { - animationTime = locationAnimator.getCurrentPlayTime(); - locationAnimator.cancel(); - } - - private static class LocationEvaluator implements TypeEvaluator<Location> { - - private Location location = new Location(MockLocationEngine.class.getSimpleName()); - - @Override - public Location evaluate(float fraction, Location startValue, Location endValue) { - counter++; - location.setLatitude(startValue.getLatitude() - + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); - location.setLongitude(startValue.getLongitude() - + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); - return location; - } - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java deleted file mode 100644 index f603050030..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.userlocation; - -import android.graphics.Color; -import android.location.Location; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.view.View; -import android.view.ViewGroup; - -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.Style; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.MapboxMapOptions; -import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.android.core.location.LocationEngineListener; - -/** - * Test activity showcasing how to change the MyLocationView drawable. - */ -public class MyLocationDrawableActivity extends BaseLocationActivity implements LocationEngineListener { - - private MapView mapView; - private MapboxMap mapboxMap; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_my_location_customization); - findViewById(R.id.progress).setVisibility(View.GONE); - - MapboxMapOptions mapboxMapOptions = new MapboxMapOptions(); - mapboxMapOptions.styleUrl(Style.MAPBOX_STREETS); - mapboxMapOptions.myLocationForegroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_android)); - mapboxMapOptions.myLocationBackgroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_android)); - mapboxMapOptions.myLocationForegroundTintColor(Color.GREEN); - mapboxMapOptions.myLocationBackgroundTintColor(Color.YELLOW); - mapboxMapOptions.myLocationBackgroundPadding(new int[] {0, 0, - (int) getResources().getDimension(R.dimen.locationview_background_drawable_padding), - (int) getResources().getDimension(R.dimen.locationview_background_drawable_padding)}); - mapboxMapOptions.myLocationAccuracyTint(Color.RED); - mapboxMapOptions.myLocationAccuracyAlpha(155); - - mapView = new MapView(this, mapboxMapOptions); - mapView.setId(R.id.mapView); - ViewGroup parent = (ViewGroup) findViewById(android.R.id.content); - parent.addView(mapView); - - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(map -> { - mapboxMap = map; - toggleGps(true); - }); - } - - @Override - protected void enableLocation(boolean enabled) { - mapboxMap.setMyLocationEnabled(enabled); - } - - @Override - public void onConnected() { - // Nothing - } - - @Override - public void onLocationChanged(Location location) { - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 14)); - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java deleted file mode 100644 index ff3c4dfbc0..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.userlocation; - -import android.app.Activity; -import android.graphics.Color; -import android.location.Location; -import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.view.View; - -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.TrackingSettings; -import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; -import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.android.core.location.LocationEngineListener; - -/** - * Test activity showcasing how to tint the MyLocationView. - */ -public class MyLocationTintActivity extends BaseLocationActivity implements LocationEngineListener { - - private MapView mapView; - private MapboxMap mapboxMap; - private boolean firstRun; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_my_location_dot_color); - - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(map -> { - mapboxMap = map; - - // enable location updates - toggleGps(true); - - // add some padding - final MyLocationViewSettings myLocationViewSettings = mapboxMap.getMyLocationViewSettings(); - myLocationViewSettings.setPadding(0, 500, 0, 0); - - // enable tracking - TrackingSettings settings = mapboxMap.getTrackingSettings(); - settings.setDismissLocationTrackingOnGesture(false); - settings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - - // handle default button clicks - ViewUtils.attachClickListener( - MyLocationTintActivity.this, - R.id.default_user_dot_coloring_button, - view -> { - myLocationViewSettings.setAccuracyTintColor(ContextCompat.getColor( - MyLocationTintActivity.this, R.color.mapbox_blue)); - myLocationViewSettings.setForegroundTintColor(ContextCompat.getColor( - MyLocationTintActivity.this, R.color.mapbox_blue)); - myLocationViewSettings.setBackgroundTintColor(Color.WHITE); - }); - - // handle tint user dot button clicks - ViewUtils.attachClickListener( - MyLocationTintActivity.this, - R.id.tint_user_dot_button, - view -> { - myLocationViewSettings.setAccuracyTintColor( - ContextCompat.getColor(MyLocationTintActivity.this, R.color.mapboxGreen)); - myLocationViewSettings.setForegroundTintColor( - ContextCompat.getColor(MyLocationTintActivity.this, R.color.mapboxGreen)); - myLocationViewSettings.setBackgroundTintColor(Color.WHITE); - }); - - // handle tint accuracy ring button clicks - ViewUtils.attachClickListener( - MyLocationTintActivity.this, - R.id.user_accuracy_ring_tint_button, - view -> { - myLocationViewSettings.setAccuracyTintColor( - ContextCompat.getColor(MyLocationTintActivity.this, R.color.accent)); - myLocationViewSettings.setForegroundTintColor( - ContextCompat.getColor(MyLocationTintActivity.this, R.color.mapbox_blue)); - myLocationViewSettings.setBackgroundTintColor(Color.WHITE); - }); - - ViewUtils.attachClickListener( - MyLocationTintActivity.this, - R.id.user_dot_transparent_button, - view -> { - myLocationViewSettings.setForegroundTintColor(Color.TRANSPARENT); - myLocationViewSettings.setBackgroundTintColor(Color.TRANSPARENT); - } - ); - }); - - } - - @Override - public void onConnected() { - // Nothing - } - - @Override - public void onLocationChanged(Location location) { - if (mapboxMap != null && firstRun) { - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 15)); - firstRun = false; - } - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - public void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - public void onPause() { - super.onPause(); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - protected void enableLocation(boolean enabled) { - if (enabled) { - mapboxMap.setMyLocationEnabled(true); - if (mapboxMap.getMyLocation() != null) { - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom( - new LatLng(mapboxMap.getMyLocation().getLatitude(), - mapboxMap.getMyLocation().getLongitude()), 15)); - } - } else { - mapboxMap.setMyLocationEnabled(false); - } - } - - private static class ViewUtils { - - public static void attachClickListener( - @NonNull Activity activity, @IdRes int buttonId, @Nullable View.OnClickListener clickListener) { - View view = activity.findViewById(buttonId); - if (view != null) { - view.setOnClickListener(clickListener); - } - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java deleted file mode 100644 index ea3a6f14bc..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.userlocation; - -import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; - -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.testapp.R; - -import timber.log.Timber; - -/** - * Test activity showcasing toggling the user location on the map. - */ -public class MyLocationToggleActivity extends BaseLocationActivity { - - private MapView mapView; - private MapboxMap mapboxMap; - private FloatingActionButton locationToggleFab; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_my_location_toggle); - - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(map -> mapboxMap = map); - - locationToggleFab = (FloatingActionButton) findViewById(R.id.fabLocationToggle); - locationToggleFab.setOnClickListener(view -> { - if (mapboxMap != null) { - toggleGps(!mapboxMap.isMyLocationEnabled()); - } - }); - } - - @Override - protected void enableLocation(boolean enabled) { - Timber.e("Enabling location: %s", enabled); - mapboxMap.setMyLocationEnabled(enabled); - if (enabled) { - locationToggleFab.setImageResource(R.drawable.ic_location_disabled); - } else { - locationToggleFab.setImageResource(R.drawable.ic_my_location); - } - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } - -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java deleted file mode 100644 index ffbb2c1a90..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java +++ /dev/null @@ -1,296 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.userlocation; - -import android.location.Location; -import android.os.Bundle; -import android.support.annotation.NonNull; -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.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import android.widget.Toast; - -import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.MyBearingTracking; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; -import com.mapbox.mapboxsdk.maps.TrackingSettings; -import com.mapbox.mapboxsdk.maps.UiSettings; -import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.android.core.location.LocationEngineListener; - -import timber.log.Timber; - -/** - * Test activity showcasing the different tracking modes the SDK exposes. - * <p> - * This includes MyLocationTracking/MyLocationBearingTracking and how the components can be configured to be dismissed - * using gesture configurations. - * </p> - */ -public class MyLocationTrackingModeActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener, - OnMapReadyCallback, LocationEngineListener { - - public static final int TRACKING_NONE_INDEX = 0; - public static final int TRACKING_FOLLOW_INDEX = 1; - public static final int BEARING_NONE_INDEX = 0; - public static final int BEARING_GPS_INDEX = 1; - public static final int BEARING_COMPASS_INDEX = 2; - - private MapView mapView; - private MapboxMap mapboxMap; - private Spinner locationSpinner; - private Spinner bearingSpinner; - private boolean firstRun = true; - - private MenuItem dismissLocationTrackingOnGestureItem; - private MenuItem dismissBearingTrackingOnGestureItem; - private MenuItem enableRotateGesturesItem; - private MenuItem enableScrollGesturesItem; - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_my_location_tracking); - setupToolbar(); - - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(this); - } - - @Override - public void onMapReady(MapboxMap mapboxMap) { - MyLocationTrackingModeActivity.this.mapboxMap = mapboxMap; - - mapboxMap.setMyLocationEnabled(true); - Mapbox.getLocationEngine().addLocationEngineListener(this); - Mapbox.getLocationEngine().requestLocationUpdates(); - } - - @Override - public void onConnected() { - // Nothing - } - - @Override - public void onLocationChanged(Location location) { - Timber.e("Location changed %s", location); - if (firstRun) { - setInitialLocation(location, 16); - } - } - - private void setInitialLocation(Location location, double zoom) { - mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), zoom)); - mapboxMap.setMyLocationEnabled(true); - setupSpinners(mapboxMap); - firstRun = false; - } - - private void setupToolbar() { - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - - locationSpinner = (Spinner) findViewById(R.id.spinner_location); - ArrayAdapter<CharSequence> locationTrackingAdapter = ArrayAdapter.createFromResource( - actionBar.getThemedContext(), R.array.user_tracking_mode, android.R.layout.simple_spinner_item); - locationTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - locationSpinner.setAdapter(locationTrackingAdapter); - - bearingSpinner = (Spinner) findViewById(R.id.spinner_bearing); - ArrayAdapter<CharSequence> bearingTrackingAdapter = ArrayAdapter.createFromResource( - actionBar.getThemedContext(), R.array.user_bearing_mode, android.R.layout.simple_spinner_item); - bearingTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - bearingSpinner.setAdapter(bearingTrackingAdapter); - } - } - - private void setupSpinners(@NonNull MapboxMap mapboxMap) { - locationSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - bearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - setCheckBoxes(); - - mapboxMap.setOnMyLocationTrackingModeChangeListener(myLocationTrackingMode -> { - locationSpinner.setOnItemSelectedListener(null); - switch (myLocationTrackingMode) { - case MyLocationTracking.TRACKING_NONE: - locationSpinner.setSelection(TRACKING_NONE_INDEX); - break; - case MyLocationTracking.TRACKING_FOLLOW: - locationSpinner.setSelection(TRACKING_FOLLOW_INDEX); - break; - } - locationSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - }); - - mapboxMap.setOnMyBearingTrackingModeChangeListener(myBearingTrackingMode -> { - bearingSpinner.setOnItemSelectedListener(null); - switch (myBearingTrackingMode) { - case MyBearingTracking.NONE: - bearingSpinner.setSelection(BEARING_NONE_INDEX); - break; - - case MyBearingTracking.GPS: - bearingSpinner.setSelection(BEARING_GPS_INDEX); - break; - - case MyBearingTracking.COMPASS: - bearingSpinner.setSelection(BEARING_COMPASS_INDEX); - break; - } - bearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - }); - } - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) throws SecurityException { - TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); - if (parent.getId() == R.id.spinner_location) { - switch (position) { - case TRACKING_NONE_INDEX: - trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE); - break; - - case TRACKING_FOLLOW_INDEX: - trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); - break; - } - } else if (parent.getId() == R.id.spinner_bearing) { - switch (position) { - case BEARING_NONE_INDEX: - trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE); - break; - - case BEARING_GPS_INDEX: - trackingSettings.setMyBearingTrackingMode(MyBearingTracking.GPS); - break; - - case BEARING_COMPASS_INDEX: - trackingSettings.setMyBearingTrackingMode(MyBearingTracking.COMPASS); - break; - } - } - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - Mapbox.getLocationEngine().removeLocationEngineListener(this); - Mapbox.getLocationEngine().removeLocationUpdates(); - mapView.onStop(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_tracking, menu); - dismissLocationTrackingOnGestureItem = menu.findItem(R.id.action_toggle_dismissible_location); - dismissBearingTrackingOnGestureItem = menu.findItem(R.id.action_toggle_dismissible_bearing); - enableRotateGesturesItem = menu.findItem(R.id.action_toggle_rotate_gesture_enabled); - enableScrollGesturesItem = menu.findItem(R.id.action_toggle_scroll_gesture_enabled); - setCheckBoxes(); - return true; - } - - private void setCheckBoxes() { - if (mapboxMap != null && dismissBearingTrackingOnGestureItem != null) { - TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); - UiSettings uiSettings = mapboxMap.getUiSettings(); - dismissBearingTrackingOnGestureItem.setChecked(trackingSettings.isDismissBearingTrackingOnGesture()); - dismissLocationTrackingOnGestureItem.setChecked(trackingSettings.isDismissLocationTrackingOnGesture()); - enableRotateGesturesItem.setChecked(uiSettings.isRotateGesturesEnabled()); - enableScrollGesturesItem.setChecked(uiSettings.isScrollGesturesEnabled()); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - boolean state; - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - case R.id.action_toggle_dismissible_location: - state = !item.isChecked(); - mapboxMap.getTrackingSettings().setDismissLocationTrackingOnGesture(state); - Toast.makeText(this, "Dismiss tracking mode on gesture = " + state, Toast.LENGTH_SHORT).show(); - item.setChecked(state); - return true; - case R.id.action_toggle_dismissible_bearing: - state = !item.isChecked(); - mapboxMap.getTrackingSettings().setDismissBearingTrackingOnGesture(state); - Toast.makeText(this, "Dismiss bearing mode on gesture = " + state, Toast.LENGTH_SHORT).show(); - item.setChecked(state); - return true; - case R.id.action_toggle_rotate_gesture_enabled: - state = !item.isChecked(); - mapboxMap.getUiSettings().setRotateGesturesEnabled(state); - Toast.makeText(this, "Rotate gesture enabled = " + state, Toast.LENGTH_SHORT).show(); - item.setChecked(state); - return true; - case R.id.action_toggle_scroll_gesture_enabled: - state = !item.isChecked(); - mapboxMap.getUiSettings().setScrollGesturesEnabled(state); - Toast.makeText(this, "Scroll gesture enabled = " + state, Toast.LENGTH_SHORT).show(); - item.setChecked(state); - return true; - default: - return super.onOptionsItemSelected(item); - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/activity/Feature.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/activity/Feature.java index d745982388..f3562b5b15 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/activity/Feature.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/activity/Feature.java @@ -9,14 +9,12 @@ public class Feature implements Parcelable { private String label; private String description; private String category; - private boolean requiresLocationPermission; - public Feature(String name, String label, String description, String category, boolean requiresLocationPermission) { + public Feature(String name, String label, String description, String category) { this.name = name; this.label = label; this.description = description; this.category = category; - this.requiresLocationPermission = requiresLocationPermission; } private Feature(Parcel in) { @@ -24,7 +22,6 @@ public class Feature implements Parcelable { label = in.readString(); description = in.readString(); category = in.readString(); - requiresLocationPermission = in.readByte() != 0; } public String getName() { @@ -48,10 +45,6 @@ public class Feature implements Parcelable { return category; } - public boolean isRequiresLocationPermission() { - return requiresLocationPermission; - } - public int describeContents() { return 0; } @@ -61,7 +54,6 @@ public class Feature implements Parcelable { out.writeString(label); out.writeString(description); out.writeString(category); - out.writeByte((byte) (requiresLocationPermission ? 1 : 0)); } public static final Parcelable.Creator<Feature> CREATOR diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled.xml deleted file mode 100644 index 4fedff778b..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled.xml +++ /dev/null @@ -1,9 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#FFFFFF" - android:pathData="M20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06c-1.13,0.12 -2.19,0.46 -3.16,0.97l1.5,1.5C10.16,5.19 11.06,5 12,5c3.87,0 7,3.13 7,7 0,0.94 -0.19,1.84 -0.52,2.65l1.5,1.5c0.5,-0.96 0.84,-2.02 0.97,-3.15L23,13v-2h-2.06zM3,4.27l2.04,2.04C3.97,7.62 3.25,9.23 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c1.77,-0.2 3.38,-0.91 4.69,-1.98L19.73,21 21,19.73 4.27,3 3,4.27zM16.27,17.54C15.09,18.45 13.61,19 12,19c-3.87,0 -7,-3.13 -7,-7 0,-1.61 0.55,-3.09 1.46,-4.27l9.81,9.81z"/> -</vector> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_location_engine.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_location_engine.xml deleted file mode 100644 index e9f461c7ee..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_location_engine.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<android.support.design.widget.CoordinatorLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:id="@id/coordinator_layout" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <com.mapbox.mapboxsdk.maps.MapView - android:id="@id/mapView" - android:layout_width="match_parent" - android:layout_height="match_parent" - app:mapbox_cameraTargetLat="40.416872" - app:mapbox_cameraTargetLng="-3.703807" - app:mapbox_cameraZoom="4"/> - - <android.support.design.widget.FloatingActionButton - android:id="@+id/fabLocationToggle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="end|bottom" - android:layout_margin="@dimen/fab_margin" - android:src="@drawable/ic_my_location" - tools:backgroundTint="@color/primary"/> - -</android.support.design.widget.CoordinatorLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml deleted file mode 100644 index addfe8427b..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<merge xmlns:android="http://schemas.android.com/apk/res/android"> - - <android.support.v4.widget.ContentLoadingProgressBar - android:id="@id/progress" - style="?android:attr/progressBarStyleLarge" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center"/> - -</merge> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml deleted file mode 100644 index de18e265de..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:mapbox="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <com.mapbox.mapboxsdk.maps.MapView - android:id="@id/mapView" - android:layout_width="match_parent" - android:layout_height="match_parent" - mapbox:mapbox_uiAttribution="false" - mapbox:mapbox_uiLogo="false"/> - - <LinearLayout - style="?android:attr/buttonBarStyle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_alignParentBottom="true" - android:background="@color/accent" - android:orientation="horizontal" - android:weightSum="4"> - - <Button - android:id="@+id/default_user_dot_coloring_button" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/button_user_dot_default" - android:textColor="@color/white"/> - - <Button - android:id="@+id/tint_user_dot_button" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/button_user_dot_tint" - android:textColor="@color/white"/> - - <Button - android:id="@+id/user_accuracy_ring_tint_button" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/button_user_accuracy_ring_tint" - android:textColor="@color/white"/> - - <Button - android:id="@+id/user_dot_transparent_button" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/button_user_transparent_tint" - android:textColor="@color/white"/> - - </LinearLayout> - -</RelativeLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml deleted file mode 100644 index 2ec35faf04..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<android.support.design.widget.CoordinatorLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:id="@id/coordinator_layout" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <com.mapbox.mapboxsdk.maps.MapView - android:id="@id/mapView" - android:layout_width="match_parent" - android:layout_height="match_parent"/> - - <android.support.design.widget.FloatingActionButton - android:id="@+id/fabLocationToggle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="end|bottom" - android:layout_margin="@dimen/fab_margin" - android:src="@drawable/ic_my_location" - tools:backgroundTint="@color/primary"/> - -</android.support.design.widget.CoordinatorLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml deleted file mode 100644 index 7236a944e9..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout 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.support.v7.widget.Toolbar - android:id="@+id/toolbar" - android:layout_width="match_parent" - android:layout_height="?attr/actionBarSize" - android:background="@color/primary" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:weightSum="2"> - - <Spinner - android:id="@+id/spinner_location" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" - android:layout_weight="1" /> - - <Spinner - android:id="@+id/spinner_bearing" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginLeft="8dp" - android:layout_marginStart="8dp" - android:layout_weight="1" /> - - </LinearLayout> - - - </android.support.v7.widget.Toolbar> - - <com.mapbox.mapboxsdk.maps.MapView - android:id="@+id/mapView" - android:layout_width="match_parent" - android:layout_height="match_parent" - app:mapbox_myLocationTintColor="@color/primary" - app:mapbox_myLocationAccuracyTintColor="@color/primary" - app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets" - app:mapbox_cameraZoom="8" /> - -</LinearLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_engine.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_engine.xml deleted file mode 100644 index dd7408df09..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_engine.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:mapbox="http://schemas.android.com/apk/res-auto"> - - <item - android:id="@+id/action_id_location_source_lost" - android:title="@string/menuitem_title_change_location_source_lost" - mapbox:showAsAction="never"/> - - <item - android:id="@+id/action_id_location_source_mock" - android:title="@string/menuitem_title_change_location_source_mock" - mapbox:showAsAction="never"/> - - <item - android:id="@+id/action_id_location_source_null" - android:title="@string/menuitem_title_change_location_source_null" - mapbox:showAsAction="never"/> - -</menu>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml index 7132c0c2a9..f0197a9716 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml @@ -2,10 +2,6 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:mapbox="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/action_user_tracking" - android:title="@string/my_location_tracking" - mapbox:showAsAction="never" /> - <item android:id="@+id/action_bangalore" android:title="@string/bangalore" mapbox:showAsAction="never" /> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml deleted file mode 100644 index 940dd9c461..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - - <group android:checkableBehavior="all"> - <item - android:id="@+id/action_toggle_dismissible_location" - android:checkable="true" - android:checked="false" - android:title="@string/menuitem_title_tracking_mode_dismiss_on_gesture" - app:showAsAction="never" /> - <item - android:id="@+id/action_toggle_dismissible_bearing" - android:checkable="true" - android:checked="false" - android:title="@string/menuitem_title_bearing_mode_dismiss_on_gesture" - app:showAsAction="never" /> - <item - android:id="@+id/action_toggle_rotate_gesture_enabled" - android:checkable="true" - android:checked="false" - android:title="@string/menuitem_title_rotate_gesture_enabled" - app:showAsAction="never" /> - <item - android:id="@+id/action_toggle_scroll_gesture_enabled" - android:checkable="true" - android:checked="false" - android:title="@string/menuitem_title_scroll_gesture_enabled" - app:showAsAction="never" /> - </group> - -</menu> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml index e7d140d7d4..04d2e8d56e 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml @@ -2,14 +2,7 @@ <resources> <string name="menuitem_title_concurrent_infowindow">Concurrent Open InfoWindows</string> <string name="menuitem_title_deselect_markers_on_tap">Deselect Markers On Tap</string> - <string name="menuitem_title_tracking_mode_dismiss_on_gesture">Dismiss location tracking on gesture</string> - <string name="menuitem_title_bearing_mode_dismiss_on_gesture">Dismiss bearing tracking on gesture</string> <string name="menuitem_title_reset">Reset</string> - <string name="menuitem_title_rotate_gesture_enabled">Enable rotate gestures</string> - <string name="menuitem_title_scroll_gesture_enabled">Enable scroll gestures</string> - <string name="menuitem_title_change_location_source_lost">Change to LOST location source</string> - <string name="menuitem_title_change_location_source_mock">Change to mock location source</string> - <string name="menuitem_title_change_location_source_null">Reset location source to null</string> <string name="menuitem_change_icon_overlap">Toggle icon overlap</string> <string name="menuitem_filter">Filter layer</string> <string name="menuitem_change_location">Change location</string> @@ -21,10 +14,6 @@ <string name="button_camera_move">Move</string> <string name="button_camera_ease">Ease</string> <string name="button_camera_animate">Animate</string> - <string name="button_user_dot_default">Default</string> - <string name="button_user_dot_tint">Tint dot</string> - <string name="button_user_accuracy_ring_tint">Tint ring</string> - <string name="button_user_transparent_tint">tran</string> <string name="button_open_dialog">Open dialog</string> <string name="button_download_region">Download region</string> <string name="button_list_regions">List regions</string> @@ -73,7 +62,6 @@ <string name="add_a_composite_categorical_function">Add a composite, categorical function</string> <string name="add_a_composite_exponential_function">Add a composite, exponential function</string> <string name="add_a_composite_interval_function">Add a composite, interval function</string> - <string name="my_location_tracking">My Location Tracking</string> <string name="bangalore">Bangalore</string> <string name="list_all_layers_in_the_style">List all layers in the style</string> <string name="list_all_sources_in_the_style">List all sources in the style</string> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml index 94763342d2..4b7ded8e3a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml @@ -7,16 +7,4 @@ <item>1000</item> <item>10000</item> </string-array> - - <string-array name="user_tracking_mode"> - <item>Disabled</item> - <item>Follow tracking</item> - </string-array> - - <string-array name="user_bearing_mode"> - <item>Disabled</item> - <item>GPS bearing</item> - <item>Compass bearing</item> - <!--<item>Combined mode</item>--> - </string-array> </resources>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml index dbc6b59db6..aafeb1cd9c 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml @@ -10,7 +10,6 @@ <string name="category_infowindow">Info Window</string> <string name="category_maplayout">Map Layout</string> <string name="category_offline">Offline</string> - <string name="category_userlocation">User Location</string> <string name="category_style">Styling</string> <string name="category_features">Features</string> <string name="category_storage">Storage</string> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index fc04851293..77ce50ecd0 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -1,10 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <string name="description_user_location_tracking">Tracks the location of the user</string> - <string name="description_user_location_customization">Customize the location of the user</string> - <string name="description_user_location_dot_color">Customize the user location color</string> - <string name="description_user_location_toggle">Toggle location of the user on and off</string> - <string name="description_custom_location_engine">Customize location engine</string> <string name="description_custom_layer">Overlay a custom native layer on the map</string> <string name="description_info_window_adapter">Learn how to create a custom InfoWindow</string> <string name="description_cameraposition">CameraPosition capabilities</string> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml index 0a43af09de..9d34183435 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml @@ -6,6 +6,5 @@ <dimen name="map_padding_bottom">256dp</dimen> <dimen name="map_padding_right">32dp</dimen> <dimen name="map_padding_top">0dp</dimen> - <dimen name="locationview_background_drawable_padding">2dp</dimen> <dimen name="navigation_drawer_width">240dp</dimen> </resources> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index e2bbf5af01..a3885dbf38 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -21,11 +21,6 @@ <string name="activity_scroll_by">Scroll By Method</string> <string name="activity_double_map">Double Map Activity</string> <string name="activity_snapshot">Snapshot Activity</string> - <string name="activity_user_tracking_mode">User tracking mode</string> - <string name="activity_user_tracking_customization">User location drawable</string> - <string name="activity_user_dot_color">User location tint color</string> - <string name="activity_user_location_toggle">User location toggle</string> - <string name="activity_custom_location_engine">Custom location engine</string> <string name="activity_custom_layer">Custom Layer</string> <string name="activity_map_padding">Map Padding</string> <string name="activity_debug_mode">Debug Mode</string> diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index 4ef4ae2f7d..e696bc3ee3 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -8,24 +8,26 @@ ext { ] versions = [ - mapboxServices: '3.0.0-beta.2', + mapboxServices : '3.0.0-beta.2', mapboxTelemetry: '3.0.0-beta.1', - supportLib : '25.4.0', - espresso : '3.0.1', - testRunner : '1.0.1', - leakCanary : '1.5.1', - lost : '3.0.4', - junit : '4.12', - mockito : '2.10.0', - robolectric : '3.5.1', - timber : '4.5.1', - okhttp : '3.9.1' + mapboxGestures : '0.1.0-20180228.152340-13', + supportLib : '25.4.0', + espresso : '3.0.1', + testRunner : '1.0.1', + leakCanary : '1.5.1', + lost : '3.0.4', + junit : '4.12', + mockito : '2.10.0', + robolectric : '3.5.1', + timber : '4.5.1', + okhttp : '3.9.1' ] dependenciesList = [ mapboxJavaServices : "com.mapbox.mapboxsdk:mapbox-sdk-services:${versions.mapboxServices}", mapboxJavaGeoJSON : "com.mapbox.mapboxsdk:mapbox-sdk-geojson:${versions.mapboxServices}", mapboxAndroidTelemetry: "com.mapbox.mapboxsdk:mapbox-android-telemetry:${versions.mapboxTelemetry}", + mapboxAndroidGestures : "com.mapbox.mapboxsdk:mapbox-android-gestures:${versions.mapboxGestures}@aar", // for testApp mapboxJavaTurf : "com.mapbox.mapboxsdk:mapbox-sdk-turf:${versions.mapboxServices}", diff --git a/platform/android/gradle/gradle-javadoc.gradle b/platform/android/gradle/gradle-javadoc.gradle index 39372b4378..cf7f8f743b 100644 --- a/platform/android/gradle/gradle-javadoc.gradle +++ b/platform/android/gradle/gradle-javadoc.gradle @@ -1,21 +1,18 @@ android.libraryVariants.all { variant -> def name = variant.name - // noinspection GroovyAssignabilityCheck task "javadoc$name"(type: Javadoc) { description = "Generates javadoc for build $name" failOnError = false destinationDir = new File(destinationDir, variant.baseName) - source = files(variant.javaCompile.source) - classpath = files(variant.javaCompile.classpath.files) + files(android.bootClasspath) - options.windowTitle("Mapbox Android SDK $VERSION_NAME Reference") - options.docTitle("Mapbox Android SDK $VERSION_NAME") - options.header("Mapbox Android SDK $VERSION_NAME Reference") + source = variant.javaCompile.source + options.windowTitle("Mapbox Maps SDK for Android $VERSION_NAME Reference") + options.docTitle("Mapbox Maps SDK for Android $VERSION_NAME") + options.header("Mapbox Maps SDK for Android $VERSION_NAME Reference") options.bottom("© 2015–2018 Mapbox. All rights reserved.") options.links("http://docs.oracle.com/javase/7/docs/api/") options.linksOffline("http://d.android.com/reference/", "$System.env.ANDROID_HOME/docs/reference") options.overview("src/main/java/overview.html") options.group("Mapbox Android SDK", "com.mapbox.*") - options.group("Third Party Libraries", "com.almeros.*") - exclude '**/R.java', '**/BuildConfig.java', 'com/almeros/**' + exclude '**/R.java', '**/BuildConfig.java' } } diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index 6e6d3cfa67..406364c1d7 100755 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -13,6 +13,7 @@ const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => { var property = spec[`light`][name]; property.name = name; property['light-property'] = true; + property.doc = property.doc.replace(/°/g,'°'); memo.push(property); return memo; }, []); @@ -28,9 +29,6 @@ var layers = Object.keys(spec.layer.type.values).map((type) => { }, []); const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => { - // disabled for now, see https://github.com/mapbox/mapbox-gl-native/issues/11172 - if (name === 'heatmap-color') return memo; - spec[`paint_${type}`][name].name = name; memo.push(spec[`paint_${type}`][name]); return memo; diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp index 549121c7ef..2b953e73f4 100644 --- a/platform/android/src/conversion/collection.hpp +++ b/platform/android/src/conversion/collection.hpp @@ -28,6 +28,7 @@ inline jni::jobject* toArrayList(JNIEnv& env, jni::jarray<T>& array) { inline std::vector<std::string> toVector(JNIEnv& env, jni::jarray<jni::jobject>& array) { std::vector<std::string> vector; std::size_t len = jni::GetArrayLength(env, array); + vector.reserve(len); for (std::size_t i = 0; i < len; i++) { jni::jstring* jstr = reinterpret_cast<jni::jstring*>(jni::GetObjectArrayElement(env, array, i)); diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 6d0bd4de4b..f7b425c40a 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -1,17 +1,121 @@ #include <jni.h> #include <GLES2/gl2.h> +#include <sstream> +#include <android/log.h> +#include <mbgl/style/layers/custom_layer.hpp> -#include <mbgl/util/logging.hpp> +// DEBUGGING -#include <mbgl/style/layers/custom_layer.hpp> +const char* LOG_TAG = "Custom Layer Example"; + +const char* stringFromError(GLenum err) { + switch (err) { + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + +#ifdef GL_TABLE_TOO_LARGE + case GL_TABLE_TOO_LARGE: + return "GL_TABLE_TOO_LARGE"; +#endif + +#ifdef GL_STACK_OVERFLOW + case GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; +#endif + +#ifdef GL_STACK_UNDERFLOW + case GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; +#endif + +#ifdef GL_CONTEXT_LOST + case GL_CONTEXT_LOST: + return "GL_CONTEXT_LOST"; +#endif + + default: + return "GL_UNKNOWN"; + } +} + +struct Error : std::runtime_error { + using std::runtime_error::runtime_error; +}; + +void checkError(const char *cmd, const char *file, int line) { + + GLenum err = GL_NO_ERROR; + if ((err = glGetError()) != GL_NO_ERROR) { + std::ostringstream message; + message << cmd << ": Error " << stringFromError(err); + + // Check for further errors + while ((err = glGetError()) != GL_NO_ERROR) { + message << ", " << stringFromError(err); + } + + message << " at " << file << ":" << line; + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, message.str().c_str()); + throw Error(message.str()); + } +} + +#ifndef NDEBUG +#define GL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }()) +#else +#define GL_CHECK_ERROR(cmd) (cmd) +#endif + +void checkLinkStatus(GLuint program) { + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) { + GLint maxLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + GLchar infoLog[maxLength]; + glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &infoLog[0]); + throw Error(infoLog); + } + +} + +void checkCompileStatus(GLuint shader) { + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + GLchar errorLog[maxLength]; + glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, &errorLog[0]); + throw Error(errorLog); + } +} + +// /DEBUGGING static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; -static const GLchar * fragmentShaderSource = "uniform vec4 fill_color; void main() { gl_FragColor = fill_color; }"; +static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; class ExampleCustomLayer { public: ~ExampleCustomLayer() { - mbgl::Log::Info(mbgl::Event::General, "~ExampleCustomLayer"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "~ExampleCustomLayer"); if (program) { glDeleteBuffers(1, &buffer); glDetachShader(program, vertexShader); @@ -23,38 +127,49 @@ public: } void initialize() { - mbgl::Log::Info(mbgl::Event::General, "Initialize"); - program = glCreateProgram(); - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); - glCompileShader(vertexShader); - glAttachShader(program, vertexShader); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); - glCompileShader(fragmentShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); - a_pos = glGetAttribLocation(program, "a_pos"); - fill_color = glGetUniformLocation(program, "fill_color"); - - GLfloat background[] = { -1,-1, 1,-1, -1,1, 1,1 }; - glGenBuffers(1, &buffer); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Initialize"); + + // Debug info + int maxAttrib; + GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib)); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Max vertex attributes: %i", maxAttrib); + + program = GL_CHECK_ERROR(glCreateProgram()); + vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); + fragmentShader = GL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)); + + GL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(vertexShader)); + checkCompileStatus(vertexShader); + GL_CHECK_ERROR(glAttachShader(program, vertexShader)); + GL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr)); + GL_CHECK_ERROR(glCompileShader(fragmentShader)); + checkCompileStatus(fragmentShader); + GL_CHECK_ERROR(glAttachShader(program, fragmentShader)); + GL_CHECK_ERROR(glLinkProgram(program)); + checkLinkStatus(program); + + a_pos = GL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); + fill_color = GL_CHECK_ERROR(glGetUniformLocation(program, "fill_color")); + + GLfloat background[] = { -1, -1, 1, -1, -1, 1, 1, 1 }; + GL_CHECK_ERROR(glGenBuffers(1, &buffer)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW)); } void render() { - mbgl::Log::Info(mbgl::Event::General, "Render"); - glUseProgram(program); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glEnableVertexAttribArray(a_pos); - glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glUniform4fv(fill_color, 1, color); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Render"); + + GL_CHECK_ERROR(glUseProgram(program)); + GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); + GL_CHECK_ERROR(glEnableVertexAttribArray(a_pos)); + GL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL)); + GL_CHECK_ERROR(glDisable(GL_STENCIL_TEST)); + GL_CHECK_ERROR(glDisable(GL_DEPTH_TEST)); + GL_CHECK_ERROR(glUniform4fv(fill_color, 1, color)); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); + } GLuint program = 0; @@ -70,12 +185,12 @@ public: GLfloat ExampleCustomLayer::color[] = { 0.0f, 1.0f, 0.0f, 1.0f }; jlong JNICALL nativeCreateContext(JNIEnv*, jobject) { - mbgl::Log::Info(mbgl::Event::General, "nativeCreateContext"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeCreateContext"); return reinterpret_cast<jlong>(new ExampleCustomLayer()); } void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat blue, jfloat alpha) { - mbgl::Log::Info(mbgl::Event::General, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "nativeSetColor: %.2f, %.2f, %.2f, %.2f", red, green, blue, alpha); ExampleCustomLayer::color[0] = red; ExampleCustomLayer::color[1] = green; ExampleCustomLayer::color[2] = blue; @@ -83,26 +198,27 @@ void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat b } void nativeInitialize(void *context) { - mbgl::Log::Info(mbgl::Event::General, "nativeInitialize"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeInitialize"); reinterpret_cast<ExampleCustomLayer*>(context)->initialize(); } void nativeRender(void *context, const mbgl::style::CustomLayerRenderParameters& /*parameters*/) { - mbgl::Log::Info(mbgl::Event::General, "nativeRender"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeRender"); reinterpret_cast<ExampleCustomLayer*>(context)->render(); } void nativeContextLost(void */*context*/) { - mbgl::Log::Info(mbgl::Event::General, "nativeContextLost"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeContextLost"); } void nativeDeinitialize(void *context) { - mbgl::Log::Info(mbgl::Event::General, "nativeDeinitialize"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeDeinitialize"); delete reinterpret_cast<ExampleCustomLayer*>(context); } extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - mbgl::Log::Info(mbgl::Event::General, "OnLoad"); + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "OnLoad"); + JNIEnv *env = nullptr; vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6); diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 6a9d7badb0..612619a30b 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -124,8 +124,11 @@ jni::Class<FileSource::ResourceTransformCallback> FileSource::ResourceTransformC std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> callback, int kind, std::string url_) { static auto method = FileSource::ResourceTransformCallback::javaClass.GetMethod<jni::String (jni::jint, jni::String)>(env, "onURL"); auto url = jni::Make<jni::String>(env, url_); + url = callback.Call(env, method, kind, url); - return jni::Make<std::string>(env, url); + auto urlStr = jni::Make<std::string>(env, url); + jni::DeleteLocalRef(env, url); + return urlStr; } } // namespace android diff --git a/platform/android/src/geojson/feature_collection.cpp b/platform/android/src/geojson/feature_collection.cpp index 59f1e317e6..18a41d48fa 100644 --- a/platform/android/src/geojson/feature_collection.cpp +++ b/platform/android/src/geojson/feature_collection.cpp @@ -7,19 +7,23 @@ namespace android { namespace geojson { mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) { - auto jFeatureList = FeatureCollection::features(env, jCollection); - auto jFeatures = java::util::List::toArray<Feature>(env, jFeatureList); - auto size = size_t(jFeatures.Length(env)); - auto collection = mbgl::FeatureCollection(); - collection.reserve(size); - for (size_t i = 0; i < size; i++) { - auto jFeature = jFeatures.Get(env, i); - collection.push_back(Feature::convert(env, jFeature)); - jni::DeleteLocalRef(env, jFeature); - } + if (jCollection) { + auto jFeatureList = FeatureCollection::features(env, jCollection); + auto jFeatures = java::util::List::toArray<Feature>(env, jFeatureList); + auto size = size_t(jFeatures.Length(env)); + collection.reserve(size); + for (size_t i = 0; i < size; i++) { + auto jFeature = jFeatures.Get(env, i); + collection.push_back(Feature::convert(env, jFeature)); + jni::DeleteLocalRef(env, jFeature); + } + + jni::DeleteLocalRef(env, jFeatures); + jni::DeleteLocalRef(env, jFeatureList); + } return collection; } diff --git a/platform/android/src/geojson/line_string.cpp b/platform/android/src/geojson/line_string.cpp index 9e99c72c4c..8eebd53550 100644 --- a/platform/android/src/geojson/line_string.cpp +++ b/platform/android/src/geojson/line_string.cpp @@ -23,8 +23,9 @@ mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<j if (jPointList) { auto jPointArray = java::util::List::toArray<Point>(env, jPointList); - auto size = jPointArray.Length(env); + lineString.reserve(size); + for (std::size_t i = 0; i < size; i++) { auto jPoint = jPointArray.Get(env, i); lineString.push_back(Point::convert(env, jPoint)); diff --git a/platform/android/src/geojson/multi_polygon.cpp b/platform/android/src/geojson/multi_polygon.cpp index f4eb0f6b2a..aadba8c8a6 100644 --- a/platform/android/src/geojson/multi_polygon.cpp +++ b/platform/android/src/geojson/multi_polygon.cpp @@ -22,8 +22,8 @@ mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv &env, jni::Obje jni::DeleteLocalRef(env, jPositionListsList); } - jni::DeleteLocalRef(env, jPointListsListList); jni::DeleteLocalRef(env, jPointListsListArray); + jni::DeleteLocalRef(env, jPointListsListList); } return multiPolygon; diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp index 5feb1b8521..e95376cd2e 100644 --- a/platform/android/src/geojson/point.cpp +++ b/platform/android/src/geojson/point.cpp @@ -1,6 +1,7 @@ #include "point.hpp" #include "../java/util.hpp" #include "../java_types.hpp" +#include "../style/value.hpp" namespace mbgl { namespace android { @@ -19,17 +20,23 @@ mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object<Point> jPoin } mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<Double>*/> jDoubleList) { - auto jDoubleArray = java::util::List::toArray<double>(env, jDoubleList); + mapbox::geojson::point point; + + if (jDoubleList) { + auto jDoubleArray = java::util::List::toArray<jobject>(env, jDoubleList); - jni::jdouble lon = jni::CallMethod<jni::jdouble>(env, - jDoubleArray.Get(env, 0), - *java::Number::doubleValueMethodId); - jni::jdouble lat = jni::CallMethod<jni::jdouble>(env, - jDoubleArray.Get(env, 1), - *java::Number::doubleValueMethodId); - mapbox::geojson::point point(lon, lat); - jni::DeleteLocalRef(env, jDoubleArray); + auto lonObject = jDoubleArray.Get(env, 0); + auto latObject = jDoubleArray.Get(env, 1); + point.x = jni::CallMethod<jni::jdouble>(env, lonObject, + *java::Number::doubleValueMethodId); + point.y = jni::CallMethod<jni::jdouble>(env, latObject, + *java::Number::doubleValueMethodId); + + jni::DeleteLocalRef(env, lonObject); + jni::DeleteLocalRef(env, latObject); + jni::DeleteLocalRef(env, jDoubleArray); + } return point; } diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp index 1fc5f9789f..01ffc6530b 100644 --- a/platform/android/src/map/camera_position.cpp +++ b/platform/android/src/map/camera_position.cpp @@ -33,7 +33,9 @@ mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, jni::Obje static auto tilt = CameraPosition::javaClass.GetField<jni::jdouble>(env, "tilt"); static auto zoom = CameraPosition::javaClass.GetField<jni::jdouble>(env, "zoom"); - auto center = LatLng::getLatLng(env, position.Get(env, target)); + auto jtarget = position.Get(env, target); + auto center = LatLng::getLatLng(env, jtarget); + jni::DeleteLocalRef(env, jtarget); return mbgl::CameraOptions { center, diff --git a/platform/android/src/map/image.cpp b/platform/android/src/map/image.cpp index 5f5c90eddd..c3b22b0054 100644 --- a/platform/android/src/map/image.cpp +++ b/platform/android/src/map/image.cpp @@ -16,7 +16,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, jni::Object<Image> image) { auto width = image.Get(env, widthField); auto pixelRatio = image.Get(env, pixelRatioField); auto pixels = image.Get(env, bufferField); - auto name = jni::Make<std::string>(env, image.Get(env, nameField)); + auto jName = image.Get(env, nameField); + auto name = jni::Make<std::string>(env, jName); + jni::DeleteLocalRef(env, jName); jni::NullCheck(env, &pixels); std::size_t size = pixels.Length(env); @@ -27,7 +29,7 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, jni::Object<Image> image) { } jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get())); - + jni::DeleteLocalRef(env, pixels); return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio}; } diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp index a58cf975a7..53f210ac33 100644 --- a/platform/android/src/style/conversion/property_value.hpp +++ b/platform/android/src/style/conversion/property_value.hpp @@ -2,6 +2,7 @@ #include <mbgl/style/property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> +#include <mbgl/style/heatmap_color_property_value.hpp> #include "../../conversion/conversion.hpp" #include "../../conversion/constant.hpp" #include "types.hpp" @@ -70,6 +71,18 @@ struct Converter<jni::jobject*, mbgl::style::DataDrivenPropertyValue<T>> { } }; +/** + * Convert core heat map color property value to java + */ +template <> +struct Converter<jni::jobject*, mbgl::style::HeatmapColorPropertyValue> { + + Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::HeatmapColorPropertyValue value) const { + PropertyValueEvaluator<mbgl::style::HeatmapColorPropertyValue> evaluator(env); + return *convert<jni::jobject*>(env, value.evaluate(evaluator)); + } +}; + } // namespace conversion } // namespace android } // namespace mbgl diff --git a/platform/android/src/style/layers/heatmap_layer.cpp b/platform/android/src/style/layers/heatmap_layer.cpp index 609499ec93..b3d90faab7 100644 --- a/platform/android/src/style/layers/heatmap_layer.cpp +++ b/platform/android/src/style/layers/heatmap_layer.cpp @@ -79,6 +79,16 @@ namespace android { layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapIntensityTransition(options); } + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getDefaultHeatmapColor(); + } + Result<jni::jobject*> converted = convert<jni::jobject*>(env, propertyValue); + return jni::Object<jni::ObjectTag>(*converted); + } + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapOpacity(jni::JNIEnv& env) { using namespace mbgl::android::conversion; Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapOpacity()); @@ -125,6 +135,7 @@ namespace android { METHOD(&HeatmapLayer::getHeatmapIntensityTransition, "nativeGetHeatmapIntensityTransition"), METHOD(&HeatmapLayer::setHeatmapIntensityTransition, "nativeSetHeatmapIntensityTransition"), METHOD(&HeatmapLayer::getHeatmapIntensity, "nativeGetHeatmapIntensity"), + METHOD(&HeatmapLayer::getHeatmapColor, "nativeGetHeatmapColor"), METHOD(&HeatmapLayer::getHeatmapOpacityTransition, "nativeGetHeatmapOpacityTransition"), METHOD(&HeatmapLayer::setHeatmapOpacityTransition, "nativeSetHeatmapOpacityTransition"), METHOD(&HeatmapLayer::getHeatmapOpacity, "nativeGetHeatmapOpacity")); diff --git a/platform/android/src/style/layers/heatmap_layer.hpp b/platform/android/src/style/layers/heatmap_layer.hpp index 85f9f0292e..9e8908b062 100644 --- a/platform/android/src/style/layers/heatmap_layer.hpp +++ b/platform/android/src/style/layers/heatmap_layer.hpp @@ -39,6 +39,8 @@ public: void setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); jni::Object<TransitionOptions> getHeatmapIntensityTransition(jni::JNIEnv&); + jni::Object<jni::ObjectTag> getHeatmapColor(jni::JNIEnv&); + jni::Object<jni::ObjectTag> getHeatmapOpacity(jni::JNIEnv&); void setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); jni::Object<TransitionOptions> getHeatmapOpacityTransition(jni::JNIEnv&); diff --git a/platform/android/src/style/layers/layer.cpp.ejs b/platform/android/src/style/layers/layer.cpp.ejs index 1debb096a3..b08f0ec4dc 100644 --- a/platform/android/src/style/layers/layer.cpp.ejs +++ b/platform/android/src/style/layers/layer.cpp.ejs @@ -48,12 +48,25 @@ namespace android { // Property getters <% for (const property of properties) { -%> +<% if (property.name != 'heatmap-color') { -%> jni::Object<jni::ObjectTag> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(jni::JNIEnv& env) { using namespace mbgl::android::conversion; Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::<%- camelize(type) %>Layer>()-><%- camelize(type) %>Layer::get<%- camelize(property.name) %>()); return jni::Object<jni::ObjectTag>(*converted); } +<% } else { -%> + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getDefaultHeatmapColor(); + } + Result<jni::jobject*> converted = convert<jni::jobject*>(env, propertyValue); + return jni::Object<jni::ObjectTag>(*converted); + } + +<% } -%> <% if (property.transition) { -%> jni::Object<TransitionOptions> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) { using namespace mbgl::android::conversion; diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index 0cd6995969..249387ea51 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -45,6 +45,11 @@ namespace android { source.as<mbgl::style::ImageSource>()->setImage(Bitmap::GetImage(env, bitmap)); } + void ImageSource::setCoordinates(jni::JNIEnv& env, jni::Object<LatLngQuad> coordinatesObject) { + source.as<mbgl::style::ImageSource>()->setCoordinates( + LatLngQuad::getLatLngArray(env, coordinatesObject)); + } + jni::Class<ImageSource> ImageSource::javaClass; jni::Object<Source> ImageSource::createJavaPeer(jni::JNIEnv& env) { @@ -66,7 +71,8 @@ namespace android { "finalize", METHOD(&ImageSource::setURL, "nativeSetUrl"), METHOD(&ImageSource::getURL, "nativeGetUrl"), - METHOD(&ImageSource::setImage, "nativeSetImage") + METHOD(&ImageSource::setImage, "nativeSetImage"), + METHOD(&ImageSource::setCoordinates, "nativeSetCoordinates") ); } diff --git a/platform/android/src/style/sources/image_source.hpp b/platform/android/src/style/sources/image_source.hpp index f0af28d357..6021a03dc3 100644 --- a/platform/android/src/style/sources/image_source.hpp +++ b/platform/android/src/style/sources/image_source.hpp @@ -30,6 +30,8 @@ public: void setImage(jni::JNIEnv&, jni::Object<Bitmap>); + void setCoordinates(jni::JNIEnv&, jni::Object<LatLngQuad>); + private: jni::Object<Source> createJavaPeer(jni::JNIEnv&); diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index 37af150ac5..2ba7757fdf 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -205,6 +205,7 @@ In style JSON | In TileJSON | In the SDK `tileSize` | — | `MGLTileSourceOptionTileSize` `attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security) `scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem` +`encoding` | – | `MGLTileSourceOptionDEMEncoding` ### Shape sources diff --git a/platform/darwin/src/MGLAccountManager.m b/platform/darwin/src/MGLAccountManager.m index 5bd96ce337..73da8ddd63 100644 --- a/platform/darwin/src/MGLAccountManager.m +++ b/platform/darwin/src/MGLAccountManager.m @@ -64,9 +64,7 @@ [MGLAccountManager sharedManager].accessToken = accessToken; #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - // Update MGLMapboxEvents - // NOTE: This is (likely) the initial setup of MGLMapboxEvents - [MGLMapboxEvents sharedManager]; + [MGLMapboxEvents setupWithAccessToken:accessToken]; #endif } diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h index 3dc268db60..2d75fa14d8 100644 --- a/platform/darwin/src/MGLTileSource.h +++ b/platform/darwin/src/MGLTileSource.h @@ -117,6 +117,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos; */ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem; + /** Tile coordinate systems that determine how tile coordinates in tile URLs are interpreted. @@ -141,6 +142,35 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) { MGLTileCoordinateSystemTMS }; + +/** + An `NSNumber` object containing an unsigned integer that specifies the encoding + formula for raster-dem tilesets. The integer corresponds to one of + the constants described in `MGLDEMEncoding`. + + The default value for this option is `MGLDEMEncodingMapbox`. + + This option is not supported by the TileJSON spec. + */ +extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionDEMEncoding; + +/** + The encoding formula used to generate the raster-dem tileset +*/ + +typedef NS_ENUM(NSUInteger, MGLDEMEncoding) { + + /** + Raster tiles generated with the [Mapbox encoding formula](https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb). + */ + MGLDEMEncodingMapbox = 0, + + /** + Raster tiles generated with the [Mapzen Terrarium encoding formula](https://aws.amazon.com/public-datasets/terrain/). + */ + MGLDEMEncodingTerrarium +}; + /** `MGLTileSource` is a map content source that supplies map tiles to be shown on the map. The location of and metadata about the tiles are defined either by an diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm index bc985bd728..c37812ab8e 100644 --- a/platform/darwin/src/MGLTileSource.mm +++ b/platform/darwin/src/MGLTileSource.mm @@ -19,6 +19,7 @@ const MGLTileSourceOption MGLTileSourceOptionCoordinateBounds = @"MGLTileSourceO const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString = @"MGLTileSourceOptionAttributionHTMLString"; const MGLTileSourceOption MGLTileSourceOptionAttributionInfos = @"MGLTileSourceOptionAttributionInfos"; const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSourceOptionTileCoordinateSystem"; +const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOptionDEMEncoding"; @implementation MGLTileSource @@ -129,5 +130,22 @@ mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTem } } + if (NSNumber *demEncodingNumber = options[MGLTileSourceOptionDEMEncoding]) { + if (![demEncodingNumber isKindOfClass:[NSValue class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionDEMEncoding must be set to an NSValue or NSNumber."]; + } + MGLDEMEncoding demEncoding; + [demEncodingNumber getValue:&demEncoding]; + switch (demEncoding) { + case MGLDEMEncodingMapbox: + tileSet.encoding = mbgl::Tileset::DEMEncoding::Mapbox; + break; + case MGLDEMEncodingTerrarium: + tileSet.encoding = mbgl::Tileset::DEMEncoding::Terrarium; + break; + } + } + return tileSet; } diff --git a/platform/darwin/test/MGLCoordinateFormatterTests.m b/platform/darwin/test/MGLCoordinateFormatterTests.m index ac083fa103..d693f739ec 100644 --- a/platform/darwin/test/MGLCoordinateFormatterTests.m +++ b/platform/darwin/test/MGLCoordinateFormatterTests.m @@ -24,7 +24,12 @@ coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239); XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°54′48″N, 77°1′57″W"); XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°54′48″ north, 77°1′57″ west"); - XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west"); + if (@available(iOS 9.0, *)) { + XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west"); + } else { + // Foundation in iOS 8 does not know how to pluralize coordinates. + XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s), 54 minute(s), and 48 second(s) north by 77 degree(s), 1 minute(s), and 57 second(s) west"); + } shortFormatter.allowsSeconds = NO; mediumFormatter.allowsSeconds = NO; @@ -33,7 +38,12 @@ coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239); XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°55′N, 77°2′W"); XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°55′ north, 77°2′ west"); - XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west"); + if (@available(iOS 9.0, *)) { + XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west"); + } else { + // Foundation in iOS 8 does not know how to pluralize coordinates. + XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s) and 55 minute(s) north by 77 degree(s) and 2 minute(s) west"); + } shortFormatter.allowsMinutes = NO; mediumFormatter.allowsMinutes = NO; @@ -42,7 +52,12 @@ coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239); XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"39°N, 77°W"); XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"39° north, 77° west"); - XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west"); + if (@available(iOS 9.0, *)) { + XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west"); + } else { + // Foundation in iOS 8 does not know how to pluralize coordinates. + XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degree(s) north by 77 degree(s) west"); + } } @end diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift index 5a6e00bc4e..a216d9ad1c 100644 --- a/platform/darwin/test/MGLDocumentationExampleTests.swift +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -391,7 +391,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { } //#-end-example-code - wait(for: [expectation], timeout: 1) + wait(for: [expectation], timeout: 5) } // For testMGLMapView(). diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index 821c5dbdb4..a5ed2f7bf5 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -573,23 +573,27 @@ using namespace std::string_literals; } - (void)testConditionalExpressionObject { - { - NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"]; - NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES]; - NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO]; - NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression]; - NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO]; - XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); - XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression); - XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO); - XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); - } - { - NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"]; - NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO]; - XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); - XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO); - XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); + // FIXME: This test crashes because iOS 8 doesn't have `+[NSExpression expressionForConditional:trueExpression:falseExpression:]`. + // https://github.com/mapbox/mapbox-gl-native/issues/11007 + if (@available(iOS 9.0, *)) { + { + NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"]; + NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES]; + NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO]; + NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression]; + NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); + } + { + NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"]; + NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO); + XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression); + } } } diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm index 818ad8200e..14b64be854 100644 --- a/platform/darwin/test/MGLFeatureTests.mm +++ b/platform/darwin/test/MGLFeatureTests.mm @@ -298,29 +298,36 @@ } - (void)testShapeCollectionFeatureGeoJSONDictionary { - MGLPointAnnotation *pointFeature = [[MGLPointAnnotation alloc] init]; + MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init]; CLLocationCoordinate2D pointCoordinate = { 10, 10 }; pointFeature.coordinate = pointCoordinate; CLLocationCoordinate2D coord1 = { 0, 0 }; CLLocationCoordinate2D coord2 = { 10, 10 }; CLLocationCoordinate2D coords[] = { coord1, coord2 }; - MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coords count:2]; + MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coords count:2]; + + MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature, polylineFeature]]; - MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature, - polyline]]; // A GeoJSON feature NSDictionary *geoJSONFeature = [shapeCollectionFeature geoJSONDictionary]; // it has the correct geometry NSDictionary *expectedGeometry = @{@"type": @"GeometryCollection", @"geometries": @[ - @{@"type": @"Point", - @"coordinates": @[@(pointCoordinate.longitude), @(pointCoordinate.latitude)]}, - @{@"type": @"LineString", - @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)], - @[@(coord2.longitude), @(coord2.latitude)]]} - ]}; + @{ @"geometry": @{@"type": @"Point", + @"coordinates": @[@(pointCoordinate.longitude), @(pointCoordinate.latitude)]}, + @"properties": [NSNull null], + @"type": @"Feature", + }, + @{ @"geometry": @{@"type": @"LineString", + @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)]]}, + @"properties": [NSNull null], + @"type": @"Feature", + } + ] + }; XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); // When the shape collection is created with an empty array of shapes diff --git a/platform/darwin/test/MGLTileSetTests.mm b/platform/darwin/test/MGLTileSetTests.mm index 4d5e1fcd05..74c84184e1 100644 --- a/platform/darwin/test/MGLTileSetTests.mm +++ b/platform/darwin/test/MGLTileSetTests.mm @@ -102,6 +102,23 @@ // the scheme is reflected by the mbgl tileset XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::TMS); + + // when the dem enciding is changed using an NSNumber + tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{ + MGLTileSourceOptionDEMEncoding: @(MGLDEMEncodingTerrarium), + }); + + // the encoding is reflected by the mbgl tileset + XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium); + + // when the dem enciding is changed using an NSValue + MGLDEMEncoding terrarium = MGLDEMEncodingTerrarium; + tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{ + MGLTileSourceOptionDEMEncoding: [NSValue value:&terrarium withObjCType:@encode(MGLDEMEncoding)], + }); + + // the encoding is reflected by the mbgl tileset + XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium); } - (void)testInvalidTileSet { diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index c11fc63ebd..95759a2f9b 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -17,6 +17,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Added an `MGLComputedShapeSource` class that allows applications to supply vector data to a style layer on a per-tile basis. ([#9983](https://github.com/mapbox/mapbox-gl-native/pull/9983)) * A style can now display smooth hillshading and customize its appearance at runtime using the `MGLHillshadeStyleLayer` class. Hillshading is based on a rasterized digital elevation model supplied by the `MGLRasterDEMSource` class. ([#10642](https://github.com/mapbox/mapbox-gl-native/pull/10642)) * The `MGLSymbolStyleLayer.textFontNames` property can now depend on a feature’s attributes. ([#10850](https://github.com/mapbox/mapbox-gl-native/pull/10850)) +* Added `MGLShapeSourceOptionWrapsCoordinates`, to specify whether the shape of an `MGLComputedShapeSource` should be wrapped to accommodate coordinates with longitudes beyond −180 and 180; and `MGLShapeSourceOptionClipsCoordinates`, to specify whether the shape of an `MGLComputedShapeSource` should be clipped at the edge of each tile. ([#11041](https://github.com/mapbox/mapbox-gl-native/pull/11041)) +* Added support for Mapzen Terrarium DEM encoding. ([#11274](https://github.com/mapbox/mapbox-gl-native/pull/11274)) ### Map rendering @@ -27,6 +29,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed an issue preventing `MGLImageSource`s from drawing on the map when the map is zoomed in and tilted. ([#10677](https://github.com/mapbox/mapbox-gl-native/pull/10677)) * Improved the sharpness of raster tiles on Retina displays. ([#10984](https://github.com/mapbox/mapbox-gl-native/pull/10984)) * Fixed a crash parsing a malformed style. ([#11001](https://github.com/mapbox/mapbox-gl-native/pull/11001)) +* Reduced memory usage by clearing in-memory tile cache before entering background. ([#11197](https://github.com/mapbox/mapbox-gl-native/pull/11197)) ### Annotations @@ -39,10 +42,19 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ### Other changes +* The `-[MGLMapView convertRect:toCoordinateBoundsFromView:]` method and the `MGLMapView.visibleCoordinateBounds` property’s getter now indicate that the coordinate bounds straddles the antimeridian by extending one side beyond ±180 degrees longitude. ([#11265](https://github.com/mapbox/mapbox-gl-native/pull/11265)) * Feature querying results now account for the `MGLSymbolStyleLayer.circleStrokeWidth` property. ([#10897](https://github.com/mapbox/mapbox-gl-native/pull/10897)) * Fixed an issue preventing labels from being transliterated when VoiceOver was enabled on iOS 10._x_ and below. ([#10881](https://github.com/mapbox/mapbox-gl-native/pull/10881)) * Labels are now transliterated from more languages when VoiceOver is enabled. ([#10881](https://github.com/mapbox/mapbox-gl-native/pull/10881)) * Long-pressing the attribution button causes the SDK’s version number to be displayed in the action sheet that appears. ([#10650](https://github.com/mapbox/mapbox-gl-native/pull/10650)) +* Reduced offline download size for styles with symbol layers that render only icons, and no text. ([#11055](https://github.com/mapbox/mapbox-gl-native/pull/11055)) +* Added haptic feedback that occurs when the user rotates the map to due north, configurable via `MGLMapView.hapticFeedbackEnabled`. ([#10847](https://github.com/mapbox/mapbox-gl-native/pull/10847)) +* Added `MGLMapView.showsScale` as the recommended way to show the scale bar. This property can be set directly in Interface Builder. ([#11335](https://github.com/mapbox/mapbox-gl-native/pull/11335)) +* Fixed an issue where the scale bar would not appear until the map had moved. ([#11335](https://github.com/mapbox/mapbox-gl-native/pull/11335)) + +## 3.7.5 - February 16, 2018 + +* Fixed an issue where requesting location services permission would trigger an unrecoverable loop. ([#11229](https://github.com/mapbox/mapbox-gl-native/pull/11229)) ## 3.7.4 - February 12, 2018 diff --git a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec index 56714a5211..56f0682073 100644 --- a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec +++ b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.0.0-beta.1' + version = '4.0.0-beta.2' m.name = 'Mapbox-iOS-SDK-nightly-dynamic' m.version = "#{version}-nightly" diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec index fb7e55bbd3..6c9bc3b564 100644 --- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec +++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.0.0-beta.1' + version = '4.0.0-beta.2' m.name = 'Mapbox-iOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index ee35103700..657417da19 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.0.0-beta.1' + version = '4.0.0-beta.2' m.name = 'Mapbox-iOS-SDK' m.version = version diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 83d38330cd..d1d886e0af 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -166,9 +166,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [self restoreState:nil]; self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"]; - self.mapView.scaleBar.hidden = NO; + self.mapView.showsScale = YES; self.mapView.showsUserHeadingIndicator = YES; - self.hudLabel.hidden = YES; if ([UIFont respondsToSelector:@selector(monospacedDigitSystemFontOfSize:weight:)]) { self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular]; } @@ -218,6 +217,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [defaults setInteger:self.mapView.userTrackingMode forKey:@"MBXUserTrackingMode"]; [defaults setBool:self.mapView.showsUserLocation forKey:@"MBXShowsUserLocation"]; [defaults setInteger:self.mapView.debugMask forKey:@"MBXDebugMask"]; + [defaults setBool:self.showZoomLevelEnabled forKey:@"MBXShowsZoomLevelHUD"]; [defaults synchronize]; } @@ -243,6 +243,11 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { { self.mapView.debugMask = (MGLMapDebugMaskOptions)uncheckedDebugMask; } + if ([defaults boolForKey:@"MBXShowsZoomLevelHUD"]) + { + self.showZoomLevelEnabled = YES; + [self updateHUD]; + } } - (UIInterfaceOrientationMask)supportedInterfaceOrientations @@ -1441,7 +1446,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { // source, categorical function that sets any feature with a "fill" attribute value of true to red color and anything without to green MGLFillStyleLayer *fillStyleLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:shapeSource]; - fillStyleLayer.fillColor = [NSExpression expressionWithFormat:@"TERNARY(fill, %@, %@)", [UIColor greenColor], [UIColor redColor]]; + fillStyleLayer.fillColor = [NSExpression expressionWithFormat:@"TERNARY(fill == YES, %@, %@)", [UIColor greenColor], [UIColor redColor]]; // source, identity function that sets any feature with an "opacity" attribute to use that value and anything without to 1.0 fillStyleLayer.fillOpacity = [NSExpression expressionWithFormat:@"TERNARY(opacity != nil, opacity, 1.0)"]; @@ -1955,6 +1960,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { - (void)updateHUD { if (!self.reuseQueueStatsEnabled && !self.showZoomLevelEnabled) return; + if (self.hudLabel.hidden) self.hudLabel.hidden = NO; + NSString *hudString; if (self.reuseQueueStatsEnabled) { diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard index 507582213f..04e4f9ab45 100644 --- a/platform/ios/app/Main.storyboard +++ b/platform/ios/app/Main.storyboard @@ -1,11 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G8c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff"> <device id="retina4_7" orientation="portrait"> <adaptation id="fullscreen"/> </device> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/> <capability name="Navigation items with more than one left or right bar item" minToolsVersion="7.0"/> @@ -26,40 +26,44 @@ <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kNe-zV-9ha" customClass="MGLMapView"> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <subviews> + <button hidden="YES" opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB"> + <rect key="frame" x="8" y="102" width="40" height="20"/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <accessibility key="accessibilityConfiguration"> + <accessibilityTraits key="traits" button="YES" notEnabled="YES"/> + </accessibility> + <constraints> + <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="40" id="viz-kn-dfK"/> + <constraint firstAttribute="height" constant="20" id="zSU-Mb-f1v"/> + </constraints> + <fontDescription key="fontDescription" type="system" pointSize="10"/> + <inset key="contentEdgeInsets" minX="4" minY="2" maxX="4" maxY="2"/> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius"> + <integer key="value" value="2"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </button> + </subviews> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <gestureRecognizers/> + <constraints> + <constraint firstItem="58y-pX-YyB" firstAttribute="top" secondItem="kNe-zV-9ha" secondAttribute="topMargin" constant="30" id="89S-qk-mPR"/> + <constraint firstItem="58y-pX-YyB" firstAttribute="leading" secondItem="kNe-zV-9ha" secondAttribute="leadingMargin" id="cXU-Qh-ilW"/> + <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="58y-pX-YyB" secondAttribute="trailing" id="txU-Gp-2du"/> + </constraints> <connections> <outlet property="delegate" destination="WaX-pd-UZQ" id="za0-3B-qR6"/> <outletCollection property="gestureRecognizers" destination="lfd-mn-7en" appends="YES" id="0PH-gH-GRm"/> </connections> </view> - <button opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB"> - <rect key="frame" x="319" y="606" width="40" height="21"/> - <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> - <accessibility key="accessibilityConfiguration"> - <accessibilityTraits key="traits" button="YES" notEnabled="YES"/> - </accessibility> - <constraints> - <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="40" id="OL2-l5-I2f"/> - <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="20" id="xHg-ye-wzT"/> - </constraints> - <fontDescription key="fontDescription" type="system" pointSize="10"/> - <inset key="contentEdgeInsets" minX="4" minY="2" maxX="4" maxY="2"/> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius"> - <integer key="value" value="2"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </button> </subviews> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstItem="kNe-zV-9ha" firstAttribute="leading" secondItem="Z9X-fc-PUC" secondAttribute="leading" id="53e-Tz-QxF"/> <constraint firstItem="kNe-zV-9ha" firstAttribute="bottom" secondItem="m8o-i7-QIy" secondAttribute="top" id="Etp-BC-E1N"/> <constraint firstAttribute="trailing" secondItem="kNe-zV-9ha" secondAttribute="trailing" id="MGr-8G-VEb"/> - <constraint firstItem="58y-pX-YyB" firstAttribute="trailing" secondItem="Z9X-fc-PUC" secondAttribute="trailingMargin" id="O3a-bR-boI"/> - <constraint firstItem="58y-pX-YyB" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Z9X-fc-PUC" secondAttribute="leadingMargin" id="ceH-yz-ewY"/> - <constraint firstItem="m8o-i7-QIy" firstAttribute="top" secondItem="58y-pX-YyB" secondAttribute="bottom" constant="40" id="cjh-ZS-Mv4"/> <constraint firstItem="kNe-zV-9ha" firstAttribute="top" secondItem="Z9X-fc-PUC" secondAttribute="top" id="qMm-e9-jxH"/> </constraints> </view> @@ -133,14 +137,14 @@ <autoresizingMask key="autoresizingMask"/> <subviews> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Inactive Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JtH-Ce-MI5"> - <rect key="frame" x="15" y="6" width="174.5" height="19.5"/> + <rect key="frame" x="16" y="6" width="174.5" height="19.5"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" type="system" pointSize="16"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="456 resources (789 MB)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="tTJ-jv-U9v"> - <rect key="frame" x="15" y="25.5" width="128" height="13.5"/> + <rect key="frame" x="16" y="25.5" width="128.5" height="13.5"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" type="system" pointSize="11"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> @@ -157,14 +161,14 @@ <autoresizingMask key="autoresizingMask"/> <subviews> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Active Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9ZK-gS-wJ4"> - <rect key="frame" x="15" y="6" width="163" height="19.5"/> + <rect key="frame" x="16" y="6" width="163" height="19.5"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" type="system" pointSize="16"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Downloading 123 of 456 resources… (789 MB downloaded)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="0xK-p8-Mmh"> - <rect key="frame" x="15" y="25.5" width="310.5" height="13.5"/> + <rect key="frame" x="16" y="25.5" width="311" height="13.5"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <fontDescription key="fontDescription" type="system" pointSize="11"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> @@ -201,7 +205,7 @@ <navigationController automaticallyAdjustsScrollViewInsets="NO" id="PSe-Ot-7Ff" sceneMemberID="viewController"> <toolbarItems/> <navigationBar key="navigationBar" contentMode="scaleToFill" id="ONr-CS-J5X"> - <rect key="frame" x="0.0" y="0.0" width="320" height="44"/> + <rect key="frame" x="0.0" y="20" width="375" height="44"/> <autoresizingMask key="autoresizingMask"/> </navigationBar> <nil name="viewControllers"/> diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index 02d23067ef..1f2803f3ec 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -154,6 +154,7 @@ In style JSON | In TileJSON | In the SDK `tileSize` | — | `MGLTileSourceOptionTileSize` `attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security) `scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem` +`encoding` | – | `MGLTileSourceOptionDEMEncoding` ### Shape sources diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index f66aa74965..b2d89fe962 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -187,13 +187,77 @@ 404C26E51D89B877000AA13D /* MGLTileSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 404C26E11D89B877000AA13D /* MGLTileSource.mm */; }; 404C26E71D89C55D000AA13D /* MGLTileSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E61D89C515000AA13D /* MGLTileSource_Private.h */; }; 404C26E81D89C55D000AA13D /* MGLTileSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E61D89C515000AA13D /* MGLTileSource_Private.h */; }; - 40599F0C1DEE1B7600182B5D /* api_mapbox_staging.der in Resources */ = {isa = PBXBuildFile; fileRef = 40599F001DEE1B2400182B5D /* api_mapbox_staging.der */; }; - 40599F0D1DEE1B7A00182B5D /* api_mapbox_com-digicert_2016.der in Resources */ = {isa = PBXBuildFile; fileRef = 40599F011DEE1B2400182B5D /* api_mapbox_com-digicert_2016.der */; }; - 40599F0E1DEE1B7E00182B5D /* api_mapbox_com-geotrust_2016.der in Resources */ = {isa = PBXBuildFile; fileRef = 40599F021DEE1B2400182B5D /* api_mapbox_com-geotrust_2016.der */; }; + 406E99B91FFEFF1B00D9FFCC /* MMEEventLogReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 406E99B11FFEFED500D9FFCC /* MMEEventLogReportViewController.m */; }; + 406E99BA1FFEFF1B00D9FFCC /* MMEEventLogReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 406E99B11FFEFED500D9FFCC /* MMEEventLogReportViewController.m */; }; + 406E99BB1FFF006C00D9FFCC /* MMEUINavigation.m in Sources */ = {isa = PBXBuildFile; fileRef = 406E99B21FFEFED500D9FFCC /* MMEUINavigation.m */; }; + 406E99BC1FFF006D00D9FFCC /* MMEUINavigation.m in Sources */ = {isa = PBXBuildFile; fileRef = 406E99B21FFEFED500D9FFCC /* MMEUINavigation.m */; }; + 40834BE61FE05E1800C1BD0D /* CLLocation+MMEMobileEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC31FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.m */; }; + 40834BE71FE05E1800C1BD0D /* MMEAPIClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA51FE05D6B00C1BD0D /* MMEAPIClient.m */; }; + 40834BE81FE05E1800C1BD0D /* MMECategoryLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC41FE05D6F00C1BD0D /* MMECategoryLoader.m */; }; + 40834BE91FE05E1800C1BD0D /* MMECommonEventData.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BCE1FE05D7100C1BD0D /* MMECommonEventData.m */; }; + 40834BEA1FE05E1800C1BD0D /* MMEConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC01FE05D6E00C1BD0D /* MMEConstants.m */; }; + 40834BEB1FE05E1800C1BD0D /* MMEDependencyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB41FE05D6D00C1BD0D /* MMEDependencyManager.m */; }; + 40834BEC1FE05E1800C1BD0D /* MMEEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC71FE05D7000C1BD0D /* MMEEvent.m */; }; + 40834BED1FE05E1800C1BD0D /* MMEEventLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB71FE05D6D00C1BD0D /* MMEEventLogger.m */; }; + 40834BEE1FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */; }; + 40834BEF1FE05E1800C1BD0D /* MMEEventsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */; }; + 40834BF01FE05E1800C1BD0D /* MMELocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */; }; + 40834BF11FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */; }; + 40834BF21FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */; }; + 40834BF31FE05E1800C1BD0D /* MMETimerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */; }; + 40834BF41FE05E1800C1BD0D /* MMETrustKitWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC11FE05D6F00C1BD0D /* MMETrustKitWrapper.m */; }; + 40834BF51FE05E1800C1BD0D /* MMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */; }; + 40834BF61FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BCA1FE05D7000C1BD0D /* MMEUIApplicationWrapper.m */; }; + 40834BF71FE05E1800C1BD0D /* MMEUniqueIdentifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BAD1FE05D6C00C1BD0D /* MMEUniqueIdentifier.m */; }; + 40834BF81FE05E1800C1BD0D /* NSData+MMEGZIP.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BAF1FE05D6C00C1BD0D /* NSData+MMEGZIP.m */; }; + 40834BF91FE05E1800C1BD0D /* MMEReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BCD1FE05D7100C1BD0D /* MMEReachability.m */; }; + 40834BFA1FE05E1800C1BD0D /* CLLocation+MMEMobileEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC31FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.m */; }; + 40834BFB1FE05E1800C1BD0D /* MMEAPIClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA51FE05D6B00C1BD0D /* MMEAPIClient.m */; }; + 40834BFC1FE05E1800C1BD0D /* MMECategoryLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC41FE05D6F00C1BD0D /* MMECategoryLoader.m */; }; + 40834BFD1FE05E1800C1BD0D /* MMECommonEventData.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BCE1FE05D7100C1BD0D /* MMECommonEventData.m */; }; + 40834BFE1FE05E1800C1BD0D /* MMEConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC01FE05D6E00C1BD0D /* MMEConstants.m */; }; + 40834BFF1FE05E1800C1BD0D /* MMEDependencyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB41FE05D6D00C1BD0D /* MMEDependencyManager.m */; }; + 40834C001FE05E1800C1BD0D /* MMEEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC71FE05D7000C1BD0D /* MMEEvent.m */; }; + 40834C011FE05E1800C1BD0D /* MMEEventLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB71FE05D6D00C1BD0D /* MMEEventLogger.m */; }; + 40834C021FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */; }; + 40834C031FE05E1800C1BD0D /* MMEEventsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */; }; + 40834C041FE05E1800C1BD0D /* MMELocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */; }; + 40834C051FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */; }; + 40834C061FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */; }; + 40834C071FE05E1800C1BD0D /* MMETimerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */; }; + 40834C081FE05E1800C1BD0D /* MMETrustKitWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC11FE05D6F00C1BD0D /* MMETrustKitWrapper.m */; }; + 40834C091FE05E1800C1BD0D /* MMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */; }; + 40834C0A1FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BCA1FE05D7000C1BD0D /* MMEUIApplicationWrapper.m */; }; + 40834C0B1FE05E1800C1BD0D /* MMEUniqueIdentifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BAD1FE05D6C00C1BD0D /* MMEUniqueIdentifier.m */; }; + 40834C0C1FE05E1800C1BD0D /* NSData+MMEGZIP.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BAF1FE05D6C00C1BD0D /* NSData+MMEGZIP.m */; }; + 40834C0D1FE05E1800C1BD0D /* MMEReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BCD1FE05D7100C1BD0D /* MMEReachability.m */; }; + 40834C401FE05F7500C1BD0D /* configuration_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C101FE05F3600C1BD0D /* configuration_utils.m */; }; + 40834C411FE05F7500C1BD0D /* parse_configuration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C141FE05F3600C1BD0D /* parse_configuration.m */; }; + 40834C421FE05F7500C1BD0D /* ssl_pin_verifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C171FE05F3600C1BD0D /* ssl_pin_verifier.m */; }; + 40834C431FE05F7500C1BD0D /* TSKSPKIHashCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C1A1FE05F3600C1BD0D /* TSKSPKIHashCache.m */; }; + 40834C441FE05F7500C1BD0D /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C1D1FE05F3600C1BD0D /* reporting_utils.m */; }; + 40834C451FE05F7500C1BD0D /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C1F1FE05F3600C1BD0D /* TSKBackgroundReporter.m */; }; + 40834C461FE05F7500C1BD0D /* TSKPinFailureReport.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C211FE05F3600C1BD0D /* TSKPinFailureReport.m */; }; + 40834C471FE05F7500C1BD0D /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C231FE05F3600C1BD0D /* TSKReportsRateLimiter.m */; }; + 40834C481FE05F7500C1BD0D /* vendor_identifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C251FE05F3600C1BD0D /* vendor_identifier.m */; }; + 40834C491FE05F7500C1BD0D /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C271FE05F3600C1BD0D /* TrustKit.m */; }; + 40834C4A1FE05F7500C1BD0D /* TSKPinningValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C2A1FE05F3600C1BD0D /* TSKPinningValidator.m */; }; + 40834C4B1FE05F7500C1BD0D /* TSKPinningValidatorResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C2E1FE05F3600C1BD0D /* TSKPinningValidatorResult.m */; }; + 40834C4C1FE05F7500C1BD0D /* TSKTrustKitConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C311FE05F3600C1BD0D /* TSKTrustKitConfig.m */; }; + 40834C4D1FE05F7600C1BD0D /* configuration_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C101FE05F3600C1BD0D /* configuration_utils.m */; }; + 40834C4E1FE05F7600C1BD0D /* parse_configuration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C141FE05F3600C1BD0D /* parse_configuration.m */; }; + 40834C4F1FE05F7600C1BD0D /* ssl_pin_verifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C171FE05F3600C1BD0D /* ssl_pin_verifier.m */; }; + 40834C501FE05F7600C1BD0D /* TSKSPKIHashCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C1A1FE05F3600C1BD0D /* TSKSPKIHashCache.m */; }; + 40834C511FE05F7600C1BD0D /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C1D1FE05F3600C1BD0D /* reporting_utils.m */; }; + 40834C521FE05F7600C1BD0D /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C1F1FE05F3600C1BD0D /* TSKBackgroundReporter.m */; }; + 40834C531FE05F7600C1BD0D /* TSKPinFailureReport.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C211FE05F3600C1BD0D /* TSKPinFailureReport.m */; }; + 40834C541FE05F7600C1BD0D /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C231FE05F3600C1BD0D /* TSKReportsRateLimiter.m */; }; + 40834C551FE05F7600C1BD0D /* vendor_identifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C251FE05F3600C1BD0D /* vendor_identifier.m */; }; + 40834C561FE05F7600C1BD0D /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C271FE05F3600C1BD0D /* TrustKit.m */; }; + 40834C571FE05F7600C1BD0D /* TSKPinningValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C2A1FE05F3600C1BD0D /* TSKPinningValidator.m */; }; + 40834C581FE05F7600C1BD0D /* TSKPinningValidatorResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C2E1FE05F3600C1BD0D /* TSKPinningValidatorResult.m */; }; + 40834C591FE05F7600C1BD0D /* TSKTrustKitConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834C311FE05F3600C1BD0D /* TSKTrustKitConfig.m */; }; 4085AF091D933DEA00F11B22 /* MGLTileSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */; }; - 408982E91DEE208200754016 /* api_mapbox_staging.der in Resources */ = {isa = PBXBuildFile; fileRef = 40599F001DEE1B2400182B5D /* api_mapbox_staging.der */; }; - 408982EA1DEE208B00754016 /* api_mapbox_com-digicert_2016.der in Resources */ = {isa = PBXBuildFile; fileRef = 40599F011DEE1B2400182B5D /* api_mapbox_com-digicert_2016.der */; }; - 408982EB1DEE209100754016 /* api_mapbox_com-geotrust_2016.der in Resources */ = {isa = PBXBuildFile; fileRef = 40599F021DEE1B2400182B5D /* api_mapbox_com-geotrust_2016.der */; }; 408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */; }; 408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */; }; 408AA8591DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */; }; @@ -201,10 +265,6 @@ 409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */; }; 40CF6DBB1DAC3C6600A4D18B /* MGLShape_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40CF6DBA1DAC3C1800A4D18B /* MGLShape_Private.h */; }; 40CFA6511D7875BB008103BD /* MGLShapeSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */; }; - 40EA6BC11EF4599600FCCDA2 /* api_mapbox_com-digicert_2017.der in Resources */ = {isa = PBXBuildFile; fileRef = 40EA6BBD1EF4598900FCCDA2 /* api_mapbox_com-digicert_2017.der */; }; - 40EA6BC21EF4599700FCCDA2 /* api_mapbox_com-digicert_2017.der in Resources */ = {isa = PBXBuildFile; fileRef = 40EA6BBD1EF4598900FCCDA2 /* api_mapbox_com-digicert_2017.der */; }; - 40EA6BC31EF4599D00FCCDA2 /* api_mapbox_com-geotrust_2017.der in Resources */ = {isa = PBXBuildFile; fileRef = 40EA6BBE1EF4598900FCCDA2 /* api_mapbox_com-geotrust_2017.der */; }; - 40EA6BC41EF4599D00FCCDA2 /* api_mapbox_com-geotrust_2017.der in Resources */ = {isa = PBXBuildFile; fileRef = 40EA6BBE1EF4598900FCCDA2 /* api_mapbox_com-geotrust_2017.der */; }; 40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */; }; 40EDA1C11CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */; }; 40EDA1C21CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */; }; @@ -253,6 +313,7 @@ 9620BB3B1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */; }; 9654C1261FFC1AB900DB6A19 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */; }; 9654C1291FFC1CCD00DB6A19 /* MGLPolygon_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1271FFC1CC000DB6A19 /* MGLPolygon_Private.h */; }; + 9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */; }; 966FCF4C1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */; }; 966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; }; 966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; }; @@ -294,8 +355,6 @@ 96E516FA20005A3D00A02306 /* MGLUserLocationHeadingArrowLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF501F3C321000F2B6DE /* MGLUserLocationHeadingArrowLayer.h */; }; 96E516FB20005A4000A02306 /* MGLUserLocationHeadingBeamLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */; }; 96E516FC20005A4400A02306 /* MGLUserLocationHeadingIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */; }; - 96E516FD20005A4700A02306 /* MGLAPIClient.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */; }; - 96E516FE20005A4C00A02306 /* MGLLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */; }; 96E516FF20005A4F00A02306 /* MGLMapboxEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */; }; 96E5170020005A6100A02306 /* Fabric.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848831CBB033F00AB86E3 /* Fabric.h */; }; 96E5170120005A6400A02306 /* Fabric+FABKits.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848821CBB033F00AB86E3 /* Fabric+FABKits.h */; }; @@ -425,12 +484,8 @@ DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848391CBAFB8500AB86E3 /* MGLUserLocation.h */; settings = {ATTRIBUTES = (Public, ); }; }; DA88484F1CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */; }; DA8848501CBAFB9800AB86E3 /* MGLAnnotationImage.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848411CBAFB9800AB86E3 /* MGLAnnotationImage.m */; }; - DA8848511CBAFB9800AB86E3 /* MGLAPIClient.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */; }; - DA8848521CBAFB9800AB86E3 /* MGLAPIClient.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */; }; DA8848531CBAFB9800AB86E3 /* MGLCompactCalloutView.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848441CBAFB9800AB86E3 /* MGLCompactCalloutView.h */; }; DA8848541CBAFB9800AB86E3 /* MGLCompactCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */; }; - DA8848551CBAFB9800AB86E3 /* MGLLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */; }; - DA8848561CBAFB9800AB86E3 /* MGLLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */; }; DA8848571CBAFB9800AB86E3 /* MGLMapboxEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */; }; DA8848581CBAFB9800AB86E3 /* MGLMapboxEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */; }; DA8848591CBAFB9800AB86E3 /* MGLMapView.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */; }; @@ -478,9 +533,7 @@ DAA4E42A1CBB730400178DFB /* NSProcessInfo+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848161CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m */; }; DAA4E42B1CBB730400178DFB /* NSString+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848181CBAFA6200AB86E3 /* NSString+MGLAdditions.m */; }; DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848411CBAFB9800AB86E3 /* MGLAnnotationImage.m */; }; - DAA4E42E1CBB730400178DFB /* MGLAPIClient.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */; }; DAA4E42F1CBB730400178DFB /* MGLCompactCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */; }; - DAA4E4301CBB730400178DFB /* MGLLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */; }; DAA4E4311CBB730400178DFB /* MGLMapboxEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */; }; DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */; }; DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88484C1CBAFB9800AB86E3 /* MGLUserLocation.m */; }; @@ -778,9 +831,84 @@ 404C26E01D89B877000AA13D /* MGLTileSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSource.h; sourceTree = "<group>"; }; 404C26E11D89B877000AA13D /* MGLTileSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTileSource.mm; sourceTree = "<group>"; }; 404C26E61D89C515000AA13D /* MGLTileSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSource_Private.h; sourceTree = "<group>"; }; - 40599F001DEE1B2400182B5D /* api_mapbox_staging.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = api_mapbox_staging.der; sourceTree = "<group>"; }; - 40599F011DEE1B2400182B5D /* api_mapbox_com-digicert_2016.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "api_mapbox_com-digicert_2016.der"; sourceTree = "<group>"; }; - 40599F021DEE1B2400182B5D /* api_mapbox_com-geotrust_2016.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "api_mapbox_com-geotrust_2016.der"; sourceTree = "<group>"; }; + 406E99B11FFEFED500D9FFCC /* MMEEventLogReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEEventLogReportViewController.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventLogReportViewController.m"; sourceTree = SOURCE_ROOT; }; + 406E99B21FFEFED500D9FFCC /* MMEUINavigation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEUINavigation.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUINavigation.m"; sourceTree = SOURCE_ROOT; }; + 406E99B31FFEFED600D9FFCC /* MMEUINavigation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEUINavigation.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUINavigation.h"; sourceTree = SOURCE_ROOT; }; + 406E99B51FFEFED600D9FFCC /* MMEEventLogReportViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEventLogReportViewController.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventLogReportViewController.h"; sourceTree = SOURCE_ROOT; }; + 40834AEF1FDF4F0100C1BD0D /* Mapbox-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Mapbox-Prefix.pch"; path = "src/Mapbox-Prefix.pch"; sourceTree = SOURCE_ROOT; }; + 40834BA31FE05D6B00C1BD0D /* MMEEventsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEventsManager.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventsManager.h"; sourceTree = SOURCE_ROOT; }; + 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEEventsManager.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventsManager.m"; sourceTree = SOURCE_ROOT; }; + 40834BA51FE05D6B00C1BD0D /* MMEAPIClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEAPIClient.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEAPIClient.m"; sourceTree = SOURCE_ROOT; }; + 40834BA61FE05D6B00C1BD0D /* MMEEventLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEventLogger.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventLogger.h"; sourceTree = SOURCE_ROOT; }; + 40834BA71FE05D6B00C1BD0D /* MMETrustKitWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMETrustKitWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETrustKitWrapper.h"; sourceTree = SOURCE_ROOT; }; + 40834BAA1FE05D6C00C1BD0D /* MMENSURLSessionWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMENSURLSessionWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSURLSessionWrapper.h"; sourceTree = SOURCE_ROOT; }; + 40834BAB1FE05D6C00C1BD0D /* MMEAPIClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEAPIClient.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEAPIClient.h"; sourceTree = SOURCE_ROOT; }; + 40834BAC1FE05D6C00C1BD0D /* MapboxMobileEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MapboxMobileEvents.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MapboxMobileEvents.h"; sourceTree = SOURCE_ROOT; }; + 40834BAD1FE05D6C00C1BD0D /* MMEUniqueIdentifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEUniqueIdentifier.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUniqueIdentifier.m"; sourceTree = SOURCE_ROOT; }; + 40834BAE1FE05D6C00C1BD0D /* MMECommonEventData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMECommonEventData.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMECommonEventData.h"; sourceTree = SOURCE_ROOT; }; + 40834BAF1FE05D6C00C1BD0D /* NSData+MMEGZIP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+MMEGZIP.m"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/NSData+MMEGZIP.m"; sourceTree = SOURCE_ROOT; }; + 40834BB01FE05D6C00C1BD0D /* MMEConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEConstants.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEConstants.h"; sourceTree = SOURCE_ROOT; }; + 40834BB11FE05D6D00C1BD0D /* MMEDependencyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEDependencyManager.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEDependencyManager.h"; sourceTree = SOURCE_ROOT; }; + 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEEventsConfiguration.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventsConfiguration.m"; sourceTree = SOURCE_ROOT; }; + 40834BB31FE05D6D00C1BD0D /* MMELocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMELocationManager.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMELocationManager.h"; sourceTree = SOURCE_ROOT; }; + 40834BB41FE05D6D00C1BD0D /* MMEDependencyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEDependencyManager.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEDependencyManager.m"; sourceTree = SOURCE_ROOT; }; + 40834BB51FE05D6D00C1BD0D /* MMECategoryLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMECategoryLoader.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMECategoryLoader.h"; sourceTree = SOURCE_ROOT; }; + 40834BB61FE05D6D00C1BD0D /* MMETypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMETypes.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETypes.h"; sourceTree = SOURCE_ROOT; }; + 40834BB71FE05D6D00C1BD0D /* MMEEventLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEEventLogger.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventLogger.m"; sourceTree = SOURCE_ROOT; }; + 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMELocationManager.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMELocationManager.m"; sourceTree = SOURCE_ROOT; }; + 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMETimerManager.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.m"; sourceTree = SOURCE_ROOT; }; + 40834BBA1FE05D6E00C1BD0D /* MMEEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEvent.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEvent.h"; sourceTree = SOURCE_ROOT; }; + 40834BBB1FE05D6E00C1BD0D /* MMEEventsConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEventsConfiguration.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventsConfiguration.h"; sourceTree = SOURCE_ROOT; }; + 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMENSDateWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.m"; sourceTree = SOURCE_ROOT; }; + 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMETypes.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETypes.m"; sourceTree = SOURCE_ROOT; }; + 40834BBE1FE05D6E00C1BD0D /* MMEUIApplicationWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEUIApplicationWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUIApplicationWrapper.h"; sourceTree = SOURCE_ROOT; }; + 40834BBF1FE05D6E00C1BD0D /* MMEUniqueIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEUniqueIdentifier.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUniqueIdentifier.h"; sourceTree = SOURCE_ROOT; }; + 40834BC01FE05D6E00C1BD0D /* MMEConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEConstants.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEConstants.m"; sourceTree = SOURCE_ROOT; }; + 40834BC11FE05D6F00C1BD0D /* MMETrustKitWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMETrustKitWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETrustKitWrapper.m"; sourceTree = SOURCE_ROOT; }; + 40834BC21FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "CLLocation+MMEMobileEvents.h"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/CLLocation+MMEMobileEvents.h"; sourceTree = SOURCE_ROOT; }; + 40834BC31FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "CLLocation+MMEMobileEvents.m"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/CLLocation+MMEMobileEvents.m"; sourceTree = SOURCE_ROOT; }; + 40834BC41FE05D6F00C1BD0D /* MMECategoryLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMECategoryLoader.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMECategoryLoader.m"; sourceTree = SOURCE_ROOT; }; + 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMENSDateWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.h"; sourceTree = SOURCE_ROOT; }; + 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMENSURLSessionWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSURLSessionWrapper.m"; sourceTree = SOURCE_ROOT; }; + 40834BC71FE05D7000C1BD0D /* MMEEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEEvent.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEvent.m"; sourceTree = SOURCE_ROOT; }; + 40834BC81FE05D7000C1BD0D /* MMENamespacedDependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMENamespacedDependencies.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENamespacedDependencies.h"; sourceTree = SOURCE_ROOT; }; + 40834BC91FE05D7000C1BD0D /* MMETimerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMETimerManager.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.h"; sourceTree = SOURCE_ROOT; }; + 40834BCA1FE05D7000C1BD0D /* MMEUIApplicationWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEUIApplicationWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUIApplicationWrapper.m"; sourceTree = SOURCE_ROOT; }; + 40834BCC1FE05D7100C1BD0D /* MMEReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEReachability.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/Reachability/MMEReachability.h"; sourceTree = SOURCE_ROOT; }; + 40834BCD1FE05D7100C1BD0D /* MMEReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEReachability.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/Reachability/MMEReachability.m"; sourceTree = SOURCE_ROOT; }; + 40834BCE1FE05D7100C1BD0D /* MMECommonEventData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMECommonEventData.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMECommonEventData.m"; sourceTree = SOURCE_ROOT; }; + 40834BCF1FE05D7100C1BD0D /* NSData+MMEGZIP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+MMEGZIP.h"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/NSData+MMEGZIP.h"; sourceTree = SOURCE_ROOT; }; + 40834C0F1FE05F3600C1BD0D /* configuration_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = configuration_utils.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/configuration_utils.h"; sourceTree = SOURCE_ROOT; }; + 40834C101FE05F3600C1BD0D /* configuration_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = configuration_utils.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/configuration_utils.m"; sourceTree = SOURCE_ROOT; }; + 40834C131FE05F3600C1BD0D /* parse_configuration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parse_configuration.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/parse_configuration.h"; sourceTree = SOURCE_ROOT; }; + 40834C141FE05F3600C1BD0D /* parse_configuration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = parse_configuration.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/parse_configuration.m"; sourceTree = SOURCE_ROOT; }; + 40834C161FE05F3600C1BD0D /* ssl_pin_verifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ssl_pin_verifier.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Pinning/ssl_pin_verifier.h"; sourceTree = SOURCE_ROOT; }; + 40834C171FE05F3600C1BD0D /* ssl_pin_verifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ssl_pin_verifier.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/Pinning/ssl_pin_verifier.m"; sourceTree = SOURCE_ROOT; }; + 40834C181FE05F3600C1BD0D /* TSKPublicKeyAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKPublicKeyAlgorithm.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Pinning/TSKPublicKeyAlgorithm.h"; sourceTree = SOURCE_ROOT; }; + 40834C191FE05F3600C1BD0D /* TSKSPKIHashCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKSPKIHashCache.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Pinning/TSKSPKIHashCache.h"; sourceTree = SOURCE_ROOT; }; + 40834C1A1FE05F3600C1BD0D /* TSKSPKIHashCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKSPKIHashCache.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/Pinning/TSKSPKIHashCache.m"; sourceTree = SOURCE_ROOT; }; + 40834C1C1FE05F3600C1BD0D /* reporting_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reporting_utils.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/reporting_utils.h"; sourceTree = SOURCE_ROOT; }; + 40834C1D1FE05F3600C1BD0D /* reporting_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = reporting_utils.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/reporting_utils.m"; sourceTree = SOURCE_ROOT; }; + 40834C1E1FE05F3600C1BD0D /* TSKBackgroundReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKBackgroundReporter.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKBackgroundReporter.h"; sourceTree = SOURCE_ROOT; }; + 40834C1F1FE05F3600C1BD0D /* TSKBackgroundReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKBackgroundReporter.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKBackgroundReporter.m"; sourceTree = SOURCE_ROOT; }; + 40834C201FE05F3600C1BD0D /* TSKPinFailureReport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKPinFailureReport.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKPinFailureReport.h"; sourceTree = SOURCE_ROOT; }; + 40834C211FE05F3600C1BD0D /* TSKPinFailureReport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKPinFailureReport.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKPinFailureReport.m"; sourceTree = SOURCE_ROOT; }; + 40834C221FE05F3600C1BD0D /* TSKReportsRateLimiter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKReportsRateLimiter.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKReportsRateLimiter.h"; sourceTree = SOURCE_ROOT; }; + 40834C231FE05F3600C1BD0D /* TSKReportsRateLimiter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKReportsRateLimiter.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKReportsRateLimiter.m"; sourceTree = SOURCE_ROOT; }; + 40834C241FE05F3600C1BD0D /* vendor_identifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vendor_identifier.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/vendor_identifier.h"; sourceTree = SOURCE_ROOT; }; + 40834C251FE05F3600C1BD0D /* vendor_identifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = vendor_identifier.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting/vendor_identifier.m"; sourceTree = SOURCE_ROOT; }; + 40834C261FE05F3600C1BD0D /* TrustKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TrustKit.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TrustKit.h"; sourceTree = SOURCE_ROOT; }; + 40834C271FE05F3600C1BD0D /* TrustKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TrustKit.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/TrustKit.m"; sourceTree = SOURCE_ROOT; }; + 40834C281FE05F3600C1BD0D /* TSKLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKLog.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKLog.h"; sourceTree = SOURCE_ROOT; }; + 40834C291FE05F3600C1BD0D /* TSKPinningValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKPinningValidator.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKPinningValidator.h"; sourceTree = SOURCE_ROOT; }; + 40834C2A1FE05F3600C1BD0D /* TSKPinningValidator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKPinningValidator.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKPinningValidator.m"; sourceTree = SOURCE_ROOT; }; + 40834C2B1FE05F3600C1BD0D /* TSKPinningValidator_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKPinningValidator_Private.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKPinningValidator_Private.h"; sourceTree = SOURCE_ROOT; }; + 40834C2C1FE05F3600C1BD0D /* TSKPinningValidatorCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKPinningValidatorCallback.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKPinningValidatorCallback.h"; sourceTree = SOURCE_ROOT; }; + 40834C2D1FE05F3600C1BD0D /* TSKPinningValidatorResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKPinningValidatorResult.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKPinningValidatorResult.h"; sourceTree = SOURCE_ROOT; }; + 40834C2E1FE05F3600C1BD0D /* TSKPinningValidatorResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKPinningValidatorResult.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKPinningValidatorResult.m"; sourceTree = SOURCE_ROOT; }; + 40834C2F1FE05F3600C1BD0D /* TSKTrustDecision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKTrustDecision.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKTrustDecision.h"; sourceTree = SOURCE_ROOT; }; + 40834C301FE05F3600C1BD0D /* TSKTrustKitConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKTrustKitConfig.h; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKTrustKitConfig.h"; sourceTree = SOURCE_ROOT; }; + 40834C311FE05F3600C1BD0D /* TSKTrustKitConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKTrustKitConfig.m; path = "vendor/mapbox-events-ios/vendor/TrustKit/TSKTrustKitConfig.m"; sourceTree = SOURCE_ROOT; }; 4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLTileSetTests.mm; path = ../../darwin/test/MGLTileSetTests.mm; sourceTree = "<group>"; }; 408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+MGLAdditions.h"; sourceTree = "<group>"; }; 408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDictionary+MGLAdditions.mm"; sourceTree = "<group>"; }; @@ -788,8 +916,6 @@ 409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLMapViewDelegateIntegrationTests.swift; sourceTree = "<group>"; }; 40CF6DBA1DAC3C1800A4D18B /* MGLShape_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShape_Private.h; sourceTree = "<group>"; }; 40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLShapeSourceTests.mm; path = ../../darwin/test/MGLShapeSourceTests.mm; sourceTree = "<group>"; }; - 40EA6BBD1EF4598900FCCDA2 /* api_mapbox_com-digicert_2017.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "api_mapbox_com-digicert_2017.der"; sourceTree = "<group>"; }; - 40EA6BBE1EF4598900FCCDA2 /* api_mapbox_com-geotrust_2017.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "api_mapbox_com-geotrust_2017.der"; sourceTree = "<group>"; }; 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView.h; sourceTree = "<group>"; }; 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationContainerView.m; sourceTree = "<group>"; }; 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeSource_Private.h; sourceTree = "<group>"; }; @@ -827,6 +953,7 @@ 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MGLSDKUpdateChecker.mm; sourceTree = "<group>"; }; 9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolyline_Private.h; sourceTree = "<group>"; }; 9654C1271FFC1CC000DB6A19 /* MGLPolygon_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolygon_Private.h; sourceTree = "<group>"; }; + 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewScaleBarTests.m; sourceTree = "<group>"; }; 9660916B1E5BBFD700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; }; 9660916C1E5BBFD900A9A03B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; }; 9660916D1E5BBFDB00A9A03B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; }; @@ -1004,12 +1131,8 @@ DA8848391CBAFB8500AB86E3 /* MGLUserLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLUserLocation.h; sourceTree = "<group>"; }; DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = "<group>"; }; DA8848411CBAFB9800AB86E3 /* MGLAnnotationImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationImage.m; sourceTree = "<group>"; }; - DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAPIClient.h; sourceTree = "<group>"; }; - DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAPIClient.m; sourceTree = "<group>"; }; DA8848441CBAFB9800AB86E3 /* MGLCompactCalloutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCompactCalloutView.h; sourceTree = "<group>"; }; DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCompactCalloutView.m; sourceTree = "<group>"; }; - DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLocationManager.h; sourceTree = "<group>"; }; - DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLLocationManager.m; sourceTree = "<group>"; }; DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapboxEvents.h; sourceTree = "<group>"; }; DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLMapboxEvents.m; sourceTree = "<group>"; }; DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapView.mm; sourceTree = "<group>"; }; @@ -1377,6 +1500,137 @@ name = "Test Helpers"; sourceTree = "<group>"; }; + 40834BA11FE05CFD00C1BD0D /* Development */ = { + isa = PBXGroup; + children = ( + 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */, + 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */, + ); + name = Development; + sourceTree = "<group>"; + }; + 40834BA21FE05D3100C1BD0D /* Runtime */ = { + isa = PBXGroup; + children = ( + 40834BC81FE05D7000C1BD0D /* MMENamespacedDependencies.h */, + 40834BAC1FE05D6C00C1BD0D /* MapboxMobileEvents.h */, + DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */, + DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */, + 40834BC21FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.h */, + 40834BC31FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.m */, + 40834BAB1FE05D6C00C1BD0D /* MMEAPIClient.h */, + 40834BA51FE05D6B00C1BD0D /* MMEAPIClient.m */, + 40834BB51FE05D6D00C1BD0D /* MMECategoryLoader.h */, + 40834BC41FE05D6F00C1BD0D /* MMECategoryLoader.m */, + 40834BAE1FE05D6C00C1BD0D /* MMECommonEventData.h */, + 40834BCE1FE05D7100C1BD0D /* MMECommonEventData.m */, + 40834BB01FE05D6C00C1BD0D /* MMEConstants.h */, + 40834BC01FE05D6E00C1BD0D /* MMEConstants.m */, + 40834BB11FE05D6D00C1BD0D /* MMEDependencyManager.h */, + 40834BB41FE05D6D00C1BD0D /* MMEDependencyManager.m */, + 40834BBA1FE05D6E00C1BD0D /* MMEEvent.h */, + 40834BC71FE05D7000C1BD0D /* MMEEvent.m */, + 40834BA61FE05D6B00C1BD0D /* MMEEventLogger.h */, + 40834BB71FE05D6D00C1BD0D /* MMEEventLogger.m */, + 406E99B51FFEFED600D9FFCC /* MMEEventLogReportViewController.h */, + 406E99B11FFEFED500D9FFCC /* MMEEventLogReportViewController.m */, + 40834BBB1FE05D6E00C1BD0D /* MMEEventsConfiguration.h */, + 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */, + 40834BA31FE05D6B00C1BD0D /* MMEEventsManager.h */, + 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */, + 40834BB31FE05D6D00C1BD0D /* MMELocationManager.h */, + 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */, + 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */, + 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */, + 40834BAA1FE05D6C00C1BD0D /* MMENSURLSessionWrapper.h */, + 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */, + 40834BC91FE05D7000C1BD0D /* MMETimerManager.h */, + 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */, + 40834BA71FE05D6B00C1BD0D /* MMETrustKitWrapper.h */, + 40834BC11FE05D6F00C1BD0D /* MMETrustKitWrapper.m */, + 40834BB61FE05D6D00C1BD0D /* MMETypes.h */, + 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */, + 40834BBE1FE05D6E00C1BD0D /* MMEUIApplicationWrapper.h */, + 40834BCA1FE05D7000C1BD0D /* MMEUIApplicationWrapper.m */, + 406E99B31FFEFED600D9FFCC /* MMEUINavigation.h */, + 406E99B21FFEFED500D9FFCC /* MMEUINavigation.m */, + 40834BBF1FE05D6E00C1BD0D /* MMEUniqueIdentifier.h */, + 40834BAD1FE05D6C00C1BD0D /* MMEUniqueIdentifier.m */, + 40834BCF1FE05D7100C1BD0D /* NSData+MMEGZIP.h */, + 40834BAF1FE05D6C00C1BD0D /* NSData+MMEGZIP.m */, + 40834BCB1FE05D7100C1BD0D /* Reachability */, + 40834C0E1FE05F3600C1BD0D /* TrustKit */, + ); + name = Runtime; + sourceTree = "<group>"; + }; + 40834BCB1FE05D7100C1BD0D /* Reachability */ = { + isa = PBXGroup; + children = ( + 40834BCC1FE05D7100C1BD0D /* MMEReachability.h */, + 40834BCD1FE05D7100C1BD0D /* MMEReachability.m */, + ); + name = Reachability; + path = "vendor/mapbox-events-ios/MapboxMobileEvents/Reachability"; + sourceTree = SOURCE_ROOT; + }; + 40834C0E1FE05F3600C1BD0D /* TrustKit */ = { + isa = PBXGroup; + children = ( + 40834C0F1FE05F3600C1BD0D /* configuration_utils.h */, + 40834C101FE05F3600C1BD0D /* configuration_utils.m */, + 40834C131FE05F3600C1BD0D /* parse_configuration.h */, + 40834C141FE05F3600C1BD0D /* parse_configuration.m */, + 40834C151FE05F3600C1BD0D /* Pinning */, + 40834C1B1FE05F3600C1BD0D /* Reporting */, + 40834C261FE05F3600C1BD0D /* TrustKit.h */, + 40834C271FE05F3600C1BD0D /* TrustKit.m */, + 40834C281FE05F3600C1BD0D /* TSKLog.h */, + 40834C291FE05F3600C1BD0D /* TSKPinningValidator.h */, + 40834C2A1FE05F3600C1BD0D /* TSKPinningValidator.m */, + 40834C2B1FE05F3600C1BD0D /* TSKPinningValidator_Private.h */, + 40834C2C1FE05F3600C1BD0D /* TSKPinningValidatorCallback.h */, + 40834C2D1FE05F3600C1BD0D /* TSKPinningValidatorResult.h */, + 40834C2E1FE05F3600C1BD0D /* TSKPinningValidatorResult.m */, + 40834C2F1FE05F3600C1BD0D /* TSKTrustDecision.h */, + 40834C301FE05F3600C1BD0D /* TSKTrustKitConfig.h */, + 40834C311FE05F3600C1BD0D /* TSKTrustKitConfig.m */, + ); + name = TrustKit; + path = "vendor/mapbox-events-ios/vendor/TrustKit"; + sourceTree = SOURCE_ROOT; + }; + 40834C151FE05F3600C1BD0D /* Pinning */ = { + isa = PBXGroup; + children = ( + 40834C161FE05F3600C1BD0D /* ssl_pin_verifier.h */, + 40834C171FE05F3600C1BD0D /* ssl_pin_verifier.m */, + 40834C181FE05F3600C1BD0D /* TSKPublicKeyAlgorithm.h */, + 40834C191FE05F3600C1BD0D /* TSKSPKIHashCache.h */, + 40834C1A1FE05F3600C1BD0D /* TSKSPKIHashCache.m */, + ); + name = Pinning; + path = "vendor/mapbox-events-ios/vendor/TrustKit/Pinning"; + sourceTree = SOURCE_ROOT; + }; + 40834C1B1FE05F3600C1BD0D /* Reporting */ = { + isa = PBXGroup; + children = ( + 40834C1C1FE05F3600C1BD0D /* reporting_utils.h */, + 40834C1D1FE05F3600C1BD0D /* reporting_utils.m */, + 40834C1E1FE05F3600C1BD0D /* TSKBackgroundReporter.h */, + 40834C1F1FE05F3600C1BD0D /* TSKBackgroundReporter.m */, + 40834C201FE05F3600C1BD0D /* TSKPinFailureReport.h */, + 40834C211FE05F3600C1BD0D /* TSKPinFailureReport.m */, + 40834C221FE05F3600C1BD0D /* TSKReportsRateLimiter.h */, + 40834C231FE05F3600C1BD0D /* TSKReportsRateLimiter.m */, + 40834C241FE05F3600C1BD0D /* vendor_identifier.h */, + 40834C251FE05F3600C1BD0D /* vendor_identifier.m */, + ); + name = Reporting; + path = "vendor/mapbox-events-ios/vendor/TrustKit/Reporting"; + sourceTree = SOURCE_ROOT; + }; 409F43FB1E9E77D10048729D /* Swift Integration */ = { isa = PBXGroup; children = ( @@ -1521,24 +1775,25 @@ 4031ACFD1E9FD26900A3EA26 /* Test Helpers */, 409F43FB1E9E77D10048729D /* Swift Integration */, 357579811D502AD4000B822E /* Styling */, - DAEDC4331D603417000224FF /* MGLAttributionInfoTests.m */, 353D23951D0B0DFE002BE09D /* MGLAnnotationViewTests.m */, + DAEDC4331D603417000224FF /* MGLAttributionInfoTests.m */, DA35A2C31CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m */, 35D9DDE11DA25EEC00DAAD69 /* MGLCodingTests.m */, DA35A2C41CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m */, DA35A2A91CCA058D00E826B2 /* MGLCoordinateFormatterTests.m */, + 3598544C1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m */, 6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */, DA1F8F3C1EBD287B00367E42 /* MGLDocumentationGuideTests.swift */, DD58A4C51D822BD000E1F038 /* MGLExpressionTests.mm */, - 3598544C1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m */, DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */, DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */, DA5DB1291FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m */, 16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */, + 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */, 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */, 1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */, - DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */, 96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */, + DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */, DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */, DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */, 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */, @@ -1557,6 +1812,7 @@ isa = PBXGroup; children = ( DA88485E1CBAFC2E00AB86E3 /* Mapbox.h */, + 40834AEF1FDF4F0100C1BD0D /* Mapbox-Prefix.pch */, DA8847DE1CBAFA3E00AB86E3 /* Foundation */, DA8F25BC1D51D2570010E6B5 /* Foundation Templates */, DA8933B91CCD2C6700E68420 /* Foundation Resources */, @@ -1636,11 +1892,6 @@ DA89339F1CCC951200E68420 /* Localizable.strings */, DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */, DA8933EF1CCD387900E68420 /* strip-frameworks.sh */, - 40599F001DEE1B2400182B5D /* api_mapbox_staging.der */, - 40599F011DEE1B2400182B5D /* api_mapbox_com-digicert_2016.der */, - 40599F021DEE1B2400182B5D /* api_mapbox_com-geotrust_2016.der */, - 40EA6BBD1EF4598900FCCDA2 /* api_mapbox_com-digicert_2017.der */, - 40EA6BBE1EF4598900FCCDA2 /* api_mapbox_com-geotrust_2017.der */, ); name = "Kit Resources"; path = resources; @@ -1874,16 +2125,10 @@ DAD165851CF4D08B001FF4B9 /* Telemetry */ = { isa = PBXGroup; children = ( - DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */, - DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */, - DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */, - DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */, - DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */, - DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */, - 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */, - 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */, AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */, AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */, + 40834BA21FE05D3100C1BD0D /* Runtime */, + 40834BA11FE05CFD00C1BD0D /* Development */, ); name = Telemetry; sourceTree = "<group>"; @@ -1918,7 +2163,6 @@ DA8848231CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h in Headers */, 404326891D5B9B27007111BD /* MGLAnnotationContainerView_Private.h in Headers */, CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */, - 1FB7DAAF1F2A4DBD00410606 /* MGLVectorSource+MGLAdditions.h in Headers */, DA88483B1CBAFB8500AB86E3 /* MGLCalloutView.h in Headers */, 35E0CFE61D3E501500188327 /* MGLStyle_Private.h in Headers */, 3510FFF01D6D9D8C00F413B2 /* NSExpression+MGLAdditions.h in Headers */, @@ -1945,7 +2189,6 @@ FA68F14A1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */, 353933FB1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h in Headers */, DA8847EF1CBAFA5100AB86E3 /* MGLAccountManager.h in Headers */, - DA8848511CBAFB9800AB86E3 /* MGLAPIClient.h in Headers */, DA35A2C91CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */, 3510FFEA1D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.h in Headers */, DA6408DB1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */, @@ -1962,7 +2205,6 @@ 071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */, DA8847F41CBAFA5100AB86E3 /* MGLOfflinePack.h in Headers */, DA88482E1CBAFA6200AB86E3 /* NSException+MGLAdditions.h in Headers */, - DA8848551CBAFB9800AB86E3 /* MGLLocationManager.h in Headers */, 96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */, 408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */, DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */, @@ -2037,7 +2279,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 96E516FE20005A4C00A02306 /* MGLLocationManager.h in Headers */, 556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */, 96E516ED200058A200A02306 /* MGLComputedShapeSource.h in Headers */, 35B82BF91D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */, @@ -2165,7 +2406,6 @@ DAF0D8191DFE6B2800B28378 /* MGLAttributionInfo_Private.h in Headers */, DABFB86A1CBE99E500D62B32 /* MGLStyle.h in Headers */, DA00FC8F1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */, - 96E516FD20005A4700A02306 /* MGLAPIClient.h in Headers */, 96E5170320005A6800A02306 /* FABKitProtocol.h in Headers */, 96E516E12000551100A02306 /* MGLMultiPoint_Private.h in Headers */, 3EA934623AD0000B7D99C3FB /* MGLRendererConfiguration.h in Headers */, @@ -2494,11 +2734,6 @@ DA8933F01CCD387900E68420 /* strip-frameworks.sh in Resources */, DAC49C5C1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */, DA8933BF1CCD2CAD00E68420 /* Foundation.stringsdict in Resources */, - 40EA6BC11EF4599600FCCDA2 /* api_mapbox_com-digicert_2017.der in Resources */, - 408982E91DEE208200754016 /* api_mapbox_staging.der in Resources */, - 408982EA1DEE208B00754016 /* api_mapbox_com-digicert_2016.der in Resources */, - 40EA6BC31EF4599D00FCCDA2 /* api_mapbox_com-geotrust_2017.der in Resources */, - 408982EB1DEE209100754016 /* api_mapbox_com-geotrust_2016.der in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2510,12 +2745,7 @@ DA8933DB1CCD31D400E68420 /* Foundation.strings in Resources */, 960D0C371ECF5AAF008E151F /* Images.xcassets in Resources */, DA8933DC1CCD31D400E68420 /* Foundation.stringsdict in Resources */, - 40EA6BC41EF4599D00FCCDA2 /* api_mapbox_com-geotrust_2017.der in Resources */, DAC49C5D1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */, - 40599F0C1DEE1B7600182B5D /* api_mapbox_staging.der in Resources */, - 40599F0D1DEE1B7A00182B5D /* api_mapbox_com-digicert_2016.der in Resources */, - 40599F0E1DEE1B7E00182B5D /* api_mapbox_com-geotrust_2016.der in Resources */, - 40EA6BC21EF4599700FCCDA2 /* api_mapbox_com-digicert_2017.der in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2600,6 +2830,7 @@ 1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */, DD58A4C61D822BD000E1F038 /* MGLExpressionTests.mm in Sources */, 3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */, + 9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */, 409D0A0D1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift in Sources */, DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */, 55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */, @@ -2625,28 +2856,44 @@ files = ( 35136D391D42271A00C20EFD /* MGLBackgroundStyleLayer.mm in Sources */, 3510FFEC1D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.mm in Sources */, + 40834C431FE05F7500C1BD0D /* TSKSPKIHashCache.m in Sources */, DAED38651D62D0FC00D7640F /* NSURL+MGLAdditions.m in Sources */, + 40834BEC1FE05E1800C1BD0D /* MMEEvent.m in Sources */, 9620BB3A1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */, 354B83981D2E873E005D9406 /* MGLUserLocationAnnotationView.m in Sources */, + 40834BEE1FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */, DA88485D1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.m in Sources */, DAD165701CF41981001FF4B9 /* MGLFeature.mm in Sources */, 30E578191DAA855E0050F07E /* UIImage+MGLAdditions.mm in Sources */, 40EDA1C11CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */, + 40834C481FE05F7500C1BD0D /* vendor_identifier.m in Sources */, DA8848541CBAFB9800AB86E3 /* MGLCompactCalloutView.m in Sources */, + 40834BEB1FE05E1800C1BD0D /* MMEDependencyManager.m in Sources */, + 40834C411FE05F7500C1BD0D /* parse_configuration.m in Sources */, DA8848251CBAFA6200AB86E3 /* MGLPointAnnotation.mm in Sources */, + 40834BEA1FE05E1800C1BD0D /* MMEConstants.m in Sources */, 929EFFAB1F56DCD4003A77D5 /* MGLAnnotationView.mm in Sources */, 35136D3C1D42272500C20EFD /* MGLCircleStyleLayer.mm in Sources */, DD9BE4F81EB263C50079A3AF /* UIViewController+MGLAdditions.m in Sources */, 350098DE1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */, DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */, + 40834BF71FE05E1800C1BD0D /* MMEUniqueIdentifier.m in Sources */, 3566C7681D4A77BA008152BC /* MGLShapeSource.mm in Sources */, + 40834C4A1FE05F7500C1BD0D /* TSKPinningValidator.m in Sources */, 400533021DB0862B0069F638 /* NSArray+MGLAdditions.mm in Sources */, 96036A03200565C700510F3D /* NSOrthography+MGLAdditions.m in Sources */, + 40834BF31FE05E1800C1BD0D /* MMETimerManager.m in Sources */, 35136D421D42274500C20EFD /* MGLRasterStyleLayer.mm in Sources */, 3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */, + 40834BF11FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */, + 40834C461FE05F7500C1BD0D /* TSKPinFailureReport.m in Sources */, + 406E99B91FFEFF1B00D9FFCC /* MMEEventLogReportViewController.m in Sources */, + 40834BE61FE05E1800C1BD0D /* CLLocation+MMEMobileEvents.m in Sources */, DA00FC901D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */, DA88482D1CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m in Sources */, + 406E99BB1FFF006C00D9FFCC /* MMEUINavigation.m in Sources */, 966FCF541F3C323300F2B6DE /* MGLUserLocationHeadingArrowLayer.m in Sources */, + 40834BE81FE05E1800C1BD0D /* MMECategoryLoader.m in Sources */, DA88485B1CBAFB9800AB86E3 /* MGLUserLocation.m in Sources */, 927FBD011F4DB05500F8BF1F /* MGLMapSnapshotter.mm in Sources */, 350098BD1D480108004B2AF0 /* MGLVectorSource.mm in Sources */, @@ -2657,27 +2904,37 @@ DA35A2B81CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */, DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.mm in Sources */, DAF25719201901E200367EF5 /* MGLHillshadeStyleLayer.mm in Sources */, + 40834BF51FE05E1800C1BD0D /* MMETypes.m in Sources */, 35136D451D42275100C20EFD /* MGLSymbolStyleLayer.mm in Sources */, + 40834C491FE05F7500C1BD0D /* TrustKit.m in Sources */, 35599DED1D46F14E0048254D /* MGLStyleValue.mm in Sources */, DA8848211CBAFA6200AB86E3 /* MGLOfflinePack.mm in Sources */, 0778DD441F67556C00A73B34 /* MGLComputedShapeSource.mm in Sources */, 3557F7B21E1D27D300CCA5E6 /* MGLDistanceFormatter.m in Sources */, + 40834C4B1FE05F7500C1BD0D /* TSKPinningValidatorResult.m in Sources */, + 40834BE71FE05E1800C1BD0D /* MMEAPIClient.m in Sources */, DA8848591CBAFB9800AB86E3 /* MGLMapView.mm in Sources */, DA8848501CBAFB9800AB86E3 /* MGLAnnotationImage.m in Sources */, + 40834BF01FE05E1800C1BD0D /* MMELocationManager.m in Sources */, DA8848281CBAFA6200AB86E3 /* MGLShape.mm in Sources */, DA35A2B31CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */, DD0902A91DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */, 35D13AB91D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */, + 40834C4C1FE05F7500C1BD0D /* TSKTrustKitConfig.m in Sources */, DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */, 071BBB001EE7613F001FB02A /* MGLImageSource.mm in Sources */, DA8848321CBAFA6200AB86E3 /* NSString+MGLAdditions.m in Sources */, + 40834C441FE05F7500C1BD0D /* reporting_utils.m in Sources */, 408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */, DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */, 35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */, + 40834BF61FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */, DA8848291CBAFA6200AB86E3 /* MGLStyle.mm in Sources */, 357FE2DF1E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */, + 40834BF81FE05E1800C1BD0D /* NSData+MMEGZIP.m in Sources */, DA88481C1CBAFA6200AB86E3 /* MGLGeometry.mm in Sources */, 558DE7A21E5615E400C7916D /* MGLFoundation.mm in Sources */, + 40834BE91FE05E1800C1BD0D /* MMECommonEventData.m in Sources */, 3510FFF21D6D9D8C00F413B2 /* NSExpression+MGLAdditions.mm in Sources */, DA88481F1CBAFA6200AB86E3 /* MGLMultiPoint.mm in Sources */, DA88482B1CBAFA6200AB86E3 /* MGLTypes.m in Sources */, @@ -2685,21 +2942,29 @@ 404C26E41D89B877000AA13D /* MGLTileSource.mm in Sources */, 07D947541F67489200E37934 /* MGLAbstractShapeSource.mm in Sources */, 355AE0011E9281DA00F3939D /* MGLScaleBar.mm in Sources */, + 40834C451FE05F7500C1BD0D /* TSKBackgroundReporter.m in Sources */, DA88481D1CBAFA6200AB86E3 /* MGLMapCamera.mm in Sources */, DACA86282019218600E9693A /* MGLRasterDEMSource.mm in Sources */, DA8848261CBAFA6200AB86E3 /* MGLPolygon.mm in Sources */, 35B82BFA1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */, - DA8848521CBAFB9800AB86E3 /* MGLAPIClient.m in Sources */, + 40834C401FE05F7500C1BD0D /* configuration_utils.m in Sources */, + 40834BF91FE05E1800C1BD0D /* MMEReachability.m in Sources */, + 40834BF21FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */, + 40834C471FE05F7500C1BD0D /* TSKReportsRateLimiter.m in Sources */, 966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */, 8989B17E201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */, DA8848301CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m in Sources */, + 40834BED1FE05E1800C1BD0D /* MMEEventLogger.m in Sources */, 353AFA161D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */, + 40834BF41FE05E1800C1BD0D /* MMETrustKitWrapper.m in Sources */, + 40834BEF1FE05E1800C1BD0D /* MMEEventsManager.m in Sources */, 35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */, DA8848241CBAFA6200AB86E3 /* MGLOfflineStorage.mm in Sources */, DA88482A1CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm in Sources */, 4049C29F1DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */, 35136D3F1D42273000C20EFD /* MGLLineStyleLayer.mm in Sources */, DA704CC41F65A475004B3F28 /* MGLMapAccessibilityElement.mm in Sources */, + 40834C421FE05F7500C1BD0D /* ssl_pin_verifier.m in Sources */, DA72620D1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */, DA88481A1CBAFA6200AB86E3 /* MGLAccountManager.m in Sources */, 3510FFFB1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */, @@ -2707,7 +2972,6 @@ DA8848271CBAFA6200AB86E3 /* MGLPolyline.mm in Sources */, DA8848581CBAFB9800AB86E3 /* MGLMapboxEvents.m in Sources */, 35CE61841D4165D9004F2359 /* UIColor+MGLAdditions.mm in Sources */, - DA8848561CBAFB9800AB86E3 /* MGLLocationManager.m in Sources */, 3EA93369F61CF70AFA50465D /* MGLRendererConfiguration.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2718,28 +2982,43 @@ files = ( 35136D3A1D42271A00C20EFD /* MGLBackgroundStyleLayer.mm in Sources */, 3510FFED1D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.mm in Sources */, + 40834C501FE05F7600C1BD0D /* TSKSPKIHashCache.m in Sources */, 354B83991D2E873E005D9406 /* MGLUserLocationAnnotationView.m in Sources */, + 40834C001FE05E1800C1BD0D /* MMEEvent.m in Sources */, 9620BB3B1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */, DAA4E4221CBB730400178DFB /* MGLPointAnnotation.mm in Sources */, + 40834C021FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */, DAED38661D62D0FC00D7640F /* NSURL+MGLAdditions.m in Sources */, DAD165711CF41981001FF4B9 /* MGLFeature.mm in Sources */, 30E5781A1DAA855E0050F07E /* UIImage+MGLAdditions.mm in Sources */, 40EDA1C21CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */, + 40834C551FE05F7600C1BD0D /* vendor_identifier.m in Sources */, DAA4E4291CBB730400178DFB /* NSBundle+MGLAdditions.m in Sources */, - DAA4E42E1CBB730400178DFB /* MGLAPIClient.m in Sources */, + 40834BFF1FE05E1800C1BD0D /* MMEDependencyManager.m in Sources */, + 40834C4E1FE05F7600C1BD0D /* parse_configuration.m in Sources */, + 40834BFE1FE05E1800C1BD0D /* MMEConstants.m in Sources */, 35136D3D1D42272500C20EFD /* MGLCircleStyleLayer.mm in Sources */, DD9BE4FA1EB263F40079A3AF /* UIViewController+MGLAdditions.m in Sources */, 350098DF1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */, DA6408DE1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */, 3566C7691D4A77BA008152BC /* MGLShapeSource.mm in Sources */, + 40834C0B1FE05E1800C1BD0D /* MMEUniqueIdentifier.m in Sources */, 400533031DB086490069F638 /* NSArray+MGLAdditions.mm in Sources */, + 40834C571FE05F7600C1BD0D /* TSKPinningValidator.m in Sources */, 35136D431D42274500C20EFD /* MGLRasterStyleLayer.mm in Sources */, 96036A04200565C700510F3D /* NSOrthography+MGLAdditions.m in Sources */, + 40834C071FE05E1800C1BD0D /* MMETimerManager.m in Sources */, 3538AA201D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */, DA00FC911D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */, + 40834C051FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */, + 40834C531FE05F7600C1BD0D /* TSKPinFailureReport.m in Sources */, + 40834BFA1FE05E1800C1BD0D /* CLLocation+MMEMobileEvents.m in Sources */, + 406E99BA1FFEFF1B00D9FFCC /* MMEEventLogReportViewController.m in Sources */, DAA4E4201CBB730400178DFB /* MGLOfflinePack.mm in Sources */, 966FCF551F3C323500F2B6DE /* MGLUserLocationHeadingArrowLayer.m in Sources */, DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */, + 406E99BC1FFF006D00D9FFCC /* MMEUINavigation.m in Sources */, + 40834BFC1FE05E1800C1BD0D /* MMECategoryLoader.m in Sources */, 927FBD021F4DB05500F8BF1F /* MGLMapSnapshotter.mm in Sources */, 350098BE1D480108004B2AF0 /* MGLVectorSource.mm in Sources */, 3566C76F1D4A8DFA008152BC /* MGLRasterSource.mm in Sources */, @@ -2750,27 +3029,36 @@ DAA4E4251CBB730400178DFB /* MGLShape.mm in Sources */, 35136D461D42275100C20EFD /* MGLSymbolStyleLayer.mm in Sources */, DAF2571A201901E200367EF5 /* MGLHillshadeStyleLayer.mm in Sources */, + 40834C091FE05E1800C1BD0D /* MMETypes.m in Sources */, 35599DEE1D46F14E0048254D /* MGLStyleValue.mm in Sources */, + 40834C561FE05F7600C1BD0D /* TrustKit.m in Sources */, DAA4E42B1CBB730400178DFB /* NSString+MGLAdditions.m in Sources */, DAA4E4261CBB730400178DFB /* MGLStyle.mm in Sources */, DAA32CC31E4C6B65006F8D24 /* MGLDistanceFormatter.m in Sources */, DAA4E41D1CBB730400178DFB /* MGLGeometry.mm in Sources */, + 40834C581FE05F7600C1BD0D /* TSKPinningValidatorResult.m in Sources */, + 40834BFB1FE05E1800C1BD0D /* MMEAPIClient.m in Sources */, DAA4E41F1CBB730400178DFB /* MGLMultiPoint.mm in Sources */, DD0902AA1DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */, + 40834C041FE05E1800C1BD0D /* MMELocationManager.m in Sources */, DA35A2B41CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */, 35D13ABA1D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */, 071BBAFF1EE7613E001FB02A /* MGLImageSource.mm in Sources */, DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */, + 40834C591FE05F7600C1BD0D /* TSKTrustKitConfig.m in Sources */, 408AA8591DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */, DAA4E4281CBB730400178DFB /* MGLTypes.m in Sources */, DA35A2A21CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */, + 40834C511FE05F7600C1BD0D /* reporting_utils.m in Sources */, 35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */, 357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */, DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */, + 40834C0A1FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */, 558DE7A31E5615E400C7916D /* MGLFoundation.mm in Sources */, 3510FFF31D6D9D8C00F413B2 /* NSExpression+MGLAdditions.mm in Sources */, - DAA4E4301CBB730400178DFB /* MGLLocationManager.m in Sources */, + 40834C0C1FE05E1800C1BD0D /* NSData+MMEGZIP.m in Sources */, DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */, + 40834BFD1FE05E1800C1BD0D /* MMECommonEventData.m in Sources */, DAA4E41E1CBB730400178DFB /* MGLMapCamera.mm in Sources */, FA68F14E1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm in Sources */, 1F7454921ECBB42C00021D39 /* MGLLight.mm in Sources */, @@ -2778,21 +3066,30 @@ 355AE0021E9281DA00F3939D /* MGLScaleBar.mm in Sources */, 4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */, 07D8C6FB1F67560100381808 /* MGLComputedShapeSource.mm in Sources */, + 40834C521FE05F7600C1BD0D /* TSKBackgroundReporter.m in Sources */, DAA4E4341CBB730400178DFB /* MGLFaux3DUserLocationAnnotationView.m in Sources */, DACA86292019218600E9693A /* MGLRasterDEMSource.mm in Sources */, 35B82BFB1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */, + 40834C4D1FE05F7600C1BD0D /* configuration_utils.m in Sources */, + 40834C0D1FE05E1800C1BD0D /* MMEReachability.m in Sources */, + 40834C061FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */, + 40834C541FE05F7600C1BD0D /* TSKReportsRateLimiter.m in Sources */, DAA4E4311CBB730400178DFB /* MGLMapboxEvents.m in Sources */, 966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */, DAA4E4231CBB730400178DFB /* MGLPolygon.mm in Sources */, 8989B17F201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */, 353AFA171D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */, + 40834C011FE05E1800C1BD0D /* MMEEventLogger.m in Sources */, 35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */, + 40834C081FE05E1800C1BD0D /* MMETrustKitWrapper.m in Sources */, + 40834C031FE05E1800C1BD0D /* MMEEventsManager.m in Sources */, DAA4E42A1CBB730400178DFB /* NSProcessInfo+MGLAdditions.m in Sources */, DAA4E4211CBB730400178DFB /* MGLOfflineStorage.mm in Sources */, 4049C2A01DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */, 07D8C6FC1F67560400381808 /* MGLAbstractShapeSource.mm in Sources */, 35136D401D42273000C20EFD /* MGLLineStyleLayer.mm in Sources */, DA704CC51F65A475004B3F28 /* MGLMapAccessibilityElement.mm in Sources */, + 40834C4F1FE05F7600C1BD0D /* ssl_pin_verifier.m in Sources */, DA72620E1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */, DAA4E42F1CBB730400178DFB /* MGLCompactCalloutView.m in Sources */, 3510FFFC1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */, @@ -3347,6 +3644,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "$SRCROOT/src/Mapbox-Prefix.pch"; HEADER_SEARCH_PATHS = ( "$(mbgl_core_INCLUDE_DIRECTORIES)", "$(mbgl_filesource_INCLUDE_DIRECTORIES)", @@ -3389,6 +3687,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "$SRCROOT/src/Mapbox-Prefix.pch"; HEADER_SEARCH_PATHS = ( "$(mbgl_core_INCLUDE_DIRECTORIES)", "$(mbgl_filesource_INCLUDE_DIRECTORIES)", diff --git a/platform/ios/resources/api_mapbox_com-digicert_2016.der b/platform/ios/resources/api_mapbox_com-digicert_2016.der Binary files differdeleted file mode 100644 index e8ef427f33..0000000000 --- a/platform/ios/resources/api_mapbox_com-digicert_2016.der +++ /dev/null diff --git a/platform/ios/resources/api_mapbox_com-digicert_2017.der b/platform/ios/resources/api_mapbox_com-digicert_2017.der Binary files differdeleted file mode 100644 index 4a190085ab..0000000000 --- a/platform/ios/resources/api_mapbox_com-digicert_2017.der +++ /dev/null diff --git a/platform/ios/resources/api_mapbox_com-geotrust_2016.der b/platform/ios/resources/api_mapbox_com-geotrust_2016.der Binary files differdeleted file mode 100644 index 1c7331dedc..0000000000 --- a/platform/ios/resources/api_mapbox_com-geotrust_2016.der +++ /dev/null diff --git a/platform/ios/resources/api_mapbox_com-geotrust_2017.der b/platform/ios/resources/api_mapbox_com-geotrust_2017.der Binary files differdeleted file mode 100644 index 7bb9befbbf..0000000000 --- a/platform/ios/resources/api_mapbox_com-geotrust_2017.der +++ /dev/null diff --git a/platform/ios/resources/api_mapbox_staging.der b/platform/ios/resources/api_mapbox_staging.der Binary files differdeleted file mode 100644 index 45f7df7c49..0000000000 --- a/platform/ios/resources/api_mapbox_staging.der +++ /dev/null diff --git a/platform/ios/src/MGLAPIClient.h b/platform/ios/src/MGLAPIClient.h deleted file mode 100644 index 4e5ea3b5e0..0000000000 --- a/platform/ios/src/MGLAPIClient.h +++ /dev/null @@ -1,15 +0,0 @@ -#import <Foundation/Foundation.h> - -#import "MGLMapboxEvents.h" -#import "MGLTypes.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface MGLAPIClient : NSObject <NSURLSessionDelegate> - -- (void)postEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler; -- (void)postEvent:(MGLMapboxEventAttributes *)event completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m deleted file mode 100644 index 8a987d76d8..0000000000 --- a/platform/ios/src/MGLAPIClient.m +++ /dev/null @@ -1,202 +0,0 @@ -#import "MGLAPIClient.h" -#import "NSBundle+MGLAdditions.h" -#import "NSData+MGLAdditions.h" -#import "MGLAccountManager.h" - -static NSString * const MGLAPIClientUserAgentBase = @"MapboxEventsiOS"; -static NSString * const MGLAPIClientBaseURL = @"https://events.mapbox.com"; -static NSString * const MGLAPIClientEventsPath = @"events/v2"; - -static NSString * const MGLAPIClientHeaderFieldUserAgentKey = @"User-Agent"; -static NSString * const MGLAPIClientHeaderFieldContentTypeKey = @"Content-Type"; -static NSString * const MGLAPIClientHeaderFieldContentTypeValue = @"application/json"; -static NSString * const MGLAPIClientHeaderFieldContentEncodingKey = @"Content-Encoding"; -static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; - -@interface MGLAPIClient () - -@property (nonatomic, copy) NSURLSession *session; -@property (nonatomic, copy) NSURL *baseURL; -@property (nonatomic, copy) NSData *digicertCert_2016; -@property (nonatomic, copy) NSData *geoTrustCert_2016; -@property (nonatomic, copy) NSData *digicertCert_2017; -@property (nonatomic, copy) NSData *geoTrustCert_2017; -@property (nonatomic, copy) NSData *testServerCert; -@property (nonatomic, copy) NSString *userAgent; -@property (nonatomic) BOOL usesTestServer; - -@end - -@implementation MGLAPIClient - -- (instancetype)init { - self = [super init]; - if (self) { - _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] - delegate:self delegateQueue:nil]; - [self loadCertificates]; - [self setupBaseURL]; - [self setupUserAgent]; - } - return self; -} - -#pragma mark Public API - -- (void)postEvents:(nonnull NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler { - __block NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self requestForEvents:events] - completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - NSError *statusError = nil; - if (httpResponse.statusCode >= 400) { - NSString *description = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"API_CLIENT_400_DESC", nil, nil, @"The session data task failed. Original request was: %@", nil), dataTask.originalRequest]; - NSString *reason = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"API_CLIENT_400_REASON", nil, nil, @"The status code was %ld", nil), (long)httpResponse.statusCode]; - NSDictionary *userInfo = @{NSLocalizedDescriptionKey: description, - NSLocalizedFailureReasonErrorKey: reason}; - statusError = [NSError errorWithDomain:MGLErrorDomain code:1 userInfo:userInfo]; - } - if (completionHandler) { - error = error ?: statusError; - completionHandler(error); - } - dataTask = nil; - }]; - [dataTask resume]; -} - -- (void)postEvent:(nonnull MGLMapboxEventAttributes *)event completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler { - [self postEvents:@[event] completionHandler:completionHandler]; -} - -#pragma mark Utilities - -- (NSURLRequest *)requestForEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { - NSString *path = [NSString stringWithFormat:@"%@?access_token=%@", MGLAPIClientEventsPath, [MGLAccountManager accessToken]]; - NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseURL]; - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; - [request setValue:self.userAgent forHTTPHeaderField:MGLAPIClientHeaderFieldUserAgentKey]; - [request setValue:MGLAPIClientHeaderFieldContentTypeValue forHTTPHeaderField:MGLAPIClientHeaderFieldContentTypeKey]; - [request setHTTPMethod:MGLAPIClientHTTPMethodPost]; - - NSData *jsonData = [self serializedDataForEvents:events]; - - // Compressing less than 3 events can have a negative impact on the size. - if (events.count > 2) { - NSData *compressedData = [jsonData mgl_compressedData]; - [request setValue:@"deflate" forHTTPHeaderField:MGLAPIClientHeaderFieldContentEncodingKey]; - [request setHTTPBody:compressedData]; - } - - // Set JSON data if events.count were less than 3 or something went wrong with compressing HTTP body data. - if (!request.HTTPBody) { - [request setValue:nil forHTTPHeaderField:MGLAPIClientHeaderFieldContentEncodingKey]; - [request setHTTPBody:jsonData]; - } - - return [request copy]; -} - -- (void)setupBaseURL { - NSString *testServerURLString = [[NSUserDefaults standardUserDefaults] stringForKey:@"MGLTelemetryTestServerURL"]; - NSURL *testServerURL = [NSURL URLWithString:testServerURLString]; - if (testServerURL && [testServerURL.scheme isEqualToString:@"https"]) { - self.baseURL = testServerURL; - self.usesTestServer = YES; - } else { - self.baseURL = [NSURL URLWithString:MGLAPIClientBaseURL]; - } -} - -- (void)loadCertificates { - NSData *certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-geotrust_2016"]; - self.geoTrustCert_2016 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-digicert_2016"]; - self.digicertCert_2016 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-geotrust_2017"]; - self.geoTrustCert_2017 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-digicert_2017"]; - self.digicertCert_2017 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_staging"]; - self.testServerCert = certificate; -} - -- (void)loadCertificate:(NSData **)certificate withResource:(NSString *)resource { - NSBundle *frameworkBundle = [NSBundle mgl_frameworkBundle]; - NSString *cerPath = [frameworkBundle pathForResource:resource ofType:@"der"]; - if (cerPath != nil) { - *certificate = [NSData dataWithContentsOfFile:cerPath]; - } -} - -- (void)setupUserAgent { - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; - NSString *appBuildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; - NSString *semanticVersion = [NSBundle mgl_frameworkInfoDictionary][@"MGLSemanticVersionString"]; - NSString *shortVersion = [NSBundle mgl_frameworkInfoDictionary][@"CFBundleShortVersionString"]; - NSString *sdkVersion = semanticVersion ?: shortVersion; - _userAgent = [NSString stringWithFormat:@"%@/%@/%@ %@/%@", appName, appVersion, appBuildNumber, MGLAPIClientUserAgentBase, sdkVersion]; -} - -#pragma mark - JSON Serialization - -- (NSData *)serializedDataForEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { - return [NSJSONSerialization dataWithJSONObject:events options:0 error:nil]; -} - -#pragma mark NSURLSessionDelegate - -- (BOOL)evaluateCertificateWithCertificateData:(NSData *)certificateData keyCount:(CFIndex)keyCount serverTrust:(SecTrustRef)serverTrust challenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { - for (int lc = 0; lc < keyCount; lc++) { - SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); - NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); - if ([remoteCertificateData isEqualToData:certificateData]) { - completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - return YES; - } - } - return NO; -} - -- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { - - if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; - SecTrustResultType trustResult; - - // Validate the certificate chain with the device's trust store anyway this *might* use revocation checking - SecTrustEvaluate(serverTrust, &trustResult); - - BOOL found = NO; // For clarity; we start in a state where the challange has not been completed and no certificate has been found - - if (trustResult == kSecTrustResultUnspecified) { - // Look for a pinned certificate in the server's certificate chain - CFIndex numKeys = SecTrustGetCertificateCount(serverTrust); - - // Check certs in the following order: digicert 2016, digicert 2017, geotrust 2016, geotrust 2017 - found = [self evaluateCertificateWithCertificateData:self.digicertCert_2016 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - if (!found) { - found = [self evaluateCertificateWithCertificateData:self.digicertCert_2017 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - if (!found) { - found = [self evaluateCertificateWithCertificateData:self.geoTrustCert_2016 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - if (!found) { - found = [self evaluateCertificateWithCertificateData:self.geoTrustCert_2017 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - - // If challenge can't be completed with any of the above certs, then try the test server if the app is configured to use the test server - if (!found && _usesTestServer) { - found = [self evaluateCertificateWithCertificateData:self.testServerCert keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - } - - if (!found) { - // No certificate was found so cancel the connection. - completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - } - } -} - -@end diff --git a/platform/ios/src/MGLLocationManager.h b/platform/ios/src/MGLLocationManager.h deleted file mode 100644 index ea23801813..0000000000 --- a/platform/ios/src/MGLLocationManager.h +++ /dev/null @@ -1,25 +0,0 @@ -#import <Foundation/Foundation.h> -#import <CoreLocation/CoreLocation.h> - -@protocol MGLLocationManagerDelegate; - -@interface MGLLocationManager : NSObject <CLLocationManagerDelegate> - -@property (nonatomic, weak) id<MGLLocationManagerDelegate> delegate; - -- (void)startUpdatingLocation; -- (void)stopUpdatingLocation; - -@end - -@protocol MGLLocationManagerDelegate <NSObject> - -@optional - -- (void)locationManager:(MGLLocationManager *)locationManager didUpdateLocations:(NSArray *)locations; -- (void)locationManagerDidStartLocationUpdates:(MGLLocationManager *)locationManager; -- (void)locationManagerBackgroundLocationUpdatesDidTimeout:(MGLLocationManager *)locationManager; -- (void)locationManagerBackgroundLocationUpdatesDidAutomaticallyPause:(MGLLocationManager *)locationManager; -- (void)locationManagerDidStopLocationUpdates:(MGLLocationManager *)locationManager; - -@end diff --git a/platform/ios/src/MGLLocationManager.m b/platform/ios/src/MGLLocationManager.m deleted file mode 100644 index 85ef4ca489..0000000000 --- a/platform/ios/src/MGLLocationManager.m +++ /dev/null @@ -1,175 +0,0 @@ -#import "MGLLocationManager.h" -#import "MGLTelemetryConfig.h" -#import <UIKit/UIKit.h> - -static const NSTimeInterval MGLLocationManagerHibernationTimeout = 300.0; -static const NSTimeInterval MGLLocationManagerHibernationPollInterval = 5.0; -static const CLLocationDistance MGLLocationManagerDistanceFilter = 5.0; -static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManagerRegionIdentifier.fence.center"; - -@interface MGLLocationManager () - -@property (nonatomic) CLLocationManager *standardLocationManager; -@property (nonatomic) BOOL hostAppHasBackgroundCapability; -@property (nonatomic, getter=isUpdatingLocation) BOOL updatingLocation; -@property (nonatomic) NSDate *backgroundLocationServiceTimeoutAllowedDate; -@property (nonatomic) NSTimer *backgroundLocationServiceTimeoutTimer; - -@end - -@implementation MGLLocationManager - -- (instancetype)init { - self = [super init]; - if (self) { - NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; - _hostAppHasBackgroundCapability = [backgroundModes containsObject:@"location"]; - } - return self; -} - -- (void)startUpdatingLocation { - if ([self isUpdatingLocation]) { - return; - } - - [self configurePassiveStandardLocationManager]; - [self startLocationServices]; -} - -- (void)stopUpdatingLocation { - if ([self isUpdatingLocation]) { - [self.standardLocationManager stopUpdatingLocation]; - [self.standardLocationManager stopMonitoringSignificantLocationChanges]; - self.updatingLocation = NO; - if ([self.delegate respondsToSelector:@selector(locationManagerDidStopLocationUpdates:)]) { - [self.delegate locationManagerDidStopLocationUpdates:self]; - } - } - if(self.standardLocationManager.monitoredRegions.count > 0) { - for(CLRegion *region in self.standardLocationManager.monitoredRegions) { - if([region.identifier isEqualToString:MGLLocationManagerRegionIdentifier]) { - [self.standardLocationManager stopMonitoringForRegion:region]; - } - } - } -} - -#pragma mark - Utilities - -- (void)configurePassiveStandardLocationManager { - if (!self.standardLocationManager) { - CLLocationManager *standardLocationManager = [[CLLocationManager alloc] init]; - standardLocationManager.delegate = self; - standardLocationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers; - standardLocationManager.distanceFilter = MGLLocationManagerDistanceFilter; - self.standardLocationManager = standardLocationManager; - } -} - -- (void)startLocationServices { - CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus]; -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000 - BOOL authorizedAlways = authorizationStatus == kCLAuthorizationStatusAuthorizedAlways; -#else - BOOL authorizedAlways = authorizationStatus == kCLAuthorizationStatusAuthorized; -#endif - if (authorizedAlways || authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse) { - // If the host app can run in the background with `always` location permissions then allow background - // updates and start the significant location change service and background timeout timer - if (self.hostAppHasBackgroundCapability && authorizedAlways) { - [self.standardLocationManager startMonitoringSignificantLocationChanges]; - [self startBackgroundTimeoutTimer]; - // On iOS 9 and above also allow background location updates - if ([self.standardLocationManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) { - self.standardLocationManager.allowsBackgroundLocationUpdates = YES; - } - } - - [self.standardLocationManager startUpdatingLocation]; - self.updatingLocation = YES; - if ([self.delegate respondsToSelector:@selector(locationManagerDidStartLocationUpdates:)]) { - [self.delegate locationManagerDidStartLocationUpdates:self]; - } - } -} - -- (void)timeoutAllowedCheck { - if (self.backgroundLocationServiceTimeoutAllowedDate == nil) { - return; - } - - if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive || - [UIApplication sharedApplication].applicationState == UIApplicationStateInactive ) { - [self startBackgroundTimeoutTimer]; - return; - } - - NSTimeInterval timeIntervalSinceTimeoutAllowed = [[NSDate date] timeIntervalSinceDate:self.backgroundLocationServiceTimeoutAllowedDate]; - if (timeIntervalSinceTimeoutAllowed > 0) { - [self.standardLocationManager stopUpdatingLocation]; - self.backgroundLocationServiceTimeoutAllowedDate = nil; - if ([self.delegate respondsToSelector:@selector(locationManagerBackgroundLocationUpdatesDidTimeout:)]) { - [self.delegate locationManagerBackgroundLocationUpdatesDidTimeout:self]; - } - } -} - -- (void)startBackgroundTimeoutTimer { - [self.backgroundLocationServiceTimeoutTimer invalidate]; - self.backgroundLocationServiceTimeoutAllowedDate = [[NSDate date] dateByAddingTimeInterval:MGLLocationManagerHibernationTimeout]; - self.backgroundLocationServiceTimeoutTimer = [NSTimer scheduledTimerWithTimeInterval:MGLLocationManagerHibernationPollInterval target:self selector:@selector(timeoutAllowedCheck) userInfo:nil repeats:YES]; -} - -- (void)establishRegionMonitoringForLocation:(CLLocation *)location { - CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:location.coordinate radius:MGLTelemetryConfig.sharedConfig.MGLLocationManagerHibernationRadius identifier:MGLLocationManagerRegionIdentifier]; - region.notifyOnEntry = NO; - region.notifyOnExit = YES; - [self.standardLocationManager startMonitoringForRegion:region]; -} - -#pragma mark - CLLocationManagerDelegate - -- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { - switch (status) { -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000 - case kCLAuthorizationStatusAuthorizedAlways: -#else - case kCLAuthorizationStatusAuthorized: -#endif - case kCLAuthorizationStatusAuthorizedWhenInUse: - [self startUpdatingLocation]; - break; - default: - [self stopUpdatingLocation]; - break; - } -} - -- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations { - CLLocation *location = locations.lastObject; - if (location.speed > 0.0) { - [self startBackgroundTimeoutTimer]; - } - if (self.standardLocationManager.monitoredRegions.count == 0 || location.horizontalAccuracy < MGLTelemetryConfig.sharedConfig.MGLLocationManagerHibernationRadius) { - [self establishRegionMonitoringForLocation:location]; - } - if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) { - [self.delegate locationManager:self didUpdateLocations:locations]; - } -} - -- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region { - [self startBackgroundTimeoutTimer]; - [self.standardLocationManager startUpdatingLocation]; -} - -- (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager { - if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { - if ([self.delegate respondsToSelector:@selector(locationManagerBackgroundLocationUpdatesDidAutomaticallyPause:)]) { - [self.delegate locationManagerBackgroundLocationUpdatesDidAutomaticallyPause:self]; - } - } -} - -@end diff --git a/platform/ios/src/MGLMapView+IBAdditions.h b/platform/ios/src/MGLMapView+IBAdditions.h index 6d5351df2b..64016e8319 100644 --- a/platform/ios/src/MGLMapView+IBAdditions.h +++ b/platform/ios/src/MGLMapView+IBAdditions.h @@ -44,6 +44,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) IBInspectable BOOL allowsTilting; @property (nonatomic) IBInspectable BOOL showsUserLocation; @property (nonatomic) IBInspectable BOOL showsHeading; +@property (nonatomic) IBInspectable BOOL showsScale; @end diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index a4dcc4cdbf..52d28d871c 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -221,8 +221,17 @@ MGL_EXPORT IB_DESIGNABLE - (IBAction)reloadStyle:(id)sender; /** + A Boolean value indicating whether the map may display scale information. + + The scale bar may not be shown at all zoom levels. The view controlled by this + property is available at `scaleBar`. The default value of this property is + `NO`. + */ +@property (nonatomic, assign) BOOL showsScale; + +/** A control indicating the scale of the map. The scale bar is positioned in the - upper-left corner. The scale bar is hidden by default. + upper-left corner. Enable the scale bar via `showsScale`. */ @property (nonatomic, readonly) UIView *scaleBar; @@ -484,6 +493,19 @@ MGL_EXPORT IB_DESIGNABLE @property(nonatomic, getter=isPitchEnabled) BOOL pitchEnabled; /** + A Boolean value that determines whether the user will receive haptic feedback + for certain interactions with the map. + + When this property is set to `YES`, the default, a `UIImpactFeedbackStyleLight` + haptic feedback event be played when the user rotates the map to due north + (0°). + + This feature requires a device that supports haptic feedback, running iOS 10 or + newer. + */ +@property(nonatomic, getter=isHapticFeedbackEnabled) BOOL hapticFeedbackEnabled; + +/** A floating-point value that determines the rate of deceleration after the user lifts their finger. @@ -659,11 +681,10 @@ MGL_EXPORT IB_DESIGNABLE want to animate the change, call `-setVisibleCoordinateBounds:animated:` instead. - If a longitude is less than −180 degrees or greater than 180 degrees, the visible - bounds straddles the antimeridian or international date line. - - For example, a visible bounds that stretches from Tokyo to San Francisco would have - coordinates of (35.68476, -220.24257) and (37.78428, -122.41310). + If a longitude is less than −180 degrees or greater than 180 degrees, the + visible bounds straddles the antimeridian or international date line. For + example, if both Tokyo and San Francisco are visible, the visible bounds might + extend from (35.68476, −220.24257) to (37.78428, −122.41310). */ @property (nonatomic) MGLCoordinateBounds visibleCoordinateBounds; @@ -671,11 +692,10 @@ MGL_EXPORT IB_DESIGNABLE Changes the receiver’s viewport to fit the given coordinate bounds, optionally animating the change. - To make the visible bounds go across the antimeridian or international date line, - specify some longitudes less than −180 degrees or greater than 180 degrees. - - For example, a visible bounds that stretches from Tokyo to San Francisco would have - coordinates of (35.68476, -220.24257) and (37.78428, -122.41310). + To bring both sides of the antimeridian or international date line into view, + specify some longitudes less than −180 degrees or greater than 180 degrees. For + example, to show both Tokyo and San Francisco simultaneously, you could set the + visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310). @param bounds The bounds that the viewport will show in its entirety. @param animated Specify `YES` to animate the change by smoothly scrolling @@ -686,6 +706,11 @@ MGL_EXPORT IB_DESIGNABLE /** Changes the receiver’s viewport to fit the given coordinate bounds and optionally some additional padding on each side. + + To bring both sides of the antimeridian or international date line into view, + specify some longitudes less than −180 degrees or greater than 180 degrees. For + example, to show both Tokyo and San Francisco simultaneously, you could set the + visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310). @param bounds The bounds that the viewport will show in its entirety. @param insets The minimum padding (in screen points) that will be visible @@ -698,6 +723,11 @@ MGL_EXPORT IB_DESIGNABLE /** Changes the receiver’s viewport to fit all of the given coordinates and optionally some additional padding on each side. + + To bring both sides of the antimeridian or international date line into view, + specify some longitudes less than −180 degrees or greater than 180 degrees. For + example, to show both Tokyo and San Francisco simultaneously, you could set the + visible coordinates to (35.68476, −220.24257) and (37.78428, −122.41310). @param coordinates The coordinates that the viewport will show. @param count The number of coordinates. This number must not be greater than @@ -712,6 +742,11 @@ MGL_EXPORT IB_DESIGNABLE /** Changes the receiver’s viewport to fit all of the given coordinates and optionally some additional padding on each side. + + To bring both sides of the antimeridian or international date line into view, + specify some longitudes less than −180 degrees or greater than 180 degrees. For + example, to show both Tokyo and San Francisco simultaneously, you could set the + visible coordinates to (35.68476, −220.24257) and (37.78428, −122.41310). @param coordinates The coordinates that the viewport will show. @param count The number of coordinates. This number must not be greater than @@ -994,6 +1029,9 @@ MGL_EXPORT IB_DESIGNABLE /** Converts a rectangle in the given view’s coordinate system to a geographic bounding box. + + If a longitude is less than −180 degrees or greater than 180 degrees, the + bounding box straddles the antimeridian or international date line. @param rect The rectangle to convert. @param view The view in whose coordinate system the rectangle is expressed. diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 2a25cb7970..fc505100a9 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -66,6 +66,7 @@ #import "MGLStyle_Private.h" #import "MGLStyleLayer_Private.h" #import "MGLMapboxEvents.h" +#import "MMEConstants.h" #import "MGLSDKUpdateChecker.h" #import "MGLCompactCalloutView.h" #import "MGLAnnotationContainerView.h" @@ -227,6 +228,7 @@ public: @property (nonatomic) CGFloat quickZoomStart; @property (nonatomic, getter=isDormant) BOOL dormant; @property (nonatomic, readonly, getter=isRotationAllowed) BOOL rotationAllowed; +@property (nonatomic) BOOL shouldTriggerHapticFeedbackForCompass; @property (nonatomic) MGLMapViewProxyAccessibilityElement *mapViewProxyAccessibilityElement; @property (nonatomic) MGLAnnotationContainerView *annotationContainerView; @property (nonatomic) MGLUserLocation *userLocation; @@ -524,6 +526,8 @@ public: [_twoFingerTap requireGestureRecognizerToFail:_twoFingerDrag]; [self addGestureRecognizer:_twoFingerTap]; + _hapticFeedbackEnabled = YES; + _decelerationRate = MGLMapViewDecelerationRateNormal; _quickZoom = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleQuickZoomGesture:)]; @@ -543,8 +547,9 @@ public: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTerminate) name:UIApplicationWillTerminateNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationWillEnterForegroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationWillResignActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationDidBecomeActiveNotification object:nil]; + // As of 3.7.5, we intentionally do not listen for `UIApplicationWillResignActiveNotification` or call `sleepGL:` in response to it, as doing + // so causes a loop when asking for location permission. See: https://github.com/mapbox/mapbox-gl-native/issues/11225 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil]; @@ -567,7 +572,8 @@ public: _targetCoordinate = kCLLocationCoordinate2DInvalid; if ([UIApplication sharedApplication].applicationState != UIApplicationStateBackground) { - [MGLMapboxEvents pushEvent:MGLEventTypeMapLoad withAttributes:@{}]; + [MGLMapboxEvents pushTurnstileEvent]; + [MGLMapboxEvents pushEvent:MMEEventTypeMapLoad withAttributes:@{}]; } } @@ -969,8 +975,8 @@ public: - (void)layoutSubviews { // Calling this here instead of in the scale bar itself because if this is done in the - // scale bar instance, it triggers a call to this this `layoutSubviews` method that - // calls `_mbglMap->setSize()` just below that triggers rendering update which triggers + // scale bar instance, it triggers a call to this `layoutSubviews` method that calls + // `_mbglMap->setSize()` just below that triggers rendering update which triggers // another scale bar update which causes a rendering update loop and a major performace // degradation. The only time the scale bar's intrinsic content size _must_ invalidated // is here as a reaction to this object's view dimension changes. @@ -1219,7 +1225,8 @@ public: [self validateLocationServices]; - [MGLMapboxEvents pushEvent:MGLEventTypeMapLoad withAttributes:@{}]; + [MGLMapboxEvents pushTurnstileEvent]; + [MGLMapboxEvents pushEvent:MMEEventTypeMapLoad withAttributes:@{}]; } } @@ -1331,7 +1338,7 @@ public: if (pan.state == UIGestureRecognizerStateBegan) { - [self trackGestureEvent:MGLEventGesturePanStart forRecognizer:pan]; + [self trackGestureEvent:MMEEventGesturePanStart forRecognizer:pan]; self.userTrackingMode = MGLUserTrackingModeNone; @@ -1379,10 +1386,10 @@ public: CLLocationCoordinate2D panCoordinate = [self convertPoint:pointInView toCoordinateFromView:pan.view]; int zoom = round([self zoomLevel]); - [MGLMapboxEvents pushEvent:MGLEventTypeMapDragEnd withAttributes:@{ - MGLEventKeyLatitude: @(panCoordinate.latitude), - MGLEventKeyLongitude: @(panCoordinate.longitude), - MGLEventKeyZoomLevel: @(zoom) + [MGLMapboxEvents pushEvent:MMEEventTypeMapDragEnd withAttributes:@{ + MMEEventKeyLatitude: @(panCoordinate.latitude), + MMEEventKeyLongitude: @(panCoordinate.longitude), + MMEEventKeyZoomLevel: @(zoom) }]; } @@ -1401,7 +1408,7 @@ public: if (pinch.state == UIGestureRecognizerStateBegan) { - [self trackGestureEvent:MGLEventGesturePinchStart forRecognizer:pinch]; + [self trackGestureEvent:MMEEventGesturePinchStart forRecognizer:pinch]; self.scale = powf(2, _mbglMap->getZoom()); @@ -1500,7 +1507,7 @@ public: if (rotate.state == UIGestureRecognizerStateBegan) { - [self trackGestureEvent:MGLEventGestureRotateStart forRecognizer:rotate]; + [self trackGestureEvent:MMEEventGestureRotateStart forRecognizer:rotate]; self.angle = MGLRadiansFromDegrees(_mbglMap->getBearing()) * -1; @@ -1509,6 +1516,8 @@ public: self.userTrackingMode = MGLUserTrackingModeFollow; } + self.shouldTriggerHapticFeedbackForCompass = NO; + [self notifyGestureDidBegin]; } else if (rotate.state == UIGestureRecognizerStateChanged) @@ -1531,6 +1540,22 @@ public: } [self cameraIsChanging]; + + // Trigger a light haptic feedback event when the user rotates to due north. + if (@available(iOS 10.0, *)) + { + if (self.isHapticFeedbackEnabled && fabs(newDegrees) <= 1 && self.shouldTriggerHapticFeedbackForCompass) + { + UIImpactFeedbackGenerator *hapticFeedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + [hapticFeedback impactOccurred]; + + self.shouldTriggerHapticFeedbackForCompass = NO; + } + else if (fabs(newDegrees) > 1) + { + self.shouldTriggerHapticFeedbackForCompass = YES; + } + } } else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled) { @@ -1572,7 +1597,7 @@ public: { return; } - [self trackGestureEvent:MGLEventGestureSingleTap forRecognizer:singleTap]; + [self trackGestureEvent:MMEEventGestureSingleTap forRecognizer:singleTap]; if (self.mapViewProxyAccessibilityElement.accessibilityElementIsFocused) { @@ -1694,7 +1719,7 @@ public: if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera]) { - [self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap]; + [self trackGestureEvent:MMEEventGestureDoubleTap forRecognizer:doubleTap]; mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y); _mbglMap->setZoom(newZoom, center, MGLDurationFromTimeInterval(MGLAnimationDuration)); @@ -1723,7 +1748,7 @@ public: if (twoFingerTap.state == UIGestureRecognizerStateBegan) { - [self trackGestureEvent:MGLEventGestureTwoFingerSingleTap forRecognizer:twoFingerTap]; + [self trackGestureEvent:MMEEventGestureTwoFingerSingleTap forRecognizer:twoFingerTap]; [self notifyGestureDidBegin]; } @@ -1762,7 +1787,7 @@ public: if (quickZoom.state == UIGestureRecognizerStateBegan) { - [self trackGestureEvent:MGLEventGestureQuickZoom forRecognizer:quickZoom]; + [self trackGestureEvent:MMEEventGestureQuickZoom forRecognizer:quickZoom]; self.scale = powf(2, _mbglMap->getZoom()); @@ -1807,7 +1832,7 @@ public: if (twoFingerDrag.state == UIGestureRecognizerStateBegan) { - [self trackGestureEvent:MGLEventGesturePitchStart forRecognizer:twoFingerDrag]; + [self trackGestureEvent:MMEEventGesturePitchStart forRecognizer:twoFingerDrag]; [self notifyGestureDidBegin]; } @@ -2012,11 +2037,11 @@ public: CLLocationCoordinate2D gestureCoordinate = [self convertPoint:pointInView toCoordinateFromView:recognizer.view]; int zoom = round([self zoomLevel]); - [MGLMapboxEvents pushEvent:MGLEventTypeMapTap withAttributes:@{ - MGLEventKeyLatitude: @(gestureCoordinate.latitude), - MGLEventKeyLongitude: @(gestureCoordinate.longitude), - MGLEventKeyZoomLevel: @(zoom), - MGLEventKeyGestureID: gestureID + [MGLMapboxEvents pushEvent:MMEEventTypeMapTap withAttributes:@{ + MMEEventKeyLatitude: @(gestureCoordinate.latitude), + MMEEventKeyLongitude: @(gestureCoordinate.longitude), + MMEEventKeyZoomLevel: @(zoom), + MMEEventKeyGestureID: gestureID }]; } @@ -2337,6 +2362,17 @@ public: self.twoFingerDrag.enabled = pitchEnabled; } +- (void)setShowsScale:(BOOL)showsScale +{ + _showsScale = showsScale; + self.scaleBar.hidden = !showsScale; + + if (showsScale) + { + [self updateScaleBar]; + } +} + #pragma mark - Accessibility - - (NSString *)accessibilityValue @@ -3419,36 +3455,24 @@ public: /// bounding box. - (mbgl::LatLngBounds)convertRect:(CGRect)rect toLatLngBoundsFromView:(nullable UIView *)view { - mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); - bounds.extend([self convertPoint:rect.origin toLatLngFromView:view]); - bounds.extend([self convertPoint:{ CGRectGetMaxX(rect), CGRectGetMinY(rect) } toLatLngFromView:view]); - bounds.extend([self convertPoint:{ CGRectGetMaxX(rect), CGRectGetMaxY(rect) } toLatLngFromView:view]); - bounds.extend([self convertPoint:{ CGRectGetMinX(rect), CGRectGetMaxY(rect) } toLatLngFromView:view]); - - // The world is wrapping if a point just outside the bounds is also within - // the rect. - mbgl::LatLng outsideLatLng; - if (bounds.west() > -180) - { - outsideLatLng = { - (bounds.south() + bounds.north()) / 2, - bounds.west() - 1, - }; - } - else if (bounds.east() < 180) - { - outsideLatLng = { - (bounds.south() + bounds.north()) / 2, - bounds.east() + 1, - }; - } - - // If the world is wrapping, extend the bounds to cover all longitudes. - if (CGRectContainsPoint(rect, [self convertLatLng:outsideLatLng toPointToView:view])) - { - bounds.extend(mbgl::LatLng(bounds.south(), -180)); - bounds.extend(mbgl::LatLng(bounds.south(), 180)); - } + auto bounds = mbgl::LatLngBounds::empty(); + auto topLeft = [self convertPoint:{ CGRectGetMinX(rect), CGRectGetMinY(rect) } toLatLngFromView:view]; + auto topRight = [self convertPoint:{ CGRectGetMaxX(rect), CGRectGetMinY(rect) } toLatLngFromView:view]; + auto bottomRight = [self convertPoint:{ CGRectGetMaxX(rect), CGRectGetMaxY(rect) } toLatLngFromView:view]; + auto bottomLeft = [self convertPoint:{ CGRectGetMinX(rect), CGRectGetMaxY(rect) } toLatLngFromView:view]; + + // If the bounds straddles the antimeridian, unwrap it so that one side + // extends beyond ±180° longitude. + auto center = [self convertPoint:{ CGRectGetMidX(rect), CGRectGetMidY(rect) } toLatLngFromView:view]; + topLeft.unwrapForShortestPath(center); + topRight.unwrapForShortestPath(center); + bottomRight.unwrapForShortestPath(center); + bottomLeft.unwrapForShortestPath(center); + + bounds.extend(topLeft); + bounds.extend(topRight); + bounds.extend(bottomRight); + bounds.extend(bottomLeft); return bounds; } @@ -5396,10 +5420,7 @@ public: } [self updateCompass]; - - if (!self.scaleBar.hidden) { - [(MGLScaleBar *)self.scaleBar setMetersPerPoint:[self metersPerPointAtLatitude:self.centerCoordinate.latitude]]; - } + [self updateScaleBar]; if ([self.delegate respondsToSelector:@selector(mapView:regionIsChangingWithReason:)]) { @@ -5417,6 +5438,7 @@ public: } [self updateCompass]; + [self updateScaleBar]; if ( ! [self isSuppressingChangeDelimiters]) { @@ -5861,6 +5883,17 @@ public: } } +- (void)updateScaleBar +{ + // Use the `hidden` property (instead of `self.showsScale`) so that we don't + // break developers who still rely on the <4.0.0 approach of directly + // setting this property. + if ( ! self.scaleBar.hidden) + { + [(MGLScaleBar *)self.scaleBar setMetersPerPoint:[self metersPerPointAtLatitude:self.centerCoordinate.latitude]]; + } +} + + (UIImage *)resourceImageNamed:(NSString *)imageName { UIImage *image = [UIImage imageNamed:imageName diff --git a/platform/ios/src/MGLMapboxEvents.h b/platform/ios/src/MGLMapboxEvents.h index 98f59ffd3f..cbac578798 100644 --- a/platform/ios/src/MGLMapboxEvents.h +++ b/platform/ios/src/MGLMapboxEvents.h @@ -1,44 +1,17 @@ #import <Foundation/Foundation.h> - -#import "MGLTypes.h" +#import "MMEEventsManager.h" NS_ASSUME_NONNULL_BEGIN -// Event types -extern NSString *const MGLEventTypeAppUserTurnstile; -extern NSString *const MGLEventTypeMapLoad; -extern NSString *const MGLEventTypeMapTap; -extern NSString *const MGLEventTypeMapDragEnd; -extern NSString *const MGLEventTypeLocation; - -// Event keys -extern NSString *const MGLEventKeyLatitude; -extern NSString *const MGLEventKeyLongitude; -extern NSString *const MGLEventKeyZoomLevel; -extern NSString *const MGLEventKeyGestureID; - -// Gestures -extern NSString *const MGLEventGestureSingleTap; -extern NSString *const MGLEventGestureDoubleTap; -extern NSString *const MGLEventGestureTwoFingerSingleTap; -extern NSString *const MGLEventGestureQuickZoom; -extern NSString *const MGLEventGesturePanStart; -extern NSString *const MGLEventGesturePinchStart; -extern NSString *const MGLEventGestureRotateStart; -extern NSString *const MGLEventGesturePitchStart; - -typedef NS_DICTIONARY_OF(NSString *, id) MGLMapboxEventAttributes; -typedef NS_MUTABLE_DICTIONARY_OF(NSString *, id) MGLMutableMapboxEventAttributes; - @interface MGLMapboxEvents : NSObject -+ (nullable instancetype)sharedManager; ++ (nullable instancetype)sharedInstance; -// You must call these methods from the main thread. -// -+ (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary; -+ (void)ensureMetricsOptoutExists; ++ (void)setupWithAccessToken:(NSString *)accessToken; ++ (void)pushTurnstileEvent; ++ (void)pushEvent:(NSString *)event withAttributes:(MMEMapboxEventAttributes *)attributeDictionary; + (void)flush; ++ (void)ensureMetricsOptoutExists; @end diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m index 273af5b3bc..05f291d8a0 100644 --- a/platform/ios/src/MGLMapboxEvents.m +++ b/platform/ios/src/MGLMapboxEvents.m @@ -1,646 +1,166 @@ #import "MGLMapboxEvents.h" -#import <UIKit/UIKit.h> -#import <CoreLocation/CoreLocation.h> -#import "MGLAccountManager.h" +#import "NSBundle+MGLAdditions.h" #import "NSProcessInfo+MGLAdditions.h" -#import "NSException+MGLAdditions.h" -#import "MGLAPIClient.h" -#import "MGLLocationManager.h" -#import "MGLTelemetryConfig.h" -#include <mbgl/storage/reachability.h> -#include <sys/sysctl.h> +static NSString * const MGLAPIClientUserAgentBase = @"mapbox-maps-ios"; +static NSString * const MGLMapboxAccountType = @"MGLMapboxAccountType"; +static NSString * const MGLMapboxMetricsEnabled = @"MGLMapboxMetricsEnabled"; +static NSString * const MGLMapboxMetricsDebugLoggingEnabled = @"MGLMapboxMetricsDebugLoggingEnabled"; +static NSString * const MGLTelemetryAccessToken = @"MGLTelemetryAccessToken"; +static NSString * const MGLTelemetryBaseURL = @"MGLTelemetryBaseURL"; -// Event types -NSString *const MGLEventTypeAppUserTurnstile = @"appUserTurnstile"; -NSString *const MGLEventTypeMapLoad = @"map.load"; -NSString *const MGLEventTypeMapTap = @"map.click"; -NSString *const MGLEventTypeMapDragEnd = @"map.dragend"; -NSString *const MGLEventTypeLocation = @"location"; -NSString *const MGLEventTypeLocalDebug = @"debug"; +@interface MGLMapboxEvents () -// Gestures -NSString *const MGLEventGestureSingleTap = @"SingleTap"; -NSString *const MGLEventGestureDoubleTap = @"DoubleTap"; -NSString *const MGLEventGestureTwoFingerSingleTap = @"TwoFingerTap"; -NSString *const MGLEventGestureQuickZoom = @"QuickZoom"; -NSString *const MGLEventGesturePanStart = @"Pan"; -NSString *const MGLEventGesturePinchStart = @"Pinch"; -NSString *const MGLEventGestureRotateStart = @"Rotation"; -NSString *const MGLEventGesturePitchStart = @"Pitch"; - -// Event keys -NSString *const MGLEventKeyLatitude = @"lat"; -NSString *const MGLEventKeyLongitude = @"lng"; -NSString *const MGLEventKeyZoomLevel = @"zoom"; -NSString *const MGLEventKeySpeed = @"speed"; -NSString *const MGLEventKeyCourse = @"course"; -NSString *const MGLEventKeyGestureID = @"gesture"; -NSString *const MGLEventHorizontalAccuracy = @"horizontalAccuracy"; -NSString *const MGLEventKeyLocalDebugDescription = @"debug.description"; - -static NSString *const MGLEventKeyEvent = @"event"; -static NSString *const MGLEventKeyCreated = @"created"; -static NSString *const MGLEventKeyVendorID = @"userId"; -static NSString *const MGLEventKeyModel = @"model"; -static NSString *const MGLEventKeyEnabledTelemetry = @"enabled.telemetry"; -static NSString *const MGLEventKeyOperatingSystem = @"operatingSystem"; -static NSString *const MGLEventKeyResolution = @"resolution"; -static NSString *const MGLEventKeyAccessibilityFontScale = @"accessibilityFontScale"; -static NSString *const MGLEventKeyOrientation = @"orientation"; -static NSString *const MGLEventKeyPluggedIn = @"pluggedIn"; -static NSString *const MGLEventKeyWifi = @"wifi"; -static NSString *const MGLEventKeySource = @"source"; -static NSString *const MGLEventKeySessionId = @"sessionId"; -static NSString *const MGLEventKeyApplicationState = @"applicationState"; -static NSString *const MGLEventKeyAltitude = @"altitude"; - -static NSString *const MGLMapboxAccountType = @"MGLMapboxAccountType"; -static NSString *const MGLMapboxMetricsEnabled = @"MGLMapboxMetricsEnabled"; - -// SDK event source -static NSString *const MGLEventSource = @"mapbox"; - -// Event application state -static NSString *const MGLApplicationStateForeground = @"Foreground"; -static NSString *const MGLApplicationStateBackground = @"Background"; -static NSString *const MGLApplicationStateInactive = @"Inactive"; -static NSString *const MGLApplicationStateUnknown = @"Unknown"; - -const NSUInteger MGLMaximumEventsPerFlush = 180; -const NSTimeInterval MGLFlushInterval = 180; - -@interface MGLMapboxEventsData : NSObject - -@property (nonatomic) NSString *vendorId; -@property (nonatomic) NSString *model; -@property (nonatomic) NSString *iOSVersion; -@property (nonatomic) CGFloat scale; - -@end - -@implementation MGLMapboxEventsData - -- (instancetype)init { - if (self = [super init]) { - _vendorId = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; - _model = [self sysInfoByName:"hw.machine"]; - _iOSVersion = [NSString stringWithFormat:@"%@ %@", [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion]; - if ([UIScreen instancesRespondToSelector:@selector(nativeScale)]) { - _scale = [UIScreen mainScreen].nativeScale; - } else { - _scale = [UIScreen mainScreen].scale; - } - } - return self; -} - -- (NSString *)sysInfoByName:(char *)typeSpecifier { - size_t size; - sysctlbyname(typeSpecifier, NULL, &size, NULL, 0); - - char *answer = malloc(size); - sysctlbyname(typeSpecifier, answer, &size, NULL, 0); - - NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding]; - - free(answer); - return results; -} +@property (nonatomic) MMEEventsManager *eventsManager; +@property (nonatomic) NSURL *baseURL; +@property (nonatomic, copy) NSString *accessToken; @end +@implementation MGLMapboxEvents -@interface MGLMapboxEvents () <MGLLocationManagerDelegate> - -@property (nonatomic) MGLMapboxEventsData *data; -@property (nonatomic, copy) NSString *appBundleId; -@property (nonatomic, readonly) NSString *instanceID; -@property (nonatomic, copy) NSString *dateForDebugLogFile; -@property (nonatomic) NSDateFormatter *rfc3339DateFormatter; -@property (nonatomic) MGLAPIClient *apiClient; -@property (nonatomic) BOOL usesTestServer; -@property (nonatomic) BOOL canEnableDebugLogging; -@property (nonatomic, getter=isPaused) BOOL paused; -@property (nonatomic) NS_MUTABLE_ARRAY_OF(MGLMapboxEventAttributes *) *eventQueue; -@property (nonatomic) dispatch_queue_t serialQueue; -@property (nonatomic) dispatch_queue_t debugLogSerialQueue; -@property (nonatomic) MGLLocationManager *locationManager; -@property (nonatomic) NSTimer *timer; -@property (nonatomic) NSDate *instanceIDRotationDate; -@property (nonatomic) NSDate *nextTurnstileSendDate; -@property (nonatomic) NSNumber *currentAccountTypeValue; -@property (nonatomic) BOOL currentMetricsEnabledValue; - -@end - -@implementation MGLMapboxEvents { - NSString *_instanceID; - UIBackgroundTaskIdentifier _backgroundTaskIdentifier; -} + (void)initialize { if (self == [MGLMapboxEvents class]) { NSBundle *bundle = [NSBundle mainBundle]; NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:MGLMapboxAccountType]; - [[NSUserDefaults standardUserDefaults] registerDefaults:@{ - MGLMapboxAccountType: accountTypeNumber ?: @0, - MGLMapboxMetricsEnabled: @YES, - @"MGLMapboxMetricsDebugLoggingEnabled": @NO, - }]; + [[NSUserDefaults standardUserDefaults] registerDefaults:@{MGLMapboxAccountType: accountTypeNumber ?: @0, + MGLMapboxMetricsEnabled: @YES, + MGLMapboxMetricsDebugLoggingEnabled: @NO}]; } } -+ (BOOL)isEnabled { -#if TARGET_OS_SIMULATOR - return NO; -#else - BOOL isLowPowerModeEnabled = NO; - if ([NSProcessInfo instancesRespondToSelector:@selector(isLowPowerModeEnabled)]) { - isLowPowerModeEnabled = [[NSProcessInfo processInfo] isLowPowerModeEnabled]; ++ (nullable instancetype)sharedInstance { + if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) { + return nil; } - return ([[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabled] && - [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType] == 0 && - !isLowPowerModeEnabled); -#endif -} - - -- (BOOL)debugLoggingEnabled { - return (self.canEnableDebugLogging && - [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"]); + + static dispatch_once_t onceToken; + static MGLMapboxEvents *_sharedInstance; + dispatch_once(&onceToken, ^{ + _sharedInstance = [[self alloc] init]; + }); + return _sharedInstance; } -- (instancetype) init { +- (instancetype)init { self = [super init]; if (self) { - [MGLTelemetryConfig.sharedConfig configurationFromKey:[[NSUserDefaults standardUserDefaults] objectForKey:MGLMapboxMetricsProfile]]; + _eventsManager = [[MMEEventsManager alloc] init]; + _eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsDebugLoggingEnabled]; + _eventsManager.accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType]; + _eventsManager.metricsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabled]; - _currentAccountTypeValue = @0; - _currentMetricsEnabledValue = YES; - - _appBundleId = [[NSBundle mainBundle] bundleIdentifier]; - _apiClient = [[MGLAPIClient alloc] init]; - - NSString *uniqueID = [[NSProcessInfo processInfo] globallyUniqueString]; - _serialQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@.%@.events.serial", _appBundleId, uniqueID] UTF8String], DISPATCH_QUEUE_SERIAL); - - _locationManager = [[MGLLocationManager alloc] init]; - _locationManager.delegate = self; - _paused = YES; - [self resumeMetricsCollection]; - - // Events Control - _eventQueue = [[NSMutableArray alloc] init]; - - // Setup Date Format - _rfc3339DateFormatter = [[NSDateFormatter alloc] init]; - NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; - - [_rfc3339DateFormatter setLocale:enUSPOSIXLocale]; - [_rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"]; - // Clear Any System TimeZone Cache - [NSTimeZone resetSystemTimeZone]; - [_rfc3339DateFormatter setTimeZone:[NSTimeZone systemTimeZone]]; - - // Configure logging - if ([self isProbablyAppStoreBuild]) { - self.canEnableDebugLogging = NO; - - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"]) { - NSLog(@"Telemetry logging is only enabled in non-app store builds."); - } - } else { - self.canEnableDebugLogging = YES; + // It is possible for the shared instance of this class to be created because of a call to + // +[MGLAccountManager load] early on in the app lifecycle of the host application. + // If user default values for access token and base URL are available, they are stored here + // on local properties so that they can be applied later once MMEEventsManager is fully initialized + // (once -[MMEEventsManager initializeWithAccessToken:userAgentBase:hostSDKVersion:] is called. + // Normally, the telem access token and base URL are not set this way. However, overriding these values + // with user defaults can be useful for testing with an alternative (test) backend system. + if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessToken]) { + self.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessToken]; } - - // Watch for changes to telemetry settings by the user - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:nil]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseOrResumeMetricsCollectionIfRequired) name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseOrResumeMetricsCollectionIfRequired) name:UIApplicationDidBecomeActiveNotification object:nil]; - - // Watch for Low Power Mode change events - if (&NSProcessInfoPowerStateDidChangeNotification != NULL) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseOrResumeMetricsCollectionIfRequired) name:NSProcessInfoPowerStateDidChangeNotification object:nil]; + if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURL]) { + self.baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURL]]; } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:nil]; } return self; } -// Called implicitly from any public class convenience methods. -// May return nil if this feature is disabled. -// -+ (nullable instancetype)sharedManager { - if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) { - return nil; - } - static dispatch_once_t onceToken; - static MGLMapboxEvents *_sharedManager; - dispatch_once(&onceToken, ^{ - _sharedManager = [[self alloc] init]; - }); - return _sharedManager; -} - - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self pauseMetricsCollection]; } -- (NSString *)instanceID { - if (self.instanceIDRotationDate && [[NSDate date] timeIntervalSinceDate:self.instanceIDRotationDate] >= 0) { - _instanceID = nil; +- (void)userDefaultsDidChange:(NSNotification *)notification { + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNonDisablingConfigurationValues]; + [self updateDisablingConfigurationValuesWithNotification:notification]; + }); +} + +- (void)updateNonDisablingConfigurationValues { + self.eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"]; + + // It is possible for `MGLTelemetryAccessToken` to have been set yet `userDefaultsDidChange:` + // is called before `setupWithAccessToken:` is called. + // In that case, setting the access token here will have no effect. In practice, that's fine + // because the access token value will be resolved when `setupWithAccessToken:` is called eventually + if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessToken]) { + self.eventsManager.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessToken]; } - if (!_instanceID) { - _instanceID = [[NSUUID UUID] UUIDString]; - NSTimeInterval twentyFourHourTimeInterval = 24 * 3600; - self.instanceIDRotationDate = [[NSDate date] dateByAddingTimeInterval:twentyFourHourTimeInterval]; + + // It is possible for `MGLTelemetryBaseURL` to have been set yet `userDefaultsDidChange:` + // is called before setupWithAccessToken: is called. + // In that case, setting the base URL here will have no effect. In practice, that's fine + // because the base URL value will be resolved when `setupWithAccessToken:` is called eventually + if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURL]) { + NSURL *baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURL]]; + self.eventsManager.baseURL = baseURL; } - return _instanceID; } -- (void)userDefaultsDidChange:(NSNotification *)notification { - +- (void)updateDisablingConfigurationValuesWithNotification:(NSNotification *)notification { // Guard against over calling pause / resume if the values this implementation actually - // cares about have not changed - + // cares about have not changed. We guard because the pause and resume method checks CoreLocation's + // authorization status and that can drag on the main thread if done too many times (e.g. if the host + // app heavily uses the user defaults API and this method is called very frequently) if ([[notification object] respondsToSelector:@selector(objectForKey:)]) { NSUserDefaults *userDefaults = [notification object]; - NSNumber *accountType = [userDefaults objectForKey:MGLMapboxAccountType]; - BOOL metricsEnabled = [[userDefaults objectForKey:MGLMapboxMetricsEnabled] boolValue]; - - if (![accountType isEqualToNumber:self.currentAccountTypeValue] || metricsEnabled != self.currentMetricsEnabledValue) { - [self pauseOrResumeMetricsCollectionIfRequired]; - self.currentAccountTypeValue = accountType; - self.currentMetricsEnabledValue = metricsEnabled; - } - } - -} - -- (void)pauseOrResumeMetricsCollectionIfRequired { - - // [CLLocationManager authorizationStatus] has been found to block in some cases so - // dispatch the call to a non-UI thread - dispatch_async(self.serialQueue, ^{ - CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; + NSInteger accountType = [userDefaults integerForKey:MGLMapboxAccountType]; + BOOL metricsEnabled = [userDefaults boolForKey:MGLMapboxMetricsEnabled]; - // Checking application state must be done on the main thread for safety and - // to avoid a thread sanitizer error - dispatch_async(dispatch_get_main_queue(), ^{ - UIApplication *application = [UIApplication sharedApplication]; - UIApplicationState state = application.applicationState; - - // Prevent blue status bar when host app has `when in use` permission only and it is not in foreground - if (status == kCLAuthorizationStatusAuthorizedWhenInUse && state == UIApplicationStateBackground) { - if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) { - _backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{ - [application endBackgroundTask:_backgroundTaskIdentifier]; - _backgroundTaskIdentifier = UIBackgroundTaskInvalid; - }]; - [self flush]; - } - [self pauseMetricsCollection]; - return; - } + if (accountType != self.eventsManager.accountType || metricsEnabled != self.eventsManager.metricsEnabled) { + self.eventsManager.accountType = accountType; + self.eventsManager.metricsEnabled = metricsEnabled; - // Toggle pause based on current pause state, user opt-out state, and low-power state. - BOOL enabled = [[self class] isEnabled]; - if (self.paused && enabled) { - [self resumeMetricsCollection]; - } else if (!self.paused && !enabled) { - [self flush]; - [self pauseMetricsCollection]; - } - }); - }); -} - -- (void)pauseMetricsCollection { - if (self.paused) { - return; - } - - self.paused = YES; - [self.timer invalidate]; - self.timer = nil; - [self.eventQueue removeAllObjects]; - self.data = nil; - - [self.locationManager stopUpdatingLocation]; -} - -- (void)resumeMetricsCollection { - if (!self.paused || ![[self class] isEnabled]) { - return; - } - - self.paused = NO; - self.data = [[MGLMapboxEventsData alloc] init]; - - [self.locationManager startUpdatingLocation]; -} - -+ (void)flush { - [[MGLMapboxEvents sharedManager] flush]; -} - -- (void)flush { - if ([MGLAccountManager accessToken] == nil) { - return; - } - - NSArray *events = [NSArray arrayWithArray:self.eventQueue]; - [self.eventQueue removeAllObjects]; - - [self postEvents:events]; - - if (self.timer) { - [self.timer invalidate]; - self.timer = nil; - } - - [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription:@"flush"}]; -} - -- (void)pushTurnstileEvent { - if (self.nextTurnstileSendDate && [[NSDate date] timeIntervalSinceDate:self.nextTurnstileSendDate] < 0) { - return; - } - - NSString *vendorID = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; - if (!vendorID) { - return; - } - - NSDictionary *turnstileEventAttributes = @{MGLEventKeyEvent: MGLEventTypeAppUserTurnstile, - MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]], - MGLEventKeyVendorID: vendorID, - MGLEventKeyEnabledTelemetry: @([[self class] isEnabled])}; - - if ([MGLAccountManager accessToken] == nil) { - return; - } - - __weak __typeof__(self) weakSelf = self; - [self.apiClient postEvent:turnstileEventAttributes completionHandler:^(NSError * _Nullable error) { - __strong __typeof__(weakSelf) strongSelf = weakSelf; - if (error) { - [strongSelf pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"Network error", - @"error": error}]; - return; + [self.eventsManager pauseOrResumeMetricsCollectionIfRequired]; } - [strongSelf writeEventToLocalDebugLog:turnstileEventAttributes]; - [strongSelf updateNextTurnstileSendDate]; - }]; -} - -- (void)updateNextTurnstileSendDate { - // Find the time a day from now (sometime tomorrow) - NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; - NSDateComponents *dayComponent = [[NSDateComponents alloc] init]; - dayComponent.day = 1; - NSDate *sometimeTomorrow = [calendar dateByAddingComponents:dayComponent toDate:[NSDate date] options:0]; - - // Find the start of tomorrow and use that as the next turnstile send date. The effect of this is that - // turnstile events can be sent as much as once per calendar day and always at the start of a session - // when a map load happens. - NSDate *startOfTomorrow = nil; - [calendar rangeOfUnit:NSCalendarUnitDay startDate:&startOfTomorrow interval:nil forDate:sometimeTomorrow]; - self.nextTurnstileSendDate = startOfTomorrow; -} - -+ (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - [[MGLMapboxEvents sharedManager] pushEvent:event withAttributes:attributeDictionary]; -} - -- (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - if (!event) { - return; - } - - if ([event isEqualToString:MGLEventTypeMapLoad]) { - [self pushTurnstileEvent]; - } - - if (self.paused) { - return; - } - - MGLMapboxEventAttributes *fullyFormedEvent = [self fullyFormedEventForEvent:event withAttributes:attributeDictionary]; - if (fullyFormedEvent) { - [self.eventQueue addObject:fullyFormedEvent]; - [self writeEventToLocalDebugLog:fullyFormedEvent]; - // Has Flush Limit Been Reached? - if (self.eventQueue.count >= MGLMaximumEventsPerFlush) { - [self flush]; - } else if (self.eventQueue.count == 1) { - // If this is first new event on queue start timer, - [self startTimer]; - } - } else { - [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"Unknown event", - @"eventName": event, - @"event.attributes": attributeDictionary}]; - } -} - -#pragma mark Events - -- (MGLMapboxEventAttributes *)fullyFormedEventForEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - if ([event isEqualToString:MGLEventTypeMapLoad]) { - return [self mapLoadEventWithAttributes:attributeDictionary]; - } else if ([event isEqualToString:MGLEventTypeMapTap]) { - return [self mapClickEventWithAttributes:attributeDictionary]; - } else if ([event isEqualToString:MGLEventTypeMapDragEnd]) { - return [self mapDragEndEventWithAttributes:attributeDictionary]; - } else if ([event isEqualToString:MGLEventTypeLocation]) { - return [self locationEventWithAttributes:attributeDictionary]; } - return nil; -} - -- (MGLMapboxEventAttributes *)locationEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary]; - attributes[MGLEventKeyEvent] = MGLEventTypeLocation; - attributes[MGLEventKeySource] = MGLEventSource; - attributes[MGLEventKeySessionId] = self.instanceID; - attributes[MGLEventKeyOperatingSystem] = self.data.iOSVersion; - NSString *currentApplicationState = [self applicationState]; - if (![currentApplicationState isEqualToString:MGLApplicationStateUnknown]) { - attributes[MGLEventKeyApplicationState] = currentApplicationState; - } - - return [self eventForAttributes:attributes attributeDictionary:attributeDictionary]; -} - -- (MGLMapboxEventAttributes *)mapLoadEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary]; - attributes[MGLEventKeyEvent] = MGLEventTypeMapLoad; - attributes[MGLEventKeyCreated] = [self.rfc3339DateFormatter stringFromDate:[NSDate date]]; - attributes[MGLEventKeyVendorID] = self.data.vendorId; - attributes[MGLEventKeyModel] = self.data.model; - attributes[MGLEventKeyOperatingSystem] = self.data.iOSVersion; - attributes[MGLEventKeyResolution] = @(self.data.scale); - attributes[MGLEventKeyAccessibilityFontScale] = @([self contentSizeScale]); - attributes[MGLEventKeyOrientation] = [self deviceOrientation]; - attributes[MGLEventKeyWifi] = @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi]); - - return [self eventForAttributes:attributes attributeDictionary:attributeDictionary]; -} - -- (MGLMapboxEventAttributes *)mapClickEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - MGLMutableMapboxEventAttributes *attributes = [self interactionEvent]; - attributes[MGLEventKeyEvent] = MGLEventTypeMapTap; - return [self eventForAttributes:attributes attributeDictionary:attributeDictionary]; -} - -- (MGLMapboxEventAttributes *)mapDragEndEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - MGLMutableMapboxEventAttributes *attributes = [self interactionEvent]; - attributes[MGLEventKeyEvent] = MGLEventTypeMapDragEnd; - - return [self eventForAttributes:attributes attributeDictionary:attributeDictionary]; } -- (MGLMutableMapboxEventAttributes *)interactionEvent { - MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary]; - attributes[MGLEventKeyCreated] = [self.rfc3339DateFormatter stringFromDate:[NSDate date]]; - attributes[MGLEventKeyOrientation] = [self deviceOrientation]; - attributes[MGLEventKeyWifi] = @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi]); - - return attributes; -} - -- (MGLMapboxEventAttributes *)eventForAttributes:(MGLMutableMapboxEventAttributes *)attributes attributeDictionary:(MGLMapboxEventAttributes *)attributeDictionary { - [attributes addEntriesFromDictionary:attributeDictionary]; - - return [attributes copy]; -} - -// Called implicitly from public use of +flush. -// -- (void)postEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { - if (self.paused) { - return; ++ (void)setupWithAccessToken:(NSString *)accessToken { + NSString *semanticVersion = [NSBundle mgl_frameworkInfoDictionary][@"MGLSemanticVersionString"]; + NSString *shortVersion = [NSBundle mgl_frameworkInfoDictionary][@"CFBundleShortVersionString"]; + NSString *sdkVersion = semanticVersion ?: shortVersion; + + // It is possible that an alternative access token was already set on this instance when the class was loaded + // Use it if it exists + NSString *resolvedAccessToken = [MGLMapboxEvents sharedInstance].accessToken ?: accessToken; + + [[[self sharedInstance] eventsManager] initializeWithAccessToken:resolvedAccessToken userAgentBase:MGLAPIClientUserAgentBase hostSDKVersion:sdkVersion]; + + // It is possible that an alternative base URL was set on this instance when the class was loaded + // Use it if it exists + if ([MGLMapboxEvents sharedInstance].baseURL) { + [[MGLMapboxEvents sharedInstance] eventsManager].baseURL = [MGLMapboxEvents sharedInstance].baseURL; } - - __weak __typeof__(self) weakSelf = self; - dispatch_async(self.serialQueue, ^{ - __strong __typeof__(weakSelf) strongSelf = weakSelf; - [self.apiClient postEvents:events completionHandler:^(NSError * _Nullable error) { - if (error) { - [strongSelf pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"Network error", - @"error": error}]; - } else { - [strongSelf pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"post", - @"debug.eventsCount": @(events.count)}]; - } - [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; - _backgroundTaskIdentifier = UIBackgroundTaskInvalid; - }]; - }); -} - -- (void)startTimer { - [self.timer invalidate]; - self.timer = [NSTimer scheduledTimerWithTimeInterval:MGLFlushInterval - target:self - selector:@selector(flush) - userInfo:nil - repeats:YES]; } -- (NSString *)deviceOrientation { - NSString *result; - - switch ([UIDevice currentDevice].orientation) { - case UIDeviceOrientationUnknown: - result = @"Unknown"; - break; - case UIDeviceOrientationPortrait: - result = @"Portrait"; - break; - case UIDeviceOrientationPortraitUpsideDown: - result = @"PortraitUpsideDown"; - break; - case UIDeviceOrientationLandscapeLeft: - result = @"LandscapeLeft"; - break; - case UIDeviceOrientationLandscapeRight: - result = @"LandscapeRight"; - break; - case UIDeviceOrientationFaceUp: - result = @"FaceUp"; - break; - case UIDeviceOrientationFaceDown: - result = @"FaceDown"; - break; - default: - result = @"Default - Unknown"; - break; - } - - return result; ++ (void)pushTurnstileEvent { + [[[self sharedInstance] eventsManager] sendTurnstileEvent]; } -- (NSString *)applicationState { - switch ([UIApplication sharedApplication].applicationState) { - case UIApplicationStateActive: - return MGLApplicationStateForeground; - case UIApplicationStateInactive: - return MGLApplicationStateInactive; - case UIApplicationStateBackground: - return MGLApplicationStateBackground; - default: - return MGLApplicationStateUnknown; - } ++ (void)pushEvent:(NSString *)event withAttributes:(MMEMapboxEventAttributes *)attributeDictionary { + [[[self sharedInstance] eventsManager] enqueueEventWithName:event attributes:attributeDictionary]; } -- (NSInteger)contentSizeScale { - NSInteger result = -9999; - - NSString *sc = [UIApplication sharedApplication].preferredContentSizeCategory; - - if ([sc isEqualToString:UIContentSizeCategoryExtraSmall]) { - result = -3; - } else if ([sc isEqualToString:UIContentSizeCategorySmall]) { - result = -2; - } else if ([sc isEqualToString:UIContentSizeCategoryMedium]) { - result = -1; - } else if ([sc isEqualToString:UIContentSizeCategoryLarge]) { - result = 0; - } else if ([sc isEqualToString:UIContentSizeCategoryExtraLarge]) { - result = 1; - } else if ([sc isEqualToString:UIContentSizeCategoryExtraExtraLarge]) { - result = 2; - } else if ([sc isEqualToString:UIContentSizeCategoryExtraExtraExtraLarge]) { - result = 3; - } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityMedium]) { - result = -11; - } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityLarge]) { - result = 10; - } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityExtraLarge]) { - result = 11; - } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityExtraExtraLarge]) { - result = 12; - } else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityExtraExtraExtraLarge]) { - result = 13; - } - - return result; ++ (void)flush { + [[[self sharedInstance] eventsManager] flush]; } + (void)ensureMetricsOptoutExists { NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; BOOL metricsEnabledSettingShownInAppFlag = [shownInAppNumber boolValue]; - + if (!metricsEnabledSettingShownInAppFlag && [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType] == 0) { // Opt-out is not configured in UI, so check for Settings.bundle id defaultEnabledValue; NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"]; - + if (appSettingsBundle) { // Dynamic Settings.bundle loading based on http://stackoverflow.com/a/510329/2094275 NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]]; @@ -651,7 +171,7 @@ const NSTimeInterval MGLFlushInterval = 180; } } } - + if (!defaultEnabledValue) { [NSException raise:@"Telemetry opt-out missing" format: @"End users must be able to opt out of Mapbox Telemetry in your app, either inside Settings (via Settings.bundle) or inside this app. " @@ -663,153 +183,4 @@ const NSTimeInterval MGLFlushInterval = 180; } } -#pragma mark CLLocationManagerUtilityDelegate - -- (void)locationManager:(MGLLocationManager *)locationManager didUpdateLocations:(NSArray *)locations { - for (CLLocation *loc in locations) { - double accuracy = 10000000; - double lat = floor(loc.coordinate.latitude * accuracy) / accuracy; - double lng = floor(loc.coordinate.longitude * accuracy) / accuracy; - double horizontalAccuracy = round(loc.horizontalAccuracy); - NSString *formattedDate = [self.rfc3339DateFormatter stringFromDate:loc.timestamp]; - [MGLMapboxEvents pushEvent:MGLEventTypeLocation withAttributes:@{MGLEventKeyCreated: formattedDate, - MGLEventKeyLatitude: @(lat), - MGLEventKeyLongitude: @(lng), - MGLEventKeyAltitude: @(round(loc.altitude)), - MGLEventHorizontalAccuracy: @(horizontalAccuracy)}]; - } -} - -- (void)locationManagerBackgroundLocationUpdatesDidAutomaticallyPause:(MGLLocationManager *)locationManager { - [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription:@"locationManager.locationManagerAutoPause"}]; -} - -- (void)locationManagerBackgroundLocationUpdatesDidTimeout:(MGLLocationManager *)locationManager { - [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription:@"locationManager.locationManagerTimeout"}]; -} - -- (void)locationManagerDidStartLocationUpdates:(MGLLocationManager *)locationManager { - [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription:@"locationManager.locationManagerStartUpdates"}]; -} - -- (void)locationManagerDidStopLocationUpdates:(MGLLocationManager *)locationManager { - [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"locationManager.locationManagerStopUpdates"}]; -} - -#pragma mark MGLMapboxEvents Debug - -- (void)pushDebugEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - if (![self debugLoggingEnabled]) { - return; - } - - if (!event) { - return; - } - - MGLMutableMapboxEventAttributes *evt = [MGLMutableMapboxEventAttributes dictionaryWithDictionary:attributeDictionary]; - [evt setObject:event forKey:@"event"]; - [evt setObject:[self.rfc3339DateFormatter stringFromDate:[NSDate date]] forKey:@"created"]; - [evt setValue:[self applicationState] forKey:@"applicationState"]; - [evt setValue:@([[self class] isEnabled]) forKey:@"telemetryEnabled"]; - [evt setObject:self.instanceID forKey:@"instance"]; - - MGLMapboxEventAttributes *finalEvent = [NSDictionary dictionaryWithDictionary:evt]; - [self writeEventToLocalDebugLog:finalEvent]; -} - -- (void)writeEventToLocalDebugLog:(MGLMapboxEventAttributes *)event { - if (![self debugLoggingEnabled]) { - return; - } - - NSLog(@"%@", [self stringForDebugEvent:event]); - - if (!self.dateForDebugLogFile) { - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd"]; - [dateFormatter setTimeZone:[NSTimeZone systemTimeZone]]; - self.dateForDebugLogFile = [dateFormatter stringFromDate:[NSDate date]]; - } - - if (!self.debugLogSerialQueue) { - NSString *uniqueID = [[NSProcessInfo processInfo] globallyUniqueString]; - self.debugLogSerialQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@.%@.events.debugLog", _appBundleId, uniqueID] UTF8String], DISPATCH_QUEUE_SERIAL); - } - - dispatch_async(self.debugLogSerialQueue, ^{ - if ([NSJSONSerialization isValidJSONObject:event]) { - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:event options:NSJSONWritingPrettyPrinted error:nil]; - - NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - jsonString = [jsonString stringByAppendingString:@",\n"]; - - NSString *logFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"telemetry_log-%@.json", self.dateForDebugLogFile]]; - - NSFileManager *fileManager = [[NSFileManager alloc] init]; - if ([fileManager fileExistsAtPath:logFilePath]) { - NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath]; - [fileHandle seekToEndOfFile]; - [fileHandle writeData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]]; - } else { - [fileManager createFileAtPath:logFilePath contents:[jsonString dataUsingEncoding:NSUTF8StringEncoding] attributes:@{ NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication }]; - } - } - }); -} - -- (NSString *)stringForDebugEvent:(MGLMapboxEventAttributes *)event { - // redact potentially sensitive location details from system console log - if ([event[@"event"] isEqualToString:MGLEventTypeLocation]) { - MGLMutableMapboxEventAttributes *evt = [MGLMutableMapboxEventAttributes dictionaryWithDictionary:event]; - [evt setObject:@"<redacted>" forKey:@"lat"]; - [evt setObject:@"<redacted>" forKey:@"lng"]; - event = evt; - } - - return [NSString stringWithFormat:@"Mapbox Telemetry event %@", event]; -} - -- (BOOL)isProbablyAppStoreBuild { -#if TARGET_IPHONE_SIMULATOR - return NO; -#else - // BugshotKit by Marco Arment https://github.com/marcoarment/BugshotKit/ - // Adapted from https://github.com/blindsightcorp/BSMobileProvision - - NSString *binaryMobileProvision = [NSString stringWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"embedded" ofType:@"mobileprovision"] encoding:NSISOLatin1StringEncoding error:NULL]; - if (!binaryMobileProvision) { - return YES; // no provision - } - - NSScanner *scanner = [NSScanner scannerWithString:binaryMobileProvision]; - NSString *plistString; - if (![scanner scanUpToString:@"<plist" intoString:nil] || ! [scanner scanUpToString:@"</plist>" intoString:&plistString]) { - return YES; // no XML plist found in provision - } - plistString = [plistString stringByAppendingString:@"</plist>"]; - - NSData *plistdata_latin1 = [plistString dataUsingEncoding:NSISOLatin1StringEncoding]; - NSError *error = nil; - NSDictionary *mobileProvision = [NSPropertyListSerialization propertyListWithData:plistdata_latin1 options:NSPropertyListImmutable format:NULL error:&error]; - if (error) { - return YES; // unknown plist format - } - - if (!mobileProvision || ! mobileProvision.count) { - return YES; // no entitlements - } - - if (mobileProvision[@"ProvisionsAllDevices"]) { - return NO; // enterprise provisioning - } - - if (mobileProvision[@"ProvisionedDevices"] && [mobileProvision[@"ProvisionedDevices"] count]) { - return NO; // development or ad-hoc - } - - return YES; // expected development/enterprise/ad-hoc entitlements not found -#endif -} - @end diff --git a/platform/ios/src/Mapbox-Prefix.pch b/platform/ios/src/Mapbox-Prefix.pch new file mode 100644 index 0000000000..6754020861 --- /dev/null +++ b/platform/ios/src/Mapbox-Prefix.pch @@ -0,0 +1 @@ +#import "MMENamespacedDependencies.h" diff --git a/platform/ios/test/MGLMapViewLayoutTests.m b/platform/ios/test/MGLMapViewLayoutTests.m index a41e7695f9..16f6cdada3 100644 --- a/platform/ios/test/MGLMapViewLayoutTests.m +++ b/platform/ios/test/MGLMapViewLayoutTests.m @@ -37,14 +37,15 @@ self.styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; [self waitForExpectationsWithTimeout:1 handler:nil]; + self.mapView.showsScale = YES; + //set zoom and heading so that scale bar and compass will be shown - [self.mapView setZoomLevel:4.5 animated:NO]; + [self.mapView setZoomLevel:10.0 animated:NO]; [self.mapView.camera setHeading:12.0]; //invoke layout [self.superView setNeedsLayout]; [self.superView layoutIfNeeded]; - } - (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { @@ -67,7 +68,7 @@ CGFloat bottomSafeAreaInset = 0.0; double accuracy = 0.01; - if ( [self.mapView respondsToSelector:@selector(safeAreaInsets)] ) { + if (@available(iOS 11.0, *)) { bottomSafeAreaInset = self.mapView.safeAreaInsets.bottom; } diff --git a/platform/ios/test/MGLMapViewScaleBarTests.m b/platform/ios/test/MGLMapViewScaleBarTests.m new file mode 100644 index 0000000000..11d1187263 --- /dev/null +++ b/platform/ios/test/MGLMapViewScaleBarTests.m @@ -0,0 +1,62 @@ +#import <Mapbox/Mapbox.h> +#import <XCTest/XCTest.h> + +@interface MGLMapViewScaleBarTests : XCTestCase + +@property (nonatomic) MGLMapView *mapView; + +@end + +@implementation MGLMapViewScaleBarTests + +- (void)setUp { + [super setUp]; + + [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; + NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; + self.mapView = [[MGLMapView alloc] initWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL]; +} + +- (void)tearDown { + self.mapView = nil; + + [super tearDown]; +} + +- (void)testShowsScale { + UIView *scaleBar = self.mapView.scaleBar; + + // Scale bar should not be enabled by default. + XCTAssertFalse(self.mapView.showsScale); + XCTAssertTrue(scaleBar.hidden); + + self.mapView.showsScale = YES; + + XCTAssertFalse(scaleBar.hidden); + + // Scale bar should not be visible at default zoom (~z0), but it should be ready. + XCTAssertFalse(CGRectIsEmpty(scaleBar.frame)); + XCTAssertEqual(scaleBar.alpha, 0); + + self.mapView.zoomLevel = 15; + XCTAssertGreaterThan(scaleBar.alpha, 0); +} + +- (void)testDirectlySettingScaleBarViewHiddenProperty { + UIView *scaleBar = self.mapView.scaleBar; + + scaleBar.hidden = NO; + XCTAssertFalse(scaleBar.hidden); + + // Directly setting `.hidden` after the map has finished initializing will not update the scale bar. + XCTAssertTrue(CGRectIsEmpty(scaleBar.frame)); + + // ... but triggering any camera event will update it. + self.mapView.zoomLevel = 1; + XCTAssertFalse(CGRectIsEmpty(scaleBar.frame)); + XCTAssertEqual(scaleBar.alpha, 0); + + self.mapView.zoomLevel = 15; + XCTAssertGreaterThan(scaleBar.alpha, 0); +} +@end diff --git a/platform/ios/vendor/mapbox-events-ios b/platform/ios/vendor/mapbox-events-ios new file mode 160000 +Subproject d522b18d8439de9073eafaad7d85e9f6a0d8d82 diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 06fedf7cc7..342262c1db 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -30,6 +30,7 @@ ### Other changes * Added Danish and Hebrew localizations. ([#10967](https://github.com/mapbox/mapbox-gl-native/pull/10967), [#11136](https://github.com/mapbox/mapbox-gl-native/pull/11134)) +* The `-[MGLMapView convertRect:toCoordinateBoundsFromView:]` method and the `MGLMapView.visibleCoordinateBounds` property’s getter now indicate that the coordinate bounds straddles the antimeridian by extending one side beyond ±180 degrees longitude. ([#11265](https://github.com/mapbox/mapbox-gl-native/pull/11265)) * Feature querying results now account for the `MGLSymbolStyleLayer.circleStrokeWidth` property. ([#10897](https://github.com/mapbox/mapbox-gl-native/pull/10897)) * Removed methods, properties, and constants that had been deprecated as of v0.6.1. ([#11205](https://github.com/mapbox/mapbox-gl-native/pull/11205)) diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md index de838cd78f..636cfa7eb7 100644 --- a/platform/macos/docs/guides/For Style Authors.md +++ b/platform/macos/docs/guides/For Style Authors.md @@ -141,6 +141,7 @@ In style JSON | In TileJSON | In the SDK `tileSize` | — | `MGLTileSourceOptionTileSize` `attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security) `scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem` +`encoding` | – | `MGLTileSourceOptionDEMEncoding` ### Shape sources diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h index 96b0932c14..050145b80b 100644 --- a/platform/macos/src/MGLMapView.h +++ b/platform/macos/src/MGLMapView.h @@ -397,11 +397,10 @@ MGL_EXPORT IB_DESIGNABLE want to animate the change, use the `-setVisibleCoordinateBounds:animated:` method instead. - If a longitude is less than −180 degrees or greater than 180 degrees, the visible - bounds straddles the antimeridian or international date line. - - For example, a visible bounds that stretches from Tokyo to San Francisco would have - coordinates of (35.68476, -220.24257) and (37.78428, -122.41310). + If a longitude is less than −180 degrees or greater than 180 degrees, the + visible bounds straddles the antimeridian or international date line. For + example, if both Tokyo and San Francisco are visible, the visible bounds might + extend from (35.68476, −220.24257) to (37.78428, −122.41310). */ @property (nonatomic) MGLCoordinateBounds visibleCoordinateBounds; @@ -409,11 +408,10 @@ MGL_EXPORT IB_DESIGNABLE Changes the receiver’s viewport to fit the given coordinate bounds, optionally animating the change. - To make the visible bounds go across the antimeridian or international date line, - specify some longitudes less than −180 degrees or greater than 180 degrees. - - For example, a visible bounds that stretches from Tokyo to San Francisco would have - coordinates of (35.68476, -220.24257) and (37.78428, -122.41310). + To bring both sides of the antimeridian or international date line into view, + specify some longitudes less than −180 degrees or greater than 180 degrees. For + example, to show both Tokyo and San Francisco simultaneously, you could set the + visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310). @param bounds The bounds that the viewport will show in its entirety. @param animated Specify `YES` to animate the change by smoothly scrolling and @@ -1060,6 +1058,9 @@ MGL_EXPORT IB_DESIGNABLE /** Converts a rectangle in the given view’s coordinate system to a geographic bounding box. + + If a longitude is less than −180 degrees or greater than 180 degrees, the + bounding box straddles the antimeridian or international date line. @param rect The rectangle to convert. @param view The view in whose coordinate system the rectangle is expressed. diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 9ec9012198..7902fb5b64 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -2717,32 +2717,24 @@ public: /// Converts a rectangle in the given view’s coordinate system to a geographic /// bounding box. - (mbgl::LatLngBounds)convertRect:(NSRect)rect toLatLngBoundsFromView:(nullable NSView *)view { - mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); - bounds.extend([self convertPoint:rect.origin toLatLngFromView:view]); - bounds.extend([self convertPoint:{ NSMaxX(rect), NSMinY(rect) } toLatLngFromView:view]); - bounds.extend([self convertPoint:{ NSMaxX(rect), NSMaxY(rect) } toLatLngFromView:view]); - bounds.extend([self convertPoint:{ NSMinX(rect), NSMaxY(rect) } toLatLngFromView:view]); - - // The world is wrapping if a point just outside the bounds is also within - // the rect. - mbgl::LatLng outsideLatLng; - if (bounds.west() > -180) { - outsideLatLng = { - (bounds.south() + bounds.north()) / 2, - bounds.west() - 1, - }; - } else if (bounds.northeast().longitude() < 180) { - outsideLatLng = { - (bounds.south() + bounds.north()) / 2, - bounds.east() + 1, - }; - } - - // If the world is wrapping, extend the bounds to cover all longitudes. - if (NSPointInRect([self convertLatLng:outsideLatLng toPointToView:view], rect)) { - bounds.extend(mbgl::LatLng(bounds.south(), -180)); - bounds.extend(mbgl::LatLng(bounds.south(), 180)); - } + auto bounds = mbgl::LatLngBounds::empty(); + auto bottomLeft = [self convertPoint:{ NSMinX(rect), NSMinY(rect) } toLatLngFromView:view]; + auto bottomRight = [self convertPoint:{ NSMaxX(rect), NSMinY(rect) } toLatLngFromView:view]; + auto topRight = [self convertPoint:{ NSMaxX(rect), NSMaxY(rect) } toLatLngFromView:view]; + auto topLeft = [self convertPoint:{ NSMinX(rect), NSMaxY(rect) } toLatLngFromView:view]; + + // If the bounds straddles the antimeridian, unwrap it so that one side + // extends beyond ±180° longitude. + auto center = [self convertPoint:{ NSMidX(rect), NSMidY(rect) } toLatLngFromView:view]; + bottomLeft.unwrapForShortestPath(center); + bottomRight.unwrapForShortestPath(center); + topRight.unwrapForShortestPath(center); + topLeft.unwrapForShortestPath(center); + + bounds.extend(bottomLeft); + bounds.extend(bottomRight); + bounds.extend(topRight); + bounds.extend(topLeft); return bounds; } diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index 8958d5c6c7..84515060a3 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -1,5 +1,6 @@ #include "node_conversion.hpp" #include "node_expression.hpp" +#include "node_feature.hpp" #include <mbgl/style/expression/parsing_context.hpp> #include <mbgl/style/expression/is_constant.hpp> @@ -24,6 +25,8 @@ void NodeExpression::Init(v8::Local<v8::Object> target) { Nan::SetPrototypeMethod(tpl, "isFeatureConstant", IsFeatureConstant); Nan::SetPrototypeMethod(tpl, "isZoomConstant", IsZoomConstant); + Nan::SetPrototypeMethod(tpl, "serialize", Serialize); + Nan::SetMethod(tpl, "parse", Parse); constructor.Reset(tpl->GetFunction()); // what is this doing? @@ -39,31 +42,31 @@ type::Type parseType(v8::Local<v8::Object> type) { {"color", type::Color}, {"value", type::Value} }; - + v8::Local<v8::Value> v8kind = Nan::Get(type, Nan::New("kind").ToLocalChecked()).ToLocalChecked(); std::string kind(*v8::String::Utf8Value(v8kind)); - + if (kind == "array") { type::Type itemType = parseType(Nan::Get(type, Nan::New("itemType").ToLocalChecked()).ToLocalChecked()->ToObject()); mbgl::optional<std::size_t> N; - + v8::Local<v8::String> Nkey = Nan::New("N").ToLocalChecked(); if (Nan::Has(type, Nkey).FromMaybe(false)) { N = Nan::Get(type, Nkey).ToLocalChecked()->ToInt32()->Value(); } return type::Array(itemType, N); } - + return types[kind]; } void NodeExpression::Parse(const Nan::FunctionCallbackInfo<v8::Value>& info) { v8::Local<v8::Function> cons = Nan::New(constructor); - + if (info.Length() < 1 || info[0]->IsUndefined()) { return Nan::ThrowTypeError("Requires a JSON style expression argument."); } - + mbgl::optional<type::Type> expected; if (info.Length() > 1 && info[1]->IsObject()) { expected = parseType(info[1]->ToObject()); @@ -84,7 +87,7 @@ void NodeExpression::Parse(const Nan::FunctionCallbackInfo<v8::Value>& info) { info.GetReturnValue().Set(wrapped); return; } - + v8::Local<v8::Array> result = Nan::New<v8::Array>(); for (std::size_t i = 0; i < ctx.getErrors().size(); i++) { const auto& error = ctx.getErrors()[i]; @@ -140,7 +143,7 @@ struct ToValue { } return scope.Escape(result); } - + v8::Local<v8::Value> operator()(const mbgl::Color& color) { return operator()(std::vector<Value> { static_cast<double>(color.r), @@ -227,4 +230,12 @@ void NodeExpression::IsZoomConstant(const Nan::FunctionCallbackInfo<v8::Value>& info.GetReturnValue().Set(Nan::New(isZoomConstant(*expression))); } +void NodeExpression::Serialize(const Nan::FunctionCallbackInfo<v8::Value>& info) { + NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder()); + const std::unique_ptr<Expression>& expression = nodeExpr->expression; + + const mbgl::Value serialized = expression->serialize(); + info.GetReturnValue().Set(toJS(serialized)); +} + } // namespace node_mbgl diff --git a/platform/node/src/node_expression.hpp b/platform/node/src/node_expression.hpp index 7af5b7ab51..05af217bde 100644 --- a/platform/node/src/node_expression.hpp +++ b/platform/node/src/node_expression.hpp @@ -32,6 +32,9 @@ private: static void GetType(const Nan::FunctionCallbackInfo<v8::Value>&); static void IsFeatureConstant(const Nan::FunctionCallbackInfo<v8::Value>&); static void IsZoomConstant(const Nan::FunctionCallbackInfo<v8::Value>&); + + static void Serialize(const Nan::FunctionCallbackInfo<v8::Value>&); + static Nan::Persistent<v8::Function> constructor; std::unique_ptr<Expression> expression; diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index ac14df0228..0fe69e8ac9 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -1154,6 +1154,10 @@ NodeMap::~NodeMap() { std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resource, mbgl::FileSource::Callback callback_) { Nan::HandleScope scope; + // Because this method may be called while this NodeMap is already eligible for garbage collection, + // we need to explicitly hold onto our own handle here so that GC during a v8 call doesn't destroy + // *this while we're still executing code. + handle(); v8::Local<v8::Value> argv[] = { Nan::New<v8::External>(this), diff --git a/platform/node/test/expression.test.js b/platform/node/test/expression.test.js index aac039ce18..ffd1c68ff2 100644 --- a/platform/node/test/expression.test.js +++ b/platform/node/test/expression.test.js @@ -32,40 +32,54 @@ function getExpectedType(spec) { suite.run('native', {ignores: ignores, tests: tests}, (fixture) => { const compiled = {}; + const recompiled = {}; const result = { - compiled + compiled, + recompiled }; const spec = fixture.propertySpec || {}; const expression = mbgl.Expression.parse(fixture.expression, getExpectedType(spec)); - if (expression instanceof mbgl.Expression) { - compiled.result = 'success'; - compiled.isFeatureConstant = expression.isFeatureConstant(); - compiled.isZoomConstant = expression.isZoomConstant(); - compiled.type = expression.getType(); + const evaluateExpression = (expression, compilationResult) => { + if (expression instanceof mbgl.Expression) { + compilationResult.result = 'success'; + compilationResult.isFeatureConstant = expression.isFeatureConstant(); + compilationResult.isZoomConstant = expression.isZoomConstant(); + compilationResult.type = expression.getType(); - const evaluate = fixture.inputs || []; - const evaluateResults = []; - for (const input of evaluate) { - const feature = Object.assign({ - type: 'Feature', - properties: {}, - geometry: { type: 'Point', coordinates: [0, 0] } - }, input[1]) + const evaluate = fixture.inputs || []; + const evaluateResults = []; + for (const input of evaluate) { + const feature = Object.assign({ + type: 'Feature', + properties: {}, + geometry: { type: 'Point', coordinates: [0, 0] } + }, input[1]) - const output = expression.evaluate(input[0], feature); - evaluateResults.push(output); - } + const output = expression.evaluate(input[0], feature); + evaluateResults.push(output); + } - if (fixture.inputs) { - result.outputs = evaluateResults; + if (fixture.inputs) { + return evaluateResults; + } + } else { + compilationResult.result = 'error'; + compilationResult.errors = expression; } - } else { - compiled.result = 'error'; - compiled.errors = expression; + } + + result.outputs = evaluateExpression(expression, compiled); + if (expression instanceof mbgl.Expression) { + result.serialized = expression.serialize(); + const recompiledExpression = mbgl.Expression.parse(result.serialized, getExpectedType(spec)); + result.roundTripOutputs = evaluateExpression(recompiledExpression, recompiled); + // Type is allowed to change through serialization + // (eg "array" -> "array<number, 3>") + // Override the round-tripped type here so that the equality check passes + recompiled.type = compiled.type; } return result; }); - diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json index 42751da30f..da79ac8a41 100644 --- a/platform/node/test/ignores.json +++ b/platform/node/test/ignores.json @@ -25,6 +25,9 @@ "render-tests/geojson/inline-polygon-symbol": "behavior needs reconciliation with gl-js", "render-tests/mixed-zoom/z10-z11": "https://github.com/mapbox/mapbox-gl-native/issues/10397", "render-tests/raster-masking/overlapping-zoom": "https://github.com/mapbox/mapbox-gl-native/issues/10195", + "render-tests/real-world/bangkok": "https://github.com/mapbox/mapbox-gl-native/issues/10412", + "render-tests/real-world/chicago": "https://github.com/mapbox/mapbox-gl-native/issues/10412", + "render-tests/real-world/sanfrancisco": "https://github.com/mapbox/mapbox-gl-native/issues/10412", "render-tests/regressions/mapbox-gl-js#2305": "https://github.com/mapbox/mapbox-gl-native/issues/6927", "render-tests/regressions/mapbox-gl-js#2467": "https://github.com/mapbox/mapbox-gl-native/issues/10619", "render-tests/regressions/mapbox-gl-js#2762": "https://github.com/mapbox/mapbox-gl-native/issues/10619", @@ -34,6 +37,7 @@ "render-tests/regressions/mapbox-gl-js#5599": "https://github.com/mapbox/mapbox-gl-native/issues/10399", "render-tests/regressions/mapbox-gl-js#5740": "https://github.com/mapbox/mapbox-gl-native/issues/10619", "render-tests/regressions/mapbox-gl-js#5982": "https://github.com/mapbox/mapbox-gl-native/issues/10619", + "render-tests/regressions/mapbox-gl-js#6160": "https://github.com/mapbox/mapbox-gl-native/pull/11206", "render-tests/regressions/mapbox-gl-native#7357": "https://github.com/mapbox/mapbox-gl-native/issues/7357", "render-tests/runtime-styling/image-add-sdf": "https://github.com/mapbox/mapbox-gl-native/issues/9847", "render-tests/runtime-styling/paint-property-fill-flat-to-extrude": "https://github.com/mapbox/mapbox-gl-native/issues/6745", diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index f40cfa1f2c..ba44adb42b 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -281,10 +281,17 @@ UniqueTexture Context::createTexture() { bool Context::supportsVertexArrays() const { static bool blacklisted = []() { - // Blacklist Adreno 2xx, 3xx as it crashes on glBuffer(Sub)Data const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + + Log::Info(Event::General, "GPU Identifier: %s", renderer.c_str()); + + // Blacklist Adreno 2xx, 3xx as it crashes on glBuffer(Sub)Data + // Blacklist ARM Mali-T720 (in some MT8163 chipsets) as it crashes on glBindVertexArray return renderer.find("Adreno (TM) 2") != std::string::npos - || renderer.find("Adreno (TM) 3") != std::string::npos; + || renderer.find("Adreno (TM) 3") != std::string::npos + || renderer.find("Mali-T720") != std::string::npos + || renderer.find("Sapphire 650") != std::string::npos; + }(); return !blacklisted && diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp index adafd8583f..a429b8d82e 100644 --- a/src/mbgl/renderer/layers/render_custom_layer.cpp +++ b/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -5,6 +5,7 @@ #include <mbgl/renderer/bucket.hpp> #include <mbgl/style/layers/custom_layer_impl.hpp> #include <mbgl/map/transform_state.hpp> +#include <mbgl/gl/gl.hpp> namespace mbgl { @@ -46,11 +47,11 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*) if (context != impl().context || !initialized) { //If the context changed, deinitialize the previous one before initializing the new one. if (context && !contextDestroyed && impl().deinitializeFn) { - impl().deinitializeFn(context); + MBGL_CHECK_ERROR(impl().deinitializeFn(context)); } context = impl().context; assert(impl().initializeFn); - impl().initializeFn(impl().context); + MBGL_CHECK_ERROR(impl().initializeFn(impl().context)); initialized = true; } @@ -75,7 +76,7 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*) parameters.fieldOfView = state.getFieldOfView(); assert(impl().renderFn); - impl().renderFn(context, parameters); + MBGL_CHECK_ERROR(impl().renderFn(context, parameters)); // Reset the view back to our original one, just in case the CustomLayer changed // the viewport or Framebuffer. diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index 0f9e3239ef..4f2e899220 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -67,7 +67,7 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { } } - if (!renderTexture) { + if (!parameters.context.supportsHalfFloatTextures || !renderTexture) { renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::UnsignedByte); renderTexture->bind(); } diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index c4372e7112..8f83a0f982 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -143,10 +143,13 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer auto it = tiles.find(tileID); return it == tiles.end() ? nullptr : it->second.get(); }; - + + // The min and max zoom for TileRange are based on the updateRenderables algorithm. + // Tiles are created at the ideal tile zoom or at lower zoom levels. Child + // tiles are used from the cache, but not created. optional<util::TileRange> tileRange = {}; if (bounds) { - tileRange = util::TileRange::fromLatLngBounds(*bounds, std::min(tileZoom, (int32_t)zoomRange.max)); + tileRange = util::TileRange::fromLatLngBounds(*bounds, zoomRange.min, std::min(tileZoom, (int32_t)zoomRange.max)); } auto createTileFn = [&](const OverscaledTileID& tileID) -> Tile* { if (tileRange && !tileRange->contains(tileID.canonical)) { diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp index 29f6a47b10..4049301b0b 100644 --- a/src/mbgl/style/expression/array_assertion.cpp +++ b/src/mbgl/style/expression/array_assertion.cpp @@ -81,6 +81,25 @@ ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx) )); } +mbgl::Value ArrayAssertion::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + + + const auto array = getType().get<type::Array>(); + if (array.itemType.is<type::StringType>() + || array.itemType.is<type::NumberType>() + || array.itemType.is<type::BooleanType>()) { + serialized.emplace_back(type::toString(array.itemType)); + if (array.N) { + serialized.emplace_back(uint64_t(*array.N)); + } + } + + serialized.emplace_back(input->serialize()); + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 0187921af9..d6f3f1b584 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -35,6 +35,10 @@ ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique<Assertion>(it->second, std::move(parsed))); } +std::string Assertion::getOperator() const { + return type::toString(getType()); +} + EvaluationResult Assertion::evaluate(const EvaluationContext& params) const { for (std::size_t i = 0; i < inputs.size(); i++) { EvaluationResult value = inputs[i]->evaluate(params); diff --git a/src/mbgl/style/expression/at.cpp b/src/mbgl/style/expression/at.cpp index e447d33bc7..725e5ddb51 100644 --- a/src/mbgl/style/expression/at.cpp +++ b/src/mbgl/style/expression/at.cpp @@ -19,15 +19,21 @@ EvaluationResult At::evaluate(const EvaluationContext& params) const { const auto i = evaluatedIndex->get<double>(); const auto inputArray = evaluatedInput->get<std::vector<Value>>(); - if (i < 0 || i >= inputArray.size()) { + if (i < 0) { return EvaluationError { - "Array index out of bounds: " + stringify(i) + - " > " + util::toString(inputArray.size()) + "." + "Array index out of bounds: " + util::toString(i) + " < 0." + }; + } + + if (i >= inputArray.size()) { + return EvaluationError { + "Array index out of bounds: " + util::toString(i) + + " > " + util::toString(inputArray.size() - 1) + "." }; } if (i != std::floor(i)) { return EvaluationError { - "Array index must be an integer, but found " + stringify(i) + " instead." + "Array index must be an integer, but found " + util::toString(i) + " instead." }; } return inputArray[static_cast<std::size_t>(i)]; diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index 56ab33fcfd..d9cd3ffdc9 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -81,6 +81,13 @@ Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> in } } +std::string Coercion::getOperator() const { + return getType().match( + [](const type::NumberType&) { return "to-number"; }, + [](const type::ColorType&) { return "to-color"; }, + [](const auto&) { assert(false); return ""; }); +} + using namespace mbgl::style::conversion; ParseResult Coercion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> types { diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 42cb655024..b1c2d74a9f 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -42,20 +42,19 @@ template <class R, class... Params> struct Signature<R (Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - Signature(R (*evaluate_)(Params...)) : + Signature(R (*evaluate_)(Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...} + std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}, + std::move(name_) ), - evaluate(evaluate_) - {} + evaluate(evaluate_) {} EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{}); } - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray)); @@ -80,16 +79,16 @@ template <class R, typename T> struct Signature<R (const Varargs<T>&)> : SignatureBase { using Args = std::vector<std::unique_ptr<Expression>>; - Signature(R (*evaluate_)(const Varargs<T>&)) : + Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - VarargsType { valueTypeToExpressionType<T>() } + VarargsType { valueTypeToExpressionType<T>() }, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args)); }; @@ -115,16 +114,16 @@ template <class R, class... Params> struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - Signature(R (*evaluate_)(const EvaluationContext&, Params...)) : + Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...} + std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray)); @@ -176,14 +175,14 @@ struct Signature<Lambda, std::enable_if_t<std::is_class<Lambda>::value>> using Definition = CompoundExpressionRegistry::Definition; template <typename Fn> -static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction) { - return std::make_unique<detail::Signature<Fn>>(evaluateFunction); +static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction, std::string name) { + return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name)); } std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() { std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions; auto define = [&](std::string name, auto fn) { - definitions[name].push_back(makeSignature(fn)); + definitions[name].push_back(makeSignature(fn, name)); }; define("e", []() -> Result<double> { return 2.718281828459045; }); @@ -272,13 +271,6 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali return object.at(key); }); - define("length", [](const std::vector<Value>& arr) -> Result<double> { - return arr.size(); - }); - define("length", [] (const std::string s) -> Result<double> { - return s.size(); - }); - define("properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> { if (!params.feature) { return EvaluationError { @@ -461,7 +453,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v } args.push_back(std::move(*parsed)); } - return createCompoundExpression(name, definition, std::move(args), ctx); + return createCompoundExpression(definition, std::move(args), ctx); } @@ -469,12 +461,11 @@ ParseResult createCompoundExpression(const std::string& name, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { - return createCompoundExpression(name, CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); + return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); } -ParseResult createCompoundExpression(const std::string& name, - const Definition& definition, +ParseResult createCompoundExpression(const Definition& definition, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { @@ -512,7 +503,7 @@ ParseResult createCompoundExpression(const std::string& name, } if (signatureContext.getErrors().size() == 0) { - return ParseResult(signature->makeExpression(name, std::move(args))); + return ParseResult(signature->makeExpression(std::move(args))); } } diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 4cb22a3e4f..30b2cba81b 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -216,6 +216,30 @@ std::vector<optional<Value>> InterpolateBase::possibleOutputs() const { return result; } +template <typename T> +mbgl::Value Interpolate<T>::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + + interpolator.match( + [&](const ExponentialInterpolator& exponential) { + serialized.emplace_back(std::vector<mbgl::Value>{{ std::string("exponential"), exponential.base }}); + }, + [&](const CubicBezierInterpolator& cubicBezier) { + static const std::string cubicBezierTag("cubic-bezier"); + auto p1 = cubicBezier.ub.getP1(); + auto p2 = cubicBezier.ub.getP2(); + serialized.emplace_back(std::vector<mbgl::Value>{{ cubicBezierTag, p1.first, p1.second, p2.first, p2.second }}); + } + ); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + }; + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/length.cpp b/src/mbgl/style/expression/length.cpp new file mode 100644 index 0000000000..258353ae4e --- /dev/null +++ b/src/mbgl/style/expression/length.cpp @@ -0,0 +1,66 @@ +#include <mbgl/style/expression/length.hpp> +#include <mbgl/util/string.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +Length::Length(std::unique_ptr<Expression> input_) + : Expression(type::Number), + input(std::move(input_)) { +} + +EvaluationResult Length::evaluate(const EvaluationContext& params) const { + const EvaluationResult value = input->evaluate(params); + if (!value) return value; + return value->match( + [] (const std::string& s) { + return EvaluationResult { double(s.size()) }; + }, + [] (const std::vector<Value>& v) { + return EvaluationResult { double(v.size()) }; + }, + [&] (const auto&) -> EvaluationResult { + return EvaluationError { "Expected value to be of type string or array, but found " + toString(typeOf(*value)) + " instead." }; + }); +} + +void Length::eachChild(const std::function<void(const Expression&)>& visit) const { + visit(*input); +} + +bool Length::operator==(const Expression& e) const { + if (auto eq = dynamic_cast<const Length*>(&e)) { + return *eq->input == *input; + } + return false; +} + +std::vector<optional<Value>> Length::possibleOutputs() const { + return { nullopt }; +} + +using namespace mbgl::style::conversion; +ParseResult Length::parse(const Convertible& value, ParsingContext& ctx) { + std::size_t length = arrayLength(value); + + if (length != 2) { + ctx.error("Expected one argument, but found " + util::toString(length) + " instead."); + return ParseResult(); + } + + ParseResult input = ctx.parse(arrayMember(value, 1), 1); + if (!input) return ParseResult(); + + type::Type type = (*input)->getType(); + if (!type.is<type::Array>() && !type.is<type::StringType>() && !type.is<type::ValueType>()) { + ctx.error("Expected argument of type string or array, but found " + toString(type) + " instead."); + return ParseResult(); + } + + return ParseResult(std::make_unique<Length>(std::move(*input))); +} + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp index fe48138ac3..242a995b0b 100644 --- a/src/mbgl/style/expression/let.cpp +++ b/src/mbgl/style/expression/let.cpp @@ -65,6 +65,17 @@ ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique<Let>(std::move(bindings_), std::move(*result_))); } +mbgl::Value Let::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + for (auto entry : bindings) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + } + serialized.emplace_back(result->serialize()); + return serialized; +} + EvaluationResult Var::evaluate(const EvaluationContext& params) const { return value->evaluate(params); } @@ -95,6 +106,10 @@ ParseResult Var::parse(const Convertible& value_, ParsingContext& ctx) { return ParseResult(std::make_unique<Var>(name_, std::move(*bindingValue))); } +mbgl::Value Var::serialize() const { + return std::vector<mbgl::Value>{{ getOperator(), name }}; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 7e79fcbfe6..8a63980dba 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -102,6 +102,14 @@ ParseResult Literal::parse(const Convertible& value, ParsingContext& ctx) { } } +mbgl::Value Literal::serialize() const { + if (getType().is<type::Array>() || getType().is<type::ObjectType>()) { + return std::vector<mbgl::Value>{{ getOperator(), *fromExpressionValue<mbgl::Value>(value) }}; + } else { + return *fromExpressionValue<mbgl::Value>(value); + } +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 0b2790b688..3d41f0bdd3 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -40,6 +40,42 @@ std::vector<optional<Value>> Match<T>::possibleOutputs() const { return result; } +template <typename T> +mbgl::Value Match<T>::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + + // Sort so serialization has an arbitrary defined order, even though branch order doesn't affect evaluation + std::map<T, std::shared_ptr<Expression>> sortedBranches(branches.begin(), branches.end()); + + // Group branches by unique match expression to support condensed serializations + // of the form [case1, case2, ...] -> matchExpression + std::map<Expression*, size_t> outputLookup; + std::vector<std::pair<Expression*, std::vector<mbgl::Value>>> groupedByOutput; + for (auto& entry : sortedBranches) { + auto outputIndex = outputLookup.find(entry.second.get()); + if (outputIndex == outputLookup.end()) { + // First time seeing this output, add it to the end of the grouped list + outputLookup[entry.second.get()] = groupedByOutput.size(); + groupedByOutput.emplace_back(entry.second.get(), std::vector<mbgl::Value>{{entry.first}}); + } else { + // We've seen this expression before, add the label to that output's group + groupedByOutput[outputIndex->second].second.emplace_back(entry.first); + } + }; + + for (auto& entry : groupedByOutput) { + entry.second.size() == 1 + ? serialized.emplace_back(entry.second[0]) // Only a single label matches this output expression + : serialized.emplace_back(entry.second); // Array of literal labels pointing to this output expression + serialized.emplace_back(entry.first->serialize()); // The output expression itself + } + + serialized.emplace_back(otherwise->serialize()); + return serialized; +} + template<> EvaluationResult Match<std::string>::evaluate(const EvaluationContext& params) const { const EvaluationResult inputValue = input->evaluate(params); diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 0215982209..364c3f740a 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -15,6 +15,7 @@ #include <mbgl/style/expression/compound_expression.hpp> #include <mbgl/style/expression/equals.hpp> #include <mbgl/style/expression/interpolate.hpp> +#include <mbgl/style/expression/length.hpp> #include <mbgl/style/expression/let.hpp> #include <mbgl/style/expression/literal.hpp> #include <mbgl/style/expression/match.hpp> @@ -89,6 +90,7 @@ const ExpressionRegistry& getExpressionRegistry() { {"case", Case::parse}, {"coalesce", Coalesce::parse}, {"interpolate", parseInterpolate}, + {"length", Length::parse}, {"let", Let::parse}, {"literal", Literal::parse}, {"match", parseMatch}, @@ -147,7 +149,7 @@ ParseResult ParsingContext::parse(const Convertible& value, TypeAnnotationOption }; const type::Type actual = (*parsed)->getType(); - if ((*expected == type::String || *expected == type::Number || *expected == type::Boolean) && actual == type::Value) { + if ((*expected == type::String || *expected == type::Number || *expected == type::Boolean || *expected == type::Object) && actual == type::Value) { if (typeAnnotationOption == includeTypeAnnotations) { parsed = { std::make_unique<Assertion>(*expected, array(std::move(*parsed))) }; } diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp index 34537d48ae..ddaf9417cb 100644 --- a/src/mbgl/style/expression/step.cpp +++ b/src/mbgl/style/expression/step.cpp @@ -168,6 +168,18 @@ ParseResult Step::parse(const mbgl::style::conversion::Convertible& value, Parsi return ParseResult(std::make_unique<Step>(*outputType, std::move(*input), std::move(stops))); } +mbgl::Value Step::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + if (entry.first > -std::numeric_limits<double>::infinity()) { + serialized.emplace_back(entry.first); + } + serialized.emplace_back(entry.second->serialize()); + } + return serialized; +} } // namespace expression } // namespace style diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index faa44e78aa..72779d4956 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -103,6 +103,37 @@ Value ValueConverter<mbgl::Value>::toExpressionValue(const mbgl::Value& value) { return mbgl::Value::visit(value, FromMBGLValue()); } +mbgl::Value ValueConverter<mbgl::Value>::fromExpressionValue(const Value& value) { + return value.match( + [&](const Color& color)->mbgl::Value { + return std::vector<mbgl::Value>{ + std::string("rgba"), + double(255 * color.r / color.a), + double(255 * color.g / color.a), + double(255 * color.b / color.a), + double(color.a) + }; + }, + [&](const std::vector<Value>& values)->mbgl::Value { + std::vector<mbgl::Value> converted; + converted.reserve(values.size()); + for (const Value& v : values) { + converted.emplace_back(fromExpressionValue(v)); + } + return converted; + }, + [&](const std::unordered_map<std::string, Value>& values)->mbgl::Value { + std::unordered_map<std::string, mbgl::Value> converted; + converted.reserve(values.size()); + for(const auto& entry : values) { + converted.emplace(entry.first, fromExpressionValue(entry.second)); + } + return converted; + }, + [&](const auto& a)->mbgl::Value { return a; } + ); +} + Value ValueConverter<float>::toExpressionValue(const float value) { return static_cast<double>(value); } @@ -237,7 +268,7 @@ template <> type::Type valueTypeToExpressionType<type::ErrorType>() { return typ template Value toExpressionValue(const mbgl::Value&); - +template optional<mbgl::Value> fromExpressionValue<mbgl::Value>(const Value&); // for to_rgba expression template type::Type valueTypeToExpressionType<std::array<double, 4>>(); diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index d330b3120a..0c7f924917 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -55,11 +55,6 @@ void Style::Impl::loadURL(const std::string& url_) { url = url_; styleRequest = fileSource.request(Resource::style(url), [this](Response res) { - // Once we get a fresh style, or the style is mutated, stop revalidating. - if (res.isFresh() || mutated) { - styleRequest.reset(); - } - // Don't allow a loaded, mutated style to be overwritten with a new version. if (mutated && loaded) { return; diff --git a/src/mbgl/util/tile_range.hpp b/src/mbgl/util/tile_range.hpp index f630a49078..8554cfb65e 100644 --- a/src/mbgl/util/tile_range.hpp +++ b/src/mbgl/util/tile_range.hpp @@ -6,41 +6,61 @@ #include <mbgl/util/projection.hpp> namespace mbgl { - namespace util { class TileRange { public: - Range<Point<double>> range; - uint8_t z; + Range<Point<uint32_t>> range; + Range<uint8_t> zoomRange; + + // Compute the range of tiles covered by the bounds at maxZoom. + static TileRange fromLatLngBounds(const LatLngBounds& bounds, uint8_t minZoom, uint8_t maxZoom) { + if (minZoom > maxZoom) { + std::swap(minZoom, maxZoom); + } + + auto swProj = Projection::project(bounds.southwest().wrapped(), maxZoom); + auto ne = bounds.northeast(); + auto neProj = Projection::project(ne.longitude() > util::LONGITUDE_MAX ? ne.wrapped() : ne , maxZoom); + + const auto maxTile = std::pow(2.0, maxZoom); + const auto minX = static_cast<uint32_t>(std::floor(swProj.x)); + const auto maxX = static_cast<uint32_t>(std::floor(neProj.x)); + const auto minY = static_cast<uint32_t>(util::clamp(std::floor(neProj.y), 0.0 , maxTile)); + const auto maxY = static_cast<uint32_t>(util::clamp(std::floor(swProj.y), 0.0, maxTile)); + + return TileRange({ {minX, minY}, {maxX, maxY} }, {minZoom, maxZoom}); + } // Compute the range of tiles covered by the bounds. static TileRange fromLatLngBounds(const LatLngBounds& bounds, uint8_t z) { - auto swProj = Projection::project(bounds.southwest().wrapped(), z); - auto ne = bounds.northeast(); - auto neProj = Projection::project(ne.longitude() > util::LONGITUDE_MAX ? ne.wrapped() : ne , z); - const auto minX = std::floor(swProj.x); - const auto maxX = std::ceil(neProj.x); - const auto minY = std::floor(neProj.y); - const auto maxY = std::ceil(swProj.y); - return TileRange({ {minX, minY}, {maxX, maxY} }, z); + return fromLatLngBounds(bounds, z, z); } bool contains(const CanonicalTileID& tileID) { - return z == tileID.z && - (range.min.x >= range.max.x ? //For wrapped bounds - tileID.x >= range.min.x || tileID.x < range.max.x : - tileID.x < range.max.x && tileID.x >= range.min.x) && - tileID.y < range.max.y && - tileID.y >= range.min.y; + if (tileID.z <= zoomRange.max && tileID.z >= zoomRange.min) { + if (tileID.z == 0) { + return true; + } + uint8_t dz = (zoomRange.max - tileID.z); + auto x0 = range.min.x >> dz; + auto x1 = range.max.x >> dz; + auto y0 = range.min.y >> dz; + auto y1 = range.max.y >> dz; + return (range.min.x > range.max.x ? //For wrapped bounds + tileID.x >= x0 || tileID.x <= x1 : + tileID.x <= x1 && tileID.x >= x0) && + tileID.y <= y1 && + tileID.y >= y0; + } + return false; } private: - TileRange(Range<Point<double>> range_, uint8_t z_) + TileRange(Range<Point<uint32_t>> range_, Range<uint8_t> z_) : range(range_), - z(z_) { + zoomRange(z_) { } - }; } // namespace util diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 9b34ea89b0..30c076ad89 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -252,7 +252,7 @@ TEST(Map, DoubleStyleLoad) { } TEST(Map, StyleFresh) { - // The map should not revalidate fresh styles. + // The map should continue to revalidate fresh styles. MapTest<FakeFileSource> test; @@ -264,11 +264,11 @@ TEST(Map, StyleFresh) { response.expires = Timestamp::max(); test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(0u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource.requests.size()); } TEST(Map, StyleExpired) { - // The map should allow expired styles to be revalidated, so long as no mutations are made. + // The map should allow expired styles to be revalidated until we get a fresh style. using namespace std::chrono_literals; @@ -284,11 +284,22 @@ TEST(Map, StyleExpired) { test.fileSource.respond(Resource::Style, response); EXPECT_EQ(1u, test.fileSource.requests.size()); + // Mutate layer. From now on, sending a response to the style won't overwrite it anymore, but + // we should continue to wait for a fresh response. test.map.getStyle().addLayer(std::make_unique<style::BackgroundLayer>("bg")); EXPECT_EQ(1u, test.fileSource.requests.size()); + // Send another expired response, and confirm that we didn't overwrite the style, but continue + // to wait for a fresh response. + test.fileSource.respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_NE(nullptr, test.map.getStyle().getLayer("bg")); + + // Send a fresh response, and confirm that we didn't overwrite the style, but continue to wait + // for a fresh response. + response.expires = util::now() + 1h; test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(0u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource.requests.size()); EXPECT_NE(nullptr, test.map.getStyle().getLayer("bg")); } @@ -352,7 +363,7 @@ TEST(Map, StyleEarlyMutation) { response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/water.json")); test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(0u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource.requests.size()); EXPECT_NE(nullptr, test.map.getStyle().getLayer("water")); } diff --git a/test/util/tile_range.test.cpp b/test/util/tile_range.test.cpp index dc8ae28705..c4c37c74d7 100644 --- a/test/util/tile_range.test.cpp +++ b/test/util/tile_range.test.cpp @@ -1,4 +1,3 @@ - #include <mbgl/util/tile_range.hpp> #include <mbgl/util/geo.hpp> #include <mbgl/map/transform.hpp> @@ -25,6 +24,18 @@ TEST(TileRange, ContainsBoundsFromTile) { EXPECT_TRUE(range.contains(CanonicalTileID(10, 162, 395))); } } + +TEST(TileRange, ContainsMultiZoom) { + auto wrappedBounds = LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 }); + auto range = util::TileRange::fromLatLngBounds(wrappedBounds, 5, 13); + EXPECT_FALSE(range.contains(CanonicalTileID(0, 0, 0))); + EXPECT_FALSE(range.contains(CanonicalTileID(5, 3, 11))); + EXPECT_FALSE(range.contains(CanonicalTileID(6, 9, 22))); + EXPECT_TRUE(range.contains(CanonicalTileID(5, 5, 12))); + EXPECT_TRUE(range.contains(CanonicalTileID(6, 10, 24))); + EXPECT_TRUE(range.contains(CanonicalTileID(13, 1310, 3166))); +} + TEST(TileRange, ContainsIntersectingTiles) { auto bounds = LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 }); auto range = util::TileRange::fromLatLngBounds(bounds, 13); |