Commit 735c5a8c authored by Jeffrey I. Schiller's avatar Jeffrey I. Schiller Committed by Evan W. Patton

DataChanged (CloudDB) now handles images

Make the DataChanged event consistent with the GotValue event as to how
it handles images.

Change-Id: I08bdbd829cd423fe435081845b863ec4200eb7c4
parent 5648f694
...@@ -13,7 +13,6 @@ import android.database.sqlite.SQLiteDatabase; ...@@ -13,7 +13,6 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.util.Base64; import android.util.Base64;
...@@ -28,9 +27,6 @@ import com.google.appinventor.components.annotations.SimpleProperty; ...@@ -28,9 +27,6 @@ import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.annotations.UsesLibraries; import com.google.appinventor.components.annotations.UsesLibraries;
import com.google.appinventor.components.annotations.UsesPermissions; import com.google.appinventor.components.annotations.UsesPermissions;
import com.google.appinventor.components.annotations.androidmanifest.IntentFilterElement;
import com.google.appinventor.components.annotations.androidmanifest.ReceiverElement;
import com.google.appinventor.components.common.ComponentCategory; import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.common.PropertyTypeConstants; import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion; import com.google.appinventor.components.common.YaVersion;
...@@ -45,7 +41,6 @@ import java.io.ByteArrayInputStream; ...@@ -45,7 +41,6 @@ import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.security.KeyStore; import java.security.KeyStore;
...@@ -54,9 +49,7 @@ import java.security.cert.CertificateFactory; ...@@ -54,9 +49,7 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
...@@ -72,7 +65,6 @@ import org.json.JSONArray; ...@@ -72,7 +65,6 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.exceptions.JedisException;
...@@ -110,7 +102,6 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone ...@@ -110,7 +102,6 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone
OnClearListener, OnDestroyListener { OnClearListener, OnDestroyListener {
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private static final String LOG_TAG = "CloudDB"; private static final String LOG_TAG = "CloudDB";
private static final String BINFILE_DIR = "/AppInventorBinaries";
private boolean importProject = false; private boolean importProject = false;
private String projectID = ""; private String projectID = "";
private String token = ""; private String token = "";
...@@ -745,7 +736,7 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone ...@@ -745,7 +736,7 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone
Log.d(LOG_TAG, "finished call jedis.get()"); Log.d(LOG_TAG, "finished call jedis.get()");
} }
if (returnValue != null) { if (returnValue != null) {
String val = getJsonRepresenationIfValueFileName(returnValue); String val = JsonUtil.getJsonRepresentationIfValueFileName(returnValue);
if(val != null) value.set(val); if(val != null) value.set(val);
else value.set(returnValue); else value.set(returnValue);
} }
...@@ -1234,57 +1225,6 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone ...@@ -1234,57 +1225,6 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone
} }
} }
/**
* Accepts a base64 encoded string and a file extension (which must be three characters).
* Decodes the string into a binary and saves it to a file on external storage and returns
* the filename assigned.
*
* Written by Jeff Schiller (jis) for the BinFile Extension
*
* @param input Base64 input string
* @param fileExtension three character file extension
* @return the name of the created file
*/
private String writeFile(String input, String fileExtension) {
try {
if (fileExtension.length() != 3) {
throw new YailRuntimeError("File Extension must be three characters", "Write Error");
}
byte [] content = Base64.decode(input, Base64.DEFAULT);
String fullDirName = Environment.getExternalStorageDirectory() + BINFILE_DIR;
File destDirectory = new File(fullDirName);
destDirectory.mkdirs();
File dest = File.createTempFile("BinFile", "." + fileExtension, destDirectory);
FileOutputStream outStream = new FileOutputStream(dest);
outStream.write(content);
outStream.close();
String retval = dest.toURI().toASCIIString();
trimDirectory(20, destDirectory);
return retval;
} catch (Exception e) {
throw new YailRuntimeError(e.getMessage(), "Write");
}
}
// keep only the last N files, where N = maxSavedFiles
// Written by Jeff Schiller (jis) for the BinFile Extension
private void trimDirectory(int maxSavedFiles, File directory) {
File [] files = directory.listFiles();
Arrays.sort(files, new Comparator<File>(){
public int compare(File f1, File f2)
{
return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
} });
int excess = files.length - maxSavedFiles;
for (int i = 0; i < excess; i++) {
files[i].delete();
}
}
// Utility to get the file extension from a filename // Utility to get the file extension from a filename
// Written by Jeff Schiller (jis) for the BinFile Extension // Written by Jeff Schiller (jis) for the BinFile Extension
private String getFileExtension(String fullName) { private String getFileExtension(String fullName) {
...@@ -1293,37 +1233,6 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone ...@@ -1293,37 +1233,6 @@ public final class CloudDB extends AndroidNonvisibleComponent implements Compone
return dotIndex == -1 ? "" : fileName.substring(dotIndex + 1); return dotIndex == -1 ? "" : fileName.substring(dotIndex + 1);
} }
/*
* Written by joymitro@gmail.com (Joydeep Mitra)
* This method converts a file path to a JSON representation.
* The code in the method was part of GetValue. For better modularity and reusability
* the logic is now part of this method, which can be invoked from wherever and
* whenever required.
*
* @param file path
* @return JSON representation
*/
private String getJsonRepresenationIfValueFileName(String value){
try {
JSONArray valueJsonList = new JSONArray(value);
List<String> valueList = JsonUtil.getStringListFromJsonArray(valueJsonList);
if (valueList.size() == 2) {
if (valueList.get(0).startsWith(".")) {
String filename = writeFile(valueList.get(1), valueList.get(0).substring(1));
System.out.println("Filename Written: " + filename);
filename = filename.replace("file:/", "file:///");
return JsonUtil.getJsonRepresentation(filename);
} else {
return null;
}
} else {
return null;
}
} catch(JSONException e) {
return null;
}
}
public ExecutorService getBackground() { public ExecutorService getBackground() {
return background; return background;
} }
......
...@@ -57,7 +57,12 @@ public class CloudDBJedisListener extends JedisPubSub { ...@@ -57,7 +57,12 @@ public class CloudDBJedisListener extends JedisPubSub {
for (Object value : valueList) { for (Object value : valueList) {
// Note: DataChanged will arrange to dispatch the event // Note: DataChanged will arrange to dispatch the event
// on the UI thread. // on the UI thread.
String retValue = JsonUtil.getJsonRepresentationIfValueFileName(value);
if (retValue == null) {
cloudDB.DataChanged(tag, value); cloudDB.DataChanged(tag, value);
} else {
cloudDB.DataChanged(tag, retValue);
}
} }
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOG_TAG, "onMessage: JSONException", e); Log.e(LOG_TAG, "onMessage: JSONException", e);
......
...@@ -6,19 +6,32 @@ ...@@ -6,19 +6,32 @@
package com.google.appinventor.components.runtime.util; package com.google.appinventor.components.runtime.util;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import com.google.appinventor.components.runtime.errors.YailRuntimeError;
import gnu.lists.FString; import gnu.lists.FString;
import gnu.math.IntFraction; import gnu.math.IntFraction;
import org.json.JSONArray; import java.io.File;
import org.json.JSONException; import java.io.FileOutputStream;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
/** /**
* Provides utility functions to convert between Java object and JSON. * Provides utility functions to convert between Java object and JSON.
* *
...@@ -26,6 +39,9 @@ import java.util.List; ...@@ -26,6 +39,9 @@ import java.util.List;
*/ */
public class JsonUtil { public class JsonUtil {
private static final String BINFILE_DIR = "/AppInventorBinaries";
private static final String LOG_TAG = "JsonUtil";
/** /**
* Prevent instantiation. * Prevent instantiation.
*/ */
...@@ -218,5 +234,105 @@ public class JsonUtil { ...@@ -218,5 +234,105 @@ public class JsonUtil {
throw new JSONException("Invalid JSON string."); throw new JSONException("Invalid JSON string.");
} }
} }
/**
* Written by joymitro@gmail.com (Joydeep Mitra)
* This method converts a file path to a JSON representation.
* The code in the method was part of GetValue. For better modularity and reusability
* the logic is now part of this method, which can be invoked from wherever and
* whenever required.
*
* 07/06/2018 (jis): Currently this routine is called by the CloudDB component
* When called from GetValue, it is handed a String (the raw
* data from Jedis) to parse. When called from the
* CloudDBJedisListener it is handed an input that has
* already been converted into a List (because the
* CloudDBJedisListener is processing a list of changes,
* not just one. Rather then having two versions of
* this function, we just do the initial JSON parsing
* if we are handed a string.
*
* @param file path
* @return JSON representation
*/
public static String getJsonRepresentationIfValueFileName(Object value){
try {
List<String> valueList;
if (value instanceof String) {
JSONArray valueJsonList = new JSONArray((String)value);
valueList = getStringListFromJsonArray(valueJsonList);
} else if (value instanceof List) {
valueList = (List<String>) value;
} else {
throw new YailRuntimeError("getJsonRepresentationIfValueFileName called on unknown type",
value.getClass().getName());
}
if (valueList.size() == 2) {
if (valueList.get(0).startsWith(".")) {
String filename = writeFile(valueList.get(1), valueList.get(0).substring(1));
System.out.println("Filename Written: " + filename);
filename = filename.replace("file:/", "file:///");
return getJsonRepresentation(filename);
} else {
return null;
}
} else {
return null;
}
} catch(JSONException e) {
Log.e(LOG_TAG, "JSONException", e);
return null;
}
}
/**
* Accepts a base64 encoded string and a file extension (which must be three characters).
* Decodes the string into a binary and saves it to a file on external storage and returns
* the filename assigned.
*
* Written by Jeff Schiller (jis) for the BinFile Extension
*
* @param input Base64 input string
* @param fileExtension three character file extension
* @return the name of the created file
*/
private static String writeFile(String input, String fileExtension) {
try {
if (fileExtension.length() != 3) {
throw new YailRuntimeError("File Extension must be three characters", "Write Error");
}
byte [] content = Base64.decode(input, Base64.DEFAULT);
String fullDirName = Environment.getExternalStorageDirectory() + BINFILE_DIR;
File destDirectory = new File(fullDirName);
destDirectory.mkdirs();
File dest = File.createTempFile("BinFile", "." + fileExtension, destDirectory);
FileOutputStream outStream = new FileOutputStream(dest);
outStream.write(content);
outStream.close();
String retval = dest.toURI().toASCIIString();
trimDirectory(20, destDirectory);
return retval;
} catch (Exception e) {
throw new YailRuntimeError(e.getMessage(), "Write");
}
}
// keep only the last N files, where N = maxSavedFiles
// Written by Jeff Schiller (jis) for the BinFile Extension
private static void trimDirectory(int maxSavedFiles, File directory) {
File [] files = directory.listFiles();
Arrays.sort(files, new Comparator<File>(){
public int compare(File f1, File f2)
{
return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
} });
int excess = files.length - maxSavedFiles;
for (int i = 0; i < excess; i++) {
files[i].delete();
}
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment