@cloudflare/realtimekit-react-native 0.0.0 → 0.0.1

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.
Files changed (83) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +83 -0
  3. package/RealtimeKitCore.podspec +19 -0
  4. package/android/build.gradle +58 -0
  5. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  6. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  7. package/android/gradlew +185 -0
  8. package/android/gradlew.bat +89 -0
  9. package/android/src/main/AndroidManifest.xml +23 -0
  10. package/android/src/main/java/com/reactnativecore/BackgroundTimer/RNBackgroundTimer.java +97 -0
  11. package/android/src/main/java/com/reactnativecore/Constants.java +14 -0
  12. package/android/src/main/java/com/reactnativecore/CoreModule.java +49 -0
  13. package/android/src/main/java/com/reactnativecore/CorePackage.java +34 -0
  14. package/android/src/main/java/com/reactnativecore/DyteHelperModule.java +268 -0
  15. package/android/src/main/java/com/reactnativecore/DyteHolder.java +7 -0
  16. package/android/src/main/java/com/reactnativecore/ForegroundService.java +48 -0
  17. package/android/src/main/java/com/reactnativecore/NotificationHelper.java +127 -0
  18. package/android/src/main/java/com/reactnativecore/RNPermissionsModule.java +226 -0
  19. package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCBluetoothManager.java +637 -0
  20. package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCProximitySensor.java +133 -0
  21. package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCUtils.java +41 -0
  22. package/android/src/main/java/com/reactnativecore/incallmanager/InCallManagerModule.java +1881 -0
  23. package/android/src/main/java/com/reactnativecore/incallmanager/InCallProximityManager.java +162 -0
  24. package/android/src/main/java/com/reactnativecore/incallmanager/InCallWakeLockUtils.java +116 -0
  25. package/android/src/main/java/com/reactnativecore/incallmanager/ThreadUtils.java +39 -0
  26. package/app.plugin.js +1 -0
  27. package/ios/BroadcastEventEmitter.h +11 -0
  28. package/ios/BroadcastEventEmitter.m +72 -0
  29. package/ios/Core.h +5 -0
  30. package/ios/Core.m +28 -0
  31. package/ios/Core.xcodeproj/project.pbxproj +287 -0
  32. package/ios/DyteRNBackgroundTimer.h +22 -0
  33. package/ios/DyteRNBackgroundTimer.m +90 -0
  34. package/ios/DyteRNPermissionHandlerNotifications.h +17 -0
  35. package/ios/DyteRNPermissionHandlerNotifications.m +127 -0
  36. package/ios/DyteRNPermissions.h +50 -0
  37. package/ios/DyteRNPermissions.m +275 -0
  38. package/ios/DyteScreensharePickerView.h +8 -0
  39. package/ios/DyteScreensharePickerView.m +27 -0
  40. package/ios/PrivacyInfo.xcprivacy +60 -0
  41. package/ios/RNInCallManager.h +16 -0
  42. package/ios/RNInCallManager.m +1354 -0
  43. package/ios/permissions/DyteRNPermissionHandlerBluetoothPeripheral.h +4 -0
  44. package/ios/permissions/DyteRNPermissionHandlerBluetoothPeripheral.m +87 -0
  45. package/ios/permissions/DyteRNPermissionHandlerCamera.h +5 -0
  46. package/ios/permissions/DyteRNPermissionHandlerCamera.m +38 -0
  47. package/ios/permissions/DyteRNPermissionHandlerMicrophone.h +5 -0
  48. package/ios/permissions/DyteRNPermissionHandlerMicrophone.m +34 -0
  49. package/ios/permissions/DyteRNPermissionHandlerPhotoLibrary.h +8 -0
  50. package/ios/permissions/DyteRNPermissionHandlerPhotoLibrary.m +70 -0
  51. package/ios/screenshare/DyteDarwinNotificationCenter.swift +21 -0
  52. package/ios/screenshare/DyteScreenshareAtomic.swift +29 -0
  53. package/ios/screenshare/DyteScreenshareHandler.swift +103 -0
  54. package/ios/screenshare/DyteScreenshareUploader.swift +139 -0
  55. package/ios/screenshare/DyteSocketConnection.swift +190 -0
  56. package/lib/BackgroundHandler.d.ts +20 -0
  57. package/lib/BackgroundHandler.js +87 -0
  58. package/lib/LocalMediaError.d.ts +4 -0
  59. package/lib/LocalMediaError.js +6 -0
  60. package/lib/LocalMediaHandler.d.ts +118 -0
  61. package/lib/LocalMediaHandler.js +853 -0
  62. package/lib/LocalMediaInterfaces.d.ts +76 -0
  63. package/lib/LocalMediaInterfaces.js +1 -0
  64. package/lib/LocalMediaUtils.d.ts +93 -0
  65. package/lib/LocalMediaUtils.js +276 -0
  66. package/lib/NativeAudioManager.d.ts +16 -0
  67. package/lib/NativeAudioManager.js +93 -0
  68. package/lib/PermissionHandler.d.ts +34 -0
  69. package/lib/PermissionHandler.js +179 -0
  70. package/lib/ReactContext.d.ts +42 -0
  71. package/lib/ReactContext.js +96 -0
  72. package/lib/ReactHooks.d.ts +11 -0
  73. package/lib/ReactHooks.js +73 -0
  74. package/lib/index.d.ts +10 -0
  75. package/lib/index.js +40 -0
  76. package/lib/utils/crypto.d.ts +17 -0
  77. package/lib/utils/crypto.js +82 -0
  78. package/package.json +51 -4
  79. package/plugin/build/withDyte.d.ts +25 -0
  80. package/plugin/build/withDyte.js +100 -0
  81. package/plugin/src/withDyte.ts +150 -0
  82. package/plugin/tsconfig.json +10 -0
  83. package/plugin/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,268 @@
1
+ package com.reactnativecore;
2
+
3
+ import android.app.Activity;
4
+ import android.app.ActivityManager;
5
+ import android.content.ComponentName;
6
+ import android.content.Intent;
7
+ import android.content.Context;
8
+ import android.content.pm.ActivityInfo;
9
+ import android.os.Build;
10
+ import android.os.Handler;
11
+ import android.os.PowerManager;
12
+ import android.util.Log;
13
+ import android.view.WindowManager;
14
+
15
+ import com.reactnativecore.ForegroundService;
16
+ import com.facebook.react.bridge.Callback;
17
+ import com.facebook.react.bridge.LifecycleEventListener;
18
+ import com.facebook.react.bridge.Promise;
19
+ import com.facebook.react.bridge.ReactApplicationContext;
20
+ import com.facebook.react.bridge.ReactContext;
21
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
22
+ import com.facebook.react.bridge.ReactMethod;
23
+ import com.facebook.react.bridge.ReadableMap;
24
+ import com.facebook.react.module.annotations.ReactModule;
25
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
26
+
27
+ import java.io.Serializable;
28
+ import java.util.HashMap;
29
+
30
+ import com.reactnativecore.DyteHolder;
31
+
32
+ @ReactModule(name = "DyteHelperModule")
33
+ public class DyteHelperModule extends ReactContextBaseJavaModule {
34
+
35
+ private final ReactApplicationContext reactContext;
36
+ private static final String ERROR_INVALID_ACTIVITY = "E_INVALID_ACTIVITY";
37
+
38
+ // react-native-background-timer start
39
+ private Handler handler;
40
+ private ReactContext reactContext2;
41
+ private Runnable runnable;
42
+ private PowerManager powerManager;
43
+ private PowerManager.WakeLock wakeLock;
44
+ private int existingOrientation;
45
+ private boolean isForcedLandscapeToggled;
46
+ private final LifecycleEventListener listener = new LifecycleEventListener() {
47
+ @Override
48
+ public void onHostResume() {
49
+ }
50
+
51
+ @Override
52
+ public void onHostPause() {
53
+ }
54
+
55
+ @Override
56
+ public void onHostDestroy() {
57
+ if (wakeLock.isHeld())
58
+ wakeLock.release();
59
+ Intent intent = new Intent(getReactApplicationContext(), ForegroundService.class);
60
+ intent.setAction(Constants.ACTION_FOREGROUND_SERVICE_STOP);
61
+ getReactApplicationContext().stopService(intent);
62
+ }
63
+ };
64
+ // react-native-background-timer end
65
+
66
+ private class Request {
67
+
68
+ public boolean[] rationaleStatuses;
69
+ public Callback callback;
70
+
71
+ public Request(boolean[] rationaleStatuses, Callback callback) {
72
+ this.rationaleStatuses = rationaleStatuses;
73
+ this.callback = callback;
74
+ }
75
+ }
76
+
77
+ public DyteHelperModule(ReactApplicationContext reactContext) {
78
+ super(reactContext);
79
+ this.reactContext = reactContext;
80
+ this.powerManager = (PowerManager) getReactApplicationContext().getSystemService(reactContext.POWER_SERVICE);
81
+ this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "dytesdk:wakelock");
82
+ reactContext.addLifecycleEventListener(listener);
83
+ }
84
+
85
+ @Override
86
+ public String getName() {
87
+ return "DyteHelper";
88
+ }
89
+
90
+ @ReactMethod
91
+ public void createNotificationChannel(Promise promise) {
92
+ NotificationHelper.getInstance(getReactApplicationContext()).createNotificationChannel(promise);
93
+ }
94
+
95
+ @ReactMethod
96
+ public void startService(Promise promise) {
97
+ ComponentName mediaService;
98
+ DyteHolder.currActivity = this.getCurrentActivity();
99
+ Intent intent = new Intent(getReactApplicationContext(), ForegroundService.class);
100
+ intent.setAction(Constants.ACTION_FOREGROUND_SERVICE_START);
101
+ try{
102
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
103
+ mediaService = getReactApplicationContext().startForegroundService(intent);
104
+ } else {
105
+ mediaService = getReactApplicationContext().startService(intent);
106
+ }
107
+ } catch (RuntimeException e) {
108
+ // Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
109
+ // See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
110
+ Log.w("DyteHelperModule", "Media projection service not started", e);
111
+ return;
112
+ }
113
+ if (mediaService != null) {
114
+ promise.resolve(null);
115
+ } else {
116
+ promise.reject(Constants.ERROR_SERVICE_ERROR, "DyteForegroundService: Foreground service is not started");
117
+ }
118
+ }
119
+
120
+ @ReactMethod
121
+ public void stopService(Promise promise) {
122
+ Intent intent = new Intent(getReactApplicationContext(), ForegroundService.class);
123
+ intent.setAction(Constants.ACTION_FOREGROUND_SERVICE_STOP);
124
+ boolean stopped = getReactApplicationContext().stopService(intent);
125
+ if (stopped) {
126
+ promise.resolve(null);
127
+ } else {
128
+ promise.reject(Constants.ERROR_SERVICE_ERROR, "DyteForegroundService: Foreground service failed to stop");
129
+ }
130
+ }
131
+ @ReactMethod
132
+ private void isForegroundServiceRunning(Promise promise) {
133
+ ActivityManager manager = (ActivityManager) this.getCurrentActivity().getSystemService(getReactApplicationContext().ACTIVITY_SERVICE);
134
+ for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
135
+ if ((ForegroundService.class).getName().equals(service.service.getClassName())) {
136
+ promise.resolve(true);
137
+ }
138
+ }
139
+ promise.resolve(false);
140
+ }
141
+
142
+ @ReactMethod
143
+ public void activateScreenWake() {
144
+ final Activity activity = getCurrentActivity();
145
+
146
+ if (activity != null) {
147
+ activity.runOnUiThread(new Runnable() {
148
+ @Override
149
+ public void run() {
150
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
151
+ }
152
+ });
153
+ }
154
+ }
155
+
156
+ @ReactMethod
157
+ public void deactivateScreenWake() {
158
+ final Activity activity = getCurrentActivity();
159
+
160
+ if (activity != null) {
161
+ activity.runOnUiThread(new Runnable() {
162
+ @Override
163
+ public void run() {
164
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
165
+ }
166
+ });
167
+ }
168
+ }
169
+
170
+ @ReactMethod
171
+ public void forceLandscape() {
172
+ final Activity activity = getCurrentActivity();
173
+
174
+ if (activity != null) {
175
+ this.isForcedLandscapeToggled = true;
176
+ activity.runOnUiThread(new Runnable() {
177
+ @Override
178
+ public void run() {
179
+ existingOrientation = activity.getRequestedOrientation();
180
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
181
+ }
182
+ });
183
+ }
184
+ }
185
+
186
+ @ReactMethod
187
+ public void forcePotrait() {
188
+ final Activity activity = getCurrentActivity();
189
+
190
+ if (activity != null) {
191
+ this.isForcedLandscapeToggled = true;
192
+ activity.runOnUiThread(new Runnable() {
193
+ @Override
194
+ public void run() {
195
+ existingOrientation = activity.getRequestedOrientation();
196
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
197
+ }
198
+ });
199
+ }
200
+ }
201
+
202
+ @ReactMethod
203
+ public void resetOrientation() {
204
+ final Activity activity = getCurrentActivity();
205
+
206
+ if (activity != null) {
207
+ this.isForcedLandscapeToggled = false;
208
+ activity.runOnUiThread(new Runnable() {
209
+ @Override
210
+ public void run() {
211
+ activity.setRequestedOrientation(existingOrientation);
212
+ }
213
+ });
214
+ }
215
+ }
216
+
217
+ @ReactMethod
218
+ public void isForcedLandscape(Promise p) {
219
+ p.resolve(this.isForcedLandscapeToggled);
220
+ }
221
+
222
+ @ReactMethod
223
+ public void backgroundTimerStart(final int delay) {
224
+ if (!wakeLock.isHeld())
225
+ wakeLock.acquire();
226
+
227
+ handler = new Handler();
228
+ runnable = new Runnable() {
229
+ @Override
230
+ public void run() {
231
+ backgroundTimerSendEvent(reactContext, "backgroundTimer");
232
+ }
233
+ };
234
+
235
+ handler.post(runnable);
236
+ }
237
+
238
+ @ReactMethod
239
+ public void backgroundTimerStop() {
240
+ if (wakeLock.isHeld())
241
+ wakeLock.release();
242
+
243
+ // avoid null pointer exceptio when stop is called without start
244
+ if (handler != null)
245
+ handler.removeCallbacks(runnable);
246
+ }
247
+
248
+ private void backgroundTimerSendEvent(ReactContext reactContext, String eventName) {
249
+ reactContext
250
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
251
+ .emit(eventName, null);
252
+ }
253
+
254
+ @ReactMethod
255
+ public void backgroundTimerSetTimeout(final int id, final double timeout) {
256
+ Handler handler = new Handler();
257
+ handler.postDelayed(new Runnable() {
258
+ @Override
259
+ public void run() {
260
+ if (getReactApplicationContext().hasActiveCatalystInstance()) {
261
+ getReactApplicationContext()
262
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
263
+ .emit("backgroundTimer.timeout", id);
264
+ }
265
+ }
266
+ }, (long) timeout);
267
+ }
268
+ }
@@ -0,0 +1,7 @@
1
+ package com.reactnativecore;
2
+
3
+ import android.app.Activity;
4
+
5
+ public class DyteHolder {
6
+ public static Activity currActivity;
7
+ }
@@ -0,0 +1,48 @@
1
+ package com.reactnativecore;
2
+
3
+ import android.app.Notification;
4
+ import android.app.Service;
5
+ import android.content.Intent;
6
+ import android.content.Context;
7
+ import android.content.pm.ServiceInfo;
8
+ import android.os.Build;
9
+ import android.os.IBinder;
10
+ import android.util.Log;
11
+ import android.app.Activity;
12
+ import android.widget.Toast;
13
+ import com.reactnativecore.DyteHolder;
14
+
15
+ public class ForegroundService extends Service {
16
+ @Override
17
+ public IBinder onBind(Intent intent) {
18
+ return null;
19
+ }
20
+
21
+ public int onStartCommand(Intent intent, int flags, int startId) {
22
+ String action = intent.getAction();
23
+ if (action != null) {
24
+ if (action.equals(Constants.ACTION_FOREGROUND_SERVICE_START)) {
25
+ if(DyteHolder.currActivity!=null) {
26
+ NotificationHelper notificationHelper = NotificationHelper.getInstance(DyteHolder.currActivity);
27
+ Notification notification = notificationHelper.buildNotification(DyteHolder.currActivity);
28
+ if (notification != null) {
29
+ try {
30
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
31
+ startForeground(notificationHelper.NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION | ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
32
+ } else {
33
+ startForeground(notificationHelper.NOTIFICATION_ID, notification);
34
+ }
35
+ } catch (RuntimeException e) {
36
+ Log.w("ForegroundService", "Failed to start ForegroundService due to: ", e);
37
+ }
38
+ }
39
+ }
40
+
41
+ } else if (action.equals(Constants.ACTION_FOREGROUND_SERVICE_STOP)) {
42
+ stopSelf();
43
+ }
44
+ }
45
+ return START_NOT_STICKY;
46
+
47
+ }
48
+ }
@@ -0,0 +1,127 @@
1
+ package com.reactnativecore;
2
+
3
+ import android.app.Notification;
4
+ import android.app.NotificationChannel;
5
+ import android.app.NotificationManager;
6
+ import android.app.PendingIntent;
7
+ import android.content.Context;
8
+ import android.content.Intent;
9
+ import android.content.pm.ApplicationInfo;
10
+ import android.content.pm.PackageManager;
11
+ import android.graphics.Bitmap;
12
+ import android.graphics.drawable.BitmapDrawable;
13
+ import android.graphics.drawable.Drawable;
14
+ import android.os.Build;
15
+ import android.util.Log;
16
+ import androidx.core.app.NotificationCompat;
17
+
18
+ import com.facebook.react.bridge.Promise;
19
+
20
+ import java.util.Random;
21
+
22
+
23
+ class NotificationHelper {
24
+ public static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
25
+ private static final String CHANNEL_ID = "DyteNotificationChannel";
26
+ private static final String CHANNEL_NAME = "Ongoing Conference Notifications";
27
+ private static final String CHANNEL_DESC = "Ongoing Conference Notifications";
28
+
29
+ private static NotificationHelper instance = null;
30
+ private NotificationManager mNotificationManager;
31
+
32
+ public static synchronized NotificationHelper getInstance(Context context) {
33
+ if (instance == null) {
34
+ instance = new NotificationHelper(context);
35
+ }
36
+ return instance;
37
+ }
38
+
39
+ private NotificationHelper(Context context) {
40
+ mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
41
+
42
+ }
43
+
44
+ void createNotificationChannel(Promise promise) {
45
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
46
+ int channelImportance = NotificationManager.IMPORTANCE_DEFAULT;
47
+ boolean enableVibration = false;
48
+ NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, channelImportance);
49
+ channel.setDescription(CHANNEL_DESC);
50
+ channel.enableVibration(enableVibration);
51
+ mNotificationManager.createNotificationChannel(channel);
52
+ promise.resolve(null);
53
+ } else {
54
+ promise.reject(Constants.ERROR_ANDROID_VERSION, "DyteForegroundService: Notification channel can be created on Android O+");
55
+ }
56
+ }
57
+
58
+ Notification buildNotification(Context context) {
59
+ if (context == null) {
60
+ return null;
61
+ }
62
+ Intent notificationIntent = new Intent(context, context.getClass());
63
+ PendingIntent pendingIntent;
64
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
65
+ pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_MUTABLE);
66
+ }
67
+ else {
68
+ pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
69
+ }
70
+
71
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
72
+ final PackageManager packageManager = context.getPackageManager();
73
+ int appIconResId = android.R.mipmap.sym_def_app_icon;
74
+ Bitmap largeIcon = null;
75
+ try {
76
+ final ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
77
+ appIconResId=applicationInfo.icon;
78
+ Drawable drawable=applicationInfo.loadIcon(packageManager);
79
+ largeIcon = ((BitmapDrawable)drawable).getBitmap();
80
+ } catch (Exception e) {
81
+ //pass
82
+ }
83
+
84
+ builder
85
+ .setCategory(NotificationCompat.CATEGORY_CALL)
86
+ .setContentTitle("Ongoing Meeting")
87
+ .setContentText("Tap to return to the meeting")
88
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
89
+ .setContentIntent(pendingIntent)
90
+ .setOngoing(true)
91
+ .setWhen(System.currentTimeMillis())
92
+ .setUsesChronometer(true)
93
+ .setAutoCancel(false)
94
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
95
+ .setOnlyAlertOnce(true)
96
+ .setSmallIcon(appIconResId);
97
+
98
+ if(largeIcon != null){
99
+ builder.setLargeIcon(largeIcon);
100
+ }
101
+
102
+ return builder.build();
103
+ }
104
+
105
+ private Class getMainActivityClass(Context context) {
106
+ String packageName = context.getPackageName();
107
+ Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
108
+ if (launchIntent == null || launchIntent.getComponent() == null) {
109
+ // Log.e("NotificationHelper", "Failed to get launch intent or component");
110
+ return null;
111
+ }
112
+ try {
113
+ return Class.forName(launchIntent.getComponent().getClassName());
114
+ } catch (ClassNotFoundException e) {
115
+ // Log.e("NotificationHelper", "Failed to get main activity class");
116
+ return null;
117
+ }
118
+ }
119
+
120
+ private int getResourceIdForResourceName(Context context, String resourceName) {
121
+ int resourceId = context.getResources().getIdentifier(resourceName, "drawable", context.getPackageName());
122
+ if (resourceId == 0) {
123
+ resourceId = context.getResources().getIdentifier(resourceName, "mipmap", context.getPackageName());
124
+ }
125
+ return resourceId;
126
+ }
127
+ }
@@ -0,0 +1,226 @@
1
+ package com.reactnativecore;
2
+
3
+ import android.Manifest;
4
+ import android.app.Activity;
5
+ import android.content.Context;
6
+ import android.content.pm.PackageManager;
7
+ import android.os.Build;
8
+ import android.util.SparseArray;
9
+ import android.os.Process;
10
+ import android.util.Log;
11
+
12
+ import androidx.annotation.Nullable;
13
+
14
+ import com.facebook.react.bridge.Callback;
15
+ import com.facebook.react.bridge.Promise;
16
+ import com.facebook.react.bridge.ReactApplicationContext;
17
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
18
+ import com.facebook.react.bridge.ReactMethod;
19
+ import com.facebook.react.bridge.ReadableArray;
20
+ import com.facebook.react.bridge.WritableMap;
21
+ import com.facebook.react.bridge.WritableNativeMap;
22
+ import com.facebook.react.modules.core.PermissionListener;
23
+ import com.facebook.react.modules.core.PermissionAwareActivity;
24
+ import java.util.ArrayList;
25
+
26
+ public class RNPermissionsModule extends ReactContextBaseJavaModule implements PermissionListener {
27
+
28
+ private final ReactApplicationContext reactContext;
29
+
30
+ private final SparseArray<Request> mRequests = new SparseArray<Request>();
31
+ private final String GRANTED = "granted";
32
+ private final String DENIED = "denied";
33
+ private final String UNAVAILABLE = "unavailable";
34
+ private final String BLOCKED = "blocked";
35
+ private final String PROMPTED = "prompted";
36
+ private int mRequestCode = 0;
37
+ private static final String ERROR_INVALID_ACTIVITY = "E_INVALID_ACTIVITY";
38
+
39
+
40
+ private class Request {
41
+
42
+ public boolean[] rationaleStatuses;
43
+ public Callback callback;
44
+
45
+ public Request(boolean[] rationaleStatuses, Callback callback) {
46
+ this.rationaleStatuses = rationaleStatuses;
47
+ this.callback = callback;
48
+ }
49
+ }
50
+
51
+ public RNPermissionsModule(ReactApplicationContext reactContext) {
52
+ super(reactContext);
53
+ this.reactContext = reactContext;
54
+ }
55
+
56
+ @Override
57
+ public String getName() {
58
+ return "DyteRNPermissions";
59
+ }
60
+
61
+
62
+ private @Nullable
63
+ String getFieldName(final String permission) {
64
+ if (permission.equals("android.permission.CAMERA"))
65
+ return "CAMERA";
66
+ if (permission.equals("android.permission.BLUETOOTH"))
67
+ return "BLUETOOTH";
68
+ if (permission.equals("android.permission.BLUETOOTH_CONNECT"))
69
+ return "BLUETOOTH_CONNECT";
70
+ if (permission.equals("android.permission.READ_EXTERNAL_STORAGE"))
71
+ return "READ_EXTERNAL_STORAGE";
72
+ if (permission.equals("android.permission.READ_PHONE_STATE"))
73
+ return "READ_PHONE_STATE";
74
+ if (permission.equals("android.permission.RECORD_AUDIO"))
75
+ return "RECORD_AUDIO";
76
+ if (permission.equals("android.permission.USE_SIP"))
77
+ return "USE_SIP";
78
+ if (permission.equals("android.permission.WRITE_EXTERNAL_STORAGE"))
79
+ return "WRITE_EXTERNAL_STORAGE";
80
+ if (permission.equals("android.permission.ACCESS_FINE_LOCATION"))
81
+ return "ACCESS_FINE_LOCATION";
82
+ return null;
83
+ }
84
+
85
+ private boolean permissionExists(final String permission) {
86
+ String fieldName = getFieldName(permission);
87
+ if (fieldName == null)
88
+ return false;
89
+
90
+ try {
91
+ Manifest.permission.class.getField(fieldName);
92
+ return true;
93
+ } catch (NoSuchFieldException ignored) {
94
+ return false;
95
+ }
96
+ }
97
+
98
+ @ReactMethod
99
+ public void checkMultiplePermissions(final ReadableArray permissions, final Promise promise) {
100
+ final WritableMap output = new WritableNativeMap();
101
+ final ArrayList<String> permissionsToCheck = new ArrayList<String>();
102
+ int checkedPermissionsCount = 0;
103
+
104
+ Context context = getReactApplicationContext().getBaseContext();
105
+
106
+ for (int i = 0; i < permissions.size(); i++) {
107
+ String permission = permissions.getString(i);
108
+
109
+ if (!permissionExists(permission)) {
110
+ output.putString(permission, UNAVAILABLE);
111
+ } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
112
+ output.putString(
113
+ permission,
114
+ context.checkPermission(permission, Process.myPid(), Process.myUid())
115
+ == PackageManager.PERMISSION_GRANTED
116
+ ? GRANTED
117
+ : BLOCKED);
118
+ } else if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) {
119
+ int x = context.checkSelfPermission(permission);
120
+ output.putString(permission, GRANTED);
121
+ } else {
122
+ output.putString(permission, PROMPTED);
123
+ }
124
+ }
125
+
126
+ promise.resolve(output);
127
+ return;
128
+ }
129
+
130
+ @ReactMethod
131
+ public void requestMultiplePermissions(final ReadableArray permissions, boolean entryFlag, final Promise promise) {
132
+ final WritableMap output = new WritableNativeMap();
133
+ final ArrayList<String> permissionsToCheck = new ArrayList<String>();
134
+ int checkedPermissionsCount = 0;
135
+
136
+ Context context = getReactApplicationContext().getBaseContext();
137
+
138
+ for (int i = 0; i < permissions.size(); i++) {
139
+ String permission = permissions.getString(i);
140
+
141
+ if (!permissionExists(permission)) {
142
+ output.putString(permission, UNAVAILABLE);
143
+ checkedPermissionsCount++;
144
+ } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
145
+ output.putString(
146
+ permission,
147
+ context.checkPermission(permission, Process.myPid(), Process.myUid())
148
+ == PackageManager.PERMISSION_GRANTED
149
+ ? GRANTED
150
+ : BLOCKED);
151
+ checkedPermissionsCount++;
152
+ } else if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) {
153
+ output.putString(permission, GRANTED);
154
+ checkedPermissionsCount++;
155
+ } else if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_DENIED) {
156
+ output.putString(permission, DENIED);
157
+ permissionsToCheck.add(permission);
158
+ checkedPermissionsCount++;
159
+ } else {
160
+ permissionsToCheck.add(permission);
161
+ }
162
+ }
163
+ if (permissions.size() == checkedPermissionsCount && permissionsToCheck.size() == 0) {
164
+ promise.resolve(output);
165
+ return;
166
+ }
167
+ try {
168
+ Activity act = getCurrentActivity();
169
+ boolean[] rationaleStatuses = new boolean[permissions.size()];
170
+
171
+ mRequests.put(mRequestCode, new Request(
172
+ rationaleStatuses,
173
+ new Callback() {
174
+ @Override
175
+ public void invoke(Object... args) {
176
+ int[] results = (int[]) args[0];
177
+
178
+ for (int j = 0; j < permissionsToCheck.size(); j++) {
179
+ String permission = permissionsToCheck.get(j);
180
+
181
+ if (results.length > 0 && results[j] == PackageManager.PERMISSION_GRANTED) {
182
+ output.putString(permission, GRANTED);
183
+ } else {
184
+ output.putString(permission, DENIED);
185
+ }
186
+ }
187
+ if(promise != null && output!=null)
188
+ promise.resolve(output);
189
+ }
190
+ }));
191
+
192
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
193
+ try {
194
+ if (!(act instanceof PermissionAwareActivity)) {
195
+ act.requestPermissions(permissionsToCheck.toArray(new String[0]), mRequestCode);
196
+ } else {
197
+ PermissionAwareActivity ac = (PermissionAwareActivity) act;
198
+ ac.requestPermissions(permissionsToCheck.toArray(new String[0]), mRequestCode, this);
199
+ }
200
+ } catch (Error e) {
201
+ promise.reject(ERROR_INVALID_ACTIVITY, e);
202
+ }
203
+ }
204
+ mRequestCode++;
205
+ } catch (Exception e) {
206
+ promise.reject(ERROR_INVALID_ACTIVITY, e);
207
+ }
208
+ }
209
+
210
+ public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
211
+ try {
212
+ if(mRequests == null) {
213
+ return false;
214
+ }
215
+ Request request = mRequests.get(requestCode, null);
216
+ if(request == null) {
217
+ return false;
218
+ }
219
+ request.callback.invoke(grantResults);
220
+ mRequests.remove(requestCode);
221
+ return mRequests.size() == 0;
222
+ } catch(Exception e) {
223
+ return false;
224
+ }
225
+ }
226
+ }