com-easystep2-datawedge-plugin-intent-cordova 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1001 @@
1
+ package com.easystep2.datawedge.plugin.intent;
2
+
3
+ import android.Manifest;
4
+ import android.app.Activity;
5
+ import android.content.BroadcastReceiver;
6
+ import android.content.ClipData;
7
+ import android.content.ComponentName;
8
+ import android.content.ContentResolver;
9
+ import android.content.Context;
10
+ import android.content.Intent;
11
+ import android.content.IntentFilter;
12
+ import android.content.pm.PackageManager;
13
+ import android.database.Cursor;
14
+ import android.net.Uri;
15
+ import android.os.Build;
16
+ import android.os.Bundle;
17
+ import android.os.Environment;
18
+ import android.provider.DocumentsContract;
19
+ import android.provider.MediaStore;
20
+ import androidx.core.app.ActivityCompat;
21
+ import androidx.core.content.ContextCompat;
22
+ import androidx.core.content.FileProvider;
23
+ import android.text.Html;
24
+ import android.util.Log;
25
+ import android.view.KeyEvent;
26
+ import android.webkit.MimeTypeMap;
27
+
28
+ import org.apache.cordova.CallbackContext;
29
+ import org.apache.cordova.CordovaActivity;
30
+ import org.apache.cordova.CordovaPlugin;
31
+ import org.apache.cordova.CordovaResourceApi;
32
+ import org.apache.cordova.PluginResult;
33
+ import org.json.JSONArray;
34
+ import org.json.JSONException;
35
+ import org.json.JSONObject;
36
+
37
+ import java.io.File;
38
+
39
+ import java.io.Serializable;
40
+ import java.lang.reflect.Array;
41
+ import java.lang.reflect.Constructor;
42
+ import java.util.ArrayList;
43
+ import java.util.Arrays;
44
+ import java.util.HashMap;
45
+ import java.util.Iterator;
46
+ import java.util.List;
47
+ import java.util.Map;
48
+
49
+ import static android.os.Environment.getExternalStorageState;
50
+
51
+ public class IntentShim extends CordovaPlugin {
52
+
53
+ private final Map<BroadcastReceiver, CallbackContext> receiverCallbacks = new HashMap<>();
54
+
55
+ private static final String LOG_TAG = "Cordova Intents Shim";
56
+ private CallbackContext onNewIntentCallbackContext = null;
57
+ private CallbackContext onActivityResultCallbackContext = null;
58
+
59
+ private Intent deferredIntent = null;
60
+
61
+ // Permission request codes
62
+ private static final int PERMISSION_REQUEST_READ_STORAGE = 101;
63
+
64
+ public IntentShim() {
65
+ // Default constructor
66
+ }
67
+
68
+ @Override
69
+ public void onDestroy() {
70
+ super.onDestroy();
71
+ try {
72
+ unregisterAllBroadcastReceivers();
73
+ }
74
+ catch (IllegalArgumentException e) {
75
+ // This can happen if the receivers were already unregistered.
76
+ // It's safe to ignore.
77
+ }
78
+ }
79
+
80
+ @Override
81
+ public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException
82
+ {
83
+ Log.d(LOG_TAG, "Action: " + action);
84
+
85
+ // Add a new action for checking and requesting permissions
86
+ if (action.equals("checkAndRequestPermissions")) {
87
+ return handleCheckAndRequestPermissions(callbackContext);
88
+ }
89
+
90
+ if (action.equals("startActivity") || action.equals("startActivityForResult"))
91
+ {
92
+ // Credit: https://github.com/chrisekelley/cordova-webintent
93
+ if (args.length() != 1) {
94
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
95
+ return false;
96
+ }
97
+
98
+ JSONObject obj = args.getJSONObject(0);
99
+ Intent intent = populateIntent(obj, callbackContext);
100
+ int requestCode = obj.has("requestCode") ? obj.getInt("requestCode") : 1;
101
+
102
+ boolean bExpectResult = false;
103
+ if (action.equals("startActivityForResult"))
104
+ {
105
+ bExpectResult = true;
106
+ this.onActivityResultCallbackContext = callbackContext;
107
+ }
108
+ startActivity(intent, bExpectResult, requestCode, callbackContext);
109
+
110
+ return true;
111
+ }
112
+ else if (action.equals("sendBroadcast"))
113
+ {
114
+ // Credit: https://github.com/chrisekelley/cordova-webintent
115
+ if (args.length() != 1) {
116
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
117
+ return false;
118
+ }
119
+
120
+ // Parse the arguments
121
+ JSONObject obj = args.getJSONObject(0);
122
+ Intent intent = populateIntent(obj, callbackContext);
123
+
124
+ sendBroadcast(intent);
125
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
126
+ return true;
127
+ }
128
+ else if (action.equals("startService"))
129
+ {
130
+ if (args.length() != 1) {
131
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
132
+ return false;
133
+ }
134
+ JSONObject obj = args.getJSONObject(0);
135
+ Intent intent = populateIntent(obj, callbackContext);
136
+ startService(intent);
137
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
138
+ return true;
139
+ }
140
+ else if (action.equals("registerBroadcastReceiver"))
141
+ {
142
+ Log.d(LOG_TAG, "Plugin no longer unregisters receivers on registerBroadcastReceiver invocation");
143
+
144
+ // No error callback
145
+ if (args.length() != 1) {
146
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
147
+ return false;
148
+ }
149
+
150
+ // Expect an array of filterActions
151
+ JSONObject obj = args.getJSONObject(0);
152
+ JSONArray filterActions = obj.has("filterActions") ? obj.getJSONArray("filterActions") : null;
153
+ if (filterActions == null || filterActions.length() == 0)
154
+ {
155
+ // The arguments are not correct
156
+ Log.w(LOG_TAG, "filterActions argument is not in the expected format");
157
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
158
+ return false;
159
+ }
160
+
161
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
162
+ result.setKeepCallback(true);
163
+
164
+ IntentFilter filter = new IntentFilter();
165
+ for (int i = 0; i < filterActions.length(); i++) {
166
+ Log.d(LOG_TAG, "Registering broadcast receiver for filter: " + filterActions.getString(i));
167
+ filter.addAction(filterActions.getString(i));
168
+ }
169
+
170
+ // Allow an array of filterCategories
171
+ JSONArray filterCategories = obj.has("filterCategories") ? obj.getJSONArray("filterCategories") : null;
172
+ if (filterCategories != null) {
173
+ for (int i = 0; i < filterCategories.length(); i++) {
174
+ Log.d(LOG_TAG, "Registering broadcast receiver for category filter: " + filterCategories.getString(i));
175
+ filter.addCategory(filterCategories.getString(i));
176
+ }
177
+ }
178
+
179
+ // Add any specified Data Schemes
180
+ JSONArray filterDataSchemes = obj.has("filterDataSchemes") ? obj.getJSONArray("filterDataSchemes") : null;
181
+ if (filterDataSchemes != null && filterDataSchemes.length() > 0)
182
+ {
183
+ for (int i = 0; i < filterDataSchemes.length(); i++)
184
+ {
185
+ Log.d(LOG_TAG, "Associating data scheme to filter: " + filterDataSchemes.getString(i));
186
+ filter.addDataScheme(filterDataSchemes.getString(i));
187
+ }
188
+ }
189
+
190
+ BroadcastReceiver broadcastReceiver = newBroadcastReceiver();
191
+
192
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
193
+ // Android 13+: Use the RECEIVER_EXPORTED flag for explicit receivers
194
+ this.cordova.getActivity().registerReceiver(broadcastReceiver, filter, Context.RECEIVER_EXPORTED);
195
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
196
+ // Android 8.0+: Need to specify flags
197
+ this.cordova.getActivity().registerReceiver(broadcastReceiver, filter, null, null);
198
+ } else {
199
+ this.cordova.getActivity().registerReceiver(broadcastReceiver, filter);
200
+ }
201
+
202
+ receiverCallbacks.put(broadcastReceiver, callbackContext);
203
+
204
+ callbackContext.sendPluginResult(result);
205
+ return true;
206
+ }
207
+ else if (action.equals("unregisterBroadcastReceiver"))
208
+ {
209
+ try
210
+ {
211
+ unregisterAllBroadcastReceivers();
212
+ }
213
+ catch (IllegalArgumentException e) {}
214
+ }
215
+ else if (action.equals("onIntent"))
216
+ {
217
+ // Credit: https://github.com/napolitano/cordova-plugin-intent
218
+ if (args.length() != 1) {
219
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
220
+ return false;
221
+ }
222
+
223
+ this.onNewIntentCallbackContext = callbackContext;
224
+
225
+ if (this.deferredIntent != null) {
226
+ fireOnNewIntent(this.deferredIntent);
227
+ this.deferredIntent = null;
228
+ }
229
+
230
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
231
+ result.setKeepCallback(true);
232
+ callbackContext.sendPluginResult(result);
233
+ return true;
234
+ }
235
+ else if (action.equals("onActivityResult"))
236
+ {
237
+ if (args.length() != 1) {
238
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
239
+ return false;
240
+ }
241
+
242
+ this.onActivityResultCallbackContext = callbackContext;
243
+
244
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
245
+ result.setKeepCallback(true);
246
+ callbackContext.sendPluginResult(result);
247
+ return true;
248
+ }
249
+ else if (action.equals("getIntent"))
250
+ {
251
+ // Credit: https://github.com/napolitano/cordova-plugin-intent
252
+ if (args.length() != 0) {
253
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
254
+ return false;
255
+ }
256
+
257
+ Intent intent;
258
+
259
+ if (this.deferredIntent != null) {
260
+ intent = this.deferredIntent;
261
+ this.deferredIntent = null;
262
+ }
263
+ else {
264
+ intent = cordova.getActivity().getIntent();
265
+ }
266
+
267
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, getIntentJson(intent)));
268
+ return true;
269
+ }
270
+ else if (action.equals("sendResult"))
271
+ {
272
+ // Assuming this application was started with startActivityForResult, send the result back
273
+ // https://github.com/darryncampbell/darryncampbell-cordova-plugin-intent/issues/3
274
+ Intent result = new Intent();
275
+ if (args.length() > 0) {
276
+ JSONObject json = args.getJSONObject(0);
277
+ JSONObject extras = (json.has("extras")) ? json.getJSONObject("extras") : null;
278
+
279
+ // Populate the extras if any exist
280
+ if (extras != null) {
281
+ JSONArray extraNames = extras.names();
282
+ for (int i = 0; i < extraNames.length(); i++) {
283
+ String key = extraNames.getString(i);
284
+ Object extrasObj = extras.get(key);
285
+ if (extrasObj instanceof JSONObject) {
286
+ // The extra is a bundle
287
+ result.putExtra(key, toBundle((JSONObject) extras.get(key)));
288
+ } else if (extrasObj instanceof Boolean) {
289
+ result.putExtra(key, extras.getBoolean(key));
290
+ } else if (extrasObj instanceof Integer) {
291
+ result.putExtra(key, extras.getInt(key));
292
+ } else if (extrasObj instanceof Long) {
293
+ result.putExtra(key, extras.getLong(key));
294
+ } else if (extrasObj instanceof Double) {
295
+ result.putExtra(key, extras.getDouble(key));
296
+ } else if (extrasObj instanceof Float) {
297
+ result.putExtra(key, extras.getDouble(key));
298
+ } else {
299
+ result.putExtra(key, extras.getString(key));
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ //set result
306
+ cordova.getActivity().setResult(Activity.RESULT_OK, result);
307
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
308
+
309
+ //finish the activity
310
+ cordova.getActivity().finish();
311
+
312
+ }
313
+ else if (action.equals("realPathFromUri"))
314
+ {
315
+ if (args.length() != 1) {
316
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
317
+ return false;
318
+ }
319
+
320
+ JSONObject obj = args.getJSONObject(0);
321
+ String realPath = getRealPathFromURI_API19(obj, callbackContext);
322
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, realPath));
323
+ return true;
324
+
325
+ }
326
+ else if (action.equals("packageExists"))
327
+ {
328
+ try {
329
+ if (args.length() < 1) {
330
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
331
+ return false;
332
+ }
333
+
334
+ PackageManager packageManager = this.cordova.getActivity().getApplicationContext().getPackageManager();
335
+ packageManager.getPackageInfo(args.getString(0), 0);
336
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, true));
337
+ return true;
338
+ } catch (PackageManager.NameNotFoundException e) {
339
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, false));
340
+ return true;
341
+ }
342
+ }
343
+
344
+ return false; // No action matched
345
+ }
346
+
347
+ private void unregisterAllBroadcastReceivers() {
348
+ Log.d(LOG_TAG, "Unregistering all broadcast receivers, size was " + receiverCallbacks.size());
349
+ for (BroadcastReceiver broadcastReceiver: receiverCallbacks.keySet()) {
350
+ try {
351
+ this.cordova.getActivity().unregisterReceiver(broadcastReceiver);
352
+ } catch (Exception e) {
353
+ Log.e(LOG_TAG, "Error unregistering broadcast receiver: " + e.getMessage());
354
+ }
355
+ }
356
+ receiverCallbacks.clear();
357
+ }
358
+
359
+ /**
360
+ * Check and request necessary permissions based on Android version
361
+ */
362
+ private boolean checkAndRequestPermissions(final CallbackContext callbackContext) {
363
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // Android 13+
364
+ boolean hasReadMediaImagesPermission = ContextCompat.checkSelfPermission(this.cordova.getActivity(),
365
+ Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED;
366
+ boolean hasReadMediaVideoPermission = ContextCompat.checkSelfPermission(this.cordova.getActivity(),
367
+ Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED;
368
+
369
+ List<String> permissionsToRequest = new ArrayList<>();
370
+
371
+ if (!hasReadMediaImagesPermission) {
372
+ permissionsToRequest.add(Manifest.permission.READ_MEDIA_IMAGES);
373
+ }
374
+
375
+ if (!hasReadMediaVideoPermission) {
376
+ permissionsToRequest.add(Manifest.permission.READ_MEDIA_VIDEO);
377
+ }
378
+
379
+ if (!permissionsToRequest.isEmpty()) {
380
+ ActivityCompat.requestPermissions(this.cordova.getActivity(),
381
+ permissionsToRequest.toArray(new String[0]), PERMISSION_REQUEST_READ_STORAGE);
382
+ callbackContext.error("Please grant necessary media permissions");
383
+ return false;
384
+ }
385
+
386
+ return true;
387
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Android 6-12
388
+ if (!hasReadStoragePermission()) {
389
+ requestReadStoragePermission(callbackContext);
390
+ return false;
391
+ }
392
+ return true;
393
+ } else {
394
+ // Pre-Android 6 doesn't need runtime permissions
395
+ return true;
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Handler for the checkAndRequestPermissions action from JS
401
+ */
402
+ private boolean handleCheckAndRequestPermissions(CallbackContext callbackContext) {
403
+ if (checkAndRequestPermissions(callbackContext)) {
404
+ callbackContext.success();
405
+ return true;
406
+ }
407
+ return false; // We've already sent an error in checkAndRequestPermissions
408
+ }
409
+
410
+ private Uri remapUriWithFileProvider(String uriAsString, final CallbackContext callbackContext)
411
+ {
412
+ // Use new permission check that handles Android 13+
413
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !checkAndRequestPermissions(callbackContext)) {
414
+ return null;
415
+ }
416
+
417
+ // Create the URI via FileProvider Special case for N and above when installing apks
418
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
419
+ // For Android 6.0+ we need to check permissions at runtime
420
+ if (!hasReadStoragePermission()) {
421
+ requestReadStoragePermission(callbackContext);
422
+ return null;
423
+ }
424
+ }
425
+
426
+ try {
427
+ String externalStorageState = getExternalStorageState();
428
+ if (externalStorageState.equals(Environment.MEDIA_MOUNTED) || externalStorageState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
429
+ String fileName = uriAsString.substring(uriAsString.indexOf('/') + 2);
430
+ File uriAsFile = new File(fileName);
431
+ if (!uriAsFile.exists()) {
432
+ Log.e(LOG_TAG, "File at path " + uriAsFile.getPath() + " with name " + uriAsFile.getName() + " does not exist");
433
+ callbackContext.error("File not found: " + uriAsFile);
434
+ return null;
435
+ }
436
+ String PACKAGE_NAME = this.cordova.getActivity().getPackageName() + ".easystep2.datawedge.plugin.intent.fileprovider";
437
+ return FileProvider.getUriForFile(this.cordova.getActivity().getApplicationContext(), PACKAGE_NAME, uriAsFile);
438
+ } else {
439
+ Log.e(LOG_TAG, "Storage directory is not mounted. Please ensure the device is not connected via USB for file transfer");
440
+ callbackContext.error("Storage directory is returning not mounted");
441
+ return null;
442
+ }
443
+ } catch (StringIndexOutOfBoundsException e) {
444
+ Log.e(LOG_TAG, "URL is not well formed", e);
445
+ callbackContext.error("URL is not well formed: " + e.getMessage());
446
+ return null;
447
+ } catch (IllegalArgumentException e) {
448
+ Log.e(LOG_TAG, "FileProvider issue", e);
449
+ callbackContext.error("FileProvider error: " + e.getMessage());
450
+ return null;
451
+ }
452
+ }
453
+
454
+ private boolean hasReadStoragePermission() {
455
+ return ContextCompat.checkSelfPermission(this.cordova.getActivity(),
456
+ Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
457
+ }
458
+
459
+ private void requestReadStoragePermission(CallbackContext callbackContext) {
460
+ ActivityCompat.requestPermissions(this.cordova.getActivity(),
461
+ new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_READ_STORAGE);
462
+ callbackContext.error("Please grant read external storage permission");
463
+ }
464
+
465
+ private String getRealPathFromURI_API19(JSONObject obj, CallbackContext callbackContext) throws JSONException
466
+ {
467
+ // Credit: https://stackoverflow.com/questions/2789276/android-get-real-path-by-uri-getpath/2790688
468
+ Uri uri = obj.has("uri") ? Uri.parse(obj.getString("uri")) : null;
469
+ if (uri == null)
470
+ {
471
+ Log.w(LOG_TAG, "URI is not a specified parameter");
472
+ throw new JSONException("URI is not a specified parameter");
473
+ }
474
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
475
+ String filePath = "";
476
+ if (uri.getHost().contains("com.android.providers.media")) {
477
+ int permissionCheck = ContextCompat.checkSelfPermission(this.cordova.getActivity(),
478
+ Manifest.permission.READ_EXTERNAL_STORAGE);
479
+ if (permissionCheck != PackageManager.PERMISSION_GRANTED)
480
+ {
481
+ // Could do better here - if the app does not already have permission should
482
+ // only continue when we get the success callback from this.
483
+ ActivityCompat.requestPermissions(this.cordova.getActivity(),
484
+ new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
485
+ callbackContext.error("Please grant read external storage permission");
486
+ return null;
487
+ }
488
+
489
+ // Image pick from recent
490
+ String wholeID = DocumentsContract.getDocumentId(uri);
491
+
492
+ // Split at colon, use second item in the array
493
+ String id = wholeID.split(":")[1];
494
+
495
+ String[] column = {MediaStore.Images.Media.DATA};
496
+
497
+ // where id is equal to
498
+ String sel = MediaStore.Images.Media._ID + "=?";
499
+
500
+ // This line requires read storage permission
501
+
502
+ Cursor cursor = this.cordova.getActivity().getApplicationContext().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
503
+ column, sel, new String[]{id}, null);
504
+
505
+ int columnIndex = cursor.getColumnIndex(column[0]);
506
+
507
+ if (cursor.moveToFirst()) {
508
+ filePath = cursor.getString(columnIndex);
509
+ }
510
+ cursor.close();
511
+ return filePath;
512
+ } else {
513
+ // image pick from gallery
514
+ String[] proj = {MediaStore.Images.Media.DATA};
515
+ Cursor cursor = this.cordova.getActivity().getApplicationContext().getContentResolver().query(uri, proj, null, null, null);
516
+ int column_index
517
+ = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
518
+ cursor.moveToFirst();
519
+ return cursor.getString(column_index);
520
+ }
521
+ }
522
+
523
+ return "Requires KK or higher";
524
+ }
525
+
526
+ private void startActivity(Intent i, boolean bExpectResult, int requestCode, CallbackContext callbackContext) {
527
+
528
+ if (i.resolveActivityInfo(this.cordova.getActivity().getPackageManager(), 0) != null)
529
+ {
530
+ if (bExpectResult)
531
+ {
532
+ cordova.setActivityResultCallback(this);
533
+ this.cordova.getActivity().startActivityForResult(i, requestCode);
534
+ }
535
+ else
536
+ {
537
+ this.cordova.getActivity().startActivity(i);
538
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
539
+ }
540
+ }
541
+ else
542
+ {
543
+ // Return an error as there is no app to handle this intent
544
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR));
545
+ }
546
+ }
547
+
548
+ private void sendBroadcast(Intent intent) {
549
+ this.cordova.getActivity().sendBroadcast(intent);
550
+ }
551
+
552
+ private void startService(Intent intent)
553
+ {
554
+ this.cordova.getActivity().startService(intent);
555
+ }
556
+
557
+ private Intent populateIntent(JSONObject obj, CallbackContext callbackContext) throws JSONException
558
+ {
559
+ // Credit: https://github.com/chrisekelley/cordova-webintent
560
+ String type = obj.has("type") ? obj.getString("type") : null;
561
+ String packageAssociated = obj.has("package") ? obj.getString("package") : null;
562
+
563
+ //Uri uri = obj.has("url") ? resourceApi.remapUri(Uri.parse(obj.getString("url"))) : null;
564
+ Uri uri = null;
565
+ final CordovaResourceApi resourceApi = webView.getResourceApi();
566
+ if (obj.has("url"))
567
+ {
568
+ String uriAsString = obj.getString("url");
569
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && uriAsString.startsWith("file://"))
570
+ {
571
+ uri = remapUriWithFileProvider(uriAsString, callbackContext);
572
+ }
573
+ else
574
+ {
575
+ uri = resourceApi.remapUri(Uri.parse(obj.getString("url")));
576
+ }
577
+ }
578
+
579
+ JSONObject extras = obj.has("extras") ? obj.getJSONObject("extras") : null;
580
+ Map<String, Object> extrasMap = new HashMap<String, Object>();
581
+ JSONObject extrasObject = null;
582
+ String extrasKey = "";
583
+ if (extras != null) {
584
+ JSONArray extraNames = extras.names();
585
+ for (int i = 0; i < extraNames.length(); i++) {
586
+ String key = extraNames.getString(i);
587
+ Object extrasObj = extras.get(key);
588
+ if (extrasObj instanceof JSONObject) {
589
+ // The extra is a bundle
590
+ extrasKey = key;
591
+ extrasObject = (JSONObject) extras.get(key);
592
+ } else {
593
+ extrasMap.put(key, extras.get(key));
594
+ }
595
+ }
596
+ }
597
+
598
+ String action = obj.has("action") ? obj.getString("action") : null;
599
+ Intent i = new Intent();
600
+ if (action != null)
601
+ i.setAction(action);
602
+
603
+ if (type != null && uri != null) {
604
+ i.setDataAndType(uri, type); //Fix the crash problem with android 2.3.6
605
+ } else {
606
+ if (type != null) {
607
+ i.setType(type);
608
+ }
609
+ if (uri != null)
610
+ {
611
+ i.setData(uri);
612
+ }
613
+ }
614
+
615
+ JSONObject component = obj.has("component") ? obj.getJSONObject("component") : null;
616
+ if (component != null)
617
+ {
618
+ // User has specified an explicit intent
619
+ String componentPackage = component.has("package") ? component.getString("package") : null;
620
+ String componentClass = component.has("class") ? component.getString("class") : null;
621
+ if (componentPackage == null || componentClass == null)
622
+ {
623
+ Log.w(LOG_TAG, "Component specified but missing corresponding package or class");
624
+ throw new JSONException("Component specified but missing corresponding package or class");
625
+ }
626
+ else
627
+ {
628
+ ComponentName componentName = new ComponentName(componentPackage, componentClass);
629
+ i.setComponent(componentName);
630
+ }
631
+ }
632
+
633
+ if (packageAssociated != null)
634
+ i.setPackage(packageAssociated);
635
+
636
+ JSONArray flags = obj.has("flags") ? obj.getJSONArray("flags") : null;
637
+ if (flags != null)
638
+ {
639
+ int length = flags.length();
640
+ for (int k = 0; k < length; k++)
641
+ {
642
+ i.addFlags(flags.getInt(k));
643
+ }
644
+ }
645
+
646
+ if (extrasObject != null)
647
+ addSerializable(i, extrasKey, extrasObject);
648
+
649
+ for (String key : extrasMap.keySet()) {
650
+ Object value = extrasMap.get(key);
651
+ String valueStr = String.valueOf(value);
652
+ // If type is text html, the extra text must sent as HTML
653
+ if (key.equals(Intent.EXTRA_TEXT) && type != null && type.equals("text/html")) {
654
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
655
+ i.putExtra(key, Html.fromHtml(valueStr, Html.FROM_HTML_MODE_LEGACY));
656
+ } else {
657
+ //noinspection deprecation
658
+ i.putExtra(key, Html.fromHtml(valueStr));
659
+ }
660
+ } else if (key.equals(Intent.EXTRA_STREAM)) {
661
+ // allows sharing of images as attachments.
662
+ // value in this case should be a URI of a file
663
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && valueStr.startsWith("file://"))
664
+ {
665
+ Uri uriOfStream = remapUriWithFileProvider(valueStr, callbackContext);
666
+ if (uriOfStream != null)
667
+ i.putExtra(key, uriOfStream);
668
+ }
669
+ else
670
+ {
671
+ //final CordovaResourceApi resourceApi = webView.getResourceApi();
672
+ i.putExtra(key, resourceApi.remapUri(Uri.parse(valueStr)));
673
+ }
674
+ } else if (key.equals(Intent.EXTRA_EMAIL)) {
675
+ // allows to add the email address of the receiver
676
+ i.putExtra(Intent.EXTRA_EMAIL, new String[] { valueStr });
677
+ } else if (key.equals(Intent.EXTRA_KEY_EVENT)) {
678
+ // allows to add a key event object
679
+ JSONObject keyEventJson = new JSONObject(valueStr);
680
+ int keyAction = keyEventJson.getInt("action");
681
+ int keyCode = keyEventJson.getInt("code");
682
+ KeyEvent keyEvent = new KeyEvent(keyAction, keyCode);
683
+ i.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
684
+ } else {
685
+ if (value instanceof Boolean) {
686
+ i.putExtra(key, Boolean.valueOf(valueStr));
687
+ } else if (value instanceof Integer) {
688
+ i.putExtra(key, Integer.valueOf(valueStr));
689
+ } else if (value instanceof Long) {
690
+ i.putExtra(key, Long.valueOf(valueStr));
691
+ } else if (value instanceof Double) {
692
+ i.putExtra(key, Double.valueOf(valueStr));
693
+ } else {
694
+ i.putExtra(key, valueStr);
695
+ }
696
+ }
697
+ }
698
+
699
+ i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
700
+
701
+ if (obj.has("chooser")) {
702
+ i = Intent.createChooser(i, obj.getString("chooser"));
703
+ }
704
+
705
+ return i;
706
+ }
707
+
708
+ @Override
709
+ public void onNewIntent(Intent intent) {
710
+ if (this.onNewIntentCallbackContext != null) {
711
+ fireOnNewIntent(intent);
712
+ } else {
713
+ // save the intent for use when onIntent action is called in the execute method
714
+ this.deferredIntent = intent;
715
+ }
716
+ }
717
+
718
+ @Override
719
+ public void onActivityResult(int requestCode, int resultCode, Intent intent)
720
+ {
721
+ super.onActivityResult(requestCode, resultCode, intent);
722
+ if (onActivityResultCallbackContext != null && intent != null)
723
+ {
724
+ intent.putExtra("requestCode", requestCode);
725
+ intent.putExtra("resultCode", resultCode);
726
+ PluginResult result = new PluginResult(PluginResult.Status.OK, getIntentJson(intent));
727
+ result.setKeepCallback(true);
728
+ onActivityResultCallbackContext.sendPluginResult(result);
729
+ }
730
+ else if (onActivityResultCallbackContext != null)
731
+ {
732
+ Intent canceledIntent = new Intent();
733
+ canceledIntent.putExtra("requestCode", requestCode);
734
+ canceledIntent.putExtra("resultCode", resultCode);
735
+ PluginResult canceledResult = new PluginResult(PluginResult.Status.OK, getIntentJson(canceledIntent));
736
+ canceledResult.setKeepCallback(true);
737
+ onActivityResultCallbackContext.sendPluginResult(canceledResult);
738
+ }
739
+
740
+ }
741
+
742
+ private BroadcastReceiver newBroadcastReceiver() {
743
+ return new BroadcastReceiver() {
744
+ @Override
745
+ public void onReceive(Context context, Intent intent) {
746
+ CallbackContext onBroadcastCallbackContext = receiverCallbacks.get(this);
747
+ if (onBroadcastCallbackContext != null)
748
+ {
749
+ PluginResult result = new PluginResult(PluginResult.Status.OK, getIntentJson(intent));
750
+ result.setKeepCallback(true);
751
+ onBroadcastCallbackContext.sendPluginResult(result);
752
+ }
753
+ }
754
+ };
755
+ }
756
+
757
+ /**
758
+ * Sends the provided Intent to the onNewIntentCallbackContext.
759
+ *
760
+ * @param intent This is the intent to send to the JS layer.
761
+ */
762
+ private void fireOnNewIntent(Intent intent) {
763
+ PluginResult result = new PluginResult(PluginResult.Status.OK, getIntentJson(intent));
764
+ result.setKeepCallback(true);
765
+ this.onNewIntentCallbackContext.sendPluginResult(result);
766
+ }
767
+
768
+ /**
769
+ * Return JSON representation of intent attributes
770
+ *
771
+ * @param intent
772
+ * Credit: https://github.com/napolitano/cordova-plugin-intent
773
+ */
774
+ private JSONObject getIntentJson(Intent intent) {
775
+ JSONObject intentJSON = null;
776
+ ClipData clipData = null;
777
+ JSONObject[] items = null;
778
+ ContentResolver cR = this.cordova.getActivity().getApplicationContext().getContentResolver();
779
+ MimeTypeMap mime = MimeTypeMap.getSingleton();
780
+
781
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
782
+ clipData = intent.getClipData();
783
+ if (clipData != null) {
784
+ int clipItemCount = clipData.getItemCount();
785
+ items = new JSONObject[clipItemCount];
786
+
787
+ for (int i = 0; i < clipItemCount; i++) {
788
+
789
+ ClipData.Item item = clipData.getItemAt(i);
790
+
791
+ try {
792
+ items[i] = new JSONObject();
793
+ items[i].put("htmlText", item.getHtmlText());
794
+ items[i].put("intent", item.getIntent());
795
+ items[i].put("text", item.getText());
796
+ items[i].put("uri", item.getUri());
797
+
798
+ if (item.getUri() != null) {
799
+ String type = cR.getType(item.getUri());
800
+ String extension = mime.getExtensionFromMimeType(cR.getType(item.getUri()));
801
+
802
+ items[i].put("type", type);
803
+ items[i].put("extension", extension);
804
+ }
805
+
806
+ } catch (JSONException e) {
807
+ Log.d(LOG_TAG, " Error thrown during intent > JSON conversion");
808
+ Log.d(LOG_TAG, e.getMessage());
809
+ Log.d(LOG_TAG, Arrays.toString(e.getStackTrace()));
810
+ }
811
+
812
+ }
813
+ }
814
+ }
815
+
816
+ try {
817
+ intentJSON = new JSONObject();
818
+
819
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
820
+ if (items != null) {
821
+ intentJSON.put("clipItems", new JSONArray(items));
822
+ }
823
+ }
824
+
825
+ intentJSON.put("type", intent.getType());
826
+ intentJSON.put("extras", toJsonObject(intent.getExtras()));
827
+ intentJSON.put("action", intent.getAction());
828
+ intentJSON.put("categories", intent.getCategories());
829
+ intentJSON.put("flags", intent.getFlags());
830
+ intentJSON.put("component", intent.getComponent());
831
+ intentJSON.put("data", intent.getData());
832
+ intentJSON.put("package", intent.getPackage());
833
+
834
+ return intentJSON;
835
+ } catch (JSONException e) {
836
+ Log.d(LOG_TAG, " Error thrown during intent > JSON conversion");
837
+ Log.d(LOG_TAG, e.getMessage());
838
+ Log.d(LOG_TAG, Arrays.toString(e.getStackTrace()));
839
+
840
+ return null;
841
+ }
842
+ }
843
+
844
+ private static JSONObject toJsonObject(Bundle bundle) {
845
+ if (bundle == null) {
846
+ return new JSONObject();
847
+ }
848
+
849
+ try {
850
+ return (JSONObject) toJsonValue(bundle);
851
+ } catch (JSONException e) {
852
+ Log.e(LOG_TAG, "Cannot convert bundle to JSON: " + e.getMessage(), e);
853
+ return new JSONObject();
854
+ }
855
+ }
856
+
857
+ private static Object toJsonValue(final Object value) throws JSONException {
858
+ // Credit: https://github.com/napolitano/cordova-plugin-intent
859
+ if (value == null) {
860
+ return null;
861
+ } else if (value instanceof Bundle) {
862
+ final Bundle bundle = (Bundle) value;
863
+ final JSONObject result = new JSONObject();
864
+ for (final String key : bundle.keySet()) {
865
+ result.put(key, toJsonValue(bundle.get(key)));
866
+ }
867
+ return result;
868
+ } else if ((value.getClass().isArray())) {
869
+ final JSONArray result = new JSONArray();
870
+ int length = Array.getLength(value);
871
+ for (int i = 0; i < length; ++i) {
872
+ result.put(i, toJsonValue(Array.get(value, i)));
873
+ }
874
+ return result;
875
+ }else if (value instanceof ArrayList<?>) {
876
+ final ArrayList arrayList = (ArrayList<?>)value;
877
+ final JSONArray result = new JSONArray();
878
+ for (int i = 0; i < arrayList.size(); i++)
879
+ result.put(toJsonValue(arrayList.get(i)));
880
+ return result;
881
+ } else if (
882
+ value instanceof String
883
+ || value instanceof Boolean
884
+ || value instanceof Integer
885
+ || value instanceof Long
886
+ || value instanceof Double) {
887
+ return value;
888
+ } else {
889
+ return String.valueOf(value);
890
+ }
891
+ }
892
+
893
+ private void addSerializable(Intent intent, String key, final JSONObject obj) {
894
+ if (obj.has("$class")) {
895
+ try {
896
+ JSONArray arguments = obj.has("arguments") ? obj.getJSONArray("arguments") : new JSONArray();
897
+
898
+ Class<?>[] argTypes = new Class[arguments.length()];
899
+ for (int i = 0; i < arguments.length(); i++) {
900
+ argTypes[i] = getType(arguments.get(i));
901
+ }
902
+
903
+ Class<?> classForName = Class.forName(obj.getString("$class"));
904
+ Constructor<?> constructor = classForName.getConstructor(argTypes);
905
+
906
+ intent.putExtra(key, (Serializable) constructor.newInstance(jsonArrayToObjectArray(arguments)));
907
+ } catch (Exception e) {
908
+ e.printStackTrace();
909
+ }
910
+ } else {
911
+ intent.putExtra(key, toBundle(obj));
912
+ }
913
+ }
914
+
915
+ private Object[] jsonArrayToObjectArray(JSONArray array) throws JSONException {
916
+ List<Object> list = new ArrayList<>();
917
+
918
+ for (int i = 0; i < array.length(); i++) {
919
+ list.add(array.get(i));
920
+ }
921
+
922
+ return list.toArray();
923
+ }
924
+
925
+ private Class<?> getType(Object obj) {
926
+ if (obj instanceof String) {
927
+ return String.class;
928
+ } else if (obj instanceof Boolean) {
929
+ return Boolean.class;
930
+ } else if (obj instanceof Float) {
931
+ return Float.class;
932
+ } else if (obj instanceof Integer) {
933
+ return Integer.class;
934
+ } else if (obj instanceof Long) {
935
+ return Long.class;
936
+ } else if (obj instanceof Double) {
937
+ return Double.class;
938
+ } else {
939
+ return null;
940
+ }
941
+ }
942
+
943
+ private Bundle toBundle(final JSONObject obj) {
944
+ Bundle returnBundle = new Bundle();
945
+ if (obj == null) {
946
+ return null;
947
+ }
948
+ try {
949
+ Iterator<?> keys = obj.keys();
950
+ while (keys.hasNext()) {
951
+ String key = (String)keys.next();
952
+
953
+ if (obj.get(key) instanceof String)
954
+ returnBundle.putString(key, obj.getString(key));
955
+ else if (obj.get(key) instanceof Boolean)
956
+ returnBundle.putBoolean(key, obj.getBoolean(key));
957
+ else if (obj.get(key) instanceof Integer)
958
+ returnBundle.putInt(key, obj.getInt(key));
959
+ else if (obj.get(key) instanceof Long)
960
+ returnBundle.putLong(key, obj.getLong(key));
961
+ else if (obj.get(key) instanceof Double)
962
+ returnBundle.putDouble(key, obj.getDouble(key));
963
+ else if (obj.get(key).getClass().isArray() || obj.get(key) instanceof JSONArray)
964
+ {
965
+ JSONArray jsonArray = obj.getJSONArray(key);
966
+ int length = jsonArray.length();
967
+ if (jsonArray.get(0) instanceof String)
968
+ {
969
+ String[] stringArray = new String[length];
970
+ for (int j = 0; j < length; j++)
971
+ stringArray[j] = jsonArray.getString(j);
972
+ returnBundle.putStringArray(key, stringArray);
973
+ //returnBundle.putParcelableArray(key, obj.get);
974
+ }
975
+ else
976
+ {
977
+ if (key.equals("PLUGIN_CONFIG")) {
978
+ ArrayList<Bundle> bundleArray = new ArrayList<Bundle>();
979
+ for (int k = 0; k < length; k++) {
980
+ bundleArray.add(toBundle(jsonArray.getJSONObject(k)));
981
+ }
982
+ returnBundle.putParcelableArrayList(key, bundleArray);
983
+ } else {
984
+ Bundle[] bundleArray = new Bundle[length];
985
+ for (int k = 0; k < length; k++)
986
+ bundleArray[k] = toBundle(jsonArray.getJSONObject(k));
987
+ returnBundle.putParcelableArray(key, bundleArray);
988
+ }
989
+ }
990
+ }
991
+ else if (obj.get(key) instanceof JSONObject)
992
+ returnBundle.putBundle(key, toBundle((JSONObject)obj.get(key)));
993
+ }
994
+ }
995
+ catch (JSONException e) {
996
+ e.printStackTrace();
997
+ }
998
+
999
+ return returnBundle;
1000
+ }
1001
+ }