diff --git a/android/tangram/jni/jniExports.cpp b/android/tangram/jni/jniExports.cpp index 8997dc8b36..5a29d99fe9 100644 --- a/android/tangram/jni/jniExports.cpp +++ b/android/tangram/jni/jniExports.cpp @@ -110,11 +110,22 @@ extern "C" { delete map; } - JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeLoadScene(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jstring path) { + JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeLoadScene(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jstring path, jobjectArray updateStrings) { assert(mapPtr > 0); auto map = reinterpret_cast(mapPtr); const char* cPath = jniEnv->GetStringUTFChars(path, NULL); - map->loadScene(resolveScenePath(cPath).c_str()); + size_t nUpdateStrings = (updateStrings == NULL) ? 0 : jniEnv->GetArrayLength(updateStrings); + + std::vector sceneUpdates; + for (size_t i = 0; i < nUpdateStrings;) { + jstring path = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++)); + jstring value = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++)); + sceneUpdates.emplace_back(stringFromJString(jniEnv, path), stringFromJString(jniEnv, value)); + jniEnv->DeleteLocalRef(path); + jniEnv->DeleteLocalRef(value); + } + + map->loadScene(resolveScenePath(cPath).c_str(), false, sceneUpdates); jniEnv->ReleaseStringUTFChars(path, cPath); } @@ -456,6 +467,25 @@ extern "C" { jnienv->ReleaseStringUTFChars(value, cValue); } + JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeQueueSceneUpdates(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jobjectArray updateStrings) { + assert(mapPtr > 0); + size_t nUpdateStrings = (updateStrings == NULL)? 0 : jniEnv->GetArrayLength(updateStrings); + + std::vector sceneUpdates; + for (size_t i = 0; i < nUpdateStrings;) { + jstring path = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++)); + jstring value = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++)); + sceneUpdates.emplace_back(stringFromJString(jniEnv, path), stringFromJString(jniEnv, value)); + jniEnv->DeleteLocalRef(path); + jniEnv->DeleteLocalRef(value); + } + + if (sceneUpdates.empty()) { return; } + + auto map = reinterpret_cast(mapPtr); + map->queueSceneUpdate(sceneUpdates); + } + JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeApplySceneUpdates(JNIEnv* jnienv, jobject obj, jlong mapPtr) { assert(mapPtr > 0); auto map = reinterpret_cast(mapPtr); diff --git a/android/tangram/src/com/mapzen/tangram/MapController.java b/android/tangram/src/com/mapzen/tangram/MapController.java index c3adcb4fae..e3b65accc3 100644 --- a/android/tangram/src/com/mapzen/tangram/MapController.java +++ b/android/tangram/src/com/mapzen/tangram/MapController.java @@ -13,8 +13,10 @@ import com.squareup.okhttp.Response; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import javax.microedition.khronos.egl.EGLConfig; @@ -222,9 +224,20 @@ static MapController getInstance(GLSurfaceView view) { * @param path Location of the YAML scene file within the application assets */ public void loadSceneFile(String path) { + loadSceneFile(path, null); + } + + /** + * Load a new scene file + * @param path Location of the YAML scene file within the application assets + * @param sceneUpdates List of {@code SceneUpdate} + */ + public void loadSceneFile(String path, List sceneUpdates) { + + String[] updateStrings = bundleSceneUpdates(sceneUpdates); scenePath = path; checkPointer(mapPointer); - nativeLoadScene(mapPointer, path); + nativeLoadScene(mapPointer, path, updateStrings); requestRender(); } @@ -738,12 +751,27 @@ public void setDebugFlag(DebugFlag flag, boolean on) { /** * Enqueue a scene component update with its corresponding YAML node value - * @param componentPath The YAML component path delimited by a '.' (example "scene.animated") - * @param value A YAML valid string (example "{ property: true }" or "true") + * @param sceneUpdate A {@code SceneUpdate} + */ + public void queueSceneUpdate(SceneUpdate sceneUpdate) { + checkPointer(mapPointer); + if (sceneUpdate == null) { + throw new IllegalArgumentException("sceneUpdate can not be null in queueSceneUpdates"); + } + nativeQueueSceneUpdate(mapPointer, sceneUpdate.getPath(), sceneUpdate.getValue()); + } + + /** + * Enqueue a scene component update with its corresponding YAML node value + * @param sceneUpdates List of {@code SceneUpdate} */ - public void queueSceneUpdate(String componentPath, String value) { + public void queueSceneUpdate(List sceneUpdates) { checkPointer(mapPointer); - nativeQueueSceneUpdate(mapPointer, componentPath, value); + if (sceneUpdates == null || sceneUpdates.size() == 0) { + throw new IllegalArgumentException("sceneUpdates can not be null or empty in queueSceneUpdates"); + } + String[] updateStrings = bundleSceneUpdates(sceneUpdates); + nativeQueueSceneUpdates(mapPointer, updateStrings); } /** @@ -804,6 +832,22 @@ void checkId(long id) { } } + private String[] bundleSceneUpdates(List sceneUpdates) { + + String[] updateStrings = null; + + if (sceneUpdates != null) { + updateStrings = new String[sceneUpdates.size() * 2]; + int index = 0; + for (SceneUpdate sceneUpdate : sceneUpdates) { + updateStrings[index++] = sceneUpdate.getPath(); + updateStrings[index++] = sceneUpdate.getValue(); + } + } + + return updateStrings; + } + boolean setMarkerStyling(long markerId, String styleStr) { checkPointer(mapPointer); checkId(markerId); @@ -861,7 +905,7 @@ boolean setMarkerDrawOrder(long markerId, int drawOrder) { private synchronized native long nativeInit(MapController instance, AssetManager assetManager); private synchronized native void nativeDispose(long mapPtr); - private synchronized native void nativeLoadScene(long mapPtr, String path); + private synchronized native void nativeLoadScene(long mapPtr, String path, String[] updateStrings); private synchronized native void nativeSetupGL(long mapPtr); private synchronized native void nativeResize(long mapPtr, int width, int height); private synchronized native boolean nativeUpdate(long mapPtr, float dt); @@ -890,7 +934,8 @@ boolean setMarkerDrawOrder(long markerId, int drawOrder) { private synchronized native void nativeHandlePinchGesture(long mapPtr, float posX, float posY, float scale, float velocity); private synchronized native void nativeHandleRotateGesture(long mapPtr, float posX, float posY, float rotation); private synchronized native void nativeHandleShoveGesture(long mapPtr, float distance); - private synchronized native void nativeQueueSceneUpdate(long mapPtr, String componentPath, String value); + private synchronized native void nativeQueueSceneUpdate(long mapPtr, String componentPath, String componentValue); + private synchronized native void nativeQueueSceneUpdates(long mapPtr, String[] updateStrings); private synchronized native void nativeApplySceneUpdates(long mapPtr); private synchronized native void nativePickFeature(long mapPtr, float posX, float posY, FeaturePickListener listener); private synchronized native void nativePickLabel(long mapPtr, float posX, float posY, LabelPickListener listener); diff --git a/android/tangram/src/com/mapzen/tangram/MapView.java b/android/tangram/src/com/mapzen/tangram/MapView.java index 656870cf7f..8885e5ff08 100644 --- a/android/tangram/src/com/mapzen/tangram/MapView.java +++ b/android/tangram/src/com/mapzen/tangram/MapView.java @@ -8,6 +8,9 @@ import android.util.AttributeSet; import android.widget.FrameLayout; +import java.util.ArrayList; +import java.util.List; + /** * {@code MapView} is a View for displaying a Tangram map. */ @@ -55,6 +58,20 @@ public interface OnMapReadyCallback { public void getMapAsync(@NonNull final OnMapReadyCallback callback, @NonNull final String sceneFilePath) { + getMapAsync(callback, sceneFilePath, null); + } + + /** + * Construct a {@code MapController} asynchronously; may only be called from the UI thread + * @param callback The object to receive the resulting MapController in a callback; + * the callback will be made on the UI thread + * @param sceneFilePath Location of the YAML scene file within the asset bundle + * @param sceneUpdates List of SceneUpdate to be applied when loading this scene + */ + public void getMapAsync(@NonNull final OnMapReadyCallback callback, + @NonNull final String sceneFilePath, + final List sceneUpdates) { + disposeTask(); final MapController mapInstance = getMapInstance(); @@ -65,7 +82,7 @@ public void getMapAsync(@NonNull final OnMapReadyCallback callback, @SuppressWarnings("WrongThread") protected Boolean doInBackground(Void... params) { mapInstance.init(); - mapInstance.loadSceneFile(sceneFilePath); + mapInstance.loadSceneFile(sceneFilePath, sceneUpdates); return true; } diff --git a/android/tangram/src/com/mapzen/tangram/SceneUpdate.java b/android/tangram/src/com/mapzen/tangram/SceneUpdate.java new file mode 100644 index 0000000000..ba63a54134 --- /dev/null +++ b/android/tangram/src/com/mapzen/tangram/SceneUpdate.java @@ -0,0 +1,25 @@ +package com.mapzen.tangram; + +/** + * {@code SceneUpdate} Represents a DataStructure to specify a yaml path and the corresponding value for a Scene Update. + */ + +public class SceneUpdate { + + private String componentPath; + private String componentValue; + + /** + * Add a point feature to this collection. + * @param path Series of yaml keys separated by a ".". Represents the scene path to be updated + * @param value A yaml string which will update the value at the specified path + */ + public SceneUpdate(String path, String value) { + this.componentPath = path; + this.componentValue = value; + } + + public String getPath() { return componentPath; } + public String getValue() { return componentValue; } + +} diff --git a/core/src/tangram.h b/core/src/tangram.h index 4228ec16d3..3a7686fa52 100644 --- a/core/src/tangram.h +++ b/core/src/tangram.h @@ -46,6 +46,7 @@ using LabelPickCallback = std::function; struct SceneUpdate { std::string path; std::string value; + SceneUpdate(std::string p, std::string v) : path(p), value(v) {} }; enum class EaseType : char {