summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/android/src/nl
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/platforms/android/src/nl')
-rwxr-xr-xStoneIsland/platforms/android/src/nl/xservices/plugins/LaunchMyApp.java136
-rwxr-xr-xStoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java533
2 files changed, 669 insertions, 0 deletions
diff --git a/StoneIsland/platforms/android/src/nl/xservices/plugins/LaunchMyApp.java b/StoneIsland/platforms/android/src/nl/xservices/plugins/LaunchMyApp.java
new file mode 100755
index 00000000..9d3f3d63
--- /dev/null
+++ b/StoneIsland/platforms/android/src/nl/xservices/plugins/LaunchMyApp.java
@@ -0,0 +1,136 @@
+package nl.xservices.plugins;
+
+import android.content.Intent;
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaActivity;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Locale;
+
+public class LaunchMyApp extends CordovaPlugin {
+
+ private static final String ACTION_CHECKINTENT = "checkIntent";
+
+ @Override
+ public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+ if (ACTION_CHECKINTENT.equalsIgnoreCase(action)) {
+ final Intent intent = ((CordovaActivity) this.webView.getContext()).getIntent();
+ final String intentString = intent.getDataString();
+ if (intentString != null && intentString.contains("://") && intent.getScheme() != null) {
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, intent.getDataString()));
+ intent.setData(null);
+ } else {
+ callbackContext.error("App was not started via the launchmyapp URL scheme. Ignoring this errorcallback is the best approach.");
+ }
+ return true;
+ } else {
+ callbackContext.error("This plugin only responds to the " + ACTION_CHECKINTENT + " action.");
+ return false;
+ }
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ final String intentString = intent.getDataString();
+ if (intentString != null && intentString.contains("://") && intent.getScheme() != null) {
+ intent.setData(null);
+ try {
+ StringWriter writer = new StringWriter(intentString.length() * 2);
+ escapeJavaStyleString(writer, intentString, true, false);
+ webView.loadUrl("javascript:handleOpenURL('" + writer.toString() + "');");
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+ // Taken from commons StringEscapeUtils
+ private static void escapeJavaStyleString(Writer out, String str, boolean escapeSingleQuote,
+ boolean escapeForwardSlash) throws IOException {
+ if (out == null) {
+ throw new IllegalArgumentException("The Writer must not be null");
+ }
+ if (str == null) {
+ return;
+ }
+ int sz;
+ sz = str.length();
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+
+ // handle unicode
+ if (ch > 0xfff) {
+ out.write("\\u" + hex(ch));
+ } else if (ch > 0xff) {
+ out.write("\\u0" + hex(ch));
+ } else if (ch > 0x7f) {
+ out.write("\\u00" + hex(ch));
+ } else if (ch < 32) {
+ switch (ch) {
+ case '\b':
+ out.write('\\');
+ out.write('b');
+ break;
+ case '\n':
+ out.write('\\');
+ out.write('n');
+ break;
+ case '\t':
+ out.write('\\');
+ out.write('t');
+ break;
+ case '\f':
+ out.write('\\');
+ out.write('f');
+ break;
+ case '\r':
+ out.write('\\');
+ out.write('r');
+ break;
+ default:
+ if (ch > 0xf) {
+ out.write("\\u00" + hex(ch));
+ } else {
+ out.write("\\u000" + hex(ch));
+ }
+ break;
+ }
+ } else {
+ switch (ch) {
+ case '\'':
+ if (escapeSingleQuote) {
+ out.write('\\');
+ }
+ out.write('\'');
+ break;
+ case '"':
+ out.write('\\');
+ out.write('"');
+ break;
+ case '\\':
+ out.write('\\');
+ out.write('\\');
+ break;
+ case '/':
+ if (escapeForwardSlash) {
+ out.write('\\');
+ }
+ out.write('/');
+ break;
+ default:
+ out.write(ch);
+ break;
+ }
+ }
+ }
+ }
+
+ private static String hex(char ch) {
+ return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
+ }
+} \ No newline at end of file
diff --git a/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java b/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java
new file mode 100755
index 00000000..f1168f89
--- /dev/null
+++ b/StoneIsland/platforms/android/src/nl/xservices/plugins/SocialSharing.java
@@ -0,0 +1,533 @@
+package nl.xservices.plugins;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.*;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+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.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+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_CAN_SHARE_VIA = "canShareVia";
+ private static final String ACTION_CAN_SHARE_VIA_EMAIL = "canShareViaEmail";
+ private static final String ACTION_SHARE_VIA = "shareVia";
+ private static final String ACTION_SHARE_VIA_TWITTER_EVENT = "shareViaTwitter";
+ 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_SENDVIAEMAIL = 2;
+
+ private CallbackContext _callbackContext;
+
+ private String pasteMessage;
+
+ private abstract class SocialSharingRunnable implements Runnable {
+ public CallbackContext callbackContext;
+ SocialSharingRunnable(CallbackContext cb) {
+ this.callbackContext = cb;
+ }
+ }
+
+ @Override
+ public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+ this._callbackContext = callbackContext; // only used for onActivityResult
+ this.pasteMessage = null;
+ if (ACTION_AVAILABLE_EVENT.equals(action)) {
+ 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);
+ } 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);
+ } 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);
+ } 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);
+ } 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);
+ } 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)) {
+ if (isEmailAvailable()) {
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
+ return true;
+ } else {
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "not available"));
+ 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);
+ } 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)) {
+ return invokeEmailIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.isNull(3) ? null : args.getJSONArray(3), args.isNull(4) ? null : args.getJSONArray(4), args.isNull(5) ? null : args.getJSONArray(5));
+ } else {
+ callbackContext.error("socialSharing." + action + " is not a supported function. Did you mean '" + ACTION_SHARE_EVENT + "'?");
+ return false;
+ }
+ }
+
+ private boolean isEmailAvailable() {
+ final Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "someone@domain.com", null));
+ 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 {
+
+ final SocialSharing plugin = this;
+ cordova.getThreadPool().execute(new SocialSharingRunnable(callbackContext) {
+ public void run() {
+ final Intent draft = new Intent(Intent.ACTION_SEND_MULTIPLE);
+ if (notEmpty(message)) {
+ Pattern htmlPattern = Pattern.compile(".*\\<[^>]+>.*", Pattern.DOTALL);
+ if (htmlPattern.matcher(message).matches()) {
+ draft.putExtra(android.content.Intent.EXTRA_TEXT, Html.fromHtml(message));
+ draft.setType("text/html");
+ } else {
+ draft.putExtra(android.content.Intent.EXTRA_TEXT, message);
+ draft.setType("text/plain");
+ }
+ }
+ if (notEmpty(subject)) {
+ draft.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
+ }
+ try {
+ if (to != null && to.length() > 0) {
+ draft.putExtra(android.content.Intent.EXTRA_EMAIL, toStringArray(to));
+ }
+ if (cc != null && cc.length() > 0) {
+ draft.putExtra(android.content.Intent.EXTRA_CC, toStringArray(cc));
+ }
+ if (bcc != null && bcc.length() > 0) {
+ draft.putExtra(android.content.Intent.EXTRA_BCC, toStringArray(bcc));
+ }
+ if (files.length() > 0) {
+ final String dir = getDownloadDir();
+ 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);
+ }
+ }
+ }
+ } catch (Exception e) {
+ callbackContext.error(e.getMessage());
+ }
+
+ draft.setType("application/octet-stream");
+ cordova.startActivityForResult(plugin, Intent.createChooser(draft, "Choose Email App"), ACTIVITY_CODE_SENDVIAEMAIL);
+ }
+ });
+
+ return true;
+ }
+
+ private String getDownloadDir() throws IOException {
+ // 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) {
+
+ final CordovaInterface mycordova = cordova;
+ final CordovaPlugin plugin = this;
+
+ cordova.getThreadPool().execute(new SocialSharingRunnable(callbackContext) {
+ public void run() {
+ String message = msg;
+ final boolean hasMultipleAttachments = files.length() > 1;
+ final Intent sendIntent = new Intent(hasMultipleAttachments ? Intent.ACTION_SEND_MULTIPLE : Intent.ACTION_SEND);
+ sendIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+
+ try {
+ if (files.length() > 0 && !"".equals(files.getString(0))) {
+ 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(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);
+ }
+ }
+ } 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)) {
+ message += " " + url;
+ } else {
+ message = url;
+ }
+ }
+ if (notEmpty(message)) {
+ sendIntent.putExtra(android.content.Intent.EXTRA_TEXT, message);
+ // sometimes required when the user picks share via sms
+ if (Build.VERSION.SDK_INT < 21) { // LOLLIPOP
+ sendIntent.putExtra("sms_body", message);
+ }
+ }
+
+ if (appPackageName != null) {
+ String packageName = appPackageName;
+ String passedActivityName = null;
+ if (packageName.contains("/")) {
+ String[] items = appPackageName.split("/");
+ packageName = items[0];
+ passedActivityName = items[1];
+ }
+ final ActivityInfo activity = getActivity(callbackContext, sendIntent, packageName);
+ if (activity != null) {
+ if (peek) {
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
+ } else {
+ sendIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ sendIntent.setComponent(new ComponentName(activity.applicationInfo.packageName,
+ passedActivityName != null ? passedActivityName : activity.name));
+ mycordova.startActivityForResult(plugin, sendIntent, 0);
+
+ if (pasteMessage != null) {
+ // add a little delay because target app (facebook only atm) needs to be started first
+ new Timer().schedule(new TimerTask() {
+ public void run() {
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ copyHintToClipboard(msg, pasteMessage);
+ showPasteMessage(pasteMessage);
+ }
+ });
+ }
+ }, 2000);
+ }
+ }
+ }
+ } else {
+ if (peek) {
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
+ } else {
+ mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, null), 1);
+ }
+ }
+ }
+ });
+ return true;
+ }
+
+ @SuppressLint("NewApi")
+ private void copyHintToClipboard(String msg, String label) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ return;
+ }
+ final ClipboardManager clipboard = (android.content.ClipboardManager) cordova.getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
+ final ClipData clip = android.content.ClipData.newPlainText(label, msg);
+ clipboard.setPrimaryClip(clip);
+ }
+
+ @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();
+ }
+
+ 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.startsWith("http") || image.startsWith("www/")) {
+ String filename = getFileName(image);
+ localImage = "file://" + dir + "/" + filename;
+ if (image.startsWith("http")) {
+ // filename optimisation taken from https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin/pull/56
+ URLConnection connection = new URL(image).openConnection();
+ String disposition = connection.getHeaderField("Content-Disposition");
+ if (disposition != null) {
+ final Pattern dispositionPattern = Pattern.compile("filename=([^;]+)");
+ Matcher matcher = dispositionPattern.matcher(disposition);
+ if (matcher.find()) {
+ filename = matcher.group(1).replaceAll("[^a-zA-Z0-9._-]", "");
+ localImage = "file://" + dir + "/" + filename;
+ }
+ }
+ saveFile(getBytes(connection.getInputStream()), dir, filename);
+ } else {
+ saveFile(getBytes(webView.getContext().getAssets().open(image)), dir, filename);
+ }
+ } else if (image.startsWith("data:")) {
+ // safeguard for https://code.google.com/p/android/issues/detail?id=7901#c43
+ if (!image.contains(";base64,")) {
+ sendIntent.setType("text/plain");
+ return null;
+ }
+ // image looks like this: data:image/png;base64,R0lGODlhDAA...
+ final String encodedImg = image.substring(image.indexOf(";base64,") + 8);
+ // correct the intent type if anything else was passed, like a pdf: data:application/pdf;base64,..
+ if (!image.contains("data:image/")) {
+ sendIntent.setType(image.substring(image.indexOf("data:") + 5, image.indexOf(";base64")));
+ }
+ // the filename needs a valid extension, so it renders correctly in target apps
+ final String imgExtension = image.substring(image.indexOf("/") + 1, image.indexOf(";base64"));
+ String fileName;
+ // if a subject was passed, use it as the filename
+ // filenames must be unique when passing in multiple files [#158]
+ if (notEmpty(subject)) {
+ fileName = sanitizeFilename(subject) + (nthFile == 0 ? "" : "_" + nthFile) + "." + imgExtension;
+ } else {
+ fileName = "file" + (nthFile == 0 ? "" : "_" + nthFile) + "." + imgExtension;
+ }
+ 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 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
+// final String subject = options.optString("subject");
+// final String image = options.optString("image");
+ final String subject = null; //options.optString("subject");
+ final String image = null; // options.optString("image");
+ final String phonenumbers = getPhoneNumbersWithManufacturerSpecificSeparators(p_phonenumbers);
+ final SocialSharing plugin = this;
+ cordova.getThreadPool().execute(new SocialSharingRunnable(callbackContext) {
+ public void run() {
+ Intent intent;
+
+ if (Build.VERSION.SDK_INT >= 19) { // Build.VERSION_CODES.KITKAT) {
+ // passing in no phonenumbers for kitkat may result in an error,
+ // but it may also work for some devices, so documentation will need to cover this case
+ intent = new Intent(Intent.ACTION_SENDTO);
+ intent.setData(Uri.parse("smsto:" + (notEmpty(phonenumbers) ? phonenumbers : "")));
+ } else {
+ intent = new Intent(Intent.ACTION_VIEW);
+ intent.setType("vnd.android-dir/mms-sms");
+ if (phonenumbers != null) {
+ intent.putExtra("address", phonenumbers);
+ }
+ }
+ intent.putExtra("sms_body", message);
+ intent.putExtra("sms_subject", subject);
+
+ try {
+ if (image != null && !"".equals(image)) {
+ final Uri fileUri = getFileUriAndSetType(intent, getDownloadDir(), image, subject, 0);
+ if (fileUri != null) {
+ intent.putExtra(Intent.EXTRA_STREAM, fileUri);
+ }
+ }
+ cordova.startActivityForResult(plugin, intent, 0);
+ } catch (Exception e) {
+ callbackContext.error(e.getMessage());
+ }
+ }
+ });
+ return true;
+ }
+
+ private static String getPhoneNumbersWithManufacturerSpecificSeparators(String phonenumbers) {
+ if (notEmpty(phonenumbers)) {
+ char separator;
+ if (android.os.Build.MANUFACTURER.equalsIgnoreCase("samsung")) {
+ separator = ',';
+ } else {
+ separator = ';';
+ }
+ return phonenumbers.replace(';', separator).replace(',', separator);
+ }
+ return null;
+ }
+
+ private ActivityInfo getActivity(final CallbackContext callbackContext, final Intent shareIntent, final String appPackageName) {
+ final PackageManager pm = webView.getContext().getPackageManager();
+ List<ResolveInfo> activityList = pm.queryIntentActivities(shareIntent, 0);
+ for (final ResolveInfo app : activityList) {
+ if ((app.activityInfo.packageName).contains(appPackageName)) {
+ return app.activityInfo;
+ }
+ }
+ // no matching app found
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, getShareActivities(activityList)));
+ return null;
+ }
+
+ private JSONArray getShareActivities(List<ResolveInfo> activityList) {
+ List<String> packages = new ArrayList<String>();
+ for (final ResolveInfo app : activityList) {
+ packages.add(app.activityInfo.packageName);
+ }
+ return new JSONArray(packages);
+ }
+
+ @Override
+ 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));
+ }
+ }
+ }
+
+ private void createOrCleanDir(final String downloadDir) throws IOException {
+ final File dir = new File(downloadDir);
+ if (!dir.exists()) {
+ if (!dir.mkdirs()) {
+ throw new IOException("CREATE_DIRS_FAILED");
+ }
+ } else {
+ cleanupOldFiles(dir);
+ }
+ }
+
+ private static String getFileName(String url) {
+ final String pattern = ".*/([^?#]+)?";
+ Pattern r = Pattern.compile(pattern);
+ Matcher m = r.matcher(url);
+ if (m.find()) {
+ return m.group(1);
+ } else {
+ return null;
+ }
+ }
+
+ private byte[] getBytes(InputStream is) throws IOException {
+ 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);
+ }
+ buffer.flush();
+ return buffer.toByteArray();
+ }
+
+ private void saveFile(byte[] bytes, String dirName, String fileName) throws IOException {
+ final File dir = new File(dirName);
+ final FileOutputStream fos = new FileOutputStream(new File(dir, fileName));
+ fos.write(bytes);
+ fos.flush();
+ fos.close();
+ }
+
+ /**
+ * As file.deleteOnExit does not work on Android, we need to delete files manually.
+ * Deleting them in onActivityResult is not a good idea, because for example a base64 encoded file
+ * will not be available for upload to Facebook (it's deleted before it's uploaded).
+ * So the best approach is deleting old files when saving (sharing) a new one.
+ */
+ private void cleanupOldFiles(File dir) {
+ for (File f : dir.listFiles()) {
+ //noinspection ResultOfMethodCallIgnored
+ f.delete();
+ }
+ }
+
+ private static boolean notEmpty(String what) {
+ return what != null &&
+ !"".equals(what) &&
+ !"null".equalsIgnoreCase(what);
+ }
+
+ private static String[] toStringArray(JSONArray jsonArray) throws JSONException {
+ String[] result = new String[jsonArray.length()];
+ for (int i = 0; i < jsonArray.length(); i++) {
+ result[i] = jsonArray.getString(i);
+ }
+ return result;
+ }
+
+ public static String sanitizeFilename(String name) {
+ return name.replaceAll("[:\\\\/*?|<> ]", "_");
+ }
+}