@capacitor-plus/android 8.0.0-beta.0
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/LICENSE +21 -0
- package/capacitor/build.gradle +94 -0
- package/capacitor/lint-baseline.xml +136 -0
- package/capacitor/lint.xml +9 -0
- package/capacitor/proguard-rules.pro +28 -0
- package/capacitor/src/main/AndroidManifest.xml +3 -0
- package/capacitor/src/main/assets/native-bridge.js +1029 -0
- package/capacitor/src/main/java/com/getcapacitor/AndroidProtocolHandler.java +94 -0
- package/capacitor/src/main/java/com/getcapacitor/App.java +61 -0
- package/capacitor/src/main/java/com/getcapacitor/AppUUID.java +65 -0
- package/capacitor/src/main/java/com/getcapacitor/Bridge.java +1627 -0
- package/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java +212 -0
- package/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java +467 -0
- package/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +105 -0
- package/capacitor/src/main/java/com/getcapacitor/CapConfig.java +709 -0
- package/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java +57 -0
- package/capacitor/src/main/java/com/getcapacitor/FileUtils.java +303 -0
- package/capacitor/src/main/java/com/getcapacitor/InvalidPluginException.java +8 -0
- package/capacitor/src/main/java/com/getcapacitor/InvalidPluginMethodException.java +16 -0
- package/capacitor/src/main/java/com/getcapacitor/JSArray.java +51 -0
- package/capacitor/src/main/java/com/getcapacitor/JSExport.java +208 -0
- package/capacitor/src/main/java/com/getcapacitor/JSExportException.java +16 -0
- package/capacitor/src/main/java/com/getcapacitor/JSInjector.java +127 -0
- package/capacitor/src/main/java/com/getcapacitor/JSObject.java +164 -0
- package/capacitor/src/main/java/com/getcapacitor/JSValue.java +65 -0
- package/capacitor/src/main/java/com/getcapacitor/Logger.java +103 -0
- package/capacitor/src/main/java/com/getcapacitor/MessageHandler.java +157 -0
- package/capacitor/src/main/java/com/getcapacitor/NativePlugin.java +37 -0
- package/capacitor/src/main/java/com/getcapacitor/PermissionState.java +31 -0
- package/capacitor/src/main/java/com/getcapacitor/Plugin.java +1050 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginCall.java +394 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginConfig.java +116 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginHandle.java +160 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginInvocationException.java +16 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginLoadException.java +19 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginManager.java +56 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginMethod.java +15 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginMethodHandle.java +33 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginResult.java +84 -0
- package/capacitor/src/main/java/com/getcapacitor/ProcessedRoute.java +37 -0
- package/capacitor/src/main/java/com/getcapacitor/RouteProcessor.java +8 -0
- package/capacitor/src/main/java/com/getcapacitor/ServerPath.java +25 -0
- package/capacitor/src/main/java/com/getcapacitor/UriMatcher.java +184 -0
- package/capacitor/src/main/java/com/getcapacitor/WebViewListener.java +57 -0
- package/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +758 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/ActivityCallback.java +10 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/CapacitorPlugin.java +35 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/Permission.java +22 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/PermissionCallback.java +10 -0
- package/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java +42 -0
- package/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java +39 -0
- package/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java +282 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java +239 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookies.java +119 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorHttp.java +119 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java +220 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/WebView.java +48 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/AssetUtil.java +358 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java +473 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java +465 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/ICapacitorHttpUrlConnection.java +15 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/MimeType.java +17 -0
- package/capacitor/src/main/java/com/getcapacitor/util/HostMask.java +123 -0
- package/capacitor/src/main/java/com/getcapacitor/util/InternalUtils.java +27 -0
- package/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java +166 -0
- package/capacitor/src/main/java/com/getcapacitor/util/PermissionHelper.java +114 -0
- package/capacitor/src/main/java/com/getcapacitor/util/WebColor.java +28 -0
- package/capacitor/src/main/res/layout/capacitor_bridge_layout_main.xml +15 -0
- package/capacitor/src/main/res/layout/no_webview.xml +14 -0
- package/capacitor/src/main/res/values/colors.xml +6 -0
- package/capacitor/src/main/res/values/strings.xml +3 -0
- package/capacitor/src/main/res/values/styles.xml +6 -0
- package/package.json +31 -0
|
@@ -0,0 +1,1050 @@
|
|
|
1
|
+
package com.getcapacitor;
|
|
2
|
+
|
|
3
|
+
import android.app.Activity;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.Intent;
|
|
6
|
+
import android.content.pm.PackageManager;
|
|
7
|
+
import android.content.res.Configuration;
|
|
8
|
+
import android.net.Uri;
|
|
9
|
+
import android.os.Bundle;
|
|
10
|
+
import androidx.activity.result.ActivityResult;
|
|
11
|
+
import androidx.activity.result.ActivityResultLauncher;
|
|
12
|
+
import androidx.activity.result.contract.ActivityResultContracts;
|
|
13
|
+
import androidx.annotation.NonNull;
|
|
14
|
+
import androidx.annotation.Nullable;
|
|
15
|
+
import androidx.appcompat.app.AppCompatActivity;
|
|
16
|
+
import androidx.core.app.ActivityCompat;
|
|
17
|
+
import com.getcapacitor.annotation.ActivityCallback;
|
|
18
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
19
|
+
import com.getcapacitor.annotation.Permission;
|
|
20
|
+
import com.getcapacitor.annotation.PermissionCallback;
|
|
21
|
+
import com.getcapacitor.util.PermissionHelper;
|
|
22
|
+
import java.lang.reflect.InvocationTargetException;
|
|
23
|
+
import java.lang.reflect.Method;
|
|
24
|
+
import java.util.ArrayList;
|
|
25
|
+
import java.util.Arrays;
|
|
26
|
+
import java.util.HashMap;
|
|
27
|
+
import java.util.HashSet;
|
|
28
|
+
import java.util.List;
|
|
29
|
+
import java.util.Locale;
|
|
30
|
+
import java.util.Map;
|
|
31
|
+
import java.util.Set;
|
|
32
|
+
import java.util.concurrent.CopyOnWriteArrayList;
|
|
33
|
+
import org.json.JSONException;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Plugin is the base class for all plugins, containing a number of
|
|
37
|
+
* convenient features for interacting with the {@link Bridge}, managing
|
|
38
|
+
* plugin permissions, tracking lifecycle events, and more.
|
|
39
|
+
*
|
|
40
|
+
* You should inherit from this class when creating new plugins, along with
|
|
41
|
+
* adding the {@link CapacitorPlugin} annotation to add additional required
|
|
42
|
+
* metadata about the Plugin
|
|
43
|
+
*/
|
|
44
|
+
public class Plugin {
|
|
45
|
+
|
|
46
|
+
// The key we will use inside of a persisted Bundle for the JSON blob
|
|
47
|
+
// for a plugin call options.
|
|
48
|
+
private static final String BUNDLE_PERSISTED_OPTIONS_JSON_KEY = "_json";
|
|
49
|
+
|
|
50
|
+
// Reference to the Bridge
|
|
51
|
+
protected Bridge bridge;
|
|
52
|
+
|
|
53
|
+
// Reference to the PluginHandle wrapper for this Plugin
|
|
54
|
+
protected PluginHandle handle;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A way for plugins to quickly save a call that they will need to reference
|
|
58
|
+
* between activity/permissions starts/requests
|
|
59
|
+
*
|
|
60
|
+
* @deprecated store calls on the bridge using the methods
|
|
61
|
+
* {@link com.getcapacitor.Bridge#saveCall(PluginCall)},
|
|
62
|
+
* {@link com.getcapacitor.Bridge#getSavedCall(String)} and
|
|
63
|
+
* {@link com.getcapacitor.Bridge#releaseCall(PluginCall)}
|
|
64
|
+
*/
|
|
65
|
+
@Deprecated
|
|
66
|
+
protected PluginCall savedLastCall;
|
|
67
|
+
|
|
68
|
+
// Stored event listeners
|
|
69
|
+
private final Map<String, List<PluginCall>> eventListeners;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Launchers used by the plugin to handle activity results
|
|
73
|
+
*/
|
|
74
|
+
private final Map<String, ActivityResultLauncher<Intent>> activityLaunchers = new HashMap<>();
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Launchers used by the plugin to handle permission results
|
|
78
|
+
*/
|
|
79
|
+
private final Map<String, ActivityResultLauncher<String[]>> permissionLaunchers = new HashMap<>();
|
|
80
|
+
|
|
81
|
+
private String lastPluginCallId;
|
|
82
|
+
|
|
83
|
+
// Stored results of an event if an event was fired and
|
|
84
|
+
// no listeners were attached yet. Only stores the last value.
|
|
85
|
+
private final Map<String, List<JSObject>> retainedEventArguments;
|
|
86
|
+
|
|
87
|
+
public Plugin() {
|
|
88
|
+
eventListeners = new HashMap<>();
|
|
89
|
+
retainedEventArguments = new HashMap<>();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Called when the plugin has been connected to the bridge
|
|
94
|
+
* and is ready to start initializing.
|
|
95
|
+
*/
|
|
96
|
+
public void load() {}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Registers activity result launchers defined on plugins, used for permission requests and
|
|
100
|
+
* activities started for result.
|
|
101
|
+
*/
|
|
102
|
+
void initializeActivityLaunchers() {
|
|
103
|
+
List<Method> pluginClassMethods = new ArrayList<>();
|
|
104
|
+
for (
|
|
105
|
+
Class<?> pluginCursor = getClass();
|
|
106
|
+
!pluginCursor.getName().equals(Object.class.getName());
|
|
107
|
+
pluginCursor = pluginCursor.getSuperclass()
|
|
108
|
+
) {
|
|
109
|
+
pluginClassMethods.addAll(Arrays.asList(pluginCursor.getDeclaredMethods()));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (final Method method : pluginClassMethods) {
|
|
113
|
+
if (method.isAnnotationPresent(ActivityCallback.class)) {
|
|
114
|
+
// register callbacks annotated with ActivityCallback for activity results
|
|
115
|
+
ActivityResultLauncher<Intent> launcher = bridge.registerForActivityResult(
|
|
116
|
+
new ActivityResultContracts.StartActivityForResult(),
|
|
117
|
+
(result) -> triggerActivityCallback(method, result)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
activityLaunchers.put(method.getName(), launcher);
|
|
121
|
+
} else if (method.isAnnotationPresent(PermissionCallback.class)) {
|
|
122
|
+
// register callbacks annotated with PermissionCallback for permission results
|
|
123
|
+
ActivityResultLauncher<String[]> launcher = bridge.registerForActivityResult(
|
|
124
|
+
new ActivityResultContracts.RequestMultiplePermissions(),
|
|
125
|
+
(permissions) -> triggerPermissionCallback(method, permissions)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
permissionLaunchers.put(method.getName(), launcher);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private void triggerPermissionCallback(Method method, Map<String, Boolean> permissionResultMap) {
|
|
134
|
+
PluginCall savedCall = bridge.getPermissionCall(handle.getId());
|
|
135
|
+
|
|
136
|
+
// validate permissions and invoke the permission result callback
|
|
137
|
+
if (bridge.validatePermissions(this, savedCall, permissionResultMap)) {
|
|
138
|
+
try {
|
|
139
|
+
method.setAccessible(true);
|
|
140
|
+
method.invoke(this, savedCall);
|
|
141
|
+
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
142
|
+
e.printStackTrace();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private void triggerActivityCallback(Method method, ActivityResult result) {
|
|
148
|
+
PluginCall savedCall = bridge.getSavedCall(lastPluginCallId);
|
|
149
|
+
if (savedCall == null) {
|
|
150
|
+
savedCall = bridge.getPluginCallForLastActivity();
|
|
151
|
+
}
|
|
152
|
+
// invoke the activity result callback
|
|
153
|
+
try {
|
|
154
|
+
method.setAccessible(true);
|
|
155
|
+
method.invoke(this, savedCall, result);
|
|
156
|
+
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
157
|
+
e.printStackTrace();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Start activity for result with the provided Intent and resolve with the provided callback method name.
|
|
163
|
+
* <p>
|
|
164
|
+
* If there is no registered activity callback for the method name passed in, the call will
|
|
165
|
+
* be rejected. Make sure a valid activity result callback method is registered using the
|
|
166
|
+
* {@link ActivityCallback} annotation.
|
|
167
|
+
*
|
|
168
|
+
* @param call the plugin call
|
|
169
|
+
* @param intent the intent used to start an activity
|
|
170
|
+
* @param callbackName the name of the callback to run when the launched activity is finished
|
|
171
|
+
* @since 3.0.0
|
|
172
|
+
*/
|
|
173
|
+
public void startActivityForResult(PluginCall call, Intent intent, String callbackName) {
|
|
174
|
+
ActivityResultLauncher<Intent> activityResultLauncher = getActivityLauncherOrReject(call, callbackName);
|
|
175
|
+
if (activityResultLauncher == null) {
|
|
176
|
+
// return when null since call was rejected in getLauncherOrReject
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
bridge.setPluginCallForLastActivity(call);
|
|
180
|
+
lastPluginCallId = call.getCallbackId();
|
|
181
|
+
bridge.saveCall(call);
|
|
182
|
+
activityResultLauncher.launch(intent);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private void permissionActivityResult(PluginCall call, String[] permissionStrings, String callbackName) {
|
|
186
|
+
ActivityResultLauncher<String[]> permissionResultLauncher = getPermissionLauncherOrReject(call, callbackName);
|
|
187
|
+
if (permissionResultLauncher == null) {
|
|
188
|
+
// return when null since call was rejected in getLauncherOrReject
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
bridge.savePermissionCall(call);
|
|
193
|
+
permissionResultLauncher.launch(permissionStrings);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get the main {@link Context} for the current Activity (your app)
|
|
198
|
+
* @return the Context for the current activity
|
|
199
|
+
*/
|
|
200
|
+
public Context getContext() {
|
|
201
|
+
return this.bridge.getContext();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get the main {@link Activity} for the app
|
|
206
|
+
* @return the Activity for the current app
|
|
207
|
+
*/
|
|
208
|
+
public AppCompatActivity getActivity() {
|
|
209
|
+
return this.bridge.getActivity();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Set the Bridge instance for this plugin
|
|
214
|
+
* @param bridge
|
|
215
|
+
*/
|
|
216
|
+
public void setBridge(Bridge bridge) {
|
|
217
|
+
this.bridge = bridge;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get the Bridge instance for this plugin
|
|
222
|
+
*/
|
|
223
|
+
public Bridge getBridge() {
|
|
224
|
+
return this.bridge;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Set the wrapper {@link PluginHandle} instance for this plugin that
|
|
229
|
+
* contains additional metadata about the Plugin instance (such
|
|
230
|
+
* as indexed methods for reflection, and {@link CapacitorPlugin} annotation data).
|
|
231
|
+
* @param pluginHandle
|
|
232
|
+
*/
|
|
233
|
+
public void setPluginHandle(PluginHandle pluginHandle) {
|
|
234
|
+
this.handle = pluginHandle;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Return the wrapper {@link PluginHandle} for this plugin.
|
|
239
|
+
*
|
|
240
|
+
* This wrapper contains additional metadata about the plugin instance,
|
|
241
|
+
* such as indexed methods for reflection, and {@link CapacitorPlugin} annotation data).
|
|
242
|
+
* @return
|
|
243
|
+
*/
|
|
244
|
+
public PluginHandle getPluginHandle() {
|
|
245
|
+
return this.handle;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get the root App ID
|
|
250
|
+
* @return
|
|
251
|
+
*/
|
|
252
|
+
public String getAppId() {
|
|
253
|
+
return getContext().getPackageName();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Called to save a {@link PluginCall} in order to reference it
|
|
258
|
+
* later, such as in an activity or permissions result handler
|
|
259
|
+
* @deprecated use {@link Bridge#saveCall(PluginCall)}
|
|
260
|
+
*
|
|
261
|
+
* @param lastCall
|
|
262
|
+
*/
|
|
263
|
+
@Deprecated
|
|
264
|
+
public void saveCall(PluginCall lastCall) {
|
|
265
|
+
this.savedLastCall = lastCall;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Set the last saved call to null to free memory
|
|
270
|
+
* @deprecated use {@link PluginCall#release(Bridge)}
|
|
271
|
+
*/
|
|
272
|
+
@Deprecated
|
|
273
|
+
public void freeSavedCall() {
|
|
274
|
+
this.savedLastCall.release(bridge);
|
|
275
|
+
this.savedLastCall = null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Get the last saved call, if any
|
|
280
|
+
* @deprecated use {@link Bridge#getSavedCall(String)}
|
|
281
|
+
*
|
|
282
|
+
* @return
|
|
283
|
+
*/
|
|
284
|
+
@Deprecated
|
|
285
|
+
public PluginCall getSavedCall() {
|
|
286
|
+
return this.savedLastCall;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get the config options for this plugin.
|
|
291
|
+
*
|
|
292
|
+
* @return a config object representing the plugin config options, or an empty config
|
|
293
|
+
* if none exists
|
|
294
|
+
*/
|
|
295
|
+
public PluginConfig getConfig() {
|
|
296
|
+
return bridge.getConfig().getPluginConfiguration(handle.getId());
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get the value for a key on the config for this plugin.
|
|
301
|
+
* @deprecated use {@link #getConfig()} and access config values using the methods available
|
|
302
|
+
* depending on the type.
|
|
303
|
+
*
|
|
304
|
+
* @param key the key for the config value
|
|
305
|
+
* @return some object containing the value from the config
|
|
306
|
+
*/
|
|
307
|
+
@Deprecated
|
|
308
|
+
public Object getConfigValue(String key) {
|
|
309
|
+
try {
|
|
310
|
+
PluginConfig pluginConfig = getConfig();
|
|
311
|
+
return pluginConfig.getConfigJSON().get(key);
|
|
312
|
+
} catch (JSONException ex) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Check whether any of the given permissions has been defined in the AndroidManifest.xml
|
|
319
|
+
* @deprecated use {@link #isPermissionDeclared(String)}
|
|
320
|
+
*
|
|
321
|
+
* @param permissions
|
|
322
|
+
* @return
|
|
323
|
+
*/
|
|
324
|
+
@Deprecated
|
|
325
|
+
public boolean hasDefinedPermissions(String[] permissions) {
|
|
326
|
+
for (String permission : permissions) {
|
|
327
|
+
if (!PermissionHelper.hasDefinedPermission(getContext(), permission)) {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Check if all annotated permissions have been defined in the AndroidManifest.xml
|
|
336
|
+
* @deprecated use {@link #isPermissionDeclared(String)}
|
|
337
|
+
*
|
|
338
|
+
* @return true if permissions are all defined in the Manifest
|
|
339
|
+
*/
|
|
340
|
+
@Deprecated
|
|
341
|
+
public boolean hasDefinedRequiredPermissions() {
|
|
342
|
+
CapacitorPlugin annotation = handle.getPluginAnnotation();
|
|
343
|
+
if (annotation == null) {
|
|
344
|
+
// Check for legacy plugin annotation, @NativePlugin
|
|
345
|
+
NativePlugin legacyAnnotation = handle.getLegacyPluginAnnotation();
|
|
346
|
+
return hasDefinedPermissions(legacyAnnotation.permissions());
|
|
347
|
+
} else {
|
|
348
|
+
for (Permission perm : annotation.permissions()) {
|
|
349
|
+
for (String permString : perm.strings()) {
|
|
350
|
+
if (!PermissionHelper.hasDefinedPermission(getContext(), permString)) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Checks if the given permission alias is correctly declared in AndroidManifest.xml
|
|
362
|
+
* @param alias a permission alias defined on the plugin
|
|
363
|
+
* @return true only if all permissions associated with the given alias are declared in the manifest
|
|
364
|
+
*/
|
|
365
|
+
public boolean isPermissionDeclared(String alias) {
|
|
366
|
+
CapacitorPlugin annotation = handle.getPluginAnnotation();
|
|
367
|
+
if (annotation != null) {
|
|
368
|
+
for (Permission perm : annotation.permissions()) {
|
|
369
|
+
if (alias.equalsIgnoreCase(perm.alias())) {
|
|
370
|
+
boolean result = true;
|
|
371
|
+
for (String permString : perm.strings()) {
|
|
372
|
+
result = result && PermissionHelper.hasDefinedPermission(getContext(), permString);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
Logger.error(String.format("isPermissionDeclared: No alias defined for %s " + "or missing @CapacitorPlugin annotation.", alias));
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Check whether the given permission has been granted by the user
|
|
386
|
+
* @deprecated use {@link #getPermissionState(String)} and {@link #getPermissionStates()} to get
|
|
387
|
+
* the states of permissions defined on the Plugin in conjunction with the @CapacitorPlugin
|
|
388
|
+
* annotation. Use the Android API {@link ActivityCompat#checkSelfPermission(Context, String)}
|
|
389
|
+
* methods to check permissions with Android permission strings
|
|
390
|
+
*
|
|
391
|
+
* @param permission
|
|
392
|
+
* @return
|
|
393
|
+
*/
|
|
394
|
+
@Deprecated
|
|
395
|
+
public boolean hasPermission(String permission) {
|
|
396
|
+
return ActivityCompat.checkSelfPermission(this.getContext(), permission) == PackageManager.PERMISSION_GRANTED;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* If the plugin annotation specified a set of permissions, this method checks if each is
|
|
401
|
+
* granted
|
|
402
|
+
* @deprecated use {@link #getPermissionState(String)} or {@link #getPermissionStates()} to
|
|
403
|
+
* check whether permissions are granted or not
|
|
404
|
+
*
|
|
405
|
+
* @return
|
|
406
|
+
*/
|
|
407
|
+
@Deprecated
|
|
408
|
+
public boolean hasRequiredPermissions() {
|
|
409
|
+
CapacitorPlugin annotation = handle.getPluginAnnotation();
|
|
410
|
+
if (annotation == null) {
|
|
411
|
+
// Check for legacy plugin annotation, @NativePlugin
|
|
412
|
+
NativePlugin legacyAnnotation = handle.getLegacyPluginAnnotation();
|
|
413
|
+
for (String perm : legacyAnnotation.permissions()) {
|
|
414
|
+
if (ActivityCompat.checkSelfPermission(this.getContext(), perm) != PackageManager.PERMISSION_GRANTED) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
for (Permission perm : annotation.permissions()) {
|
|
423
|
+
for (String permString : perm.strings()) {
|
|
424
|
+
if (ActivityCompat.checkSelfPermission(this.getContext(), permString) != PackageManager.PERMISSION_GRANTED) {
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Request all of the specified permissions in the CapacitorPlugin annotation (if any)
|
|
435
|
+
*
|
|
436
|
+
* If there is no registered permission callback for the PluginCall passed in, the call will
|
|
437
|
+
* be rejected. Make sure a valid permission callback method is registered using the
|
|
438
|
+
* {@link PermissionCallback} annotation.
|
|
439
|
+
*
|
|
440
|
+
* @since 3.0.0
|
|
441
|
+
* @param call the plugin call
|
|
442
|
+
* @param callbackName the name of the callback to run when the permission request is complete
|
|
443
|
+
*/
|
|
444
|
+
protected void requestAllPermissions(@NonNull PluginCall call, @NonNull String callbackName) {
|
|
445
|
+
CapacitorPlugin annotation = handle.getPluginAnnotation();
|
|
446
|
+
if (annotation != null) {
|
|
447
|
+
HashSet<String> perms = new HashSet<>();
|
|
448
|
+
for (Permission perm : annotation.permissions()) {
|
|
449
|
+
perms.addAll(Arrays.asList(perm.strings()));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
permissionActivityResult(call, perms.toArray(new String[0]), callbackName);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Request permissions using an alias defined on the plugin.
|
|
458
|
+
*
|
|
459
|
+
* If there is no registered permission callback for the PluginCall passed in, the call will
|
|
460
|
+
* be rejected. Make sure a valid permission callback method is registered using the
|
|
461
|
+
* {@link PermissionCallback} annotation.
|
|
462
|
+
*
|
|
463
|
+
* @param alias an alias defined on the plugin
|
|
464
|
+
* @param call the plugin call involved in originating the request
|
|
465
|
+
* @param callbackName the name of the callback to run when the permission request is complete
|
|
466
|
+
*/
|
|
467
|
+
protected void requestPermissionForAlias(@NonNull String alias, @NonNull PluginCall call, @NonNull String callbackName) {
|
|
468
|
+
requestPermissionForAliases(new String[] { alias }, call, callbackName);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Request permissions using aliases defined on the plugin.
|
|
473
|
+
*
|
|
474
|
+
* If there is no registered permission callback for the PluginCall passed in, the call will
|
|
475
|
+
* be rejected. Make sure a valid permission callback method is registered using the
|
|
476
|
+
* {@link PermissionCallback} annotation.
|
|
477
|
+
*
|
|
478
|
+
* @param aliases a set of aliases defined on the plugin
|
|
479
|
+
* @param call the plugin call involved in originating the request
|
|
480
|
+
* @param callbackName the name of the callback to run when the permission request is complete
|
|
481
|
+
*/
|
|
482
|
+
protected void requestPermissionForAliases(@NonNull String[] aliases, @NonNull PluginCall call, @NonNull String callbackName) {
|
|
483
|
+
if (aliases.length == 0) {
|
|
484
|
+
Logger.error("No permission alias was provided");
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
String[] permissions = getPermissionStringsForAliases(aliases);
|
|
489
|
+
|
|
490
|
+
if (permissions.length > 0) {
|
|
491
|
+
permissionActivityResult(call, permissions, callbackName);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Gets the Android permission strings defined on the {@link CapacitorPlugin} annotation with
|
|
497
|
+
* the provided aliases.
|
|
498
|
+
*
|
|
499
|
+
* @param aliases aliases for permissions defined on the plugin
|
|
500
|
+
* @return Android permission strings associated with the provided aliases, if exists
|
|
501
|
+
*/
|
|
502
|
+
private String[] getPermissionStringsForAliases(@NonNull String[] aliases) {
|
|
503
|
+
CapacitorPlugin annotation = handle.getPluginAnnotation();
|
|
504
|
+
HashSet<String> perms = new HashSet<>();
|
|
505
|
+
for (Permission perm : annotation.permissions()) {
|
|
506
|
+
if (Arrays.asList(aliases).contains(perm.alias())) {
|
|
507
|
+
perms.addAll(Arrays.asList(perm.strings()));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return perms.toArray(new String[0]);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Gets the activity launcher associated with the calling methodName, or rejects the call if
|
|
516
|
+
* no registered launcher exists
|
|
517
|
+
*
|
|
518
|
+
* @param call the plugin call
|
|
519
|
+
* @param methodName the name of the activity callback method
|
|
520
|
+
* @return a launcher, or null if none found
|
|
521
|
+
*/
|
|
522
|
+
private @Nullable ActivityResultLauncher<Intent> getActivityLauncherOrReject(PluginCall call, String methodName) {
|
|
523
|
+
ActivityResultLauncher<Intent> activityLauncher = activityLaunchers.get(methodName);
|
|
524
|
+
|
|
525
|
+
// if there is no registered launcher, reject the call with an error and return null
|
|
526
|
+
if (activityLauncher == null) {
|
|
527
|
+
String registerError =
|
|
528
|
+
"There is no ActivityCallback method registered for the name: %s. " +
|
|
529
|
+
"Please define a callback method annotated with @ActivityCallback " +
|
|
530
|
+
"that receives arguments: (PluginCall, ActivityResult)";
|
|
531
|
+
registerError = String.format(Locale.US, registerError, methodName);
|
|
532
|
+
Logger.error(registerError);
|
|
533
|
+
call.reject(registerError);
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return activityLauncher;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Gets the permission launcher associated with the calling methodName, or rejects the call if
|
|
542
|
+
* no registered launcher exists
|
|
543
|
+
*
|
|
544
|
+
* @param call the plugin call
|
|
545
|
+
* @param methodName the name of the permission callback method
|
|
546
|
+
* @return a launcher, or null if none found
|
|
547
|
+
*/
|
|
548
|
+
private @Nullable ActivityResultLauncher<String[]> getPermissionLauncherOrReject(PluginCall call, String methodName) {
|
|
549
|
+
ActivityResultLauncher<String[]> permissionLauncher = permissionLaunchers.get(methodName);
|
|
550
|
+
|
|
551
|
+
// if there is no registered launcher, reject the call with an error and return null
|
|
552
|
+
if (permissionLauncher == null) {
|
|
553
|
+
String registerError =
|
|
554
|
+
"There is no PermissionCallback method registered for the name: %s. " +
|
|
555
|
+
"Please define a callback method annotated with @PermissionCallback " +
|
|
556
|
+
"that receives arguments: (PluginCall)";
|
|
557
|
+
registerError = String.format(Locale.US, registerError, methodName);
|
|
558
|
+
Logger.error(registerError);
|
|
559
|
+
call.reject(registerError);
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return permissionLauncher;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Request all of the specified permissions in the CapacitorPlugin annotation (if any)
|
|
568
|
+
*
|
|
569
|
+
* @deprecated use {@link #requestAllPermissions(PluginCall, String)} in conjunction with @CapacitorPlugin
|
|
570
|
+
*/
|
|
571
|
+
@Deprecated
|
|
572
|
+
public void pluginRequestAllPermissions() {
|
|
573
|
+
NativePlugin legacyAnnotation = handle.getLegacyPluginAnnotation();
|
|
574
|
+
ActivityCompat.requestPermissions(getActivity(), legacyAnnotation.permissions(), legacyAnnotation.permissionRequestCode());
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Helper for requesting a specific permission
|
|
579
|
+
*
|
|
580
|
+
* @param permission the permission to request
|
|
581
|
+
* @param requestCode the requestCode to use to associate the result with the plugin
|
|
582
|
+
* @deprecated use {@link #requestPermissionForAlias(String, PluginCall, String)} in conjunction with @CapacitorPlugin
|
|
583
|
+
*/
|
|
584
|
+
@Deprecated
|
|
585
|
+
public void pluginRequestPermission(String permission, int requestCode) {
|
|
586
|
+
ActivityCompat.requestPermissions(getActivity(), new String[] { permission }, requestCode);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Helper for requesting specific permissions
|
|
591
|
+
* @deprecated use {@link #requestPermissionForAliases(String[], PluginCall, String)} in conjunction
|
|
592
|
+
* with @CapacitorPlugin
|
|
593
|
+
*
|
|
594
|
+
* @param permissions the set of permissions to request
|
|
595
|
+
* @param requestCode the requestCode to use to associate the result with the plugin
|
|
596
|
+
*/
|
|
597
|
+
@Deprecated
|
|
598
|
+
public void pluginRequestPermissions(String[] permissions, int requestCode) {
|
|
599
|
+
ActivityCompat.requestPermissions(getActivity(), permissions, requestCode);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Get the permission state for the provided permission alias.
|
|
604
|
+
*
|
|
605
|
+
* @param alias the permission alias to get
|
|
606
|
+
* @return the state of the provided permission alias or null
|
|
607
|
+
*/
|
|
608
|
+
public PermissionState getPermissionState(String alias) {
|
|
609
|
+
return getPermissionStates().get(alias);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Helper to check all permissions defined on a plugin and see the state of each.
|
|
614
|
+
*
|
|
615
|
+
* @since 3.0.0
|
|
616
|
+
* @return A mapping of permission aliases to the associated granted status.
|
|
617
|
+
*/
|
|
618
|
+
public Map<String, PermissionState> getPermissionStates() {
|
|
619
|
+
return bridge.getPermissionStates(this);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Add a listener for the given event
|
|
624
|
+
* @param eventName
|
|
625
|
+
* @param call
|
|
626
|
+
*/
|
|
627
|
+
private void addEventListener(String eventName, PluginCall call) {
|
|
628
|
+
List<PluginCall> listeners = eventListeners.get(eventName);
|
|
629
|
+
if (listeners == null || listeners.isEmpty()) {
|
|
630
|
+
listeners = new ArrayList<>();
|
|
631
|
+
eventListeners.put(eventName, listeners);
|
|
632
|
+
|
|
633
|
+
// Must add the call before sending retained arguments
|
|
634
|
+
listeners.add(call);
|
|
635
|
+
|
|
636
|
+
sendRetainedArgumentsForEvent(eventName);
|
|
637
|
+
} else {
|
|
638
|
+
listeners.add(call);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Remove a listener from the given event
|
|
644
|
+
* @param eventName
|
|
645
|
+
* @param call
|
|
646
|
+
*/
|
|
647
|
+
private void removeEventListener(String eventName, PluginCall call) {
|
|
648
|
+
List<PluginCall> listeners = eventListeners.get(eventName);
|
|
649
|
+
if (listeners == null) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
listeners.remove(call);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Notify all listeners that an event occurred
|
|
658
|
+
* @param eventName
|
|
659
|
+
* @param data
|
|
660
|
+
*/
|
|
661
|
+
protected void notifyListeners(String eventName, JSObject data, boolean retainUntilConsumed) {
|
|
662
|
+
Logger.verbose(getLogTag(), "Notifying listeners for event " + eventName);
|
|
663
|
+
List<PluginCall> listeners = eventListeners.get(eventName);
|
|
664
|
+
if (listeners == null || listeners.isEmpty()) {
|
|
665
|
+
Logger.debug(getLogTag(), "No listeners found for event " + eventName);
|
|
666
|
+
if (retainUntilConsumed) {
|
|
667
|
+
List<JSObject> argList = retainedEventArguments.get(eventName);
|
|
668
|
+
|
|
669
|
+
if (argList == null) {
|
|
670
|
+
argList = new ArrayList<JSObject>();
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
argList.add(data);
|
|
674
|
+
retainedEventArguments.put(eventName, argList);
|
|
675
|
+
}
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
CopyOnWriteArrayList<PluginCall> listenersCopy = new CopyOnWriteArrayList(listeners);
|
|
680
|
+
for (PluginCall call : listenersCopy) {
|
|
681
|
+
call.resolve(data);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Notify all listeners that an event occurred
|
|
687
|
+
* This calls {@link Plugin#notifyListeners(String, JSObject, boolean)}
|
|
688
|
+
* with retainUntilConsumed set to false
|
|
689
|
+
* @param eventName
|
|
690
|
+
* @param data
|
|
691
|
+
*/
|
|
692
|
+
protected void notifyListeners(String eventName, JSObject data) {
|
|
693
|
+
notifyListeners(eventName, data, false);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Check if there are any listeners for the given event
|
|
698
|
+
*/
|
|
699
|
+
protected boolean hasListeners(String eventName) {
|
|
700
|
+
List<PluginCall> listeners = eventListeners.get(eventName);
|
|
701
|
+
if (listeners == null) {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
return !listeners.isEmpty();
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Send retained arguments (if any) for this event. This
|
|
709
|
+
* is called only when the first listener for an event is added
|
|
710
|
+
* @param eventName
|
|
711
|
+
*/
|
|
712
|
+
private void sendRetainedArgumentsForEvent(String eventName) {
|
|
713
|
+
// copy retained args and null source to prevent potential race conditions
|
|
714
|
+
List<JSObject> retainedArgs = retainedEventArguments.get(eventName);
|
|
715
|
+
if (retainedArgs == null) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
retainedEventArguments.remove(eventName);
|
|
720
|
+
|
|
721
|
+
for (JSObject retained : retainedArgs) {
|
|
722
|
+
notifyListeners(eventName, retained);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Exported plugin call for adding a listener to this plugin
|
|
728
|
+
* @param call
|
|
729
|
+
*/
|
|
730
|
+
@SuppressWarnings("unused")
|
|
731
|
+
@PluginMethod(returnType = PluginMethod.RETURN_NONE)
|
|
732
|
+
public void addListener(PluginCall call) {
|
|
733
|
+
String eventName = call.getString("eventName");
|
|
734
|
+
call.setKeepAlive(true);
|
|
735
|
+
addEventListener(eventName, call);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Exported plugin call to remove a listener from this plugin
|
|
740
|
+
* @param call
|
|
741
|
+
*/
|
|
742
|
+
@SuppressWarnings("unused")
|
|
743
|
+
@PluginMethod(returnType = PluginMethod.RETURN_NONE)
|
|
744
|
+
public void removeListener(PluginCall call) {
|
|
745
|
+
String eventName = call.getString("eventName");
|
|
746
|
+
String callbackId = call.getString("callbackId");
|
|
747
|
+
PluginCall savedCall = bridge.getSavedCall(callbackId);
|
|
748
|
+
if (savedCall != null) {
|
|
749
|
+
removeEventListener(eventName, savedCall);
|
|
750
|
+
bridge.releaseCall(savedCall);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Exported plugin call to remove all listeners from this plugin
|
|
756
|
+
* @param call
|
|
757
|
+
*/
|
|
758
|
+
@SuppressWarnings("unused")
|
|
759
|
+
@PluginMethod(returnType = PluginMethod.RETURN_PROMISE)
|
|
760
|
+
public void removeAllListeners(PluginCall call) {
|
|
761
|
+
eventListeners.clear();
|
|
762
|
+
call.resolve();
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
public void removeAllListeners() {
|
|
766
|
+
eventListeners.clear();
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Exported plugin call for checking the granted status for each permission
|
|
771
|
+
* declared on the plugin. This plugin call responds with a mapping of permissions to
|
|
772
|
+
* the associated granted status.
|
|
773
|
+
*
|
|
774
|
+
* @since 3.0.0
|
|
775
|
+
*/
|
|
776
|
+
@PluginMethod
|
|
777
|
+
@PermissionCallback
|
|
778
|
+
public void checkPermissions(PluginCall pluginCall) {
|
|
779
|
+
Map<String, PermissionState> permissionsResult = getPermissionStates();
|
|
780
|
+
|
|
781
|
+
if (permissionsResult.size() == 0) {
|
|
782
|
+
// if no permissions are defined on the plugin, resolve undefined
|
|
783
|
+
pluginCall.resolve();
|
|
784
|
+
} else {
|
|
785
|
+
JSObject permissionsResultJSON = new JSObject();
|
|
786
|
+
for (Map.Entry<String, PermissionState> entry : permissionsResult.entrySet()) {
|
|
787
|
+
permissionsResultJSON.put(entry.getKey(), entry.getValue());
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
pluginCall.resolve(permissionsResultJSON);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Exported plugin call to request all permissions for this plugin.
|
|
796
|
+
* To manually request permissions within a plugin use:
|
|
797
|
+
* {@link #requestAllPermissions(PluginCall, String)}, or
|
|
798
|
+
* {@link #requestPermissionForAlias(String, PluginCall, String)}, or
|
|
799
|
+
* {@link #requestPermissionForAliases(String[], PluginCall, String)}
|
|
800
|
+
*
|
|
801
|
+
* @param call the plugin call
|
|
802
|
+
*/
|
|
803
|
+
@PluginMethod
|
|
804
|
+
public void requestPermissions(PluginCall call) {
|
|
805
|
+
CapacitorPlugin annotation = handle.getPluginAnnotation();
|
|
806
|
+
if (annotation == null) {
|
|
807
|
+
handleLegacyPermission(call);
|
|
808
|
+
} else {
|
|
809
|
+
// handle permission requests for plugins defined with @CapacitorPlugin (since 3.0.0)
|
|
810
|
+
String[] permAliases = null;
|
|
811
|
+
Set<String> autoGrantPerms = new HashSet<>();
|
|
812
|
+
|
|
813
|
+
// If call was made with a list of specific permission aliases to request, save them
|
|
814
|
+
// to be requested
|
|
815
|
+
JSArray providedPerms = call.getArray("permissions");
|
|
816
|
+
List<String> providedPermsList = null;
|
|
817
|
+
|
|
818
|
+
if (providedPerms != null) {
|
|
819
|
+
try {
|
|
820
|
+
providedPermsList = providedPerms.toList();
|
|
821
|
+
} catch (JSONException ignore) {
|
|
822
|
+
// do nothing
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// If call was made without any custom permissions, request all from plugin annotation
|
|
827
|
+
Set<String> aliasSet = new HashSet<>();
|
|
828
|
+
if (providedPermsList == null || providedPermsList.isEmpty()) {
|
|
829
|
+
for (Permission perm : annotation.permissions()) {
|
|
830
|
+
// If a permission is defined with no permission strings, separate it for auto-granting.
|
|
831
|
+
// Otherwise, the alias is added to the list to be requested.
|
|
832
|
+
if (perm.strings().length == 0 || (perm.strings().length == 1 && perm.strings()[0].isEmpty())) {
|
|
833
|
+
if (!perm.alias().isEmpty()) {
|
|
834
|
+
autoGrantPerms.add(perm.alias());
|
|
835
|
+
}
|
|
836
|
+
} else {
|
|
837
|
+
aliasSet.add(perm.alias());
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
permAliases = aliasSet.toArray(new String[0]);
|
|
842
|
+
} else {
|
|
843
|
+
for (Permission perm : annotation.permissions()) {
|
|
844
|
+
if (providedPermsList.contains(perm.alias())) {
|
|
845
|
+
aliasSet.add(perm.alias());
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (aliasSet.isEmpty()) {
|
|
850
|
+
call.reject("No valid permission alias was requested of this plugin.");
|
|
851
|
+
} else {
|
|
852
|
+
permAliases = aliasSet.toArray(new String[0]);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (permAliases != null && permAliases.length > 0) {
|
|
857
|
+
// request permissions using provided aliases or all defined on the plugin
|
|
858
|
+
requestPermissionForAliases(permAliases, call, "checkPermissions");
|
|
859
|
+
} else if (!autoGrantPerms.isEmpty()) {
|
|
860
|
+
// if the plugin only has auto-grant permissions, return all as GRANTED
|
|
861
|
+
JSObject permissionsResults = new JSObject();
|
|
862
|
+
|
|
863
|
+
for (String perm : autoGrantPerms) {
|
|
864
|
+
permissionsResults.put(perm, PermissionState.GRANTED.toString());
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
call.resolve(permissionsResults);
|
|
868
|
+
} else {
|
|
869
|
+
// no permissions are defined on the plugin, resolve undefined
|
|
870
|
+
call.resolve();
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
@SuppressWarnings("deprecation")
|
|
876
|
+
private void handleLegacyPermission(PluginCall call) {
|
|
877
|
+
// handle permission requests for plugins defined with @NativePlugin (prior to 3.0.0)
|
|
878
|
+
NativePlugin legacyAnnotation = this.handle.getLegacyPluginAnnotation();
|
|
879
|
+
String[] perms = legacyAnnotation.permissions();
|
|
880
|
+
if (perms.length > 0) {
|
|
881
|
+
saveCall(call);
|
|
882
|
+
pluginRequestPermissions(perms, legacyAnnotation.permissionRequestCode());
|
|
883
|
+
} else {
|
|
884
|
+
call.resolve();
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* Handle request permissions result. A plugin using the deprecated {@link NativePlugin}
|
|
890
|
+
* should override this to handle the result, or this method will handle the result
|
|
891
|
+
* for our convenient requestPermissions call.
|
|
892
|
+
* @deprecated in favor of using callbacks in conjunction with {@link CapacitorPlugin}
|
|
893
|
+
*
|
|
894
|
+
* @param requestCode
|
|
895
|
+
* @param permissions
|
|
896
|
+
* @param grantResults
|
|
897
|
+
*/
|
|
898
|
+
@Deprecated
|
|
899
|
+
protected void handleRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
900
|
+
if (!hasDefinedPermissions(permissions)) {
|
|
901
|
+
StringBuilder builder = new StringBuilder();
|
|
902
|
+
builder.append("Missing the following permissions in AndroidManifest.xml:\n");
|
|
903
|
+
String[] missing = PermissionHelper.getUndefinedPermissions(getContext(), permissions);
|
|
904
|
+
for (String perm : missing) {
|
|
905
|
+
builder.append(perm + "\n");
|
|
906
|
+
}
|
|
907
|
+
savedLastCall.reject(builder.toString());
|
|
908
|
+
savedLastCall = null;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Called before the app is destroyed to give a plugin the chance to
|
|
914
|
+
* save the last call options for a saved plugin. By default, this
|
|
915
|
+
* method saves the full JSON blob of the options call. Since Bundle sizes
|
|
916
|
+
* may be limited, plugins that expect to be called with large data
|
|
917
|
+
* objects (such as a file), should override this method and selectively
|
|
918
|
+
* store option values in a {@link Bundle} to avoid exceeding limits.
|
|
919
|
+
* @return a new {@link Bundle} with fields set from the options of the last saved {@link PluginCall}
|
|
920
|
+
*/
|
|
921
|
+
protected Bundle saveInstanceState() {
|
|
922
|
+
PluginCall savedCall = bridge.getSavedCall(lastPluginCallId);
|
|
923
|
+
|
|
924
|
+
if (savedCall == null) {
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
Bundle ret = new Bundle();
|
|
929
|
+
JSObject callData = savedCall.getData();
|
|
930
|
+
|
|
931
|
+
if (callData != null) {
|
|
932
|
+
ret.putString(BUNDLE_PERSISTED_OPTIONS_JSON_KEY, callData.toString());
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
return ret;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Called when the app is opened with a previously un-handled
|
|
940
|
+
* activity response. If the plugin that started the activity
|
|
941
|
+
* stored data in {@link Plugin#saveInstanceState()} then this
|
|
942
|
+
* method will be called to allow the plugin to restore from that.
|
|
943
|
+
* @param state
|
|
944
|
+
*/
|
|
945
|
+
protected void restoreState(Bundle state) {}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Handle activity result, should be overridden by each plugin
|
|
949
|
+
*
|
|
950
|
+
* @deprecated provide a callback method using the {@link ActivityCallback} annotation and use
|
|
951
|
+
* the {@link #startActivityForResult(PluginCall, Intent, String)} method
|
|
952
|
+
*
|
|
953
|
+
* @param requestCode
|
|
954
|
+
* @param resultCode
|
|
955
|
+
* @param data
|
|
956
|
+
*/
|
|
957
|
+
@Deprecated
|
|
958
|
+
protected void handleOnActivityResult(int requestCode, int resultCode, Intent data) {}
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Handle onNewIntent
|
|
962
|
+
* @param intent
|
|
963
|
+
*/
|
|
964
|
+
protected void handleOnNewIntent(Intent intent) {}
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* Handle onConfigurationChanged
|
|
968
|
+
* @param newConfig
|
|
969
|
+
*/
|
|
970
|
+
protected void handleOnConfigurationChanged(Configuration newConfig) {}
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Handle onStart
|
|
974
|
+
*/
|
|
975
|
+
protected void handleOnStart() {}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Handle onRestart
|
|
979
|
+
*/
|
|
980
|
+
protected void handleOnRestart() {}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Handle onResume
|
|
984
|
+
*/
|
|
985
|
+
protected void handleOnResume() {}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Handle onPause
|
|
989
|
+
*/
|
|
990
|
+
protected void handleOnPause() {}
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* Handle onStop
|
|
994
|
+
*/
|
|
995
|
+
protected void handleOnStop() {}
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
* Handle onDestroy
|
|
999
|
+
*/
|
|
1000
|
+
protected void handleOnDestroy() {}
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* Give the plugins a chance to take control when a URL is about to be loaded in the WebView.
|
|
1004
|
+
* Returning true causes the WebView to abort loading the URL.
|
|
1005
|
+
* Returning false causes the WebView to continue loading the URL.
|
|
1006
|
+
* Returning null will defer to the default Capacitor policy
|
|
1007
|
+
*/
|
|
1008
|
+
@SuppressWarnings("unused")
|
|
1009
|
+
public Boolean shouldOverrideLoad(Uri url) {
|
|
1010
|
+
return null;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/**
|
|
1014
|
+
* Start a new Activity.
|
|
1015
|
+
*
|
|
1016
|
+
* Note: This method must be used by all plugins instead of calling
|
|
1017
|
+
* {@link Activity#startActivityForResult} as it associates the plugin with
|
|
1018
|
+
* any resulting data from the new Activity even if this app
|
|
1019
|
+
* is destroyed by the OS (to free up memory, for example).
|
|
1020
|
+
* @param intent
|
|
1021
|
+
* @param resultCode
|
|
1022
|
+
*/
|
|
1023
|
+
@Deprecated
|
|
1024
|
+
protected void startActivityForResult(PluginCall call, Intent intent, int resultCode) {
|
|
1025
|
+
bridge.startActivityForPluginWithResult(call, intent, resultCode);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Execute the given runnable on the Bridge's task handler
|
|
1030
|
+
* @param runnable
|
|
1031
|
+
*/
|
|
1032
|
+
public void execute(Runnable runnable) {
|
|
1033
|
+
bridge.execute(runnable);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* Shortcut for getting the plugin log tag
|
|
1038
|
+
* @param subTags
|
|
1039
|
+
*/
|
|
1040
|
+
protected String getLogTag(String... subTags) {
|
|
1041
|
+
return Logger.tags(subTags);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Gets a plugin log tag with the child's class name as subTag.
|
|
1046
|
+
*/
|
|
1047
|
+
protected String getLogTag() {
|
|
1048
|
+
return Logger.tags(this.getClass().getSimpleName());
|
|
1049
|
+
}
|
|
1050
|
+
}
|