@cloudflare/realtimekit-react-native 0.0.0 → 0.0.1-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/README.md +83 -0
- package/RealtimeKitCore.podspec +19 -0
- package/android/build.gradle +58 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/android/gradlew +185 -0
- package/android/gradlew.bat +89 -0
- package/android/src/main/AndroidManifest.xml +23 -0
- package/android/src/main/java/com/reactnativecore/BackgroundTimer/RNBackgroundTimer.java +97 -0
- package/android/src/main/java/com/reactnativecore/Constants.java +14 -0
- package/android/src/main/java/com/reactnativecore/CoreModule.java +49 -0
- package/android/src/main/java/com/reactnativecore/CorePackage.java +34 -0
- package/android/src/main/java/com/reactnativecore/DyteHelperModule.java +268 -0
- package/android/src/main/java/com/reactnativecore/DyteHolder.java +7 -0
- package/android/src/main/java/com/reactnativecore/ForegroundService.java +48 -0
- package/android/src/main/java/com/reactnativecore/NotificationHelper.java +127 -0
- package/android/src/main/java/com/reactnativecore/RNPermissionsModule.java +226 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCBluetoothManager.java +637 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCProximitySensor.java +133 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/AppRTCUtils.java +41 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/InCallManagerModule.java +1881 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/InCallProximityManager.java +162 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/InCallWakeLockUtils.java +116 -0
- package/android/src/main/java/com/reactnativecore/incallmanager/ThreadUtils.java +39 -0
- package/app.plugin.js +1 -0
- package/ios/BroadcastEventEmitter.h +11 -0
- package/ios/BroadcastEventEmitter.m +72 -0
- package/ios/Core.h +5 -0
- package/ios/Core.m +28 -0
- package/ios/Core.xcodeproj/project.pbxproj +287 -0
- package/ios/DyteRNBackgroundTimer.h +22 -0
- package/ios/DyteRNBackgroundTimer.m +90 -0
- package/ios/DyteRNPermissionHandlerNotifications.h +17 -0
- package/ios/DyteRNPermissionHandlerNotifications.m +127 -0
- package/ios/DyteRNPermissions.h +50 -0
- package/ios/DyteRNPermissions.m +275 -0
- package/ios/DyteScreensharePickerView.h +8 -0
- package/ios/DyteScreensharePickerView.m +27 -0
- package/ios/PrivacyInfo.xcprivacy +60 -0
- package/ios/RNInCallManager.h +16 -0
- package/ios/RNInCallManager.m +1354 -0
- package/ios/permissions/DyteRNPermissionHandlerBluetoothPeripheral.h +4 -0
- package/ios/permissions/DyteRNPermissionHandlerBluetoothPeripheral.m +87 -0
- package/ios/permissions/DyteRNPermissionHandlerCamera.h +5 -0
- package/ios/permissions/DyteRNPermissionHandlerCamera.m +38 -0
- package/ios/permissions/DyteRNPermissionHandlerMicrophone.h +5 -0
- package/ios/permissions/DyteRNPermissionHandlerMicrophone.m +34 -0
- package/ios/permissions/DyteRNPermissionHandlerPhotoLibrary.h +8 -0
- package/ios/permissions/DyteRNPermissionHandlerPhotoLibrary.m +70 -0
- package/ios/screenshare/DyteDarwinNotificationCenter.swift +21 -0
- package/ios/screenshare/DyteScreenshareAtomic.swift +29 -0
- package/ios/screenshare/DyteScreenshareHandler.swift +103 -0
- package/ios/screenshare/DyteScreenshareUploader.swift +139 -0
- package/ios/screenshare/DyteSocketConnection.swift +190 -0
- package/lib/BackgroundHandler.d.ts +20 -0
- package/lib/BackgroundHandler.js +87 -0
- package/lib/LocalMediaError.d.ts +4 -0
- package/lib/LocalMediaError.js +6 -0
- package/lib/LocalMediaHandler.d.ts +118 -0
- package/lib/LocalMediaHandler.js +853 -0
- package/lib/LocalMediaInterfaces.d.ts +76 -0
- package/lib/LocalMediaInterfaces.js +1 -0
- package/lib/LocalMediaUtils.d.ts +93 -0
- package/lib/LocalMediaUtils.js +276 -0
- package/lib/NativeAudioManager.d.ts +16 -0
- package/lib/NativeAudioManager.js +93 -0
- package/lib/PermissionHandler.d.ts +34 -0
- package/lib/PermissionHandler.js +179 -0
- package/lib/ReactContext.d.ts +42 -0
- package/lib/ReactContext.js +96 -0
- package/lib/ReactHooks.d.ts +11 -0
- package/lib/ReactHooks.js +73 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +40 -0
- package/lib/utils/crypto.d.ts +17 -0
- package/lib/utils/crypto.js +82 -0
- package/package.json +51 -4
- package/plugin/build/withDyte.d.ts +25 -0
- package/plugin/build/withDyte.js +100 -0
- package/plugin/src/withDyte.ts +150 -0
- package/plugin/tsconfig.json +10 -0
- 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,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
|
+
}
|