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

Commit

Permalink
Update SocialSharing Android source
Browse files Browse the repository at this point in the history
  • Loading branch information
martykan committed Mar 30, 2016
1 parent 561fa0c commit 7043403
Showing 1 changed file with 168 additions and 56 deletions.
224 changes: 168 additions & 56 deletions platforms/android/src/nl/xservices/plugins/SocialSharing.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.text.Html;
import android.util.Base64;
import android.view.Gravity;
import android.widget.Toast;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.apache.http.util.ByteArrayBuffer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
Expand All @@ -42,10 +43,13 @@ public class SocialSharing extends CordovaPlugin {
private static final String ACTION_SHARE_VIA_FACEBOOK_EVENT = "shareViaFacebook";
private static final String ACTION_SHARE_VIA_FACEBOOK_WITH_PASTEMESSAGEHINT = "shareViaFacebookWithPasteMessageHint";
private static final String ACTION_SHARE_VIA_WHATSAPP_EVENT = "shareViaWhatsApp";
private static final String ACTION_SHARE_VIA_INSTAGRAM_EVENT = "shareViaInstagram";
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_SEND = 1;
private static final int ACTIVITY_CODE_SENDVIAEMAIL = 2;
private static final int ACTIVITY_CODE_SENDVIAWHATSAPP = 3;

private CallbackContext _callbackContext;

Expand Down Expand Up @@ -75,7 +79,16 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
this.pasteMessage = args.getString(4);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", false);
} 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", false);
}
} 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);
} 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);
} else if (ACTION_CAN_SHARE_VIA_EMAIL.equals(action)) {
Expand All @@ -100,7 +113,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo

private boolean isEmailAvailable() {
final Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "[email protected]", null));
return cordova.getActivity().getPackageManager().queryIntentActivities(intent, 0).size() > 1;
return cordova.getActivity().getPackageManager().queryIntentActivities(intent, 0).size() > 0;
}

private boolean invokeEmailIntent(final CallbackContext callbackContext, final String message, final String subject, final JSONArray to, final JSONArray cc, final JSONArray bcc, final JSONArray files) throws JSONException {
Expand Down Expand Up @@ -133,16 +146,18 @@ public void run() {
draft.putExtra(android.content.Intent.EXTRA_BCC, toStringArray(bcc));
}
if (files.length() > 0) {
ArrayList<Uri> fileUris = new ArrayList<Uri>();
final String dir = getDownloadDir();
for (int i = 0; i < files.length(); i++) {
final Uri fileUri = getFileUriAndSetType(draft, dir, files.getString(i), subject, i);
if (fileUri != null) {
fileUris.add(fileUri);
if (dir != null) {
ArrayList<Uri> fileUris = new ArrayList<Uri>();
for (int i = 0; i < files.length(); i++) {
final Uri fileUri = getFileUriAndSetType(draft, dir, files.getString(i), subject, i);
if (fileUri != null) {
fileUris.add(fileUri);
}
}
if (!fileUris.isEmpty()) {
draft.putExtra(Intent.EXTRA_STREAM, fileUris);
}
}
if (!fileUris.isEmpty()) {
draft.putExtra(Intent.EXTRA_STREAM, fileUris);
}
}
} catch (Exception e) {
Expand All @@ -158,11 +173,15 @@ public void run() {
}

private String getDownloadDir() throws IOException {
final String dir = webView.getContext().getExternalFilesDir(null) + "/socialsharing-downloads"; // external

// final String dir = webView.getContext().getCacheDir() + "/socialsharing-downloads"; // internal (no external permission needed)
createOrCleanDir(dir);
return dir;
// better check, otherwise it may crash the app
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
// we need to use external storage since we need to share to another app
final String dir = webView.getContext().getExternalFilesDir(null) + "/socialsharing-downloads";
createOrCleanDir(dir);
return dir;
} else {
return null;
}
}

private boolean doSendIntent(final CallbackContext callbackContext, final String msg, final String subject, final JSONArray files, final String url, final String appPackageName, final boolean peek) {
Expand All @@ -177,34 +196,39 @@ public void run() {
final Intent sendIntent = new Intent(hasMultipleAttachments ? Intent.ACTION_SEND_MULTIPLE : Intent.ACTION_SEND);
sendIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);

if (files.length() > 0) {
ArrayList<Uri> fileUris = new ArrayList<Uri>();
try {
try {
if (files.length() > 0 && !"".equals(files.getString(0))) {
final String dir = getDownloadDir();
Uri fileUri = null;
for (int i = 0; i < files.length(); i++) {
fileUri = getFileUriAndSetType(sendIntent, dir, files.getString(i), subject, i);
if (fileUri != null) {
fileUris.add(fileUri);
if (dir != null) {
ArrayList<Uri> fileUris = new ArrayList<Uri>();
Uri fileUri = null;
for (int i = 0; i < files.length(); i++) {
fileUri = getFileUriAndSetType(sendIntent, dir, files.getString(i), subject, i);
if (fileUri != null) {
fileUris.add(fileUri);
}
}
}
if (!fileUris.isEmpty()) {
if (hasMultipleAttachments) {
sendIntent.putExtra(Intent.EXTRA_STREAM, fileUris);
} else {
sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
if (!fileUris.isEmpty()) {
if (hasMultipleAttachments) {
sendIntent.putExtra(Intent.EXTRA_STREAM, fileUris);
} else {
sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
}
}
} else {
sendIntent.setType("text/plain");
}
} catch (Exception e) {
callbackContext.error(e.getMessage());
} else {
sendIntent.setType("text/plain");
}
} else {
sendIntent.setType("text/plain");
} catch (Exception e) {
callbackContext.error(e.getMessage());
}

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)) {
Expand All @@ -215,7 +239,10 @@ public void run() {
}
if (notEmpty(message)) {
sendIntent.putExtra(android.content.Intent.EXTRA_TEXT, message);
sendIntent.putExtra("sms_body", message); // sometimes required when the user picks share via sms
// sometimes required when the user picks share via sms
if (Build.VERSION.SDK_INT < 21) { // LOLLIPOP
sendIntent.putExtra("sms_body", message);
}
}

if (appPackageName != null) {
Expand All @@ -242,7 +269,8 @@ public void run() {
public void run() {
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
showPasteMessage(msg, pasteMessage);
copyHintToClipboard(msg, pasteMessage);
showPasteMessage(pasteMessage);
}
});
}
Expand All @@ -254,7 +282,7 @@ public void run() {
if (peek) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
} else {
mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, null), 1);
mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, null), ACTIVITY_CODE_SEND);
}
}
}
Expand All @@ -263,16 +291,20 @@ public void run() {
}

@SuppressLint("NewApi")
private void showPasteMessage(String msg, String label) {
private void copyHintToClipboard(String msg, String label) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return;
}
// copy to clipboard
final ClipboardManager clipboard = (android.content.ClipboardManager) cordova.getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
final ClipData clip = android.content.ClipData.newPlainText(label, msg);
clipboard.setPrimaryClip(clip);
}

// show a toast
@SuppressLint("NewApi")
private void showPasteMessage(String label) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return;
}
final Toast toast = Toast.makeText(webView.getContext(), label, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
Expand All @@ -294,6 +326,10 @@ private Uri getFileUriAndSetType(Intent sendIntent, String dir, String image, St
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;
}
}
Expand Down Expand Up @@ -325,12 +361,80 @@ private Uri getFileUriAndSetType(Intent sendIntent, String dir, String image, St
}
saveFile(Base64.decode(encodedImg, Base64.DEFAULT), dir, fileName);
localImage = "file://" + dir + "/" + fileName;
} else if (image.startsWith("df:")) {
// safeguard for https://code.google.com/p/android/issues/detail?id=7901#c43
if (!image.contains(";base64,")) {
sendIntent.setType("text/plain");
return null;
}
// format looks like this : df:filename.txt;data:image/png;base64,R0lGODlhDAA...
final String fileName = image.substring(image.indexOf("df:") + 3, image.indexOf(";data:"));
final String fileType = image.substring(image.indexOf(";data:") + 6, image.indexOf(";base64,"));
final String encodedImg = image.substring(image.indexOf(";base64,") + 8);
sendIntent.setType(fileType);
saveFile(Base64.decode(encodedImg, Base64.DEFAULT), dir, sanitizeFilename(fileName));
localImage = "file://" + dir + "/" + fileName;
} else if (!image.startsWith("file://")) {
throw new IllegalArgumentException("URL_NOT_SUPPORTED");
}
return Uri.parse(localImage);
}

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() {
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 {
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
Expand Down Expand Up @@ -411,11 +515,13 @@ private JSONArray getShareActivities(List<ResolveInfo> activityList) {

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (ACTIVITY_CODE_SENDVIAEMAIL == requestCode) {
super.onActivityResult(requestCode, resultCode, intent);
_callbackContext.success();
} else {
_callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, resultCode == Activity.RESULT_OK));
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));
}
}
}

Expand All @@ -430,23 +536,29 @@ private void createOrCleanDir(final String downloadDir) throws IOException {
}
}

private String getFileName(String url) {
final int lastIndexOfSlash = url.lastIndexOf('/');
if (lastIndexOfSlash == -1) {
return url;
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 url.substring(lastIndexOfSlash + 1);
return "file";
}
}

private byte[] getBytes(InputStream is) throws IOException {
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(5000);
int current;
while ((current = bis.read()) != -1) {
baf.append((byte) current);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return baf.toByteArray();
buffer.flush();
return buffer.toByteArray();
}

private void saveFile(byte[] bytes, String dirName, String fileName) throws IOException {
Expand Down

0 comments on commit 7043403

Please sign in to comment.