/* * Copyright 2014 Artem Chikin * Copyright 2014 Artem Herasymchuk * Copyright 2014 Tom Krywitsky * Copyright 2014 Henry Pabst * Copyright 2014 Bradley Simons * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ca.ualberta.cmput301w14t08.geochan.json; import java.io.ByteArrayOutputStream; import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Base64; import ca.ualberta.cmput301w14t08.geochan.models.Comment; import ca.ualberta.cmput301w14t08.geochan.models.GeoLocation; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; /** * Handles the offline serialization and deserialization of Comment objects * to and from JSON format. * * @author Artem Chikin * @author Artem Herasymchuk * */ public class CommentOfflineJsonConverter implements JsonSerializer<Comment>, JsonDeserializer<Comment> { /** * Serializes a Comment object into JSON format (for offline storage). * * @param comment * the Comment to serialize * @param type * the Type * @param context * the JSON serialization context * * @return A JsonElement representing the serialized Comment. */ @Override public JsonElement serialize(Comment comment, Type type, JsonSerializationContext context) { JsonObject object = new JsonObject(); object.addProperty("commentDate", comment.getCommentDate().getTime()); if (comment.getLocation() != null) { object.addProperty("location", comment.getLocation().getLatitude() + "," + comment.getLocation().getLongitude()); if (comment.getLocation().getLocationDescription() != null) { object.addProperty("locationDescription", comment.getLocation() .getLocationDescription()); } } else { object.addProperty("location", "-999,-999"); } object.addProperty("user", comment.getUser()); object.addProperty("hash", comment.getHash()); object.addProperty("id", comment.getId()); object.addProperty("textPost", comment.getTextPost()); object.addProperty("hasImage", comment.hasImage()); if (comment.hasImage()) { Bitmap bitmapThumb = comment.getImageThumb(); /* * http://stackoverflow.com/questions/9224056/android-bitmap-to-base64 * -string * * Serialize just the thumbnail as the image is serialized * separately */ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmapThumb.compress(Bitmap.CompressFormat.JPEG, 90, byteArrayOutputStream); byte[] byteThumbArray = byteArrayOutputStream.toByteArray(); String encodedThumb = Base64.encodeToString(byteThumbArray, Base64.NO_WRAP); object.addProperty("imageThumbnail", encodedThumb); } object.addProperty("depth", comment.getDepth()); if (comment.getParent() != null) { object.addProperty("parent", comment.getParent().getId()); } return object; } /** * Deserializes a Comment object from JSON format (for offline storage). * @param json * the JSON element to deserialize * @param type * the Type * @param context * the JSON deserialization context * * @return The deserialized Comment. * * @throws JsonParseException */ @Override public Comment deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { JsonObject object = json.getAsJsonObject(); long commentDate = object.get("commentDate").getAsLong(); String locationString = object.get("location").getAsString(); List<String> locationEntries = Arrays.asList(locationString.split(",")); double latitude = Double.parseDouble(locationEntries.get(0)); double longitude = Double.parseDouble(locationEntries.get(1)); String locationDescription = null; if (object.get("locationDescription") != null) { locationDescription = object.get("locationDescription").getAsString(); } GeoLocation location = new GeoLocation(latitude, longitude); location.setLocationDescription(locationDescription); String user = object.get("user").getAsString(); String hash = object.get("hash").getAsString(); String id = object.get("id").getAsString(); String textPost = object.get("textPost").getAsString(); Bitmap thumbnail = null; boolean hasImage = object.get("hasImage").getAsBoolean(); if (hasImage) { /* * http://stackoverflow.com/a/5878773 * Sando's workaround for running out of memory on decoding bitmaps. * * Only deserialize the thumbnail as the full image is deserialized * separately. */ BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inDither = false; opts.inPurgeable = true; opts.inInputShareable = true; opts.inTempStorage = new byte[32 * 1024]; String encodedThumb = object.get("imageThumbnail").getAsString(); byte[] thumbArray = Base64.decode(encodedThumb, Base64.NO_WRAP); thumbnail = BitmapFactory.decodeByteArray(thumbArray, 0, thumbArray.length, opts); } int depth = object.get("depth").getAsInt(); final Comment comment = new Comment(textPost, null, location, null); comment.getCommentDate().setTime(commentDate); comment.setUser(user); comment.setHash(hash); comment.setDepth(depth); comment.setId(Long.parseLong(id)); if (hasImage) { comment.setImageThumb(thumbnail); } return comment; } }