cordova.plugins.diagnostic 6.0.4
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/.github/FUNDING.yml +6 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +123 -0
- package/.github/ISSUE_TEMPLATE/documentation-issue.md +36 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +41 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +37 -0
- package/.github/stale.yml +17 -0
- package/CHANGELOG.md +390 -0
- package/README.md +3709 -0
- package/cordova.plugins.diagnostic.d.ts +1113 -0
- package/package.json +54 -0
- package/plugin.xml +496 -0
- package/scripts/apply-modules.js +165 -0
- package/scripts/logger.js +94 -0
- package/src/android/Diagnostic.java +856 -0
- package/src/android/Diagnostic_Bluetooth.java +297 -0
- package/src/android/Diagnostic_Camera.java +134 -0
- package/src/android/Diagnostic_External_Storage.java +273 -0
- package/src/android/Diagnostic_Location.java +319 -0
- package/src/android/Diagnostic_NFC.java +270 -0
- package/src/android/Diagnostic_Notifications.java +157 -0
- package/src/android/Diagnostic_Wifi.java +155 -0
- package/src/ios/Diagnostic.h +56 -0
- package/src/ios/Diagnostic.m +282 -0
- package/src/ios/Diagnostic_Bluetooth.h +24 -0
- package/src/ios/Diagnostic_Bluetooth.m +170 -0
- package/src/ios/Diagnostic_Calendar.h +24 -0
- package/src/ios/Diagnostic_Calendar.m +94 -0
- package/src/ios/Diagnostic_Camera.h +27 -0
- package/src/ios/Diagnostic_Camera.m +194 -0
- package/src/ios/Diagnostic_Contacts.h +24 -0
- package/src/ios/Diagnostic_Contacts.m +93 -0
- package/src/ios/Diagnostic_Location.h +31 -0
- package/src/ios/Diagnostic_Location.m +284 -0
- package/src/ios/Diagnostic_Microphone.h +21 -0
- package/src/ios/Diagnostic_Microphone.m +97 -0
- package/src/ios/Diagnostic_Motion.h +27 -0
- package/src/ios/Diagnostic_Motion.m +143 -0
- package/src/ios/Diagnostic_Notifications.h +22 -0
- package/src/ios/Diagnostic_Notifications.m +235 -0
- package/src/ios/Diagnostic_Reminders.h +24 -0
- package/src/ios/Diagnostic_Reminders.m +93 -0
- package/src/ios/Diagnostic_Wifi.h +19 -0
- package/src/ios/Diagnostic_Wifi.m +108 -0
- package/src/windows/diagnosticProxy.bluetooth.js +23 -0
- package/src/windows/diagnosticProxy.camera.js +35 -0
- package/src/windows/diagnosticProxy.js +137 -0
- package/src/windows/diagnosticProxy.location.js +54 -0
- package/src/windows/diagnosticProxy.wifi.js +18 -0
- package/www/android/diagnostic.bluetooth.js +211 -0
- package/www/android/diagnostic.calendar.js +90 -0
- package/www/android/diagnostic.camera.js +203 -0
- package/www/android/diagnostic.contacts.js +91 -0
- package/www/android/diagnostic.external_storage.js +102 -0
- package/www/android/diagnostic.js +1309 -0
- package/www/android/diagnostic.location.js +282 -0
- package/www/android/diagnostic.microphone.js +89 -0
- package/www/android/diagnostic.nfc.js +127 -0
- package/www/android/diagnostic.notifications.js +74 -0
- package/www/android/diagnostic.wifi.js +90 -0
- package/www/ios/diagnostic.bluetooth.js +127 -0
- package/www/ios/diagnostic.calendar.js +97 -0
- package/www/ios/diagnostic.camera.js +212 -0
- package/www/ios/diagnostic.contacts.js +98 -0
- package/www/ios/diagnostic.js +990 -0
- package/www/ios/diagnostic.location.js +236 -0
- package/www/ios/diagnostic.microphone.js +99 -0
- package/www/ios/diagnostic.motion.js +160 -0
- package/www/ios/diagnostic.notifications.js +189 -0
- package/www/ios/diagnostic.reminders.js +97 -0
- package/www/ios/diagnostic.wifi.js +80 -0
- package/www/windows/diagnostic.bluetooth.js +51 -0
- package/www/windows/diagnostic.camera.js +41 -0
- package/www/windows/diagnostic.js +169 -0
- package/www/windows/diagnostic.location.js +35 -0
- package/www/windows/diagnostic.wifi.js +51 -0
|
@@ -0,0 +1,856 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
or more contributor license agreements. See the NOTICE file
|
|
4
|
+
distributed with this work for additional information
|
|
5
|
+
regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
to you under the Apache License, Version 2.0 (the
|
|
7
|
+
"License"); you may not use this file except in compliance
|
|
8
|
+
with the License. You may obtain a copy of the License at
|
|
9
|
+
|
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
|
|
12
|
+
Unless required by applicable law or agreed to in writing,
|
|
13
|
+
software distributed under the License is distributed on an
|
|
14
|
+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
KIND, either express or implied. See the License for the
|
|
16
|
+
specific language governing permissions and limitations
|
|
17
|
+
under the License.
|
|
18
|
+
*/
|
|
19
|
+
package cordova.plugins;
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Imports
|
|
23
|
+
*/
|
|
24
|
+
import java.io.BufferedReader;
|
|
25
|
+
import java.io.File;
|
|
26
|
+
import java.io.InputStreamReader;
|
|
27
|
+
import java.lang.reflect.Method;
|
|
28
|
+
import java.util.Collections;
|
|
29
|
+
import java.util.HashMap;
|
|
30
|
+
import java.util.Map;
|
|
31
|
+
import java.util.Random;
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
import org.apache.cordova.CordovaWebView;
|
|
35
|
+
import org.apache.cordova.CallbackContext;
|
|
36
|
+
import org.apache.cordova.CordovaPlugin;
|
|
37
|
+
import org.apache.cordova.CordovaInterface;
|
|
38
|
+
import org.json.JSONArray;
|
|
39
|
+
import org.json.JSONException;
|
|
40
|
+
import org.json.JSONObject;
|
|
41
|
+
|
|
42
|
+
import android.Manifest;
|
|
43
|
+
import android.app.Activity;
|
|
44
|
+
import android.app.AlarmManager;
|
|
45
|
+
import android.app.PendingIntent;
|
|
46
|
+
import android.content.SharedPreferences;
|
|
47
|
+
import android.net.Uri;
|
|
48
|
+
import android.os.Build;
|
|
49
|
+
import android.util.Log;
|
|
50
|
+
|
|
51
|
+
import android.content.Context;
|
|
52
|
+
import android.content.Intent;
|
|
53
|
+
import android.content.pm.PackageManager;
|
|
54
|
+
import android.provider.Settings;
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
import androidx.core.app.ActivityCompat;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Diagnostic plugin implementation for Android
|
|
61
|
+
*/
|
|
62
|
+
public class Diagnostic extends CordovaPlugin{
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
/*************
|
|
66
|
+
* Constants *
|
|
67
|
+
*************/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Tag for debug log messages
|
|
71
|
+
*/
|
|
72
|
+
public static final String TAG = "Diagnostic";
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Map of "dangerous" permissions that need to be requested at run-time (Android 6.0/API 23 and above)
|
|
77
|
+
* See http://developer.android.com/guide/topics/security/permissions.html#perm-groups
|
|
78
|
+
*/
|
|
79
|
+
protected static final Map<String, String> permissionsMap;
|
|
80
|
+
static {
|
|
81
|
+
Map<String, String> _permissionsMap = new HashMap <String, String>();
|
|
82
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "READ_CALENDAR", Manifest.permission.READ_CALENDAR);
|
|
83
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "WRITE_CALENDAR", Manifest.permission.WRITE_CALENDAR);
|
|
84
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "CAMERA", Manifest.permission.CAMERA);
|
|
85
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "READ_CONTACTS", Manifest.permission.READ_CONTACTS);
|
|
86
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "WRITE_CONTACTS", Manifest.permission.WRITE_CONTACTS);
|
|
87
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "GET_ACCOUNTS", Manifest.permission.GET_ACCOUNTS);
|
|
88
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "ACCESS_FINE_LOCATION", Manifest.permission.ACCESS_FINE_LOCATION);
|
|
89
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "ACCESS_COARSE_LOCATION", Manifest.permission.ACCESS_COARSE_LOCATION);
|
|
90
|
+
// Add as string as Manifest.permission.ACCESS_BACKGROUND_LOCATION not defined in < API 29:
|
|
91
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "ACCESS_BACKGROUND_LOCATION", "android.permission.ACCESS_BACKGROUND_LOCATION");
|
|
92
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "RECORD_AUDIO", Manifest.permission.RECORD_AUDIO);
|
|
93
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "READ_PHONE_STATE", Manifest.permission.READ_PHONE_STATE);
|
|
94
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "CALL_PHONE", Manifest.permission.CALL_PHONE);
|
|
95
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "ADD_VOICEMAIL", Manifest.permission.ADD_VOICEMAIL);
|
|
96
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "USE_SIP", Manifest.permission.USE_SIP);
|
|
97
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "PROCESS_OUTGOING_CALLS", Manifest.permission.PROCESS_OUTGOING_CALLS);
|
|
98
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "SEND_SMS", Manifest.permission.SEND_SMS);
|
|
99
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "RECEIVE_SMS", Manifest.permission.RECEIVE_SMS);
|
|
100
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "READ_SMS", Manifest.permission.READ_SMS);
|
|
101
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "RECEIVE_WAP_PUSH", Manifest.permission.RECEIVE_WAP_PUSH);
|
|
102
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "RECEIVE_MMS", Manifest.permission.RECEIVE_MMS);
|
|
103
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "WRITE_EXTERNAL_STORAGE", Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
|
104
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "READ_CALL_LOG", Manifest.permission.READ_CALL_LOG);
|
|
105
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "WRITE_CALL_LOG", Manifest.permission.WRITE_CALL_LOG);
|
|
106
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "READ_EXTERNAL_STORAGE", Manifest.permission.READ_EXTERNAL_STORAGE);
|
|
107
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "BODY_SENSORS", Manifest.permission.BODY_SENSORS);
|
|
108
|
+
// Add as string as Manifest.permission.ACTIVITY_RECOGNITION not defined in < API 29:
|
|
109
|
+
Diagnostic.addBiDirMapEntry(_permissionsMap, "ACTIVITY_RECOGNITION", "android.permission.ACTIVITY_RECOGNITION");
|
|
110
|
+
permissionsMap = Collections.unmodifiableMap(_permissionsMap);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* Map of permission request code to callback context
|
|
116
|
+
*/
|
|
117
|
+
protected HashMap<String, CallbackContext> callbackContexts = new HashMap<String, CallbackContext>();
|
|
118
|
+
|
|
119
|
+
/*
|
|
120
|
+
* Map of permission request code to permission statuses
|
|
121
|
+
*/
|
|
122
|
+
protected HashMap<String, JSONObject> permissionStatuses = new HashMap<String, JSONObject>();
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* User authorised permission
|
|
127
|
+
*/
|
|
128
|
+
protected static final String STATUS_GRANTED = "GRANTED";
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* User denied permission (without checking "never ask again")
|
|
132
|
+
*/
|
|
133
|
+
protected static final String STATUS_DENIED_ONCE = "DENIED_ONCE";
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* User denied permission and checked "never ask again"
|
|
137
|
+
*/
|
|
138
|
+
protected static final String STATUS_DENIED_ALWAYS = "DENIED_ALWAYS";
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Authorisation has not yet been requested for permission
|
|
142
|
+
*/
|
|
143
|
+
protected static final String STATUS_NOT_REQUESTED = "NOT_REQUESTED";
|
|
144
|
+
|
|
145
|
+
public static final String CPU_ARCH_UNKNOWN = "unknown";
|
|
146
|
+
public static final String CPU_ARCH_ARMv6 = "ARMv6";
|
|
147
|
+
public static final String CPU_ARCH_ARMv7 = "ARMv7";
|
|
148
|
+
public static final String CPU_ARCH_ARMv8 = "ARMv8";
|
|
149
|
+
public static final String CPU_ARCH_X86 = "X86";
|
|
150
|
+
public static final String CPU_ARCH_X86_64 = "X86_64";
|
|
151
|
+
public static final String CPU_ARCH_MIPS = "MIPS";
|
|
152
|
+
public static final String CPU_ARCH_MIPS_64 = "MIPS_64";
|
|
153
|
+
|
|
154
|
+
protected static final String externalStorageClassName = "cordova.plugins.Diagnostic_External_Storage";
|
|
155
|
+
protected static final Integer GET_EXTERNAL_SD_CARD_DETAILS_PERMISSION_REQUEST = 1000;
|
|
156
|
+
|
|
157
|
+
/*************
|
|
158
|
+
* Variables *
|
|
159
|
+
*************/
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Singleton class instance
|
|
163
|
+
*/
|
|
164
|
+
public static Diagnostic instance = null;
|
|
165
|
+
|
|
166
|
+
boolean debugEnabled = false;
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Current Cordova callback context (on this thread)
|
|
171
|
+
*/
|
|
172
|
+
protected CallbackContext currentContext;
|
|
173
|
+
|
|
174
|
+
protected Context applicationContext;
|
|
175
|
+
|
|
176
|
+
protected SharedPreferences sharedPref;
|
|
177
|
+
protected SharedPreferences.Editor editor;
|
|
178
|
+
|
|
179
|
+
/*************
|
|
180
|
+
* Public API
|
|
181
|
+
************/
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Constructor.
|
|
185
|
+
*/
|
|
186
|
+
public Diagnostic() {}
|
|
187
|
+
|
|
188
|
+
public static Diagnostic getInstance(){
|
|
189
|
+
return instance;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Sets the context of the Command. This can then be used to do things like
|
|
194
|
+
* get file paths associated with the Activity.
|
|
195
|
+
*
|
|
196
|
+
* @param cordova The context of the main Activity.
|
|
197
|
+
* @param webView The CordovaWebView Cordova is running in.
|
|
198
|
+
*/
|
|
199
|
+
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
|
200
|
+
Log.d(TAG, "initialize()");
|
|
201
|
+
instance = this;
|
|
202
|
+
|
|
203
|
+
applicationContext = this.cordova.getActivity().getApplicationContext();
|
|
204
|
+
sharedPref = cordova.getActivity().getSharedPreferences(TAG, Activity.MODE_PRIVATE);
|
|
205
|
+
editor = sharedPref.edit();
|
|
206
|
+
|
|
207
|
+
super.initialize(cordova, webView);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Executes the request and returns PluginResult.
|
|
212
|
+
*
|
|
213
|
+
* @param action The action to execute.
|
|
214
|
+
* @param args JSONArry of arguments for the plugin.
|
|
215
|
+
* @param callbackContext The callback id used when calling back into JavaScript.
|
|
216
|
+
* @return True if the action was valid, false if not.
|
|
217
|
+
*/
|
|
218
|
+
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
|
219
|
+
currentContext = callbackContext;
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
if (action.equals("enableDebug")){
|
|
223
|
+
debugEnabled = true;
|
|
224
|
+
logDebug("Debug enabled");
|
|
225
|
+
callbackContext.success();
|
|
226
|
+
} else if (action.equals("switchToSettings")){
|
|
227
|
+
switchToAppSettings();
|
|
228
|
+
callbackContext.success();
|
|
229
|
+
} else if (action.equals("switchToMobileDataSettings")){
|
|
230
|
+
switchToMobileDataSettings();
|
|
231
|
+
callbackContext.success();
|
|
232
|
+
} else if (action.equals("switchToWirelessSettings")){
|
|
233
|
+
switchToWirelessSettings();
|
|
234
|
+
callbackContext.success();
|
|
235
|
+
} else if(action.equals("isDataRoamingEnabled")) {
|
|
236
|
+
callbackContext.success(isDataRoamingEnabled() ? 1 : 0);
|
|
237
|
+
} else if(action.equals("getPermissionAuthorizationStatus")) {
|
|
238
|
+
this.getPermissionAuthorizationStatus(args);
|
|
239
|
+
} else if(action.equals("getPermissionsAuthorizationStatus")) {
|
|
240
|
+
this.getPermissionsAuthorizationStatus(args);
|
|
241
|
+
} else if(action.equals("requestRuntimePermission")) {
|
|
242
|
+
this.requestRuntimePermission(args);
|
|
243
|
+
} else if(action.equals("requestRuntimePermissions")) {
|
|
244
|
+
this.requestRuntimePermissions(args);
|
|
245
|
+
} else if(action.equals("isADBModeEnabled")) {
|
|
246
|
+
callbackContext.success(isADBModeEnabled() ? 1 : 0);
|
|
247
|
+
} else if(action.equals("isDeviceRooted")) {
|
|
248
|
+
callbackContext.success(isDeviceRooted() ? 1 : 0);
|
|
249
|
+
} else if(action.equals("restart")) {
|
|
250
|
+
this.restart(args);
|
|
251
|
+
} else if(action.equals("getArchitecture")) {
|
|
252
|
+
callbackContext.success(getCPUArchitecture());
|
|
253
|
+
} else {
|
|
254
|
+
handleError("Invalid action");
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}catch(Exception e ) {
|
|
258
|
+
handleError("Exception occurred: ".concat(e.getMessage()));
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
public void restart(JSONArray args) throws Exception{
|
|
265
|
+
boolean cold = args.getBoolean(0);
|
|
266
|
+
if(cold){
|
|
267
|
+
doColdRestart();
|
|
268
|
+
}else{
|
|
269
|
+
doWarmRestart();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
public boolean isDataRoamingEnabled() throws Exception {
|
|
275
|
+
boolean result;
|
|
276
|
+
if (Build.VERSION.SDK_INT < 17) {
|
|
277
|
+
result = Settings.System.getInt(this.cordova.getActivity().getContentResolver(), Settings.Global.DATA_ROAMING, 0) == 1;
|
|
278
|
+
}else{
|
|
279
|
+
result = Settings.Global.getInt(this.cordova.getActivity().getContentResolver(), Settings.Global.DATA_ROAMING, 0) == 1;
|
|
280
|
+
}
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
public void switchToAppSettings() {
|
|
285
|
+
logDebug("Switch to App Settings");
|
|
286
|
+
Intent appIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
|
287
|
+
Uri uri = Uri.fromParts("package", cordova.getActivity().getPackageName(), null);
|
|
288
|
+
appIntent.setData(uri);
|
|
289
|
+
cordova.getActivity().startActivity(appIntent);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
public void switchToMobileDataSettings() {
|
|
294
|
+
logDebug("Switch to Mobile Data Settings");
|
|
295
|
+
Intent settingsIntent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);
|
|
296
|
+
cordova.getActivity().startActivity(settingsIntent);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
public void switchToWirelessSettings() {
|
|
300
|
+
logDebug("Switch to wireless Settings");
|
|
301
|
+
Intent settingsIntent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
|
|
302
|
+
cordova.getActivity().startActivity(settingsIntent);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
public void getPermissionsAuthorizationStatus(JSONArray args) throws Exception{
|
|
306
|
+
JSONArray permissions = args.getJSONArray(0);
|
|
307
|
+
JSONObject statuses = _getPermissionsAuthorizationStatus(jsonArrayToStringArray(permissions));
|
|
308
|
+
currentContext.success(statuses);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
public void getPermissionAuthorizationStatus(JSONArray args) throws Exception{
|
|
312
|
+
String permission = args.getString(0);
|
|
313
|
+
JSONArray permissions = new JSONArray();
|
|
314
|
+
permissions.put(permission);
|
|
315
|
+
JSONObject statuses = _getPermissionsAuthorizationStatus(jsonArrayToStringArray(permissions));
|
|
316
|
+
currentContext.success(statuses.getString(permission));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
public void requestRuntimePermissions(JSONArray args) throws Exception{
|
|
320
|
+
JSONArray permissions = args.getJSONArray(0);
|
|
321
|
+
int requestId = storeContextByRequestId();
|
|
322
|
+
_requestRuntimePermissions(permissions, requestId);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
public void requestRuntimePermission(JSONArray args) throws Exception{
|
|
326
|
+
requestRuntimePermission(args.getString(0));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
public void requestRuntimePermission(String permission) throws Exception{
|
|
330
|
+
requestRuntimePermission(permission, storeContextByRequestId());
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
public void requestRuntimePermission(String permission, int requestId) throws Exception{
|
|
334
|
+
JSONArray permissions = new JSONArray();
|
|
335
|
+
permissions.put(permission);
|
|
336
|
+
_requestRuntimePermissions(permissions, requestId);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* get device ADB mode info
|
|
341
|
+
*/
|
|
342
|
+
public int getADBMode(){
|
|
343
|
+
int mode;
|
|
344
|
+
if (Build.VERSION.SDK_INT >= 17){ // Jelly_Bean_MR1 and above
|
|
345
|
+
mode = Settings.Global.getInt(applicationContext.getContentResolver(), Settings.Global.ADB_ENABLED, 0);
|
|
346
|
+
} else { // Pre-Jelly_Bean_MR1
|
|
347
|
+
mode = Settings.Secure.getInt(applicationContext.getContentResolver(), Settings.Secure.ADB_ENABLED, 0);
|
|
348
|
+
}
|
|
349
|
+
return mode;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* checks if ADB mode is on
|
|
354
|
+
* especially for debug mode check
|
|
355
|
+
*/
|
|
356
|
+
public boolean isADBModeEnabled(){
|
|
357
|
+
boolean result = false;
|
|
358
|
+
try {
|
|
359
|
+
result = getADBMode() == 1;
|
|
360
|
+
} catch (Exception e) {
|
|
361
|
+
logError(e.getMessage());
|
|
362
|
+
}
|
|
363
|
+
logDebug("ADB mode enabled: " + result);
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* checks if device is rooted
|
|
369
|
+
* refer to: https://stackoverflow.com/questions/1101380
|
|
370
|
+
*/
|
|
371
|
+
public boolean isDeviceRooted(){
|
|
372
|
+
// from build info
|
|
373
|
+
String buildTags = android.os.Build.TAGS;
|
|
374
|
+
if (buildTags != null && buildTags.contains("test-keys")) {
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// from binary exists
|
|
379
|
+
try {
|
|
380
|
+
String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su",
|
|
381
|
+
"/data/local/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/data/local/su" };
|
|
382
|
+
for (String path : paths) {
|
|
383
|
+
if (new File(path).exists()) {
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
} catch (Exception e) {
|
|
388
|
+
logDebug(e.getMessage());
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// from command authority
|
|
392
|
+
Process process = null;
|
|
393
|
+
try {
|
|
394
|
+
process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
|
|
395
|
+
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
396
|
+
if (in.readLine() != null) {
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
} catch (Exception e) {
|
|
400
|
+
logDebug(e.getMessage());
|
|
401
|
+
} finally {
|
|
402
|
+
if (process != null) process.destroy();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
/************
|
|
410
|
+
* Internals
|
|
411
|
+
***********/
|
|
412
|
+
|
|
413
|
+
public void logDebug(String msg) {
|
|
414
|
+
if(debugEnabled){
|
|
415
|
+
Log.d(TAG, msg);
|
|
416
|
+
executeGlobalJavascript("console.log(\""+TAG+"[native]: "+escapeDoubleQuotes(msg)+"\")");
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
public void logInfo(String msg){
|
|
421
|
+
Log.i(TAG, msg);
|
|
422
|
+
if(debugEnabled){
|
|
423
|
+
executeGlobalJavascript("console.info(\""+TAG+"[native]: "+escapeDoubleQuotes(msg)+"\")");
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
public void logWarning(String msg){
|
|
428
|
+
Log.w(TAG, msg);
|
|
429
|
+
if(debugEnabled){
|
|
430
|
+
executeGlobalJavascript("console.warn(\""+TAG+"[native]: "+escapeDoubleQuotes(msg)+"\")");
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public void logError(String msg){
|
|
435
|
+
Log.e(TAG, msg);
|
|
436
|
+
if(debugEnabled){
|
|
437
|
+
executeGlobalJavascript("console.error(\""+TAG+"[native]: "+escapeDoubleQuotes(msg)+"\")");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
public String escapeDoubleQuotes(String string){
|
|
442
|
+
String escapedString = string.replace("\"", "\\\"");
|
|
443
|
+
escapedString = escapedString.replace("%22", "\\%22");
|
|
444
|
+
return escapedString;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Handles an error while executing a plugin API method in the specified context.
|
|
449
|
+
* Calls the registered Javascript plugin error handler callback.
|
|
450
|
+
* @param errorMsg Error message to pass to the JS error handler
|
|
451
|
+
*/
|
|
452
|
+
public void handleError(String errorMsg, CallbackContext context){
|
|
453
|
+
try {
|
|
454
|
+
logError(errorMsg);
|
|
455
|
+
context.error(errorMsg);
|
|
456
|
+
} catch (Exception e) {
|
|
457
|
+
logError(e.toString());
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Handles an error while executing a plugin API method in the current context.
|
|
463
|
+
* Calls the registered Javascript plugin error handler callback.
|
|
464
|
+
* @param errorMsg Error message to pass to the JS error handler
|
|
465
|
+
*/
|
|
466
|
+
public void handleError(String errorMsg) {
|
|
467
|
+
handleError(errorMsg, currentContext);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Handles error during a runtime permissions request.
|
|
472
|
+
* Calls the registered Javascript plugin error handler callback
|
|
473
|
+
* then removes entries associated with the request ID.
|
|
474
|
+
* @param errorMsg Error message to pass to the JS error handler
|
|
475
|
+
* @param requestId The ID of the runtime request
|
|
476
|
+
*/
|
|
477
|
+
public void handleError(String errorMsg, int requestId){
|
|
478
|
+
CallbackContext context;
|
|
479
|
+
String sRequestId = String.valueOf(requestId);
|
|
480
|
+
if (callbackContexts.containsKey(sRequestId)) {
|
|
481
|
+
context = callbackContexts.get(sRequestId);
|
|
482
|
+
}else{
|
|
483
|
+
context = currentContext;
|
|
484
|
+
}
|
|
485
|
+
handleError(errorMsg, context);
|
|
486
|
+
clearRequest(requestId);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
protected JSONObject _getPermissionsAuthorizationStatus(String[] permissions) throws Exception{
|
|
490
|
+
JSONObject statuses = new JSONObject();
|
|
491
|
+
for(int i=0; i<permissions.length; i++){
|
|
492
|
+
String permission = permissions[i];
|
|
493
|
+
if(!permissionsMap.containsKey(permission)){
|
|
494
|
+
throw new Exception("Permission name '"+permission+"' is not a valid permission");
|
|
495
|
+
}
|
|
496
|
+
if(Build.VERSION.SDK_INT < 29 && permission.equals("ACCESS_BACKGROUND_LOCATION")){
|
|
497
|
+
// This version of Android doesn't support background location permission so check for standard coarse location permission
|
|
498
|
+
permission = "ACCESS_COARSE_LOCATION";
|
|
499
|
+
}
|
|
500
|
+
if(Build.VERSION.SDK_INT < 29 && permission.equals("ACTIVITY_RECOGNITION")){
|
|
501
|
+
// This version of Android doesn't support activity recognition permission so check for body sensors permission
|
|
502
|
+
permission = "BODY_SENSORS";
|
|
503
|
+
}
|
|
504
|
+
String androidPermission = permissionsMap.get(permission);
|
|
505
|
+
Log.v(TAG, "Get authorisation status for "+androidPermission);
|
|
506
|
+
boolean granted = hasPermission(androidPermission);
|
|
507
|
+
if(granted){
|
|
508
|
+
statuses.put(permission, Diagnostic.STATUS_GRANTED);
|
|
509
|
+
}else{
|
|
510
|
+
boolean showRationale = shouldShowRequestPermissionRationale(this.cordova.getActivity(), androidPermission);
|
|
511
|
+
if(!showRationale){
|
|
512
|
+
if(isPermissionRequested(permission)){
|
|
513
|
+
statuses.put(permission, Diagnostic.STATUS_DENIED_ALWAYS);
|
|
514
|
+
}else{
|
|
515
|
+
statuses.put(permission, Diagnostic.STATUS_NOT_REQUESTED);
|
|
516
|
+
}
|
|
517
|
+
}else{
|
|
518
|
+
statuses.put(permission, Diagnostic.STATUS_DENIED_ONCE);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return statuses;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
protected void _requestRuntimePermissions(JSONArray permissions, int requestId) throws Exception{
|
|
526
|
+
JSONObject currentPermissionsStatuses = _getPermissionsAuthorizationStatus(jsonArrayToStringArray(permissions));
|
|
527
|
+
JSONArray permissionsToRequest = new JSONArray();
|
|
528
|
+
for(int i = 0; i<currentPermissionsStatuses.names().length(); i++){
|
|
529
|
+
String permission = currentPermissionsStatuses.names().getString(i);
|
|
530
|
+
boolean granted = currentPermissionsStatuses.getString(permission) == Diagnostic.STATUS_GRANTED;
|
|
531
|
+
if(granted){
|
|
532
|
+
Log.d(TAG, "Permission already granted for "+permission);
|
|
533
|
+
JSONObject requestStatuses = permissionStatuses.get(String.valueOf(requestId));
|
|
534
|
+
requestStatuses.put(permission, Diagnostic.STATUS_GRANTED);
|
|
535
|
+
permissionStatuses.put(String.valueOf(requestId), requestStatuses);
|
|
536
|
+
}else{
|
|
537
|
+
String androidPermission = permissionsMap.get(permission);
|
|
538
|
+
Log.d(TAG, "Requesting permission for "+androidPermission);
|
|
539
|
+
permissionsToRequest.put(androidPermission);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if(permissionsToRequest.length() > 0){
|
|
543
|
+
Log.v(TAG, "Requesting permissions");
|
|
544
|
+
requestPermissions(this, requestId, jsonArrayToStringArray(permissionsToRequest));
|
|
545
|
+
|
|
546
|
+
}else{
|
|
547
|
+
Log.d(TAG, "No permissions to request: returning result");
|
|
548
|
+
sendRuntimeRequestResult(requestId);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
protected void sendRuntimeRequestResult(int requestId){
|
|
553
|
+
String sRequestId = String.valueOf(requestId);
|
|
554
|
+
CallbackContext context = callbackContexts.get(sRequestId);
|
|
555
|
+
JSONObject statuses = permissionStatuses.get(sRequestId);
|
|
556
|
+
Log.v(TAG, "Sending runtime request result for id="+sRequestId);
|
|
557
|
+
context.success(statuses);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
protected int storeContextByRequestId(){
|
|
561
|
+
return storeContextByRequestId(currentContext);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
protected int storeContextByRequestId(CallbackContext callbackContext){
|
|
565
|
+
String requestId = generateRandomRequestId();
|
|
566
|
+
callbackContexts.put(requestId, callbackContext);
|
|
567
|
+
permissionStatuses.put(requestId, new JSONObject());
|
|
568
|
+
return Integer.valueOf(requestId);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
protected String generateRandomRequestId(){
|
|
572
|
+
String requestId = null;
|
|
573
|
+
|
|
574
|
+
while(requestId == null){
|
|
575
|
+
requestId = generateRandom();
|
|
576
|
+
if(callbackContexts.containsKey(requestId)){
|
|
577
|
+
requestId = null;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return requestId;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
protected String generateRandom(){
|
|
584
|
+
Random rn = new Random();
|
|
585
|
+
int random = rn.nextInt(1000000) + 1;
|
|
586
|
+
return Integer.toString(random);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
protected String[] jsonArrayToStringArray(JSONArray array) throws JSONException{
|
|
590
|
+
if(array==null)
|
|
591
|
+
return null;
|
|
592
|
+
|
|
593
|
+
String[] arr=new String[array.length()];
|
|
594
|
+
for(int i=0; i<arr.length; i++) {
|
|
595
|
+
arr[i]=array.optString(i);
|
|
596
|
+
}
|
|
597
|
+
return arr;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
protected CallbackContext getContextById(String requestId) throws Exception{
|
|
601
|
+
if (!callbackContexts.containsKey(requestId)) {
|
|
602
|
+
throw new Exception("No context found for request id=" + requestId);
|
|
603
|
+
}
|
|
604
|
+
return callbackContexts.get(requestId);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
protected void clearRequest(int requestId){
|
|
608
|
+
String sRequestId = String.valueOf(requestId);
|
|
609
|
+
if (!callbackContexts.containsKey(sRequestId)) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
callbackContexts.remove(sRequestId);
|
|
613
|
+
permissionStatuses.remove(sRequestId);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Adds a bi-directional entry to a map in the form on 2 entries: key>value and value>key
|
|
618
|
+
* @param map
|
|
619
|
+
* @param key
|
|
620
|
+
* @param value
|
|
621
|
+
*/
|
|
622
|
+
protected static void addBiDirMapEntry(Map map, Object key, Object value){
|
|
623
|
+
map.put(key, value);
|
|
624
|
+
map.put(value, key);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
protected boolean hasPermission(String permission) throws Exception{
|
|
628
|
+
boolean hasPermission = true;
|
|
629
|
+
Method method = null;
|
|
630
|
+
try {
|
|
631
|
+
method = cordova.getClass().getMethod("hasPermission", permission.getClass());
|
|
632
|
+
Boolean bool = (Boolean) method.invoke(cordova, permission);
|
|
633
|
+
hasPermission = bool.booleanValue();
|
|
634
|
+
} catch (NoSuchMethodException e) {
|
|
635
|
+
logWarning("Cordova v" + CordovaWebView.CORDOVA_VERSION + " does not support runtime permissions so defaulting to GRANTED for " + permission);
|
|
636
|
+
}
|
|
637
|
+
return hasPermission;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
protected void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) throws Exception{
|
|
641
|
+
try {
|
|
642
|
+
java.lang.reflect.Method method = cordova.getClass().getMethod("requestPermissions", org.apache.cordova.CordovaPlugin.class ,int.class, java.lang.String[].class);
|
|
643
|
+
method.invoke(cordova, plugin, requestCode, permissions);
|
|
644
|
+
for(String permission : permissions){
|
|
645
|
+
setPermissionRequested(permissionsMap.get(permission));
|
|
646
|
+
}
|
|
647
|
+
} catch (NoSuchMethodException e) {
|
|
648
|
+
throw new Exception("requestPermissions() method not found in CordovaInterface implementation of Cordova v" + CordovaWebView.CORDOVA_VERSION);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
protected boolean shouldShowRequestPermissionRationale(Activity activity, String permission) throws Exception{
|
|
653
|
+
boolean shouldShow;
|
|
654
|
+
try {
|
|
655
|
+
java.lang.reflect.Method method = ActivityCompat.class.getMethod("shouldShowRequestPermissionRationale", Activity.class, java.lang.String.class);
|
|
656
|
+
Boolean bool = (Boolean) method.invoke(null, activity, permission);
|
|
657
|
+
shouldShow = bool.booleanValue();
|
|
658
|
+
} catch (NoSuchMethodException e) {
|
|
659
|
+
throw new Exception("shouldShowRequestPermissionRationale() method not found in ActivityCompat class.");
|
|
660
|
+
}
|
|
661
|
+
return shouldShow;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
public void executeGlobalJavascript(final String jsString){
|
|
665
|
+
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
666
|
+
@Override
|
|
667
|
+
public void run() {
|
|
668
|
+
webView.loadUrl("javascript:" + jsString);
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
public void executePluginJavascript(final String jsString){
|
|
674
|
+
executeGlobalJavascript("cordova.plugins.diagnostic." + jsString);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Performs a warm app restart - restarts only Cordova main activity
|
|
679
|
+
*/
|
|
680
|
+
protected void doWarmRestart() {
|
|
681
|
+
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
682
|
+
@Override
|
|
683
|
+
public void run() {
|
|
684
|
+
try {
|
|
685
|
+
logInfo("Warm restarting main activity");
|
|
686
|
+
instance.cordova.getActivity().recreate();
|
|
687
|
+
} catch (Exception ex) {
|
|
688
|
+
handleError("Unable to warm restart main activity: " + ex.getMessage());
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Performs a full cold app restart - restarts application
|
|
696
|
+
* https://stackoverflow.com/a/22345538/777265
|
|
697
|
+
*/
|
|
698
|
+
protected void doColdRestart() {
|
|
699
|
+
String baseError = "Unable to cold restart application: ";
|
|
700
|
+
try {
|
|
701
|
+
logInfo("Cold restarting application");
|
|
702
|
+
Context c = applicationContext;
|
|
703
|
+
//check if the context is given
|
|
704
|
+
if (c != null) {
|
|
705
|
+
//fetch the packagemanager so we can get the default launch activity
|
|
706
|
+
// (you can replace this intent with any other activity if you want
|
|
707
|
+
PackageManager pm = c.getPackageManager();
|
|
708
|
+
//check if we got the PackageManager
|
|
709
|
+
if (pm != null) {
|
|
710
|
+
//create the intent with the default start activity for your application
|
|
711
|
+
Intent mStartActivity = pm.getLaunchIntentForPackage(
|
|
712
|
+
c.getPackageName()
|
|
713
|
+
);
|
|
714
|
+
if (mStartActivity != null) {
|
|
715
|
+
//mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
716
|
+
//create a pending intent so the application is restarted after System.exit(0) was called.
|
|
717
|
+
// We use an AlarmManager to call this intent in 100ms
|
|
718
|
+
int mPendingIntentId = 223344;
|
|
719
|
+
PendingIntent mPendingIntent = PendingIntent
|
|
720
|
+
.getActivity(c, mPendingIntentId, mStartActivity,
|
|
721
|
+
PendingIntent.FLAG_CANCEL_CURRENT);
|
|
722
|
+
AlarmManager mgr = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
|
|
723
|
+
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
|
|
724
|
+
Log.i(TAG,"Killing application for cold restart");
|
|
725
|
+
//kill the application
|
|
726
|
+
System.exit(0);
|
|
727
|
+
} else {
|
|
728
|
+
handleError(baseError+"StartActivity is null");
|
|
729
|
+
}
|
|
730
|
+
} else {
|
|
731
|
+
handleError(baseError+"PackageManager is null");
|
|
732
|
+
}
|
|
733
|
+
} else {
|
|
734
|
+
handleError(baseError+"Context is null");
|
|
735
|
+
}
|
|
736
|
+
} catch (Exception ex) {
|
|
737
|
+
handleError(baseError+ ex.getMessage());
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
protected String getCPUArchitecture(){
|
|
742
|
+
String arch = CPU_ARCH_UNKNOWN;
|
|
743
|
+
|
|
744
|
+
String abi = null;
|
|
745
|
+
|
|
746
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
747
|
+
abi = Build.CPU_ABI;
|
|
748
|
+
} else {
|
|
749
|
+
abi = Build.SUPPORTED_ABIS[0];
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
if (abi == "armeabi") {
|
|
754
|
+
arch = CPU_ARCH_ARMv6;
|
|
755
|
+
} else if (abi.equals("armeabi-v7a")) {
|
|
756
|
+
arch = CPU_ARCH_ARMv7;
|
|
757
|
+
} else if (abi.equals("arm64-v8a")) {
|
|
758
|
+
arch = CPU_ARCH_ARMv8;
|
|
759
|
+
} else if (abi.equals("x86")) {
|
|
760
|
+
arch = CPU_ARCH_X86;
|
|
761
|
+
} else if (abi.equals("x86_64")) {
|
|
762
|
+
arch = CPU_ARCH_X86_64;
|
|
763
|
+
} else if (abi.equals("mips")) {
|
|
764
|
+
arch = CPU_ARCH_MIPS;
|
|
765
|
+
} else if (abi.equals("mips64")) {
|
|
766
|
+
arch = CPU_ARCH_MIPS_64;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
return arch;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
protected void setPermissionRequested(String permission){
|
|
773
|
+
editor.putBoolean(permission, true);
|
|
774
|
+
boolean success = editor.commit();
|
|
775
|
+
if(!success){
|
|
776
|
+
handleError("Failed to set permission requested flag for " + permission);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
protected boolean isPermissionRequested(String permission){
|
|
781
|
+
return sharedPref.getBoolean(permission, false);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/************
|
|
785
|
+
* Overrides
|
|
786
|
+
***********/
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Callback received when a runtime permissions request has been completed.
|
|
790
|
+
* Retrieves the stateful Cordova context and permission statuses associated with the requestId,
|
|
791
|
+
* then updates the list of status based on the grantResults before passing the result back via the context.
|
|
792
|
+
*
|
|
793
|
+
* @param requestCode - ID that was used when requesting permissions
|
|
794
|
+
* @param permissions - list of permissions that were requested
|
|
795
|
+
* @param grantResults - list of flags indicating if above permissions were granted or denied
|
|
796
|
+
*/
|
|
797
|
+
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
|
|
798
|
+
String sRequestId = String.valueOf(requestCode);
|
|
799
|
+
Log.v(TAG, "Received result for permissions request id=" + sRequestId);
|
|
800
|
+
try {
|
|
801
|
+
|
|
802
|
+
CallbackContext context = getContextById(sRequestId);
|
|
803
|
+
JSONObject statuses = permissionStatuses.get(sRequestId);
|
|
804
|
+
|
|
805
|
+
for (int i = 0, len = permissions.length; i < len; i++) {
|
|
806
|
+
String androidPermission = permissions[i];
|
|
807
|
+
String permission = permissionsMap.get(androidPermission);
|
|
808
|
+
if(Build.VERSION.SDK_INT < 29 && permission.equals("ACCESS_BACKGROUND_LOCATION")){
|
|
809
|
+
// This version of Android doesn't support background location permission so use standard coarse location permission
|
|
810
|
+
permission = "ACCESS_COARSE_LOCATION";
|
|
811
|
+
}
|
|
812
|
+
if(Build.VERSION.SDK_INT < 29 && permission.equals("ACTIVITY_RECOGNITION")){
|
|
813
|
+
// This version of Android doesn't support activity recognition permission so check for body sensors permission
|
|
814
|
+
permission = "BODY_SENSORS";
|
|
815
|
+
}
|
|
816
|
+
String status;
|
|
817
|
+
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
|
|
818
|
+
boolean showRationale = shouldShowRequestPermissionRationale(this.cordova.getActivity(), androidPermission);
|
|
819
|
+
if (!showRationale) {
|
|
820
|
+
if(isPermissionRequested(permission)){
|
|
821
|
+
// user denied WITH "never ask again"
|
|
822
|
+
status = Diagnostic.STATUS_DENIED_ALWAYS;
|
|
823
|
+
}else{
|
|
824
|
+
// The app doesn't have permission and the user has not been asked for the permission before
|
|
825
|
+
status = Diagnostic.STATUS_NOT_REQUESTED;
|
|
826
|
+
}
|
|
827
|
+
} else {
|
|
828
|
+
// user denied WITHOUT "never ask again"
|
|
829
|
+
status = Diagnostic.STATUS_DENIED_ONCE;
|
|
830
|
+
}
|
|
831
|
+
} else {
|
|
832
|
+
// Permission granted
|
|
833
|
+
status = Diagnostic.STATUS_GRANTED;
|
|
834
|
+
}
|
|
835
|
+
statuses.put(permission, status);
|
|
836
|
+
Log.v(TAG, "Authorisation for " + permission + " is " + statuses.get(permission));
|
|
837
|
+
clearRequest(requestCode);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
Class<?> externalStorageClass = null;
|
|
841
|
+
try {
|
|
842
|
+
externalStorageClass = Class.forName(externalStorageClassName);
|
|
843
|
+
} catch( ClassNotFoundException e ){}
|
|
844
|
+
|
|
845
|
+
if(requestCode == GET_EXTERNAL_SD_CARD_DETAILS_PERMISSION_REQUEST && externalStorageClass != null){
|
|
846
|
+
Method method = externalStorageClass.getMethod("onReceivePermissionResult");
|
|
847
|
+
method.invoke(null);
|
|
848
|
+
}else{
|
|
849
|
+
context.success(statuses);
|
|
850
|
+
}
|
|
851
|
+
}catch(Exception e ) {
|
|
852
|
+
handleError("Exception occurred onRequestPermissionsResult: ".concat(e.getMessage()), requestCode);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
}
|