summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2016-11-08 12:37:03 -0500
committerJules Laplace <jules@okfoc.us>2016-11-08 12:37:03 -0500
commitef4f212fc1482136dba1e690ec589b315b4a377f (patch)
tree0b7e16d72567fafcfd3e08d7c5c591ad07a63458 /StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java
parent5fa81da81260d65113f57a293b6256d334fe8e2d (diff)
build 0.7.0
Diffstat (limited to 'StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java')
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java280
1 files changed, 261 insertions, 19 deletions
diff --git a/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java b/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java
index f1168f89..8de31da8 100755..100644
--- a/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java
+++ b/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java
@@ -26,7 +26,9 @@ import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Matcher;
@@ -36,6 +38,7 @@ public class SocialSharing extends CordovaPlugin {
private static final String ACTION_AVAILABLE_EVENT = "available";
private static final String ACTION_SHARE_EVENT = "share";
+ private static final String ACTION_SHARE_WITH_OPTIONS_EVENT = "shareWithOptions";
private static final String ACTION_CAN_SHARE_VIA = "canShareVia";
private static final String ACTION_CAN_SHARE_VIA_EMAIL = "canShareViaEmail";
private static final String ACTION_SHARE_VIA = "shareVia";
@@ -47,7 +50,10 @@ public class SocialSharing extends CordovaPlugin {
private static final String ACTION_SHARE_VIA_SMS_EVENT = "shareViaSMS";
private static final String ACTION_SHARE_VIA_EMAIL_EVENT = "shareViaEmail";
- private static final int ACTIVITY_CODE_SENDVIAEMAIL = 2;
+ private static final int ACTIVITY_CODE_SEND__BOOLRESULT = 1;
+ private static final int ACTIVITY_CODE_SEND__OBJECT = 2;
+ private static final int ACTIVITY_CODE_SENDVIAEMAIL = 3;
+ private static final int ACTIVITY_CODE_SENDVIAWHATSAPP = 4;
private CallbackContext _callbackContext;
@@ -55,6 +61,7 @@ public class SocialSharing extends CordovaPlugin {
private abstract class SocialSharingRunnable implements Runnable {
public CallbackContext callbackContext;
+
SocialSharingRunnable(CallbackContext cb) {
this.callbackContext = cb;
}
@@ -68,23 +75,29 @@ public class SocialSharing extends CordovaPlugin {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
return true;
} else if (ACTION_SHARE_EVENT.equals(action)) {
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), null, false);
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), null, null, false, true);
+ } else if (ACTION_SHARE_WITH_OPTIONS_EVENT.equals(action)) {
+ return shareWithOptions(callbackContext, args.getJSONObject(0));
} else if (ACTION_SHARE_VIA_TWITTER_EVENT.equals(action)) {
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "twitter", false);
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "twitter", null, false, true);
} else if (ACTION_SHARE_VIA_FACEBOOK_EVENT.equals(action)) {
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", false);
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", null, false, true);
} else if (ACTION_SHARE_VIA_FACEBOOK_WITH_PASTEMESSAGEHINT.equals(action)) {
this.pasteMessage = args.getString(4);
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", false);
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", null, false, true);
} else if (ACTION_SHARE_VIA_WHATSAPP_EVENT.equals(action)) {
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "whatsapp", false);
+ if (notEmpty(args.getString(4))) {
+ return shareViaWhatsAppDirectly(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4));
+ } else {
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "whatsapp", null, false, true);
+ }
} else if (ACTION_SHARE_VIA_INSTAGRAM_EVENT.equals(action)) {
if (notEmpty(args.getString(0))) {
copyHintToClipboard(args.getString(0), "Instagram paste message");
}
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "instagram", false);
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "instagram", null, false, true);
} else if (ACTION_CAN_SHARE_VIA.equals(action)) {
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), true);
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), null, true, true);
} else if (ACTION_CAN_SHARE_VIA_EMAIL.equals(action)) {
if (isEmailAvailable()) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
@@ -94,7 +107,7 @@ public class SocialSharing extends CordovaPlugin {
return false;
}
} else if (ACTION_SHARE_VIA.equals(action)) {
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), false);
+ return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), null, false, true);
} else if (ACTION_SHARE_VIA_SMS_EVENT.equals(action)) {
return invokeSMSIntent(callbackContext, args.getJSONObject(0), args.getString(1));
} else if (ACTION_SHARE_VIA_EMAIL_EVENT.equals(action)) {
@@ -158,8 +171,17 @@ public class SocialSharing extends CordovaPlugin {
callbackContext.error(e.getMessage());
}
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ draft.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
draft.setType("application/octet-stream");
- cordova.startActivityForResult(plugin, Intent.createChooser(draft, "Choose Email App"), ACTIVITY_CODE_SENDVIAEMAIL);
+
+ // as an experiment for #300 we're explicitly running it on the ui thread here
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ cordova.startActivityForResult(plugin, Intent.createChooser(draft, "Choose Email App"), ACTIVITY_CODE_SENDVIAEMAIL);
+ }
+ });
}
});
@@ -178,7 +200,30 @@ public class SocialSharing extends CordovaPlugin {
}
}
- private boolean doSendIntent(final CallbackContext callbackContext, final String msg, final String subject, final JSONArray files, final String url, final String appPackageName, final boolean peek) {
+ private boolean shareWithOptions(CallbackContext callbackContext, JSONObject jsonObject) {
+ return doSendIntent(
+ callbackContext,
+ jsonObject.optString("message", null),
+ jsonObject.optString("subject", null),
+ jsonObject.optJSONArray("files") == null ? new JSONArray() : jsonObject.optJSONArray("files"),
+ jsonObject.optString("url", null),
+ null,
+ jsonObject.optString("chooserTitle", null),
+ false,
+ false
+ );
+ }
+
+ private boolean doSendIntent(
+ final CallbackContext callbackContext,
+ final String msg,
+ final String subject,
+ final JSONArray files,
+ final String url,
+ final String appPackageName,
+ final String chooserTitle,
+ final boolean peek,
+ final boolean boolResult) {
final CordovaInterface mycordova = cordova;
final CordovaPlugin plugin = this;
@@ -222,6 +267,7 @@ public class SocialSharing extends CordovaPlugin {
if (notEmpty(subject)) {
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
}
+
// add the URL to the message, as there seems to be no separate field
if (notEmpty(url)) {
if (notEmpty(message)) {
@@ -238,6 +284,9 @@ public class SocialSharing extends CordovaPlugin {
}
}
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
if (appPackageName != null) {
String packageName = appPackageName;
String passedActivityName = null;
@@ -254,7 +303,13 @@ public class SocialSharing extends CordovaPlugin {
sendIntent.addCategory(Intent.CATEGORY_LAUNCHER);
sendIntent.setComponent(new ComponentName(activity.applicationInfo.packageName,
passedActivityName != null ? passedActivityName : activity.name));
- mycordova.startActivityForResult(plugin, sendIntent, 0);
+
+ // as an experiment for #300 we're explicitly running it on the ui thread here
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ mycordova.startActivityForResult(plugin, sendIntent, 0);
+ }
+ });
if (pasteMessage != null) {
// add a little delay because target app (facebook only atm) needs to be started first
@@ -275,7 +330,13 @@ public class SocialSharing extends CordovaPlugin {
if (peek) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
} else {
- mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, null), 1);
+ // experimenting a bit
+ // as an experiment for #300 we're explicitly running it on the ui thread here
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, chooserTitle), boolResult ? ACTIVITY_CODE_SEND__BOOLRESULT : ACTIVITY_CODE_SEND__OBJECT);
+ }
+ });
}
}
}
@@ -306,7 +367,12 @@ public class SocialSharing extends CordovaPlugin {
private Uri getFileUriAndSetType(Intent sendIntent, String dir, String image, String subject, int nthFile) throws IOException {
// we're assuming an image, but this can be any filetype you like
String localImage = image;
- sendIntent.setType("image/*");
+ if (image.endsWith("mp4") || image.endsWith("mov") || image.endsWith("3gp")){
+ sendIntent.setType("video/*");
+ } else {
+ sendIntent.setType("image/*");
+ }
+
if (image.startsWith("http") || image.startsWith("www/")) {
String filename = getFileName(image);
localImage = "file://" + dir + "/" + filename;
@@ -319,6 +385,10 @@ public class SocialSharing extends CordovaPlugin {
Matcher matcher = dispositionPattern.matcher(disposition);
if (matcher.find()) {
filename = matcher.group(1).replaceAll("[^a-zA-Z0-9._-]", "");
+ if (filename.length() == 0) {
+ // in this case we can't determine a filetype so some targets (gmail) may not render it correctly
+ filename = "file";
+ }
localImage = "file://" + dir + "/" + filename;
}
}
@@ -365,10 +435,160 @@ public class SocialSharing extends CordovaPlugin {
localImage = "file://" + dir + "/" + fileName;
} else if (!image.startsWith("file://")) {
throw new IllegalArgumentException("URL_NOT_SUPPORTED");
+ } else {
+ //get file MIME type
+ String type = getMIMEType(image);
+ //set intent data and Type
+ sendIntent.setType(type);
}
return Uri.parse(localImage);
}
+ private String getMIMEType(String fileName) {
+ String type = "*/*";
+ int dotIndex = fileName.lastIndexOf(".");
+ if (dotIndex == -1) {
+ return type;
+ }
+ final String end = fileName.substring(dotIndex+1, fileName.length()).toLowerCase();
+ String fromMap = MIME_Map.get(end);
+ return fromMap == null ? type : fromMap;
+ }
+
+ private static final Map<String, String> MIME_Map = new HashMap<String, String>();
+ static {
+ MIME_Map.put("3gp", "video/3gpp");
+ MIME_Map.put("apk", "application/vnd.android.package-archive");
+ MIME_Map.put("asf", "video/x-ms-asf");
+ MIME_Map.put("avi", "video/x-msvideo");
+ MIME_Map.put("bin", "application/octet-stream");
+ MIME_Map.put("bmp", "image/bmp");
+ MIME_Map.put("c", "text/plain");
+ MIME_Map.put("class", "application/octet-stream");
+ MIME_Map.put("conf", "text/plain");
+ MIME_Map.put("cpp", "text/plain");
+ MIME_Map.put("doc", "application/msword");
+ MIME_Map.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ MIME_Map.put("xls", "application/vnd.ms-excel");
+ MIME_Map.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+ MIME_Map.put("exe", "application/octet-stream");
+ MIME_Map.put("gif", "image/gif");
+ MIME_Map.put("gtar", "application/x-gtar");
+ MIME_Map.put("gz", "application/x-gzip");
+ MIME_Map.put("h", "text/plain");
+ MIME_Map.put("htm", "text/html");
+ MIME_Map.put("html", "text/html");
+ MIME_Map.put("jar", "application/java-archive");
+ MIME_Map.put("java", "text/plain");
+ MIME_Map.put("jpeg", "image/jpeg");
+ MIME_Map.put("jpg", "image/*");
+ MIME_Map.put("js", "application/x-javascript");
+ MIME_Map.put("log", "text/plain");
+ MIME_Map.put("m3u", "audio/x-mpegurl");
+ MIME_Map.put("m4a", "audio/mp4a-latm");
+ MIME_Map.put("m4b", "audio/mp4a-latm");
+ MIME_Map.put("m4p", "audio/mp4a-latm");
+ MIME_Map.put("m4u", "video/vnd.mpegurl");
+ MIME_Map.put("m4v", "video/x-m4v");
+ MIME_Map.put("mov", "video/quicktime");
+ MIME_Map.put("mp2", "audio/x-mpeg");
+ MIME_Map.put("mp3", "audio/x-mpeg");
+ MIME_Map.put("mp4", "video/mp4");
+ MIME_Map.put("mpc", "application/vnd.mpohun.certificate");
+ MIME_Map.put("mpe", "video/mpeg");
+ MIME_Map.put("mpeg", "video/mpeg");
+ MIME_Map.put("mpg", "video/mpeg");
+ MIME_Map.put("mpg4", "video/mp4");
+ MIME_Map.put("mpga", "audio/mpeg");
+ MIME_Map.put("msg", "application/vnd.ms-outlook");
+ MIME_Map.put("ogg", "audio/ogg");
+ MIME_Map.put("pdf", "application/pdf");
+ MIME_Map.put("png", "image/png");
+ MIME_Map.put("pps", "application/vnd.ms-powerpoint");
+ MIME_Map.put("ppt", "application/vnd.ms-powerpoint");
+ MIME_Map.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
+ MIME_Map.put("prop", "text/plain");
+ MIME_Map.put("rc", "text/plain");
+ MIME_Map.put("rmvb", "audio/x-pn-realaudio");
+ MIME_Map.put("rtf", "application/rtf");
+ MIME_Map.put("sh", "text/plain");
+ MIME_Map.put("tar", "application/x-tar");
+ MIME_Map.put("tgz", "application/x-compressed");
+ MIME_Map.put("txt", "text/plain");
+ MIME_Map.put("wav", "audio/x-wav");
+ MIME_Map.put("wma", "audio/x-ms-wma");
+ MIME_Map.put("wmv", "audio/x-ms-wmv");
+ MIME_Map.put("wps", "application/vnd.ms-works");
+ MIME_Map.put("xml", "text/plain");
+ MIME_Map.put("z", "application/x-compress");
+ MIME_Map.put("zip", "application/x-zip-compressed");
+ MIME_Map.put("", "*/*");
+ }
+
+ private boolean shareViaWhatsAppDirectly(final CallbackContext callbackContext, String message, final String subject, final JSONArray files, final String url, final String number) {
+ // add the URL to the message, as there seems to be no separate field
+ if (notEmpty(url)) {
+ if (notEmpty(message)) {
+ message += " " + url;
+ } else {
+ message = url;
+ }
+ }
+ final String shareMessage = message;
+ final SocialSharing plugin = this;
+ cordova.getThreadPool().execute(new SocialSharingRunnable(callbackContext) {
+ public void run() {
+ final Intent intent = new Intent(Intent.ACTION_SENDTO);
+ intent.setData(Uri.parse("smsto:" + number));
+
+ intent.putExtra("sms_body", shareMessage);
+ intent.putExtra("sms_subject", subject);
+ intent.setPackage("com.whatsapp");
+
+ try {
+ if (files.length() > 0 && !"".equals(files.getString(0))) {
+ final boolean hasMultipleAttachments = files.length() > 1;
+ final String dir = getDownloadDir();
+ if (dir != null) {
+ ArrayList<Uri> fileUris = new ArrayList<Uri>();
+ Uri fileUri = null;
+ for (int i = 0; i < files.length(); i++) {
+ fileUri = getFileUriAndSetType(intent, dir, files.getString(i), subject, i);
+ if (fileUri != null) {
+ fileUris.add(fileUri);
+ }
+ }
+ if (!fileUris.isEmpty()) {
+ if (hasMultipleAttachments) {
+ intent.putExtra(Intent.EXTRA_STREAM, fileUris);
+ } else {
+ intent.putExtra(Intent.EXTRA_STREAM, fileUri);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ callbackContext.error(e.getMessage());
+ }
+ try {
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ // update: didn't help (doesn't seem to hurt either though)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // as an experiment for #300 we're explicitly running it on the ui thread here
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ cordova.startActivityForResult(plugin, intent, ACTIVITY_CODE_SENDVIAWHATSAPP);
+ }
+ });
+ } catch (Exception e) {
+ callbackContext.error(e.getMessage());
+ }
+ }
+ });
+ return true;
+ }
+
private boolean invokeSMSIntent(final CallbackContext callbackContext, JSONObject options, String p_phonenumbers) {
final String message = options.optString("message");
// TODO test this on a real SMS enabled device before releasing it
@@ -404,6 +624,9 @@ public class SocialSharing extends CordovaPlugin {
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
}
}
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
cordova.startActivityForResult(plugin, intent, 0);
} catch (Exception e) {
callbackContext.error(e.getMessage());
@@ -451,10 +674,26 @@ public class SocialSharing extends CordovaPlugin {
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (_callbackContext != null) {
- if (ACTIVITY_CODE_SENDVIAEMAIL == requestCode) {
- _callbackContext.success();
- } else {
- _callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, resultCode == Activity.RESULT_OK));
+ switch (requestCode) {
+ case ACTIVITY_CODE_SEND__BOOLRESULT:
+ _callbackContext.sendPluginResult(new PluginResult(
+ PluginResult.Status.OK,
+ resultCode == Activity.RESULT_OK));
+ break;
+ case ACTIVITY_CODE_SEND__OBJECT:
+ JSONObject json = new JSONObject();
+ try {
+ json.put("completed", resultCode == Activity.RESULT_OK);
+ json.put("app", ""); // we need a completely different approach if we want to support this on Android. Idea: https://clickclickclack.wordpress.com/2012/01/03/intercepting-androids-action_send-intents/
+ _callbackContext.sendPluginResult(new PluginResult(
+ PluginResult.Status.OK,
+ json));
+ } catch (JSONException e) {
+ _callbackContext.error(e.getMessage());
+ }
+ break;
+ default:
+ _callbackContext.success();
}
}
}
@@ -471,13 +710,16 @@ public class SocialSharing extends CordovaPlugin {
}
private static String getFileName(String url) {
+ if (url.endsWith("/")) {
+ url = url.substring(0, url.length()-1);
+ }
final String pattern = ".*/([^?#]+)?";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(url);
if (m.find()) {
return m.group(1);
} else {
- return null;
+ return "file";
}
}