cordova-plugin-mserviceinterface-2.0 1.0.102 → 1.0.104
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.
- package/package.json +1 -1
- package/plugin.xml +6 -8
- package/scripts/mservice-deeplink-setup.js +67 -16
- package/src/android/AttachmentFileIO.java +59 -0
- package/src/android/CameraActivity.java +111 -10
- package/src/android/GeofenceBroadcastReceiver.java +99 -23
- package/src/android/doubleogradle.gradle +0 -4
- package/src/android/mInterface.java +505 -602
- package/src/android/mInterfaceReceiver.java +11 -53
- package/src/android/mInterfaceService.java +539 -315
- package/src/android/mInterfaceUtil.java +184 -183
- package/src/android/res/layout/activity_camera.xml +12 -0
|
@@ -9,7 +9,7 @@ import android.app.AlertDialog;
|
|
|
9
9
|
import android.app.PendingIntent;
|
|
10
10
|
import android.app.ProgressDialog;
|
|
11
11
|
import android.content.ContentResolver;
|
|
12
|
-
import android.content.
|
|
12
|
+
import android.content.ActivityNotFoundException;
|
|
13
13
|
import android.content.Context;
|
|
14
14
|
import android.content.DialogInterface;
|
|
15
15
|
import android.content.Intent;
|
|
@@ -26,6 +26,7 @@ import android.graphics.Color;
|
|
|
26
26
|
import android.graphics.Matrix;
|
|
27
27
|
import android.graphics.Paint;
|
|
28
28
|
import android.location.Location;
|
|
29
|
+
import android.location.LocationManager;
|
|
29
30
|
import android.media.MediaMetadataRetriever;
|
|
30
31
|
import android.media.ThumbnailUtils;
|
|
31
32
|
import android.net.ConnectivityManager;
|
|
@@ -35,7 +36,9 @@ import android.os.AsyncTask;
|
|
|
35
36
|
import android.os.Build;
|
|
36
37
|
import android.os.Bundle;
|
|
37
38
|
import android.os.Environment;
|
|
38
|
-
import android.
|
|
39
|
+
import android.os.Handler;
|
|
40
|
+
import android.os.Looper;
|
|
41
|
+
import android.os.SystemClock;
|
|
39
42
|
import android.provider.MediaStore;
|
|
40
43
|
import android.provider.OpenableColumns;
|
|
41
44
|
import android.provider.Settings;
|
|
@@ -43,7 +46,6 @@ import android.text.TextUtils;
|
|
|
43
46
|
import android.util.Base64;
|
|
44
47
|
import android.util.Log;
|
|
45
48
|
import android.util.Patterns;
|
|
46
|
-
import android.view.KeyEvent;
|
|
47
49
|
import android.webkit.MimeTypeMap;
|
|
48
50
|
import android.widget.ProgressBar;
|
|
49
51
|
import android.widget.Toast;
|
|
@@ -52,9 +54,13 @@ import androidx.annotation.NonNull;
|
|
|
52
54
|
import androidx.annotation.Nullable;
|
|
53
55
|
import androidx.annotation.RequiresApi;
|
|
54
56
|
import androidx.core.app.ActivityCompat;
|
|
57
|
+
import androidx.core.location.LocationManagerCompat;
|
|
55
58
|
import androidx.exifinterface.media.ExifInterface;
|
|
56
59
|
|
|
57
60
|
import com.google.android.gms.common.ConnectionResult;
|
|
61
|
+
import com.google.android.gms.common.GoogleApiAvailability;
|
|
62
|
+
import com.google.android.gms.location.CurrentLocationRequest;
|
|
63
|
+
import com.google.android.gms.tasks.CancellationTokenSource;
|
|
58
64
|
import com.google.android.gms.common.api.GoogleApiClient;
|
|
59
65
|
import com.google.android.gms.common.api.PendingResult;
|
|
60
66
|
import com.google.android.gms.common.api.ResultCallback;
|
|
@@ -102,6 +108,7 @@ import java.util.Arrays;
|
|
|
102
108
|
import java.util.Collections;
|
|
103
109
|
import java.util.Date;
|
|
104
110
|
import java.util.List;
|
|
111
|
+
import java.util.Locale;
|
|
105
112
|
import java.util.Stack;
|
|
106
113
|
import java.util.TimeZone;
|
|
107
114
|
import java.util.zip.ZipEntry;
|
|
@@ -118,6 +125,11 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
118
125
|
public Stack<ProgressDialog> spinnerDialogStack = new Stack<ProgressDialog>();
|
|
119
126
|
private static final int PICK_FILE_REQUEST = 1;
|
|
120
127
|
public CallbackContext callback;
|
|
128
|
+
private CallbackContext permissionCallback;
|
|
129
|
+
private int pendingPermissionRequest = -1;
|
|
130
|
+
private static final int REQUEST_PERMISSIONS = 4101;
|
|
131
|
+
private static final int REQUEST_LOCATION_PERMISSION = 4102;
|
|
132
|
+
private static final int REQUEST_MEDIA_PERMISSION = 4103;
|
|
121
133
|
private static JSONArray arguments = null;
|
|
122
134
|
private String pictureFilePath;
|
|
123
135
|
private String cameraAttachmentInd = "false";
|
|
@@ -136,7 +148,6 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
136
148
|
private static final String PORTRAIT = "portrait";
|
|
137
149
|
private static final String LANDSCAPE = "landscape";
|
|
138
150
|
private static final String ANDROID_PLATFORM = "Android";
|
|
139
|
-
String currentLocationInd = "";
|
|
140
151
|
Location mCurrentLocation1;
|
|
141
152
|
LocationRequest mLocationRequest1;
|
|
142
153
|
GoogleApiClient mGoogleApiClient1;
|
|
@@ -155,15 +166,39 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
155
166
|
super.onResume(multitasking);
|
|
156
167
|
//To avoid starting service after getting permissions initially.
|
|
157
168
|
if (!mInterfaceUtil.deviceID.equalsIgnoreCase("")) {
|
|
158
|
-
|
|
159
|
-
cordova.getActivity().startService(new Intent(cordova.getActivity().getApplicationContext(), mInterfaceService.class));
|
|
160
|
-
}
|
|
169
|
+
mInterfaceService.start(cordova.getActivity());
|
|
161
170
|
}
|
|
162
171
|
} catch (Exception e) {
|
|
163
172
|
System.out.println("onResume: " + e.getMessage());
|
|
164
173
|
}
|
|
165
174
|
}
|
|
166
175
|
|
|
176
|
+
@Override
|
|
177
|
+
public void onPause(boolean multitasking) {
|
|
178
|
+
mInterfaceService.stopIfNotTracking(cordova.getActivity());
|
|
179
|
+
super.onPause(multitasking);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@Override
|
|
183
|
+
public void onDestroy() {
|
|
184
|
+
locationPluginDestroyed = true;
|
|
185
|
+
cancelCurrentLocationRequest();
|
|
186
|
+
mInterfaceService.stopIfNotTracking(cordova.getActivity());
|
|
187
|
+
if (mGoogleApiClient1 != null) {
|
|
188
|
+
if (mGoogleApiClient1.isConnected()) {
|
|
189
|
+
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient1, this);
|
|
190
|
+
}
|
|
191
|
+
mGoogleApiClient1.disconnect();
|
|
192
|
+
}
|
|
193
|
+
super.onDestroy();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@Override
|
|
197
|
+
public void onReset() {
|
|
198
|
+
cancelCurrentLocationRequest();
|
|
199
|
+
super.onReset();
|
|
200
|
+
}
|
|
201
|
+
|
|
167
202
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
168
203
|
@Override
|
|
169
204
|
public boolean execute(final String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
|
@@ -199,13 +234,11 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
199
234
|
try {
|
|
200
235
|
boolean appInfoUpdated = new mInterfaceUtil().updateAppInfo(args);
|
|
201
236
|
System.out.println("appInfoUpdated: " + appInfoUpdated);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
cordova.getActivity().startService(new Intent(cordova.getActivity().getApplicationContext(), mInterfaceService.class));
|
|
237
|
+
if (mInterfaceService.start(cordova.getActivity())) {
|
|
238
|
+
callbackContext.success("Success");
|
|
205
239
|
} else {
|
|
206
|
-
|
|
240
|
+
callbackContext.error("Unable to start service while the app is in the background");
|
|
207
241
|
}
|
|
208
|
-
callbackContext.success("Success");
|
|
209
242
|
} catch (Exception e) {
|
|
210
243
|
System.out.println("Unable to StartService, Exception is: " + e.getMessage());
|
|
211
244
|
callbackContext.error("Unable to StartService, Exception is: " + e.getMessage());
|
|
@@ -471,6 +504,10 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
471
504
|
String str = "false";
|
|
472
505
|
if (isServiceRunning(mInterfaceService.class)) {
|
|
473
506
|
str = "true";
|
|
507
|
+
// Legacy JS skips StartService when this returns true.
|
|
508
|
+
// Recheck an existing queue-only/tracking service here,
|
|
509
|
+
// preserving the callback contract and eligibility guards.
|
|
510
|
+
mInterfaceService.start(cordova.getActivity());
|
|
474
511
|
System.out.println("service check is: " + str + " " + isServiceRunning(mInterfaceService.class));
|
|
475
512
|
}
|
|
476
513
|
callbackContext.success(str);
|
|
@@ -604,19 +641,8 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
604
641
|
callbackContext.error(e.getMessage());
|
|
605
642
|
}
|
|
606
643
|
} else if ("GetCurrentLocation".equals(action)) {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
callback = callbackContext;
|
|
610
|
-
createLocationRequest1();
|
|
611
|
-
this.mGoogleApiClient1 = new GoogleApiClient.Builder(cordova.getActivity())
|
|
612
|
-
.addConnectionCallbacks(this)
|
|
613
|
-
.addOnConnectionFailedListener(this)
|
|
614
|
-
.addApi(LocationServices.API)
|
|
615
|
-
.build();
|
|
616
|
-
mGoogleApiClient1.connect();
|
|
617
|
-
} catch (Exception e) {
|
|
618
|
-
callbackContext.error(e.getMessage());
|
|
619
|
-
}
|
|
644
|
+
getCurrentLocation(callbackContext);
|
|
645
|
+
return true;
|
|
620
646
|
} else if (action.equals("GetSyncIndicator")) {
|
|
621
647
|
try {
|
|
622
648
|
File newQueueFolder, oldQueueFolder;
|
|
@@ -826,25 +852,14 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
826
852
|
builder.setNegativeButton("Not Now", new DialogInterface.OnClickListener() {
|
|
827
853
|
@Override
|
|
828
854
|
public void onClick(DialogInterface dialog, int which) {
|
|
829
|
-
dialog.
|
|
855
|
+
dialog.dismiss();
|
|
830
856
|
callbackContext.success("Success");
|
|
831
857
|
}
|
|
832
858
|
});
|
|
833
859
|
alertDialog = builder.create();
|
|
834
860
|
alertDialog.setCanceledOnTouchOutside(false);
|
|
835
861
|
alertDialog.show();
|
|
836
|
-
alertDialog.
|
|
837
|
-
|
|
838
|
-
@Override
|
|
839
|
-
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
|
840
|
-
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
841
|
-
dialog.dismiss();
|
|
842
|
-
callbackContext.error("failure");
|
|
843
|
-
}
|
|
844
|
-
return true;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
});
|
|
862
|
+
alertDialog.setOnCancelListener(dialog -> callbackContext.error("failure"));
|
|
848
863
|
} else if (action.equals("UpdateConfirm")) {
|
|
849
864
|
/* OPEN THE PLAYSTORE MSERVICE APP */
|
|
850
865
|
String appVersion, softwareProductVersion, softwareProductSubVersion;
|
|
@@ -867,17 +882,7 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
867
882
|
alertDialog = builder.create();
|
|
868
883
|
alertDialog.setCanceledOnTouchOutside(false);
|
|
869
884
|
alertDialog.show();
|
|
870
|
-
alertDialog.
|
|
871
|
-
|
|
872
|
-
@Override
|
|
873
|
-
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
|
874
|
-
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
875
|
-
dialog.dismiss();
|
|
876
|
-
callbackContext.error("failure");
|
|
877
|
-
}
|
|
878
|
-
return true;
|
|
879
|
-
}
|
|
880
|
-
});
|
|
885
|
+
alertDialog.setOnCancelListener(dialog -> callbackContext.error("failure"));
|
|
881
886
|
} else if (action.equals("UpdateNew")) {
|
|
882
887
|
try {
|
|
883
888
|
cordova.getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + cordova.getActivity().getApplicationContext().getPackageName())));
|
|
@@ -907,6 +912,8 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
907
912
|
}
|
|
908
913
|
} else if (action.equals("CaptureImageFromCamera")) {
|
|
909
914
|
try {
|
|
915
|
+
attachmentDestPath = "";
|
|
916
|
+
cameraAttachmentInd = "false";
|
|
910
917
|
if (args.length() > 0) {
|
|
911
918
|
attachmentDestPath = args.optJSONObject(0).optString("destinationPath");
|
|
912
919
|
cameraAttachmentInd = args.getJSONObject(0).optString("attachmentInd");
|
|
@@ -918,6 +925,8 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
918
925
|
}
|
|
919
926
|
} else if (action.equals("PickImageFromGallery")) {
|
|
920
927
|
try {
|
|
928
|
+
attachmentDestPath = "";
|
|
929
|
+
galleryAttachmentInd = "false";
|
|
921
930
|
if (args.length() > 0) {
|
|
922
931
|
attachmentDestPath = args.optJSONObject(0).optString("destinationPath");
|
|
923
932
|
galleryAttachmentInd = args.getJSONObject(0).optString("attachmentInd");
|
|
@@ -1493,6 +1502,122 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1493
1502
|
return false;
|
|
1494
1503
|
}
|
|
1495
1504
|
|
|
1505
|
+
private static final long CURRENT_LOCATION_TIMEOUT_MS = 10_000L;
|
|
1506
|
+
private static final String CURRENT_LOCATION_TIMEOUT_ERROR = "Unable to obtain current location within 10 seconds";
|
|
1507
|
+
private final Handler currentLocationHandler = new Handler(Looper.getMainLooper());
|
|
1508
|
+
private CurrentLocationOperation currentLocationOperation;
|
|
1509
|
+
private volatile boolean locationPluginDestroyed;
|
|
1510
|
+
|
|
1511
|
+
private void getCurrentLocation(final CallbackContext resultCallback) {
|
|
1512
|
+
final long deadline = SystemClock.elapsedRealtime() + CURRENT_LOCATION_TIMEOUT_MS;
|
|
1513
|
+
currentLocationHandler.post(() -> {
|
|
1514
|
+
if (locationPluginDestroyed) {
|
|
1515
|
+
resultCallback.error("Current location request cancelled: plugin destroyed");
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
if (currentLocationOperation != null) {
|
|
1519
|
+
resultCallback.error("A current location request is already in progress");
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
CurrentLocationOperation operation = new CurrentLocationOperation(resultCallback, deadline);
|
|
1523
|
+
currentLocationOperation = operation;
|
|
1524
|
+
operation.start();
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
private void cancelCurrentLocationRequest() {
|
|
1529
|
+
currentLocationHandler.post(() -> {
|
|
1530
|
+
if (currentLocationOperation != null) {
|
|
1531
|
+
currentLocationOperation.finish(null, "Current location request cancelled");
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// All request state and completion listeners run on the main looper. This
|
|
1537
|
+
// callback is separate from the shared camera/scanner/GPS-settings callback.
|
|
1538
|
+
private final class CurrentLocationOperation {
|
|
1539
|
+
private final CallbackContext resultCallback;
|
|
1540
|
+
private final long deadline;
|
|
1541
|
+
private final CancellationTokenSource cancellation = new CancellationTokenSource();
|
|
1542
|
+
private final Runnable timeout = () -> finish(null, CURRENT_LOCATION_TIMEOUT_ERROR);
|
|
1543
|
+
private boolean completed;
|
|
1544
|
+
|
|
1545
|
+
CurrentLocationOperation(CallbackContext resultCallback, long deadline) {
|
|
1546
|
+
this.resultCallback = resultCallback;
|
|
1547
|
+
this.deadline = deadline;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
void start() {
|
|
1551
|
+
long remaining = deadline - SystemClock.elapsedRealtime();
|
|
1552
|
+
if (remaining <= 0) {
|
|
1553
|
+
finish(null, CURRENT_LOCATION_TIMEOUT_ERROR);
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
currentLocationHandler.postDelayed(timeout, remaining);
|
|
1557
|
+
try {
|
|
1558
|
+
Context context = cordova.getActivity().getApplicationContext();
|
|
1559
|
+
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|
|
1560
|
+
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
|
1561
|
+
finish(null, "Location permission not granted");
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
LocationManager manager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
|
1565
|
+
if (manager == null || !LocationManagerCompat.isLocationEnabled(manager)) {
|
|
1566
|
+
finish(null, "Device location is disabled");
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) != ConnectionResult.SUCCESS) {
|
|
1570
|
+
finish(null, "Google Play services is unavailable");
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
remaining = deadline - SystemClock.elapsedRealtime();
|
|
1574
|
+
if (remaining <= 0) {
|
|
1575
|
+
finish(null, CURRENT_LOCATION_TIMEOUT_ERROR);
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
CurrentLocationRequest request = new CurrentLocationRequest.Builder()
|
|
1579
|
+
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
|
|
1580
|
+
.setMaxUpdateAgeMillis(0)
|
|
1581
|
+
.setDurationMillis(remaining)
|
|
1582
|
+
.build();
|
|
1583
|
+
// No network precondition: a satellite fix can be available offline.
|
|
1584
|
+
LocationServices.getFusedLocationProviderClient(context)
|
|
1585
|
+
.getCurrentLocation(request, cancellation.getToken())
|
|
1586
|
+
.addOnSuccessListener(location -> finish(location,
|
|
1587
|
+
location == null ? "Current location is unavailable" : null))
|
|
1588
|
+
.addOnFailureListener(error -> finish(null,
|
|
1589
|
+
"Unable to obtain current location: " + error.getMessage()))
|
|
1590
|
+
.addOnCanceledListener(() -> finish(null, "Current location request cancelled"));
|
|
1591
|
+
} catch (Exception error) {
|
|
1592
|
+
finish(null, "Unable to obtain current location: " + error.getMessage());
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
void finish(Location location, String error) {
|
|
1597
|
+
if (completed) return;
|
|
1598
|
+
completed = true;
|
|
1599
|
+
currentLocationHandler.removeCallbacks(timeout);
|
|
1600
|
+
if (currentLocationOperation == this) currentLocationOperation = null;
|
|
1601
|
+
// Cancels outstanding acquisition on timeout/reset and releases the
|
|
1602
|
+
// one-shot request on every terminal path. Late results are ignored.
|
|
1603
|
+
try {
|
|
1604
|
+
cancellation.cancel();
|
|
1605
|
+
} catch (RuntimeException cancellationError) {
|
|
1606
|
+
Log.w(TAG, "Unable to cancel current location acquisition", cancellationError);
|
|
1607
|
+
}
|
|
1608
|
+
if (SystemClock.elapsedRealtime() >= deadline) {
|
|
1609
|
+
location = null;
|
|
1610
|
+
error = CURRENT_LOCATION_TIMEOUT_ERROR;
|
|
1611
|
+
}
|
|
1612
|
+
if (location != null) {
|
|
1613
|
+
resultCallback.success(location.getLatitude() + "," + location.getLongitude());
|
|
1614
|
+
} else {
|
|
1615
|
+
resultCallback.error(error);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
|
|
1496
1621
|
public void createLocationRequest1() {
|
|
1497
1622
|
try {
|
|
1498
1623
|
mLocationRequest1 = new LocationRequest();
|
|
@@ -1577,7 +1702,6 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1577
1702
|
boolean permissionGranted = true, checkPermission = true;
|
|
1578
1703
|
List<String> list;
|
|
1579
1704
|
try {
|
|
1580
|
-
callback = callbackContext;
|
|
1581
1705
|
Context context = cordova.getActivity().getApplicationContext();
|
|
1582
1706
|
String[] permissions = args.optJSONObject(0).optString("permissions").split(",");
|
|
1583
1707
|
if (permissions[0].equalsIgnoreCase("android.permission.ACCESS_BACKGROUND_LOCATION")) {
|
|
@@ -1595,12 +1719,12 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1595
1719
|
}
|
|
1596
1720
|
}
|
|
1597
1721
|
if (!permissionGranted) {
|
|
1598
|
-
|
|
1722
|
+
callbackContext.error("failure");
|
|
1599
1723
|
} else {
|
|
1600
|
-
|
|
1724
|
+
callbackContext.success("success");
|
|
1601
1725
|
}
|
|
1602
1726
|
} else {
|
|
1603
|
-
|
|
1727
|
+
callbackContext.success("success");
|
|
1604
1728
|
}
|
|
1605
1729
|
} catch (Exception e) {
|
|
1606
1730
|
e.printStackTrace();
|
|
@@ -1615,69 +1739,106 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1615
1739
|
}
|
|
1616
1740
|
|
|
1617
1741
|
private void getLocationPermission(JSONArray args, CallbackContext callbackContext) {
|
|
1618
|
-
boolean permissionGranted = true;
|
|
1619
|
-
List<String> list;
|
|
1620
1742
|
try {
|
|
1621
|
-
|
|
1622
|
-
Context context = cordova.getActivity().getApplicationContext();
|
|
1623
|
-
String[] permissions = args.optJSONObject(0).optString("permissions").split(",");
|
|
1624
|
-
list = new ArrayList<String>(Arrays.asList(permissions));
|
|
1625
|
-
permissions = list.toArray(new String[0]);
|
|
1626
|
-
|
|
1627
|
-
for (int i = 0; i < permissions.length; i++) {
|
|
1628
|
-
if (ActivityCompat.checkSelfPermission(context, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
|
|
1629
|
-
permissionGranted = false;
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
if (!permissionGranted) {
|
|
1633
|
-
PermissionHelper.requestPermissions(this, 111, permissions);
|
|
1634
|
-
} else {
|
|
1635
|
-
callback.success("success");
|
|
1636
|
-
}
|
|
1743
|
+
requestPermissionsIfNeeded(normalizePermissions(args, false), REQUEST_LOCATION_PERMISSION, callbackContext);
|
|
1637
1744
|
} catch (Exception e) {
|
|
1638
|
-
e.
|
|
1745
|
+
callbackContext.error("getLocationPermission failed: " + e.getMessage());
|
|
1639
1746
|
}
|
|
1640
1747
|
}
|
|
1641
1748
|
|
|
1642
1749
|
private void getPermissions(JSONArray args, CallbackContext callbackContext) {
|
|
1643
|
-
boolean permissionGranted = true;
|
|
1644
|
-
List<String> list;
|
|
1645
1750
|
try {
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1751
|
+
requestPermissionsIfNeeded(normalizePermissions(args, true), REQUEST_PERMISSIONS, callbackContext);
|
|
1752
|
+
} catch (Exception e) {
|
|
1753
|
+
callbackContext.error("getPermissions failed: " + e.getMessage());
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
private String[] normalizePermissions(JSONArray args, boolean initialRequest) throws JSONException {
|
|
1758
|
+
List<String> permissions = new ArrayList<>();
|
|
1759
|
+
for (String value : args.getJSONObject(0).getString("permissions").split(",")) {
|
|
1760
|
+
String permission = value.trim();
|
|
1761
|
+
if (permission.isEmpty()) continue;
|
|
1762
|
+
// Files and photos are selected through URI grants into app-private storage.
|
|
1763
|
+
if (Manifest.permission.READ_MEDIA_IMAGES.equals(permission)
|
|
1764
|
+
|| Manifest.permission.READ_MEDIA_VIDEO.equals(permission)
|
|
1765
|
+
|| Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED.equals(permission)
|
|
1766
|
+
|| Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)
|
|
1767
|
+
|| Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) continue;
|
|
1768
|
+
if (Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission)
|
|
1769
|
+
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
|
|
1770
|
+
|| (initialRequest && Build.VERSION.SDK_INT != Build.VERSION_CODES.Q))) continue;
|
|
1771
|
+
if (Manifest.permission.POST_NOTIFICATIONS.equals(permission)
|
|
1772
|
+
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) continue;
|
|
1773
|
+
if ((Manifest.permission.READ_MEDIA_IMAGES.equals(permission)
|
|
1774
|
+
|| Manifest.permission.READ_MEDIA_VIDEO.equals(permission)
|
|
1775
|
+
|| Manifest.permission.READ_MEDIA_AUDIO.equals(permission))
|
|
1776
|
+
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
1777
|
+
permission = Manifest.permission.READ_EXTERNAL_STORAGE;
|
|
1673
1778
|
}
|
|
1779
|
+
if (Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED.equals(permission)
|
|
1780
|
+
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) continue;
|
|
1781
|
+
if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)
|
|
1782
|
+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) continue;
|
|
1783
|
+
if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)
|
|
1784
|
+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) continue;
|
|
1785
|
+
if (!permissions.contains(permission)) permissions.add(permission);
|
|
1786
|
+
}
|
|
1787
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|
|
1788
|
+
&& (permissions.contains(Manifest.permission.READ_MEDIA_IMAGES)
|
|
1789
|
+
|| permissions.contains(Manifest.permission.READ_MEDIA_VIDEO))
|
|
1790
|
+
&& !permissions.contains(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)) {
|
|
1791
|
+
permissions.add(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED);
|
|
1792
|
+
}
|
|
1793
|
+
return permissions.toArray(new String[0]);
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
private boolean isPermissionSatisfied(String permission) {
|
|
1797
|
+
Context context = cordova.getActivity();
|
|
1798
|
+
if (ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) return true;
|
|
1799
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
1800
|
+
if (Manifest.permission.READ_MEDIA_IMAGES.equals(permission) || Manifest.permission.READ_MEDIA_VIDEO.equals(permission)) {
|
|
1801
|
+
return ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
|
|
1802
|
+
== PackageManager.PERMISSION_GRANTED;
|
|
1803
|
+
}
|
|
1804
|
+
if (Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED.equals(permission)) {
|
|
1805
|
+
return ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED
|
|
1806
|
+
|| ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
return false;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
private boolean hasRequestedPermissions(String[] permissions) {
|
|
1813
|
+
for (String permission : permissions) {
|
|
1814
|
+
if (!isPermissionSatisfied(permission)) return false;
|
|
1815
|
+
}
|
|
1816
|
+
return true;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
private void requestPermissionsIfNeeded(String[] permissions, int requestCode, CallbackContext callbackContext) {
|
|
1820
|
+
if (hasRequestedPermissions(permissions)) {
|
|
1821
|
+
callbackContext.success("success");
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
if (permissionCallback != null) {
|
|
1825
|
+
callbackContext.error("Another permission request is in progress");
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
permissionCallback = callbackContext;
|
|
1829
|
+
pendingPermissionRequest = requestCode;
|
|
1830
|
+
try {
|
|
1831
|
+
PermissionHelper.requestPermissions(this, requestCode, permissions);
|
|
1674
1832
|
} catch (Exception e) {
|
|
1675
|
-
|
|
1833
|
+
permissionCallback = null;
|
|
1834
|
+
pendingPermissionRequest = -1;
|
|
1835
|
+
callbackContext.error("Unable to request permission: " + e.getMessage());
|
|
1676
1836
|
}
|
|
1677
1837
|
}
|
|
1678
1838
|
|
|
1679
1839
|
public void captureImageLiveCamera(CallbackContext callbackContext) {
|
|
1680
1840
|
callback = callbackContext;
|
|
1841
|
+
pictureFilePath = null;
|
|
1681
1842
|
Context context = cordova.getActivity().getApplicationContext();
|
|
1682
1843
|
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
|
1683
1844
|
File photoFile = null;
|
|
@@ -1685,6 +1846,7 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1685
1846
|
photoFile = createImageFile();
|
|
1686
1847
|
} catch (IOException ex) {
|
|
1687
1848
|
callback.error("there is error in create image");
|
|
1849
|
+
return;
|
|
1688
1850
|
}
|
|
1689
1851
|
//Continue only if the File was successfully created
|
|
1690
1852
|
if (photoFile != null) {
|
|
@@ -1699,11 +1861,14 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1699
1861
|
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
|
|
1700
1862
|
pluginResult.setKeepCallback(true);
|
|
1701
1863
|
callbackContext.sendPluginResult(pluginResult);
|
|
1864
|
+
} else {
|
|
1865
|
+
callbackContext.error("Unable to create the camera output file");
|
|
1702
1866
|
}
|
|
1703
1867
|
}
|
|
1704
1868
|
|
|
1705
1869
|
public void captureImage(CallbackContext callbackContext) {
|
|
1706
1870
|
callback = callbackContext;
|
|
1871
|
+
pictureFilePath = null;
|
|
1707
1872
|
Intent intent = new Intent(cordova.getActivity(), CameraActivity.class);
|
|
1708
1873
|
cordova.startActivityForResult(this, intent, REQUEST_IMAGE_CAPTURE);
|
|
1709
1874
|
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
|
|
@@ -1713,26 +1878,32 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1713
1878
|
|
|
1714
1879
|
void pickImageFromGallery(CallbackContext callbackContext) {
|
|
1715
1880
|
try {
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1881
|
+
callback = callbackContext;
|
|
1882
|
+
Intent intent;
|
|
1883
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
1884
|
+
intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
|
|
1885
|
+
intent.setType("image/*");
|
|
1720
1886
|
} else {
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
i.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
|
1887
|
+
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
|
1888
|
+
intent.setType("image/*");
|
|
1889
|
+
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
1725
1890
|
}
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1891
|
+
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
1892
|
+
try {
|
|
1893
|
+
cordova.startActivityForResult(this, intent, PICK_IMAGE_FROM_GALLERY);
|
|
1894
|
+
} catch (ActivityNotFoundException unavailable) {
|
|
1895
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) throw unavailable;
|
|
1896
|
+
Intent fallback = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
|
1897
|
+
fallback.setType("image/*");
|
|
1898
|
+
fallback.addCategory(Intent.CATEGORY_OPENABLE);
|
|
1899
|
+
fallback.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
1900
|
+
cordova.startActivityForResult(this, fallback, PICK_IMAGE_FROM_GALLERY);
|
|
1901
|
+
}
|
|
1902
|
+
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
|
|
1903
|
+
result.setKeepCallback(true);
|
|
1904
|
+
callbackContext.sendPluginResult(result);
|
|
1734
1905
|
} catch (Exception e) {
|
|
1735
|
-
callbackContext.error("pickImageFromGallery failed
|
|
1906
|
+
callbackContext.error("pickImageFromGallery failed: " + e.getMessage());
|
|
1736
1907
|
}
|
|
1737
1908
|
}
|
|
1738
1909
|
|
|
@@ -1923,10 +2094,10 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1923
2094
|
fileProperities.put("fileExtension", fileExtension);
|
|
1924
2095
|
fileProperities.put("thumbnail", thumbnail);
|
|
1925
2096
|
attachmentDestPath = "";
|
|
1926
|
-
|
|
2097
|
+
callbackContext.success(fileProperities);
|
|
1927
2098
|
} catch (Exception e) {
|
|
1928
2099
|
attachmentDestPath = "";
|
|
1929
|
-
|
|
2100
|
+
callbackContext.error("convertImageTo64BaseString failed, exception is : " + e.getMessage());
|
|
1930
2101
|
}
|
|
1931
2102
|
}
|
|
1932
2103
|
} catch (Exception e) {
|
|
@@ -1935,7 +2106,7 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1935
2106
|
}
|
|
1936
2107
|
|
|
1937
2108
|
} catch (Exception e) {
|
|
1938
|
-
e.
|
|
2109
|
+
callbackContext.error("convertImageTo64BaseString failed: " + e.getMessage());
|
|
1939
2110
|
}
|
|
1940
2111
|
|
|
1941
2112
|
}
|
|
@@ -1970,23 +2141,11 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
1970
2141
|
}
|
|
1971
2142
|
|
|
1972
2143
|
public Intent getPickImageChooserIntent() {
|
|
1973
|
-
Intent
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
} else {
|
|
1979
|
-
openFile = new Intent(Intent.ACTION_GET_CONTENT);
|
|
1980
|
-
openFile.setType("*/*");
|
|
1981
|
-
openFile.addCategory(Intent.CATEGORY_OPENABLE);
|
|
1982
|
-
openFile.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
|
1983
|
-
}
|
|
1984
|
-
selectFile = Intent.createChooser(openFile, "Select File");
|
|
1985
|
-
return selectFile;
|
|
1986
|
-
} catch (Exception e) {
|
|
1987
|
-
e.printStackTrace();
|
|
1988
|
-
}
|
|
1989
|
-
return null;
|
|
2144
|
+
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
|
2145
|
+
intent.setType("*/*");
|
|
2146
|
+
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
2147
|
+
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
2148
|
+
return Intent.createChooser(intent, "Select File");
|
|
1990
2149
|
}
|
|
1991
2150
|
|
|
1992
2151
|
//App version plugin
|
|
@@ -2004,35 +2163,31 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2004
2163
|
|
|
2005
2164
|
//Rotate Screen plugin
|
|
2006
2165
|
public void rotateScreen(JSONArray args, CallbackContext callbackContext) {
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
activity.setRequestedOrientation(
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
|
2166
|
+
final String orientation = args.optString(0);
|
|
2167
|
+
cordova.getActivity().runOnUiThread(() -> {
|
|
2168
|
+
try {
|
|
2169
|
+
Activity activity = cordova.getActivity();
|
|
2170
|
+
String currentOrientation = activity.getResources().getConfiguration().orientation
|
|
2171
|
+
== Configuration.ORIENTATION_LANDSCAPE ? "landscape" : "portrait";
|
|
2172
|
+
int requested;
|
|
2173
|
+
switch (orientation) {
|
|
2174
|
+
case ANY: requested = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; break;
|
|
2175
|
+
case LANDSCAPE_PRIMARY: requested = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break;
|
|
2176
|
+
case PORTRAIT_PRIMARY: requested = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break;
|
|
2177
|
+
case LANDSCAPE: requested = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; break;
|
|
2178
|
+
case PORTRAIT: requested = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; break;
|
|
2179
|
+
case LANDSCAPE_SECONDARY: requested = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; break;
|
|
2180
|
+
case PORTRAIT_SECONDARY: requested = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; break;
|
|
2181
|
+
default: callbackContext.error("Unsupported screen orientation"); return;
|
|
2182
|
+
}
|
|
2183
|
+
// A best-effort request: API 36 large screens can ignore fixed orientations.
|
|
2184
|
+
// Return the previous orientation as before, not a claim that a lock was applied.
|
|
2185
|
+
activity.setRequestedOrientation(requested);
|
|
2186
|
+
callbackContext.success(currentOrientation);
|
|
2187
|
+
} catch (Exception e) {
|
|
2188
|
+
callbackContext.error("rotateScreen failed: " + e.getMessage());
|
|
2031
2189
|
}
|
|
2032
|
-
|
|
2033
|
-
} catch (Exception e) {
|
|
2034
|
-
callbackContext.success("rotateScreen failed, exception is : " + e.getMessage());
|
|
2035
|
-
}
|
|
2190
|
+
});
|
|
2036
2191
|
}
|
|
2037
2192
|
|
|
2038
2193
|
public void deviceInfo(CallbackContext callbackContext) {
|
|
@@ -2130,12 +2285,20 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2130
2285
|
final String imageSourcePath,
|
|
2131
2286
|
final String imgSrcType,
|
|
2132
2287
|
final String destinationPath) {
|
|
2288
|
+
convertImageTo64BaseStringAsync(cb, imageSourcePath, imgSrcType, destinationPath, false);
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
private void convertImageTo64BaseStringAsync(final CallbackContext cb,
|
|
2292
|
+
final String imageSourcePath,
|
|
2293
|
+
final String imgSrcType,
|
|
2294
|
+
final String destinationPath,
|
|
2295
|
+
final boolean deleteImported) {
|
|
2133
2296
|
cordova.getThreadPool().execute(new Runnable() {
|
|
2134
2297
|
@Override public void run() {
|
|
2135
|
-
|
|
2136
|
-
OutputStream desFileWriter = null;
|
|
2298
|
+
|
|
2137
2299
|
ByteArrayOutputStream baos = null;
|
|
2138
2300
|
Bitmap bitmap = null;
|
|
2301
|
+
File compressedTemp = null;
|
|
2139
2302
|
try {
|
|
2140
2303
|
// Common bits
|
|
2141
2304
|
final String[] parts = imageSourcePath.split("/");
|
|
@@ -2154,33 +2317,20 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2154
2317
|
.setCompressFormat(Bitmap.CompressFormat.JPEG)
|
|
2155
2318
|
.compressToFile(fileToCompress);
|
|
2156
2319
|
|
|
2320
|
+
compressedTemp = compressedImageFile;
|
|
2157
2321
|
String timeStamp = new java.text.SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());
|
|
2158
2322
|
final String baseDir = (destinationPath != null && !destinationPath.isEmpty())
|
|
2159
2323
|
? (mInterfaceUtil.rootDirectory + "/" + destinationPath)
|
|
2160
2324
|
: (mInterfaceUtil.rootDirectory + "/" + mInterfaceUtil.packageName + "/images");
|
|
2161
2325
|
final String outName = baseName + "_" + timeStamp + ".jpg";
|
|
2162
|
-
final String outFullPath = baseDir + "/" + outName;
|
|
2163
|
-
|
|
2164
2326
|
File outDir = new File(baseDir);
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
if (compressedImageFile.exists()) {
|
|
2169
|
-
srcFileReader = new FileInputStream(compressedImageFile);
|
|
2170
|
-
desFileWriter = new FileOutputStream(new File(outFullPath));
|
|
2171
|
-
byte[] buf = new byte[64 * 1024];
|
|
2172
|
-
int n;
|
|
2173
|
-
while ((n = srcFileReader.read(buf)) > 0) {
|
|
2174
|
-
desFileWriter.write(buf, 0, n);
|
|
2175
|
-
}
|
|
2176
|
-
desFileWriter.flush();
|
|
2327
|
+
String rootPath = mInterfaceUtil.rootDirectory.getCanonicalPath() + File.separator;
|
|
2328
|
+
if (!outDir.getCanonicalPath().startsWith(rootPath)) {
|
|
2329
|
+
throw new IOException("Attachment destination must be inside app storage");
|
|
2177
2330
|
}
|
|
2331
|
+
File outFile = AttachmentFileIO.copy(
|
|
2332
|
+
new FileInputStream(compressedImageFile), outDir, outName);
|
|
2178
2333
|
|
|
2179
|
-
// (Optional) load to normalize EXIF rotation like the sync version did
|
|
2180
|
-
try { bitmap = handleImageRotation(outFullPath); } catch (Throwable ignore) {}
|
|
2181
|
-
|
|
2182
|
-
// Build properties
|
|
2183
|
-
File outFile = new File(outFullPath);
|
|
2184
2334
|
org.json.JSONObject fileProps = new org.json.JSONObject();
|
|
2185
2335
|
fileProps.put("filePath", outFile.getParent());
|
|
2186
2336
|
fileProps.put("fileName", outFile.getName());
|
|
@@ -2189,25 +2339,37 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2189
2339
|
fileProps.put("thumbnail", thumbnail);
|
|
2190
2340
|
|
|
2191
2341
|
// Match original behavior: clear attachmentDestPath if you rely on that global
|
|
2192
|
-
|
|
2342
|
+
|
|
2193
2343
|
|
|
2194
2344
|
postSuccess(cb, fileProps);
|
|
2195
2345
|
return;
|
|
2196
2346
|
}
|
|
2197
2347
|
|
|
2198
|
-
// === CAMERA / GALLERY
|
|
2348
|
+
// === CAMERA / GALLERY → return BASE64 string ===
|
|
2199
2349
|
// Decode with downsampling and fix rotation
|
|
2200
2350
|
BitmapFactory.Options o = new BitmapFactory.Options();
|
|
2201
2351
|
o.inJustDecodeBounds = true; BitmapFactory.decodeFile(imageSourcePath, o);
|
|
2202
2352
|
o.inSampleSize = calcInSampleSize(o, 1920, 1920);
|
|
2203
2353
|
o.inJustDecodeBounds = false;
|
|
2204
2354
|
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2355
|
+
bitmap = BitmapFactory.decodeFile(imageSourcePath, o);
|
|
2356
|
+
if (bitmap != null) {
|
|
2357
|
+
try {
|
|
2358
|
+
ExifInterface exif = new ExifInterface(imageSourcePath);
|
|
2359
|
+
Matrix matrix = new Matrix();
|
|
2360
|
+
switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
|
|
2361
|
+
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: matrix.setScale(-1, 1); break;
|
|
2362
|
+
case ExifInterface.ORIENTATION_ROTATE_180: matrix.setRotate(180); break;
|
|
2363
|
+
case ExifInterface.ORIENTATION_FLIP_VERTICAL: matrix.setScale(1, -1); break;
|
|
2364
|
+
case ExifInterface.ORIENTATION_TRANSPOSE: matrix.setRotate(90); matrix.postScale(-1, 1); break;
|
|
2365
|
+
case ExifInterface.ORIENTATION_ROTATE_90: matrix.setRotate(90); break;
|
|
2366
|
+
case ExifInterface.ORIENTATION_TRANSVERSE: matrix.setRotate(270); matrix.postScale(-1, 1); break;
|
|
2367
|
+
case ExifInterface.ORIENTATION_ROTATE_270: matrix.setRotate(270); break;
|
|
2368
|
+
}
|
|
2369
|
+
Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
|
2370
|
+
if (rotated != bitmap) bitmap.recycle();
|
|
2371
|
+
bitmap = rotated;
|
|
2372
|
+
} catch (IOException ignored) { }
|
|
2211
2373
|
}
|
|
2212
2374
|
if (bitmap == null) {
|
|
2213
2375
|
postError(cb, "decode_failed");
|
|
@@ -2224,18 +2386,18 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2224
2386
|
File f = new File(imageSourcePath);
|
|
2225
2387
|
if (f.exists()) f.delete();
|
|
2226
2388
|
} catch (Throwable ignore) {}
|
|
2227
|
-
|
|
2389
|
+
|
|
2228
2390
|
} else if ("gallery".equalsIgnoreCase(imgSrcType)) {
|
|
2229
|
-
|
|
2391
|
+
|
|
2230
2392
|
}
|
|
2231
2393
|
|
|
2232
2394
|
postSuccess(cb, encodedImage);
|
|
2233
2395
|
} catch (Exception e) {
|
|
2234
|
-
|
|
2396
|
+
|
|
2235
2397
|
postError(cb, "convertImageTo64BaseStringAsync failed: " + e.getMessage());
|
|
2236
2398
|
} finally {
|
|
2237
|
-
|
|
2238
|
-
|
|
2399
|
+
if (compressedTemp != null && !compressedTemp.getAbsolutePath().equals(imageSourcePath)) compressedTemp.delete();
|
|
2400
|
+
if (deleteImported) new File(imageSourcePath).delete();
|
|
2239
2401
|
try { if (baos != null) baos.close(); } catch (Exception ignore) {}
|
|
2240
2402
|
try { if (bitmap != null) bitmap.recycle(); } catch (Exception ignore) {}
|
|
2241
2403
|
}
|
|
@@ -2245,19 +2407,9 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2245
2407
|
|
|
2246
2408
|
|
|
2247
2409
|
private String copyFileFromUriFast(Context ctx, Uri uri, String destName, String destDir) {
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
if (!dir.exists() && !dir.mkdirs()) return null;
|
|
2252
|
-
java.io.File out = new java.io.File(dir, destName);
|
|
2253
|
-
try (java.io.InputStream in = ctx.getContentResolver().openInputStream(uri);
|
|
2254
|
-
java.io.OutputStream os = new java.io.FileOutputStream(out)) {
|
|
2255
|
-
if (in == null) return null;
|
|
2256
|
-
byte[] buf = new byte[64 * 1024];
|
|
2257
|
-
int n; while ((n = in.read(buf)) != -1) os.write(buf, 0, n);
|
|
2258
|
-
os.flush();
|
|
2259
|
-
return out.getAbsolutePath();
|
|
2260
|
-
} catch (Exception e) {
|
|
2410
|
+
try {
|
|
2411
|
+
return copySelectedFile(ctx, uri, destName, destDir);
|
|
2412
|
+
} catch (IOException e) {
|
|
2261
2413
|
android.util.Log.e("mInterface", "copyFileFromUriFast", e);
|
|
2262
2414
|
return null;
|
|
2263
2415
|
}
|
|
@@ -2270,15 +2422,17 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2270
2422
|
case LOCATION_ACCURACY_REQUEST_NEW:
|
|
2271
2423
|
switch (resultCode) {
|
|
2272
2424
|
case Activity.RESULT_OK:
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2425
|
+
if (mInterfaceService.start(cordova.getActivity())) {
|
|
2426
|
+
callback.success();
|
|
2427
|
+
} else {
|
|
2428
|
+
callback.error("Unable to resume location service");
|
|
2429
|
+
}
|
|
2276
2430
|
break;
|
|
2277
2431
|
case Activity.RESULT_CANCELED:
|
|
2278
2432
|
callback.error("oops! you have cancelled...");
|
|
2279
2433
|
break;
|
|
2280
2434
|
}
|
|
2281
|
-
|
|
2435
|
+
return;
|
|
2282
2436
|
}
|
|
2283
2437
|
if (SCANCODEINT == 118 && callback != null) {
|
|
2284
2438
|
if (resultCode == RESULT_OK) {
|
|
@@ -2304,176 +2458,12 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2304
2458
|
SCANCODEINT = 0;
|
|
2305
2459
|
callback.error(resultCode);
|
|
2306
2460
|
}
|
|
2307
|
-
}else if (requestCode == PICK_IMAGE_FROM_GALLERY
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
if (cb == null) return;
|
|
2311
|
-
|
|
2312
|
-
try {
|
|
2313
|
-
if (resultCode != RESULT_OK || data == null) {
|
|
2314
|
-
cb.error("canceled");
|
|
2315
|
-
return;
|
|
2316
|
-
}
|
|
2317
|
-
|
|
2318
|
-
// Photo Picker may return via getData() or ClipData
|
|
2319
|
-
Uri uri = data.getData();
|
|
2320
|
-
if (uri == null && data.getClipData() != null && data.getClipData().getItemCount() > 0) {
|
|
2321
|
-
uri = data.getClipData().getItemAt(0).getUri();
|
|
2322
|
-
}
|
|
2323
|
-
if (uri == null) {
|
|
2324
|
-
cb.error("no_file_selected");
|
|
2325
|
-
return;
|
|
2326
|
-
}
|
|
2327
|
-
|
|
2328
|
-
final Uri selectedUri = uri;
|
|
2329
|
-
final String destPath = attachmentDestPath; // capture current dest
|
|
2330
|
-
final String galleryInd = String.valueOf(galleryAttachmentInd);
|
|
2331
|
-
|
|
2332
|
-
// Offload ALL heavy work (resolver, copy, bitmap/encode) to Cordova thread pool
|
|
2333
|
-
cordova.getThreadPool().execute(new Runnable() {
|
|
2334
|
-
@Override public void run() {
|
|
2335
|
-
try {
|
|
2336
|
-
ContentResolver cr = cordova.getActivity().getContentResolver();
|
|
2337
|
-
|
|
2338
|
-
String mime = null;
|
|
2339
|
-
try { mime = cr.getType(selectedUri); } catch (Throwable ignore) {}
|
|
2340
|
-
|
|
2341
|
-
String defExt = (mime != null && mime.contains("/"))
|
|
2342
|
-
? mime.substring(mime.indexOf('/') + 1).toLowerCase()
|
|
2343
|
-
: "jpg";
|
|
2344
|
-
|
|
2345
|
-
// Get a display name if provider allows; otherwise build a sane fallback
|
|
2346
|
-
String fileName = safeGetDisplayName(cr, selectedUri, defExt);
|
|
2347
|
-
String ext = fileName.contains(".")
|
|
2348
|
-
? fileName.substring(fileName.lastIndexOf('.')).toLowerCase()
|
|
2349
|
-
: ("." + defExt);
|
|
2350
|
-
|
|
2351
|
-
// Copy the user-selected URI into app-private storage (no READ_MEDIA_* needed)
|
|
2352
|
-
String localPath = copyFileFromUriFast(
|
|
2353
|
-
cordova.getActivity().getApplicationContext(),
|
|
2354
|
-
selectedUri, fileName, destPath);
|
|
2355
|
-
|
|
2356
|
-
if (localPath == null) {
|
|
2357
|
-
cb.error("copy_failed");
|
|
2358
|
-
return;
|
|
2359
|
-
}
|
|
2360
|
-
|
|
2361
|
-
// Accept only image-like picks (by MIME or extension)
|
|
2362
|
-
boolean imageLike =
|
|
2363
|
-
(mime != null && mime.startsWith("image/")) ||
|
|
2364
|
-
ext.equals(".jpg") || ext.equals(".jpeg") ||
|
|
2365
|
-
ext.equals(".png") || ext.equals(".heic");
|
|
2366
|
-
|
|
2367
|
-
if (!imageLike) {
|
|
2368
|
-
cb.error("Only JPEG/PNG/HEIC images are allowed.");
|
|
2369
|
-
return;
|
|
2370
|
-
}
|
|
2371
|
-
|
|
2372
|
-
// Run your existing conversion on a worker too (non-blocking)
|
|
2373
|
-
if ("true".equals(galleryInd)) {
|
|
2374
|
-
convertImageTo64BaseStringAsync(cb, localPath, "compress", destPath);
|
|
2375
|
-
} else {
|
|
2376
|
-
convertImageTo64BaseStringAsync(cb, localPath, "gallery", "");
|
|
2377
|
-
}
|
|
2378
|
-
} catch (Exception e) {
|
|
2379
|
-
cb.error("PICK_IMAGE_FROM_GALLERY: " + e.getMessage());
|
|
2380
|
-
}
|
|
2381
|
-
}
|
|
2382
|
-
});
|
|
2383
|
-
return; // IMPORTANT: stop here so no other branch falls through
|
|
2384
|
-
} catch (Exception e) {
|
|
2385
|
-
cb.error("PICK_IMAGE_FROM_GALLERY dispatch failed: " + e.getMessage());
|
|
2386
|
-
return;
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
else if (requestCode == NEW_FILE_PICK_REQUEST && callback != null) {
|
|
2390
|
-
try {
|
|
2391
|
-
Uri uri = data.getData();
|
|
2392
|
-
String fileName, extension, filePath;
|
|
2393
|
-
JSONObject fileProperities;
|
|
2394
|
-
Cursor cursor = null;
|
|
2395
|
-
if (uri.getScheme().equals("file")) {
|
|
2396
|
-
fileName = uri.getLastPathSegment();
|
|
2397
|
-
if (fileName.indexOf(".") > 0) {
|
|
2398
|
-
fileName = fileName.substring(0, fileName.lastIndexOf("."));
|
|
2399
|
-
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
2400
|
-
extension = "." + fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
|
2401
|
-
fileName = fileName + "_" + timeStamp + extension;
|
|
2402
|
-
}
|
|
2403
|
-
} else {
|
|
2404
|
-
try {
|
|
2405
|
-
cursor = cordova.getActivity().getApplicationContext().getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DISPLAY_NAME}, null, null, null);
|
|
2406
|
-
if (cursor != null && cursor.moveToFirst()) {
|
|
2407
|
-
int displayNameIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DISPLAY_NAME);
|
|
2408
|
-
if (displayNameIndex != -1) {
|
|
2409
|
-
fileName = cursor.getString(displayNameIndex);
|
|
2410
|
-
} else {
|
|
2411
|
-
fileName = "";
|
|
2412
|
-
}
|
|
2413
|
-
extension = "." + fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
|
2414
|
-
if (!extension.equals(".jpeg") && !extension.equals(".jpg") && !extension.equals(".png")) {
|
|
2415
|
-
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
2416
|
-
fileName = fileName.substring(0, fileName.lastIndexOf("."));
|
|
2417
|
-
fileName = fileName + "_" + timeStamp + extension;
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
|
-
} else {
|
|
2421
|
-
fileName = uri.getLastPathSegment();
|
|
2422
|
-
}
|
|
2423
|
-
} finally {
|
|
2424
|
-
if (cursor != null) {
|
|
2425
|
-
cursor.close();
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
}
|
|
2429
|
-
|
|
2430
|
-
extension = "." + fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
|
2431
|
-
|
|
2432
|
-
filePath = copyFileFromUri(cordova.getActivity().getApplicationContext(), uri, fileName, attachmentDestPath, callback);
|
|
2433
|
-
File file = new File(filePath);
|
|
2434
|
-
String mimeType = getMimeType(filePath, uri);
|
|
2435
|
-
System.out.println("Mime type is: " + mimeType);
|
|
2436
|
-
double fileSize = file.length();
|
|
2437
|
-
if (filePath != null) {
|
|
2438
|
-
try {
|
|
2439
|
-
if (requestCode == NEW_FILE_PICK_REQUEST) {
|
|
2440
|
-
if (extension.equals(".heic")) {
|
|
2441
|
-
convertImageTo64BaseString(callback, filePath, "compress", attachmentDestPath);
|
|
2442
|
-
} else if (mimeType != null) {
|
|
2443
|
-
if (mimeType.contains("image")) {
|
|
2444
|
-
convertImageTo64BaseString(callback, filePath, "compress", attachmentDestPath);
|
|
2445
|
-
} else {
|
|
2446
|
-
fileProperities = new JSONObject();
|
|
2447
|
-
fileProperities.put("filePath", filePath.substring(0, filePath.lastIndexOf(File.separator)));
|
|
2448
|
-
fileProperities.put("fileName", fileName);
|
|
2449
|
-
fileProperities.put("fileSize", fileSize);
|
|
2450
|
-
fileProperities.put("fileExtension", extension);
|
|
2451
|
-
fileProperities.put("thumbnail", getFileThumbnail(filePath, extension));
|
|
2452
|
-
attachmentDestPath = "";
|
|
2453
|
-
callback.success(fileProperities);
|
|
2454
|
-
}
|
|
2455
|
-
} else {
|
|
2456
|
-
fileProperities = new JSONObject();
|
|
2457
|
-
fileProperities.put("filePath", filePath.substring(0, filePath.lastIndexOf(File.separator)));
|
|
2458
|
-
fileProperities.put("fileName", fileName);
|
|
2459
|
-
fileProperities.put("fileSize", fileSize);
|
|
2460
|
-
fileProperities.put("fileExtension", extension);
|
|
2461
|
-
fileProperities.put("thumbnail", getFileThumbnail(filePath, extension));
|
|
2462
|
-
callback.success(fileProperities);
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
} catch (Exception e) {
|
|
2466
|
-
callback.error("onActivityResult failed, exception is : " + e.getMessage());
|
|
2467
|
-
}
|
|
2468
|
-
} else {
|
|
2469
|
-
callback.error("onActivityResult: Selected file path is null");
|
|
2470
|
-
}
|
|
2471
|
-
} catch (Exception e) {
|
|
2472
|
-
callback.error("onActivityResult failed, exception is : " + e.getMessage());
|
|
2473
|
-
}
|
|
2461
|
+
} else if ((requestCode == PICK_IMAGE_FROM_GALLERY || requestCode == NEW_FILE_PICK_REQUEST
|
|
2462
|
+
|| requestCode == PICK_FILE_REQUEST) && callback != null) {
|
|
2463
|
+
handlePickedFile(requestCode, resultCode, data);
|
|
2474
2464
|
} else if (requestCode == REQUEST_IMAGE_CAPTURE && callback != null) {
|
|
2475
2465
|
if (resultCode == RESULT_OK) {
|
|
2476
|
-
String imagePath = data.getStringExtra("imagePath");
|
|
2466
|
+
String imagePath = data == null ? null : data.getStringExtra("imagePath");
|
|
2477
2467
|
if (imagePath != null && !imagePath.isEmpty()) {
|
|
2478
2468
|
pictureFilePath = imagePath;
|
|
2479
2469
|
if (cameraAttachmentInd.equals("true")) {
|
|
@@ -2485,12 +2475,10 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2485
2475
|
callback.error("failure");
|
|
2486
2476
|
}
|
|
2487
2477
|
} else if (resultCode == Activity.RESULT_CANCELED) {
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
}
|
|
2493
|
-
}
|
|
2478
|
+
if (pictureFilePath != null && !pictureFilePath.isEmpty()) {
|
|
2479
|
+
File file = new File(pictureFilePath);
|
|
2480
|
+
if (file.exists()) file.delete();
|
|
2481
|
+
}
|
|
2494
2482
|
callback.error("failure");
|
|
2495
2483
|
} else {
|
|
2496
2484
|
callback.error(resultCode);
|
|
@@ -2499,158 +2487,10 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2499
2487
|
if (resultCode == RESULT_OK) {
|
|
2500
2488
|
convertImageTo64BaseString(callback, pictureFilePath, "compress", attachmentDestPath);
|
|
2501
2489
|
} else if (resultCode == Activity.RESULT_CANCELED) {
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
file.delete();
|
|
2505
|
-
}
|
|
2506
|
-
callback.error("failure");
|
|
2507
|
-
} else {
|
|
2508
|
-
callback.error(resultCode);
|
|
2509
|
-
}
|
|
2510
|
-
} else if (requestCode == PICK_FILE_REQUEST && callback != null) {
|
|
2511
|
-
if (resultCode == RESULT_OK) {
|
|
2512
|
-
String fileName = null,
|
|
2513
|
-
getfilePath = null,
|
|
2514
|
-
filePath,
|
|
2515
|
-
fileExtension,
|
|
2516
|
-
fileType,
|
|
2517
|
-
fileSize = null,
|
|
2518
|
-
storageDefinition;
|
|
2519
|
-
final String docId,
|
|
2520
|
-
type,
|
|
2521
|
-
id;
|
|
2522
|
-
final String[] split;
|
|
2523
|
-
final String tag,
|
|
2524
|
-
path;
|
|
2525
|
-
final int splitIndex;
|
|
2526
|
-
Cursor cursor;
|
|
2527
|
-
long getSize;
|
|
2528
|
-
JSONObject fileProperities;
|
|
2529
|
-
Uri uri = data.getData(); //get uri for selected file
|
|
2530
|
-
fileType = this.cordova.getActivity().getContentResolver().getType(uri); // get mimeType for selected file
|
|
2531
|
-
File getFileName,
|
|
2532
|
-
file;
|
|
2533
|
-
try {
|
|
2534
|
-
//API LEVEL 19 AND ABOVE (TO GET FILEPATH)
|
|
2535
|
-
if (Build.VERSION.SDK_INT >= 19 && !Build.MANUFACTURER.equals("samsung") && DocumentsContract.isDocumentUri(cordova.getActivity(), uri)) {
|
|
2536
|
-
if ("com.android.externalstorage.documents".equals(uri.getAuthority())) { // ExternalStorageProvider
|
|
2537
|
-
docId = DocumentsContract.getDocumentId(uri);
|
|
2538
|
-
split = docId.split(":");
|
|
2539
|
-
type = split[0];
|
|
2540
|
-
if ("primary".equalsIgnoreCase(type)) {
|
|
2541
|
-
getfilePath = mInterfaceUtil.rootDirectory + "/" + split[1];
|
|
2542
|
-
} else {
|
|
2543
|
-
if (Environment.isExternalStorageRemovable()) {
|
|
2544
|
-
storageDefinition = System.getenv("EXTERNAL_STORAGE");
|
|
2545
|
-
getfilePath = storageDefinition;
|
|
2546
|
-
} else {
|
|
2547
|
-
splitIndex = docId.indexOf(':', 1);
|
|
2548
|
-
tag = docId.substring(0, splitIndex);
|
|
2549
|
-
path = docId.substring(splitIndex + 1);
|
|
2550
|
-
if (new mInterfaceUtil().getPathToNonPrimaryVolume(cordova.getActivity(), tag) != null) {
|
|
2551
|
-
storageDefinition = new mInterfaceUtil().getPathToNonPrimaryVolume(cordova.getActivity(), tag) + "/" + path;
|
|
2552
|
-
file = new File(storageDefinition);
|
|
2553
|
-
if (file.exists() && file.canRead()) {
|
|
2554
|
-
getfilePath = storageDefinition;
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { // DownloadsProvider
|
|
2560
|
-
id = DocumentsContract.getDocumentId(uri);
|
|
2561
|
-
final Uri contentUri = ContentUris.withAppendedId(
|
|
2562
|
-
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
|
|
2563
|
-
getfilePath = new mInterfaceUtil().getDataColumn(cordova.getActivity(), contentUri, null, null);
|
|
2564
|
-
|
|
2565
|
-
} else if ("com.android.providers.media.documents".equals(uri.getAuthority())) { // MediaProvider
|
|
2566
|
-
docId = DocumentsContract.getDocumentId(uri);
|
|
2567
|
-
split = docId.split(":");
|
|
2568
|
-
type = split[0];
|
|
2569
|
-
Uri contentUri = null;
|
|
2570
|
-
if ("image".equals(type)) {
|
|
2571
|
-
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
|
2572
|
-
} else if ("video".equals(type)) {
|
|
2573
|
-
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
|
2574
|
-
} else if ("audio".equals(type)) {
|
|
2575
|
-
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
|
2576
|
-
}
|
|
2577
|
-
final String selection = "_id=?";
|
|
2578
|
-
final String[] selectionArgs = new String[]{
|
|
2579
|
-
split[1]
|
|
2580
|
-
};
|
|
2581
|
-
getfilePath = new mInterfaceUtil().getDataColumn(cordova.getActivity(), contentUri, selection, selectionArgs);
|
|
2582
|
-
}
|
|
2583
|
-
// *** API Level 19 and Above (To Get FileName,FileExtension and FileSize)**** //
|
|
2584
|
-
cursor = cordova.getActivity().getContentResolver().query(uri, null, null, null, null, null);
|
|
2585
|
-
try {
|
|
2586
|
-
if (cursor != null && cursor.moveToFirst()) {
|
|
2587
|
-
int displayNameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
|
2588
|
-
if (displayNameIndex != -1) {
|
|
2589
|
-
fileName = cursor.getString(displayNameIndex);
|
|
2590
|
-
} else {
|
|
2591
|
-
fileName = "";
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
int fileSizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
|
|
2595
|
-
if (!cursor.isNull(fileSizeIndex) && fileSizeIndex != -1) {
|
|
2596
|
-
fileSize = cursor.getString(fileSizeIndex);
|
|
2597
|
-
} else {
|
|
2598
|
-
fileSize = "0";
|
|
2599
|
-
}
|
|
2600
|
-
}
|
|
2601
|
-
} finally {
|
|
2602
|
-
cursor.close();
|
|
2603
|
-
}
|
|
2604
|
-
// *** API Level 19 below and SAMSUNG (To Get FileProperties of MediaFiles)**** //
|
|
2605
|
-
} else {
|
|
2606
|
-
if (fileType != null) {
|
|
2607
|
-
String[] projection = {
|
|
2608
|
-
MediaStore.Images.Media.DATA,
|
|
2609
|
-
MediaStore.Images.Media.SIZE,
|
|
2610
|
-
MediaStore.Images.Media.DISPLAY_NAME
|
|
2611
|
-
};
|
|
2612
|
-
cursor = cordova.getActivity().getContentResolver().query(uri, projection, null, null, null);
|
|
2613
|
-
if (cursor.moveToFirst()) {
|
|
2614
|
-
getfilePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
|
|
2615
|
-
fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));
|
|
2616
|
-
fileSize = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE));
|
|
2617
|
-
}
|
|
2618
|
-
cursor.close();
|
|
2619
|
-
// API LEVEL 19 BELOW AND SAMSUNG (TO GET FILEPROPERTIES OF NORMAL FILES(EX:txt,.pdf,etc..,))
|
|
2620
|
-
} else {
|
|
2621
|
-
getfilePath = data.getData().getPath();
|
|
2622
|
-
filePath = getfilePath.substring(0, getfilePath.lastIndexOf(File.separator));
|
|
2623
|
-
getFileName = new File(getfilePath);
|
|
2624
|
-
fileName = getFileName.getName();
|
|
2625
|
-
getSize = getFileName.length();
|
|
2626
|
-
fileSize = String.valueOf(getSize);
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
filePath = getfilePath.substring(0, getfilePath.lastIndexOf(File.separator));
|
|
2630
|
-
fileExtension = "." + getfilePath.substring(getfilePath.lastIndexOf(".") + 1).toLowerCase();
|
|
2631
|
-
// SEND BELOW JSON OBJECT TO PLUGIN CALLBACK
|
|
2632
|
-
if (filePath != null) {
|
|
2633
|
-
try {
|
|
2634
|
-
if (fileExtension.equals(".jpeg") || fileExtension.equals(".jpg") || fileExtension.equals(".png")) {
|
|
2635
|
-
convertImageTo64BaseString(callback, filePath + "/" + fileName, "compress", attachmentDestPath);
|
|
2636
|
-
} else {
|
|
2637
|
-
fileProperities = new JSONObject();
|
|
2638
|
-
fileProperities.put("filePath", filePath);
|
|
2639
|
-
fileProperities.put("fileName", fileName);
|
|
2640
|
-
fileProperities.put("fileSize", fileSize);
|
|
2641
|
-
fileProperities.put("fileExtension", fileExtension);
|
|
2642
|
-
callback.success(fileProperities);
|
|
2643
|
-
}
|
|
2644
|
-
} catch (Exception e) {
|
|
2645
|
-
callback.error("Failed to process PICK_FILE_REQUEST");
|
|
2646
|
-
}
|
|
2647
|
-
} else {
|
|
2648
|
-
callback.error("File path was null");
|
|
2649
|
-
}
|
|
2650
|
-
} catch (Exception e) {
|
|
2651
|
-
e.printStackTrace();
|
|
2490
|
+
if (pictureFilePath != null && !pictureFilePath.isEmpty()) {
|
|
2491
|
+
File file = new File(pictureFilePath);
|
|
2492
|
+
if (file.exists()) file.delete();
|
|
2652
2493
|
}
|
|
2653
|
-
} else if (resultCode == Activity.RESULT_CANCELED) {
|
|
2654
2494
|
callback.error("failure");
|
|
2655
2495
|
} else {
|
|
2656
2496
|
callback.error(resultCode);
|
|
@@ -2665,62 +2505,130 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2665
2505
|
|
|
2666
2506
|
@Override
|
|
2667
2507
|
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
callback.success("success");
|
|
2682
|
-
} else {
|
|
2683
|
-
callback.error(failedPermission);
|
|
2508
|
+
if (requestCode != pendingPermissionRequest || permissionCallback == null) return;
|
|
2509
|
+
CallbackContext resultCallback = permissionCallback;
|
|
2510
|
+
permissionCallback = null;
|
|
2511
|
+
pendingPermissionRequest = -1;
|
|
2512
|
+
if (grantResults.length == 0) {
|
|
2513
|
+
resultCallback.error("failure");
|
|
2514
|
+
return;
|
|
2515
|
+
}
|
|
2516
|
+
for (String permission : permissions) {
|
|
2517
|
+
if (!isPermissionSatisfied(permission)) {
|
|
2518
|
+
resultCallback.error(Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission)
|
|
2519
|
+
? "background_location" : "failure");
|
|
2520
|
+
return;
|
|
2684
2521
|
}
|
|
2685
|
-
} catch (Exception e) {
|
|
2686
|
-
e.printStackTrace();
|
|
2687
2522
|
}
|
|
2523
|
+
resultCallback.success("success");
|
|
2688
2524
|
}
|
|
2689
2525
|
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2526
|
+
private void handlePickedFile(int requestCode, int resultCode, Intent data) {
|
|
2527
|
+
final CallbackContext resultCallback = callback;
|
|
2528
|
+
callback = null;
|
|
2529
|
+
if (resultCallback == null) return;
|
|
2530
|
+
if (resultCode != RESULT_OK) {
|
|
2531
|
+
attachmentDestPath = "";
|
|
2532
|
+
if (resultCode == Activity.RESULT_CANCELED) resultCallback.error(requestCode == PICK_IMAGE_FROM_GALLERY ? "canceled" : "failure");
|
|
2533
|
+
else resultCallback.error(resultCode);
|
|
2534
|
+
return;
|
|
2535
|
+
}
|
|
2536
|
+
Uri selected = data == null ? null : data.getData();
|
|
2537
|
+
if (selected == null && data != null && data.getClipData() != null
|
|
2538
|
+
&& data.getClipData().getItemCount() > 0) {
|
|
2539
|
+
selected = data.getClipData().getItemAt(0).getUri();
|
|
2540
|
+
}
|
|
2541
|
+
final Uri uri = selected;
|
|
2542
|
+
if (uri == null) {
|
|
2543
|
+
attachmentDestPath = "";
|
|
2544
|
+
resultCallback.error("No file was selected");
|
|
2545
|
+
return;
|
|
2546
|
+
}
|
|
2547
|
+
final String destination = attachmentDestPath;
|
|
2548
|
+
final boolean gallery = requestCode == PICK_IMAGE_FROM_GALLERY;
|
|
2549
|
+
final boolean compressGallery = "true".equals(galleryAttachmentInd);
|
|
2550
|
+
attachmentDestPath = "";
|
|
2551
|
+
// Copy cloud/document content immediately while the picker URI grant is valid.
|
|
2552
|
+
cordova.getThreadPool().execute(() -> {
|
|
2553
|
+
try {
|
|
2554
|
+
Context context = cordova.getActivity().getApplicationContext();
|
|
2555
|
+
ContentResolver resolver = context.getContentResolver();
|
|
2556
|
+
String mimeType = null;
|
|
2557
|
+
try { mimeType = resolver.getType(uri); } catch (RuntimeException ignored) { }
|
|
2558
|
+
String displayName = getSelectedDisplayName(resolver, uri, mimeType);
|
|
2559
|
+
String extension = getExtension(displayName);
|
|
2560
|
+
if (gallery && !("image/jpeg".equals(mimeType) || "image/png".equals(mimeType)
|
|
2561
|
+
|| "image/heic".equals(mimeType) || "image/heif".equals(mimeType)
|
|
2562
|
+
|| ".jpg".equals(extension) || ".jpeg".equals(extension)
|
|
2563
|
+
|| ".png".equals(extension) || ".heic".equals(extension) || ".heif".equals(extension))) {
|
|
2564
|
+
resultCallback.error("Only JPEG, PNG or HEIC images are allowed to attach.");
|
|
2565
|
+
return;
|
|
2566
|
+
}
|
|
2567
|
+
// A gallery import is an intermediate file, never the user's original photo.
|
|
2568
|
+
String path = copySelectedFile(context, uri, displayName, gallery ? "" : destination);
|
|
2569
|
+
File imported = new File(path);
|
|
2570
|
+
boolean image = gallery || (mimeType != null && mimeType.startsWith("image/"))
|
|
2571
|
+
|| ".heic".equals(extension) || ".heif".equals(extension);
|
|
2572
|
+
if (image) {
|
|
2573
|
+
convertImageTo64BaseStringAsync(resultCallback, path,
|
|
2574
|
+
gallery && !compressGallery ? "gallery" : "compress", destination, true);
|
|
2575
|
+
} else {
|
|
2576
|
+
JSONObject properties = new JSONObject();
|
|
2577
|
+
properties.put("filePath", imported.getParent());
|
|
2578
|
+
properties.put("fileName", imported.getName());
|
|
2579
|
+
properties.put("fileSize", imported.length());
|
|
2580
|
+
properties.put("fileExtension", getExtension(imported.getName()));
|
|
2581
|
+
properties.put("thumbnail", getFileThumbnail(path, getExtension(imported.getName())));
|
|
2582
|
+
resultCallback.success(properties);
|
|
2583
|
+
}
|
|
2584
|
+
} catch (Exception e) {
|
|
2585
|
+
resultCallback.error("Unable to read the selected file: " + e.getMessage());
|
|
2706
2586
|
}
|
|
2587
|
+
});
|
|
2588
|
+
}
|
|
2707
2589
|
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
if (
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
while ((bytesRead = inputStream.read(buffer, 0, buffer.length)) >= 0) {
|
|
2715
|
-
outputStream.write(buffer, 0, buffer.length);
|
|
2716
|
-
}
|
|
2717
|
-
} else {
|
|
2718
|
-
callback.error("Error occurred in opening outputStream");
|
|
2590
|
+
private String getSelectedDisplayName(ContentResolver resolver, Uri uri, String mimeType) {
|
|
2591
|
+
String name = null;
|
|
2592
|
+
try (Cursor cursor = resolver.query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null)) {
|
|
2593
|
+
if (cursor != null && cursor.moveToFirst()) {
|
|
2594
|
+
int column = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
|
2595
|
+
if (column >= 0) name = cursor.getString(column);
|
|
2719
2596
|
}
|
|
2597
|
+
} catch (RuntimeException ignored) {
|
|
2598
|
+
// Providers are not required to supply a display name.
|
|
2599
|
+
}
|
|
2600
|
+
if (name == null || name.trim().isEmpty()) name = "attachment";
|
|
2601
|
+
if (getExtension(name).isEmpty() && mimeType != null) {
|
|
2602
|
+
String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
|
|
2603
|
+
if (extension != null) name += "." + extension;
|
|
2604
|
+
}
|
|
2605
|
+
return name;
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
private String getExtension(String name) {
|
|
2609
|
+
int dot = name.lastIndexOf('.');
|
|
2610
|
+
return dot > 0 ? name.substring(dot).toLowerCase(Locale.ROOT) : "";
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
private String copySelectedFile(Context context, Uri uri, String fileName, String destinationPath) throws IOException {
|
|
2614
|
+
File root = mInterfaceUtil.rootDirectory;
|
|
2615
|
+
if (root == null) throw new IOException("App storage is unavailable");
|
|
2616
|
+
File directory = new File(root, TextUtils.isEmpty(destinationPath)
|
|
2617
|
+
? mInterfaceUtil.packageName + "/images" : destinationPath);
|
|
2618
|
+
String rootPath = root.getCanonicalPath() + File.separator;
|
|
2619
|
+
if (!directory.getCanonicalPath().startsWith(rootPath)) {
|
|
2620
|
+
throw new IOException("Attachment destination must be inside app storage");
|
|
2621
|
+
}
|
|
2622
|
+
return AttachmentFileIO.copy(context.getContentResolver().openInputStream(uri), directory, fileName).getAbsolutePath();
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
public String copyFileFromUri(Context context, Uri uri, String fileName, String destinationPath, CallbackContext resultCallback) {
|
|
2626
|
+
try {
|
|
2627
|
+
return copySelectedFile(context, uri, fileName, destinationPath);
|
|
2720
2628
|
} catch (Exception e) {
|
|
2721
|
-
|
|
2629
|
+
resultCallback.error("copyFileFromUri failed: " + e.getMessage());
|
|
2630
|
+
return null;
|
|
2722
2631
|
}
|
|
2723
|
-
return outPutFilePath;
|
|
2724
2632
|
}
|
|
2725
2633
|
|
|
2726
2634
|
/* CHECKING THE BACKGROUND SERVICE RUNNING OR NOT */
|
|
@@ -2801,36 +2709,31 @@ public class mInterface extends CordovaPlugin implements com.google.android.gms.
|
|
|
2801
2709
|
final Status status = locationSettingsResult.getStatus();
|
|
2802
2710
|
switch (status.getStatusCode()) {
|
|
2803
2711
|
case LocationSettingsStatusCodes.SUCCESS:
|
|
2712
|
+
callback.success();
|
|
2804
2713
|
break;
|
|
2805
2714
|
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
|
|
2806
2715
|
try {
|
|
2807
2716
|
this.cordova.setActivityResultCallback(this);
|
|
2808
2717
|
status.startResolutionForResult(this.cordova.getActivity(), LOCATION_ACCURACY_REQUEST_NEW);
|
|
2809
2718
|
} catch (IntentSender.SendIntentException e) {
|
|
2810
|
-
|
|
2719
|
+
callback.error("Unable to open location settings: " + e.getMessage());
|
|
2811
2720
|
}
|
|
2812
2721
|
break;
|
|
2813
2722
|
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
|
|
2814
|
-
|
|
2723
|
+
callback.error("Location settings cannot be changed on this device");
|
|
2724
|
+
break;
|
|
2725
|
+
default:
|
|
2726
|
+
callback.error("Unable to check location settings: " + status.getStatusCode());
|
|
2815
2727
|
break;
|
|
2816
2728
|
}
|
|
2817
2729
|
} catch (Exception e) {
|
|
2818
|
-
|
|
2730
|
+
callback.error("LocationSettingsResult failed, exception is : " + e.getMessage());
|
|
2819
2731
|
}
|
|
2820
2732
|
}
|
|
2821
2733
|
|
|
2822
2734
|
@Override
|
|
2823
2735
|
public void onLocationChanged(@NonNull Location location) {
|
|
2824
2736
|
mCurrentLocation1 = location;
|
|
2825
|
-
try {
|
|
2826
|
-
System.out.println(mCurrentLocation1.getLatitude() + "," + mCurrentLocation1.getLongitude());
|
|
2827
|
-
if (currentLocationInd.equals("true")) {
|
|
2828
|
-
currentLocationInd = "";
|
|
2829
|
-
callback.success(mCurrentLocation1.getLatitude() + "," + mCurrentLocation1.getLongitude());
|
|
2830
|
-
}
|
|
2831
|
-
} catch (Exception e) {
|
|
2832
|
-
callback.error("onLocationChanged failed, exception is : " + e.getMessage());
|
|
2833
|
-
}
|
|
2834
2737
|
}
|
|
2835
2738
|
|
|
2836
2739
|
private class DownloadTask extends AsyncTask<String, Integer, String> {
|