Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Android API for scene loading with scene updates #1173

Merged
merged 6 commits into from
Dec 22, 2016

Conversation

tallytalwar
Copy link
Member

@tallytalwar tallytalwar commented Dec 13, 2016

  • MapView provides an overloaded getMapAsync which accepts an ArrayList of SceneUpdates (new
    Class).
  • MapController::loadSceneFile provides an overloaded method to accept an ArrayList of SceneUpdates
  • MapController::queueSceneUpdates provides an overloaded method to accept an ArrayList of
    SceneUpdates

public void queueSceneUpdate(ArrayList<SceneUpdate> sceneUpdates) {
checkPointer(mapPointer);
for(SceneUpdate sceneUpdate : sceneUpdates) {
nativeQueueSceneUpdate(mapPointer, sceneUpdate.path, sceneUpdate.value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to make it a single call here nativeQueueSceneUpdates(long mapPtr, String[] sceneUpdatePaths, String[] sceneUpdateValues)? It would reduce jumping between platform code and core library.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, will update.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend using the SceneUpdate type in the older queueSceneUpdate method as well.

set(path, value);
}

public SceneUpdate set(String p, String v) {
Copy link
Member

@karimnaaji karimnaaji Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make this public we should be more explicit on the variable names p and v.
I'm not sure we need the default constructor SceneUpdate() and this setter since the variable are public.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just being more formal here. Will remove the constructor and directly assign.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend removing the setter and only setting members in the constructor.

public SceneUpdate set(String p, String v) {
path = p;
value = v;
return this;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the return?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying something else before. Will update this.

@matteblair matteblair self-requested a review December 14, 2016 16:49
@@ -118,6 +118,25 @@ extern "C" {
jniEnv->ReleaseStringUTFChars(path, cPath);
}

JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeLoadSceneWithUpdates(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jstring path, jobjectArray jsceneUpdatePaths, jobjectArray jsceneUpdateValues) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we could merge this with the method above and just pass a null array when no updates are given.

* @param path Location of the YAML scene file within the application assets
* @param sceneUpdates List of path:value pairs to be applied when loading this scene
*/
public void loadSceneFile(String path, ArrayList<SceneUpdate> sceneUpdates) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods should take a List<SceneUpdate>, the List interface should be preferred to concrete types when we don't need the specific type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also check this for null.

public String path;
public String value;

public SceneUpdate() { this("", ""); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend removing this constructor.

public class SceneUpdate {

public String path;
public String value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend making these members private and adding getters.

set(path, value);
}

public SceneUpdate set(String p, String v) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend removing the setter and only setting members in the constructor.

public void queueSceneUpdate(ArrayList<SceneUpdate> sceneUpdates) {
checkPointer(mapPointer);
for(SceneUpdate sceneUpdate : sceneUpdates) {
nativeQueueSceneUpdate(mapPointer, sceneUpdate.path, sceneUpdate.value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend using the SceneUpdate type in the older queueSceneUpdate method as well.


public SceneUpdate() { this("", ""); }

public SceneUpdate(String path, String value) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend adding documentation explaining the meaning of these arguments.

@@ -65,7 +81,11 @@ public void getMapAsync(@NonNull final OnMapReadyCallback callback,
@SuppressWarnings("WrongThread")
protected Boolean doInBackground(Void... params) {
mapInstance.init();
mapInstance.loadSceneFile(sceneFilePath);
if (sceneUpdates.size() > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch should be unnecessary if we allow empty or null lists as the second argument to loadSceneFile.

@tallytalwar
Copy link
Member Author

Addressed all comments here: 7353bbe

@karimnaaji
Copy link
Member

karimnaaji commented Dec 19, 2016

Comments got removed of the pull request: 7353bbe#commitcomment-20205669. Merging once updated.

@tallytalwar
Copy link
Member Author

Ohh, thanks @karimnaaji . Updated.

@matteblair
Copy link
Member

matteblair commented Dec 19, 2016

I have changes to suggest for this - don't merge quite yet please.

@tallytalwar tallytalwar force-pushed the android-sceneLoadUpdates branch from e77febb to 4b54361 Compare December 21, 2016 00:17
@karimnaaji
Copy link
Member

@ecgreb this one needs your approval! It's good to merge otherwise.

Copy link
Contributor

@ecgreb ecgreb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Public API looks good to me. Two suggestions inline regarding input validation and duplicate code.

* @param sceneUpdates List of {@code SceneUpdate}
*/
public void queueSceneUpdate(List<SceneUpdate> sceneUpdates) {
checkPointer(mapPointer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to provide some input validation on sceneUpdates param. Perhaps throw an IllegalArgumentException if it is empty or null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, tangram will be handling a null or empty sceneUpdates gracefully, through the jni code here:

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<Tangram::SceneUpdate> 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; }
.

Am I missing java thingy, which will help here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No the code won't break but it could be helpful to the developer if we provided some explicit feedback rather than failing silently in the case of invalid input.

Also passing data across the JNI is expensive. If we can avoid that by checking the input in Java first that would be preferable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok Both are valid points. Updated here: 8c1ff13

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

String[] updateStrings = null;

if (sceneUpdates != null) {
updateStrings = new String[sceneUpdates.size() * 2];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic to build updateStrings is repeated again below in queueSceneUpdate(...). Could be extracted into a private method?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed here: c362285

@tallytalwar
Copy link
Member Author

tallytalwar commented Dec 22, 2016

With an update to arguments for queueSceneUpdates, this now is an API breaking change (for the next release).

Will rebase this with master and merge.

tallytalwar and others added 6 commits December 21, 2016 23:32
- MapView provides an overloaded `getMapAsync` which accepts an ArrayList of SceneUpdates (new
Class).
- MapController::loadSceneFile provides an overloaded method to accept an ArrayList of SceneUpdates
- MapController::queueSceneUpdates provides an overloaded method to accept an ArrayList of
SceneUpdates
path -> getPath
value -> getValue
- BundleSceneUpdate private method bundles list of scene updates as an array of strings alternating
scene yaml path and corresponding value
@tallytalwar tallytalwar force-pushed the android-sceneLoadUpdates branch from 8c1ff13 to 67eb847 Compare December 22, 2016 04:47
@tallytalwar tallytalwar merged commit 75f31f2 into master Dec 22, 2016
@tallytalwar tallytalwar deleted the android-sceneLoadUpdates branch December 22, 2016 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants