Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[android] #3891 - simplify metadata conversion and fix metadata object
Browse files Browse the repository at this point in the history
  • Loading branch information
zugaldia committed Feb 25, 2016
1 parent af11e54 commit f1e09ce
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static byte[] serialize(Object obj) throws IOException {
os.writeObject(obj);
return out.toByteArray();
}

public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class OfflineActivity extends AppCompatActivity

private final static String LOG_TAG = "OfflineActivity";

private final static String KEY_REGION_NAME = "KEY_REGION_NAME";

/*
* UI elements
*/
Expand Down Expand Up @@ -219,19 +221,15 @@ public void onError(String error) {
}

private String getRegionName(OfflineRegion offlineRegion) {
String regionName;

// Known issue
regionName = "Region " + offlineRegion.getID();

// try {
// byte[] metadata = offlineRegion.getMetadata().getMetadata();
// HashMap<String, String> data = (HashMap<String, String>) OfflineRegionMetadata.deserialize(metadata);
// regionName = data.get("name");
// } catch (Exception e) {
// Log.d(LOG_TAG, "Failed to decode metadata: " + e.getMessage());
// regionName = "Region " + offlineRegion.getID();
// }
String regionName = "Region " + offlineRegion.getID();

try {
byte[] metadata = offlineRegion.getMetadata().getMetadata();
HashMap<String, String> data = (HashMap<String, String>) OfflineRegionMetadata.deserialize(metadata);
regionName = data.get(KEY_REGION_NAME);
} catch (Exception e) {
Log.e(LOG_TAG, "Failed to decode metadata: " + e.getMessage());
}

return regionName;
}
Expand Down Expand Up @@ -262,7 +260,7 @@ public void onDownloadRegionDialogPositiveClick(final String regionName) {
OfflineRegionMetadata metadata = null;
try {
HashMap<String, String> data = new HashMap<>();
data.put("name", regionName);
data.put(KEY_REGION_NAME, regionName);
byte[] dataEncoded = OfflineRegionMetadata.serialize(data);
metadata = new OfflineRegionMetadata(dataEncoded);
} catch (IOException e) {
Expand Down
94 changes: 24 additions & 70 deletions platform/android/src/jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,74 +435,20 @@ std::pair<mbgl::AnnotationSegment, mbgl::ShapeAnnotation::Properties> annotation
return std::make_pair(segment, shapeProperties);
}

/*
* Adapted from https://github.com/dropbox/djinni/blob/master/support-lib/jni/Marshal.hpp
*/

void jniExceptionCheck(JNIEnv * env) {
if (!env) {
mbgl::Log::Error(mbgl::Event::JNI, "Empty environment.");
abort();
}

const jthrowable e(env->ExceptionOccurred());
if (e) {
env->ExceptionClear();
}
}

static std::vector<uint8_t> metadata_from_java(JNIEnv* jniEnv, jbyteArray j) {
assert(j != nullptr);

std::vector<uint8_t> ret;
jsize length = jniEnv->GetArrayLength(j);
jniExceptionCheck(jniEnv);

if (!length) {
mbgl::Log::Error(mbgl::Event::JNI, "jbyteArray was empty.");
return ret;
}

{
auto deleter = [jniEnv, j] (void* c) {
if (c) {
jniEnv->ReleasePrimitiveArrayCritical(j, c, JNI_ABORT);
}
};

std::unique_ptr<uint8_t, decltype(deleter)> ptr(
reinterpret_cast<uint8_t*>(jniEnv->GetPrimitiveArrayCritical(j, nullptr)),
deleter
);

if (ptr) {
// Construct and then move-assign. This copies the elements only once,
// and avoids having to initialize before filling (as with resize())
ret = std::vector<uint8_t>{ptr.get(), ptr.get() + length};
} else {
// Something failed.
jniExceptionCheck(jniEnv);
}
}

mbgl::Log::Error(mbgl::Event::JNI, "jbyteArray conversion completed.");
return ret;
}

static jbyteArray metadata_from_native(JNIEnv* jniEnv, const std::vector<uint8_t>& c) {
assert(c.size() <= std::numeric_limits<jsize>::max());
jbyteArray j = jniEnv->NewByteArray(static_cast<jsize>(c.size()));
jniExceptionCheck(jniEnv);

// Using .data() on an empty vector is UB
if(c.empty()) {
mbgl::Log::Error(mbgl::Event::JNI, "std::vector<uint8_t> was empty.");
return j;
}

jniEnv->SetByteArrayRegion(j, 0, c.size(), reinterpret_cast<const jbyte*>(c.data()));

mbgl::Log::Error(mbgl::Event::JNI, "std::vector<uint8_t> conversion completed.");
static std::vector<uint8_t> metadata_from_java(JNIEnv* env, jbyteArray j) {
mbgl::Log::Debug(mbgl::Event::JNI, "metadata_from_java");
jsize length = env->GetArrayLength(j);
std::vector<uint8_t> c;
c.resize(length);
env->GetByteArrayRegion(j, 0, length, reinterpret_cast<jbyte*>(c.data()));
return c;
}

static jbyteArray metadata_from_native(JNIEnv* env, const std::vector<uint8_t>& c) {
mbgl::Log::Debug(mbgl::Event::JNI, "metadata_from_java");
jsize length = static_cast<jsize>(c.size());
jbyteArray j = env->NewByteArray(length);
env->SetByteArrayRegion(j, 0, c.size(), reinterpret_cast<const jbyte*>(c.data()));
return j;
}

Expand Down Expand Up @@ -1817,7 +1763,11 @@ void JNICALL listOfflineRegions(JNIEnv *env, jobject obj, jlong defaultFileSourc
jobject jregion = env2->NewObject(offlineRegionClass, offlineRegionConstructorId);
env2->SetObjectField(jregion, offlineRegionOfflineManagerId, obj);
env2->SetLongField(jregion, offlineRegionIdId, region.getID());
env2->SetObjectField(jregion, offlineRegionMetadataId, metadata_from_native(env2, region.getMetadata()));

// Metadata object
jbyteArray metadata = metadata_from_native(env2, region.getMetadata());
jobject jmetadata = env2->NewObject(offlineRegionMetadataClass, offlineRegionMetadataConstructorId, metadata);
env2->SetObjectField(jregion, offlineRegionMetadataId, jmetadata);

// Moves the region on the stack into a heap-allocated one
env2->SetLongField(jregion, offlineRegionPtrId,
Expand Down Expand Up @@ -1896,7 +1846,11 @@ void JNICALL createOfflineRegion(JNIEnv *env, jobject obj, jlong defaultFileSour
jobject jregion = env2->NewObject(offlineRegionClass, offlineRegionConstructorId);
env2->SetObjectField(jregion, offlineRegionOfflineManagerId, obj);
env2->SetLongField(jregion, offlineRegionIdId, region->getID());
env2->SetObjectField(jregion, offlineRegionMetadataId, metadata_from_native(env2, region->getMetadata()));

// Metadata object
jbyteArray xmetadata = metadata_from_native(env2, region->getMetadata());
jobject xjmetadata = env2->NewObject(offlineRegionMetadataClass, offlineRegionMetadataConstructorId, xmetadata);
env2->SetObjectField(jregion, offlineRegionMetadataId, xjmetadata);

// Moves the region on the stack into a heap-allocated one
env2->SetLongField(jregion, offlineRegionPtrId,
Expand Down

0 comments on commit f1e09ce

Please sign in to comment.