edoctor-sendbird-calls 1.0.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.
Files changed (71) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +33 -0
  3. package/android/build.gradle +82 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +34 -0
  6. package/android/src/main/AndroidManifestNew.xml +2 -0
  7. package/android/src/main/java/com/edoctorsendbirdcalls/ComingCallActivity.java +41 -0
  8. package/android/src/main/java/com/edoctorsendbirdcalls/RNSendBirdCallsModule.java +2068 -0
  9. package/android/src/main/java/com/edoctorsendbirdcalls/RNSendBirdCallsPackage.java +32 -0
  10. package/android/src/main/java/com/edoctorsendbirdcalls/RNVSendBirdCallsVideo.java +10 -0
  11. package/android/src/main/java/com/edoctorsendbirdcalls/RNVSendBirdCallsVideoManager.java +77 -0
  12. package/android/src/main/java/com/edoctorsendbirdcalls/RNVideoViewGroup.java +109 -0
  13. package/android/src/main/java/com/edoctorsendbirdcalls/SharedUtils.java +127 -0
  14. package/android/src/main/java/com/edoctorsendbirdcalls/VcCallReceiver.java +37 -0
  15. package/android/src/main/java/com/edoctorsendbirdcalls/VcHeadlessService.java +23 -0
  16. package/android/src/main/java/com/edoctorsendbirdcalls/VoIPBaseService.java +100 -0
  17. package/android/src/main/java/com/edoctorsendbirdcalls/VoIPService.java +164 -0
  18. package/android/src/main/java/com/edoctorsendbirdcalls/XiaomiUtilities.java +75 -0
  19. package/android/src/main/res/drawable/bar_selector_white.xml +18 -0
  20. package/android/src/main/res/drawable/button_answer.xml +8 -0
  21. package/android/src/main/res/drawable/button_reject.xml +8 -0
  22. package/android/src/main/res/drawable/call_notification_line.xml +8 -0
  23. package/android/src/main/res/drawable/ic_answer.xml +5 -0
  24. package/android/src/main/res/drawable/ic_call_notification_answer.xml +6 -0
  25. package/android/src/main/res/drawable/ic_call_notification_decline.xml +9 -0
  26. package/android/src/main/res/drawable/ic_reject.xml +5 -0
  27. package/android/src/main/res/drawable/rn_edit_text_material.xml +36 -0
  28. package/android/src/main/res/layout/call_notification.xml +124 -0
  29. package/edoctor-sendbird-calls.podspec +27 -0
  30. package/ios/CXCallManager.swift +211 -0
  31. package/ios/CXProvider.swift +38 -0
  32. package/ios/Extensions/UIKit/UIColor.swift +30 -0
  33. package/ios/Extensions/UIKit/UIView+Extension.swift +61 -0
  34. package/ios/Extensions/UIKit/UIViewController.swift +28 -0
  35. package/ios/PrivacyInfo.xcprivacy +47 -0
  36. package/ios/RNSendBirdCalls-Bridging-Header.h +3 -0
  37. package/ios/RNSendBirdCalls.mm +94 -0
  38. package/ios/RNSendBirdCalls.swift +549 -0
  39. package/ios/RNSendBirdCallsHelper.swift +28 -0
  40. package/ios/RNVSendBirdCallsVideo.swift +55 -0
  41. package/ios/RNVSendBirdCallsVideoManager.mm +6 -0
  42. package/ios/RNVSendBirdCallsVideoManager.swift +15 -0
  43. package/ios/SendBirdCallsExtentions.swift +46 -0
  44. package/lib/module/SendBirdCalls.js +377 -0
  45. package/lib/module/SendBirdCalls.js.map +1 -0
  46. package/lib/module/SendBirdCallsEvents.js +108 -0
  47. package/lib/module/SendBirdCallsEvents.js.map +1 -0
  48. package/lib/module/SendBirdCallsVideo.js +33 -0
  49. package/lib/module/SendBirdCallsVideo.js.map +1 -0
  50. package/lib/module/index.js +14 -0
  51. package/lib/module/index.js.map +1 -0
  52. package/lib/module/index.type.js +2 -0
  53. package/lib/module/index.type.js.map +1 -0
  54. package/lib/module/package.json +1 -0
  55. package/lib/typescript/package.json +1 -0
  56. package/lib/typescript/src/SendBirdCalls.d.ts +63 -0
  57. package/lib/typescript/src/SendBirdCalls.d.ts.map +1 -0
  58. package/lib/typescript/src/SendBirdCallsEvents.d.ts +36 -0
  59. package/lib/typescript/src/SendBirdCallsEvents.d.ts.map +1 -0
  60. package/lib/typescript/src/SendBirdCallsVideo.d.ts +18 -0
  61. package/lib/typescript/src/SendBirdCallsVideo.d.ts.map +1 -0
  62. package/lib/typescript/src/index.d.ts +5 -0
  63. package/lib/typescript/src/index.d.ts.map +1 -0
  64. package/lib/typescript/src/index.type.d.ts +14 -0
  65. package/lib/typescript/src/index.type.d.ts.map +1 -0
  66. package/package.json +154 -0
  67. package/src/SendBirdCalls.ts +472 -0
  68. package/src/SendBirdCallsEvents.ts +141 -0
  69. package/src/SendBirdCallsVideo.tsx +44 -0
  70. package/src/index.tsx +11 -0
  71. package/src/index.type.ts +20 -0
@@ -0,0 +1,32 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ import com.facebook.react.ReactPackage;
6
+ import com.facebook.react.bridge.NativeModule;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.uimanager.ViewManager;
9
+
10
+ import java.util.ArrayList;
11
+ import java.util.Collections;
12
+ import java.util.List;
13
+
14
+ public class RNSendBirdCallsPackage implements ReactPackage {
15
+
16
+ @NonNull
17
+ @Override
18
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
19
+ List<NativeModule> modules = new ArrayList<>();
20
+ modules.add(new RNSendBirdCallsModule(reactContext));
21
+ return modules;
22
+ }
23
+
24
+ @NonNull
25
+ @Override
26
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
27
+ List<ViewManager> viewManagers = new ArrayList<>();
28
+ // Uncomment if you have video view manager
29
+ viewManagers.add(new RNVSendBirdCallsVideoManager());
30
+ return viewManagers;
31
+ }
32
+ }
@@ -0,0 +1,10 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import com.facebook.react.uimanager.ThemedReactContext;
4
+
5
+ public class RNVSendBirdCallsVideo extends RNVideoViewGroup {
6
+
7
+ public RNVSendBirdCallsVideo(ThemedReactContext themedReactContext) {
8
+ super(themedReactContext);
9
+ }
10
+ }
@@ -0,0 +1,77 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import android.view.View;
4
+
5
+ import androidx.annotation.NonNull;
6
+ import androidx.annotation.Nullable;
7
+
8
+ import com.facebook.react.uimanager.ThemedReactContext;
9
+ import com.facebook.react.uimanager.ViewGroupManager;
10
+ import com.facebook.react.uimanager.annotations.ReactProp;
11
+ import com.sendbird.calls.DirectCall;
12
+ import com.sendbird.calls.SendBirdCall;
13
+ import com.sendbird.calls.SendBirdVideoView;
14
+
15
+ import org.jetbrains.annotations.NotNull;
16
+ import org.webrtc.RendererCommon;
17
+
18
+ public class RNVSendBirdCallsVideoManager extends ViewGroupManager<RNVSendBirdCallsVideo> {
19
+
20
+ private int propWidth;
21
+ private int propHeight;
22
+ private String curCallId;
23
+ private DirectCall directCall;
24
+
25
+ @NotNull
26
+ @Override
27
+ public String getName() {
28
+ return "RNVSendBirdCallsVideo";
29
+ }
30
+
31
+ @NonNull
32
+ @NotNull
33
+ @Override
34
+ protected RNVSendBirdCallsVideo createViewInstance(@NonNull @NotNull ThemedReactContext reactContext) {
35
+ return new RNVSendBirdCallsVideo(reactContext);
36
+ }
37
+
38
+ @ReactProp(name = "callId")
39
+ public void callId(RNVSendBirdCallsVideo view, @Nullable String callId) {
40
+ if(callId.length() > 0) {
41
+ curCallId = callId;
42
+ directCall = SendBirdCall.getCall(callId);
43
+ }
44
+ }
45
+
46
+ @ReactProp(name = "local", defaultBoolean = false)
47
+ public void local(RNVSendBirdCallsVideo view, @Nullable Boolean local) {
48
+ SendBirdVideoView videoView = view.getSurfaceViewRenderer();
49
+ if(directCall == null) return;
50
+ if(local) {
51
+ directCall.setLocalVideoView(videoView);
52
+ }else {
53
+ directCall.setRemoteVideoView(videoView);
54
+ }
55
+ }
56
+
57
+ @ReactProp(name = "scaleFit", defaultBoolean = true)
58
+ public void scaleFit(RNVSendBirdCallsVideo view, @Nullable Boolean scaleFit) {
59
+ SendBirdVideoView videoView = view.getSurfaceViewRenderer();
60
+ if(directCall == null) return;
61
+ if(scaleFit) {
62
+ view.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
63
+ }else {
64
+ view.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
65
+ }
66
+ }
67
+
68
+ public void manuallyLayoutChildren(View view) {
69
+ // propWidth and propHeight coming from react-native props
70
+ int width = propWidth;
71
+ int height = propHeight;
72
+ view.measure(
73
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
74
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
75
+ view.layout(0, 0, width, height);
76
+ }
77
+ }
@@ -0,0 +1,109 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import android.graphics.Point;
4
+ import android.view.ViewGroup;
5
+
6
+ import androidx.annotation.StringDef;
7
+
8
+ import com.facebook.react.uimanager.ThemedReactContext;
9
+ import com.sendbird.calls.SendBirdVideoView;
10
+
11
+ import org.webrtc.RendererCommon;
12
+
13
+
14
+ import java.lang.annotation.Retention;
15
+ import java.lang.annotation.RetentionPolicy;
16
+
17
+ import static com.rnsendbirdcalls.RNVideoViewGroup.Events.ON_FRAME_DIMENSIONS_CHANGED;
18
+
19
+ public class RNVideoViewGroup extends ViewGroup {
20
+ private SendBirdVideoView surfaceViewRenderer = null;
21
+ private int videoWidth = 0;
22
+ private int videoHeight = 0;
23
+ private final Object layoutSync = new Object();
24
+ private RendererCommon.ScalingType scalingType = RendererCommon.ScalingType.SCALE_ASPECT_FIT;
25
+
26
+ @Retention(RetentionPolicy.SOURCE)
27
+ @StringDef({ON_FRAME_DIMENSIONS_CHANGED})
28
+ public @interface Events {
29
+ String ON_FRAME_DIMENSIONS_CHANGED = "onFrameDimensionsChanged";
30
+ }
31
+
32
+ public RNVideoViewGroup(ThemedReactContext themedReactContext) {
33
+ super(themedReactContext);
34
+ surfaceViewRenderer = new SendBirdVideoView(themedReactContext);
35
+ surfaceViewRenderer.setEnableHardwareScaler(true);
36
+ addView(surfaceViewRenderer);
37
+
38
+ // surfaceViewRenderer.setListener(
39
+ // new RendererCommon.RendererEvents() {
40
+ // @Override
41
+ // public void onFirstFrameRendered() {
42
+ //
43
+ // }
44
+ //
45
+ // @Override
46
+ // public void onFrameResolutionChanged(int vw, int vh, int rotation) {
47
+ // synchronized (layoutSync) {
48
+ // if (rotation == 90 || rotation == 270) {
49
+ // videoHeight = vw;
50
+ // videoWidth = vh;
51
+ // } else {
52
+ // videoHeight = vh;
53
+ // videoWidth = vw;
54
+ // }
55
+ // RNVideoViewGroup.this.forceLayout();
56
+ //
57
+ // WritableMap event = new WritableNativeMap();
58
+ // event.putInt("height", vh);
59
+ // event.putInt("width", vw);
60
+ // event.putInt("rotation", rotation);
61
+ // pushEvent(RNVideoViewGroup.this, ON_FRAME_DIMENSIONS_CHANGED, event);
62
+ // }
63
+ // }
64
+ // }
65
+ // );
66
+ }
67
+
68
+ public SendBirdVideoView getSurfaceViewRenderer() {
69
+ return surfaceViewRenderer;
70
+ }
71
+
72
+ public void setScalingType(RendererCommon.ScalingType scalingType) {
73
+ this.scalingType = scalingType;
74
+ }
75
+
76
+ @Override
77
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
78
+ int height = b - t;
79
+ int width = r - l;
80
+ if (height == 0 || width == 0) {
81
+ l = t = r = b = 0;
82
+ } else {
83
+ int videoHeight;
84
+ int videoWidth;
85
+ synchronized (layoutSync) {
86
+ videoHeight = this.videoHeight;
87
+ videoWidth = this.videoWidth;
88
+ }
89
+
90
+ if (videoHeight == 0 || videoWidth == 0) {
91
+ videoHeight = 480;
92
+ videoWidth = 640;
93
+ }
94
+
95
+ Point displaySize = RendererCommon.getDisplaySize(
96
+ this.scalingType,
97
+ videoWidth / (float) videoHeight,
98
+ width,
99
+ height
100
+ );
101
+
102
+ l = (width - displaySize.x) / 2;
103
+ t = (height - displaySize.y) / 2;
104
+ r = l + displaySize.x;
105
+ b = t + displaySize.y;
106
+ }
107
+ surfaceViewRenderer.layout(l, t, r, b);
108
+ }
109
+ }
@@ -0,0 +1,127 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import android.annotation.SuppressLint;
4
+ import android.app.ActivityManager;
5
+ import android.app.KeyguardManager;
6
+ import android.content.Context;
7
+ import android.content.Intent;
8
+ import android.os.Build;
9
+ import android.os.Bundle;
10
+ import android.os.PowerManager;
11
+ import android.util.Log;
12
+
13
+ import com.facebook.react.bridge.ReactContext;
14
+ import com.facebook.react.common.LifecycleState;
15
+
16
+ import java.util.List;
17
+
18
+ @SuppressWarnings({"unused", "JavaDoc", "WeakerAccess"})
19
+ public class SharedUtils {
20
+ /**
21
+ * We need to check if app is in foreground otherwise the app will crash.
22
+ * http://stackoverflow.com/questions/8489993/check-android-application-is-in-foreground-or-not
23
+ *
24
+ * @param context Context
25
+ * @return boolean
26
+ */
27
+ public static boolean isAppInForeground(Context context) {
28
+ ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
29
+ if (activityManager == null) return false;
30
+
31
+ List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
32
+ if (appProcesses == null) return false;
33
+
34
+ final String packageName = context.getPackageName();
35
+ for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
36
+ if (
37
+ appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
38
+ && appProcess.processName.equals(packageName)
39
+ ) {
40
+ ReactContext reactContext;
41
+
42
+ try {
43
+ reactContext = (ReactContext) context;
44
+ } catch (ClassCastException exception) {
45
+ // Not react context so default to true
46
+ return true;
47
+ }
48
+
49
+ return reactContext.getLifecycleState() == LifecycleState.RESUMED;
50
+ }
51
+ }
52
+
53
+ return false;
54
+ }
55
+
56
+ public static boolean getDeviceLocked(Context context) {
57
+ boolean isLocked = false;
58
+ // First we check the locked state
59
+ KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(context.KEYGUARD_SERVICE);
60
+ boolean inKeyguardRestrictedInputMode = keyguardManager.inKeyguardRestrictedInputMode();
61
+ if (inKeyguardRestrictedInputMode) {
62
+ isLocked = true;
63
+ } else {
64
+ // If password is not set in the settings, the inKeyguardRestrictedInputMode() returns false,
65
+ // so we need to check if screen on for this case
66
+ PowerManager powerManager = (PowerManager) context.getSystemService(context.POWER_SERVICE);
67
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
68
+ isLocked = !powerManager.isInteractive();
69
+ } else {
70
+ //noinspection deprecation
71
+ isLocked = !powerManager.isScreenOn();
72
+ }
73
+ }
74
+ return isLocked;
75
+ }
76
+
77
+ public static Class<?> getMainActivityClass(Context appContext){
78
+ try {
79
+ final Package appPackage = appContext.getClass().getPackage();
80
+ assert appPackage != null;
81
+ final String className = appPackage.getName() + ".MainActivity";
82
+ return Class.forName(className);
83
+ } catch (Exception e){
84
+ e.printStackTrace();
85
+ }
86
+ return null;
87
+ }
88
+
89
+ public static void navigateMainApp(Context context, Bundle bundle) {
90
+ try {
91
+ Intent intent = new Intent(context, getMainActivityClass(context));
92
+ intent.putExtras(bundle);
93
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
94
+ context.startActivity(intent);
95
+ cancelComingCallNotification();
96
+ }catch (Exception e){
97
+ e.printStackTrace();
98
+ }
99
+ }
100
+
101
+ public static void startComingCallActivity(Context context, Bundle bundle) {
102
+ try {
103
+ Intent intent = new Intent(context, ComingCallActivity.class);
104
+ intent.putExtras(bundle);
105
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
106
+ context.startActivity(intent);
107
+ }catch (Exception e){
108
+ e.printStackTrace();
109
+ }
110
+ }
111
+
112
+ public static void cancelComingCallNotification(){
113
+ VoIPBaseService instance = VoIPService.getSharedInstance();
114
+ if(instance != null) {
115
+ instance.stopSelf();
116
+ }
117
+ }
118
+
119
+ @SuppressLint("PrivateApi")
120
+ public static String getSystemProperty(String key) {
121
+ try {
122
+ Class props = Class.forName("android.os.SystemProperties");
123
+ return (String) props.getMethod("get", String.class).invoke(null, key);
124
+ } catch (Exception ignore) { }
125
+ return null;
126
+ }
127
+ }
@@ -0,0 +1,37 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+
4
+ import android.content.BroadcastReceiver;
5
+ import android.content.Context;
6
+ import android.content.Intent;
7
+ import android.os.Bundle;
8
+
9
+ import com.facebook.react.HeadlessJsTaskService;
10
+
11
+ public class VcCallReceiver extends BroadcastReceiver {
12
+
13
+ private void acceptIncomingCallFromNotification(Context context, Bundle extras) {
14
+ extras.putString("CALL_STATUS", "ANSWERED");
15
+ SharedUtils.navigateMainApp(context, extras);
16
+ }
17
+
18
+ @Override
19
+ public void onReceive(Context context, Intent intent) {
20
+ Bundle extras = intent.getExtras();
21
+ if ((context.getPackageName() + ".DECLINE_CALL").equals(intent.getAction())) {
22
+ if(extras != null) extras.putString("ACTION", "DENIED");
23
+ } else if ((context.getPackageName() + ".ANSWER_CALL").equals(intent.getAction())) {
24
+ if(extras != null) extras.putString("ACTION", "ACCEPT");
25
+ acceptIncomingCallFromNotification(context.getApplicationContext(), extras);
26
+ }
27
+
28
+ Intent serviceIntent = new Intent(context, VcHeadlessService.class);
29
+ serviceIntent.putExtras(extras);
30
+ context.startService(serviceIntent);
31
+ HeadlessJsTaskService.acquireWakeLockNow(context);
32
+
33
+ if (VoIPBaseService.getSharedInstance() != null) {
34
+ VoIPBaseService.getSharedInstance().stopSelf();
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,23 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import android.content.Intent;
4
+ import android.os.Bundle;
5
+
6
+ import com.facebook.react.HeadlessJsTaskService;
7
+ import com.facebook.react.bridge.Arguments;
8
+ import com.facebook.react.jstasks.HeadlessJsTaskConfig;
9
+ import javax.annotation.Nullable;
10
+
11
+ public class VcHeadlessService extends HeadlessJsTaskService {
12
+
13
+ @Override
14
+ protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
15
+ Bundle extras = intent.getExtras();
16
+ return new HeadlessJsTaskConfig(
17
+ "VcHeadlessService",
18
+ Arguments.fromBundle(extras),
19
+ 60000, // timeout for the task
20
+ true // optional: defines whether or not the task is allowed in foreground. Default is false
21
+ );
22
+ }
23
+ }
@@ -0,0 +1,100 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import android.annotation.SuppressLint;
4
+ import android.app.KeyguardManager;
5
+ import android.app.NotificationManager;
6
+ import android.app.Service;
7
+ import android.content.Context;
8
+ import android.content.Intent;
9
+ import android.content.IntentFilter;
10
+ import android.net.ConnectivityManager;
11
+ import android.os.Build;
12
+ import android.os.PowerManager;
13
+ import android.telephony.TelephonyManager;
14
+ import android.util.Log;
15
+
16
+ import androidx.core.app.NotificationManagerCompat;
17
+
18
+ @SuppressLint("NewApi")
19
+ public abstract class VoIPBaseService extends Service {
20
+
21
+ private String TAG = "VOIP_BASE_SERVICE_TAG";
22
+
23
+ protected static final int ID_INCOMING_CALL_NOTIFICATION = 202;
24
+
25
+ protected static final String NOTIFICATION_CHANNEL = "edoctor_call_channel";
26
+
27
+ protected static final boolean USE_CONNECTION_SERVICE = isDeviceCompatibleWithConnectionServiceAPI();
28
+
29
+ protected static VoIPBaseService sharedInstance;
30
+ protected boolean notificationsDisabled = false;
31
+ protected PowerManager.WakeLock proximityWakelock;
32
+ protected PowerManager.WakeLock cpuWakelock;
33
+
34
+ public static VoIPBaseService getSharedInstance() { return sharedInstance; }
35
+
36
+ @Override
37
+ public void onDestroy() {
38
+ Log.d(TAG, "======== VoIP SERVICE STOPPING ========");
39
+ stopForeground(true);
40
+ if (proximityWakelock != null && proximityWakelock.isHeld()) {
41
+ proximityWakelock.release();
42
+ }
43
+ NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
44
+ manager.cancel(ID_INCOMING_CALL_NOTIFICATION);
45
+ super.onDestroy();
46
+ if (cpuWakelock != null && cpuWakelock.isHeld()) {
47
+ cpuWakelock.release();
48
+ }
49
+ sharedInstance = null;
50
+ }
51
+
52
+ @SuppressLint("InvalidWakeLockTag")
53
+ @Override
54
+ public void onCreate() {
55
+ super.onCreate();
56
+ Log.d(TAG, "======== VoIP SERVICE STARTING ========");
57
+ try {
58
+ cpuWakelock = ((PowerManager) getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "edoctor-voip");
59
+ cpuWakelock.acquire();
60
+ IntentFilter filter = new IntentFilter();
61
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
62
+ if (!USE_CONNECTION_SERVICE) {
63
+ filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
64
+ filter.addAction(Intent.ACTION_SCREEN_ON);
65
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
66
+ }
67
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !NotificationManagerCompat.from(this.getApplicationContext()).areNotificationsEnabled()) {
68
+ notificationsDisabled = true;
69
+ }
70
+ } catch (Exception x) { }
71
+ }
72
+
73
+ protected boolean isAcknowledgeCall(){
74
+ boolean isAcknowledge = true;
75
+ if (Build.VERSION.SDK_INT >= 19 && XiaomiUtilities.isMIUI() && !XiaomiUtilities.isCustomPermissionGranted(this.getApplicationContext(), XiaomiUtilities.OP_SHOW_WHEN_LOCKED)) {
76
+ if (((KeyguardManager) getSystemService(KEYGUARD_SERVICE)).inKeyguardRestrictedInputMode()) {
77
+ Log.d(TAG, "MIUI: no permission to show when locked but the screen is locked. ¯\\_(ツ)_/¯");
78
+ isAcknowledge = false;
79
+ }
80
+ }
81
+ return isAcknowledge;
82
+ }
83
+
84
+ private static boolean isDeviceCompatibleWithConnectionServiceAPI() {
85
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
86
+ return false;
87
+ }
88
+ // some non-Google devices don't implement the ConnectionService API correctly so, sadly,
89
+ // we'll have to whitelist only a handful of known-compatible devices for now
90
+ return false;/*"angler".equals(Build.PRODUCT) // Nexus 6P
91
+ || "bullhead".equals(Build.PRODUCT) // Nexus 5X
92
+ || "sailfish".equals(Build.PRODUCT) // Pixel
93
+ || "marlin".equals(Build.PRODUCT) // Pixel XL
94
+ || "walleye".equals(Build.PRODUCT) // Pixel 2
95
+ || "taimen".equals(Build.PRODUCT) // Pixel 2 XL
96
+ || "blueline".equals(Build.PRODUCT) // Pixel 3
97
+ || "crosshatch".equals(Build.PRODUCT) // Pixel 3 XL
98
+ || MessagesController.getGlobalMainSettings().getBoolean("dbg_force_connection_service", false);*/
99
+ }
100
+ }
@@ -0,0 +1,164 @@
1
+ package com.rnsendbirdcalls;
2
+
3
+ import android.annotation.SuppressLint;
4
+ import android.app.Notification;
5
+ import android.app.NotificationChannel;
6
+ import android.app.NotificationManager;
7
+ import android.app.PendingIntent;
8
+ import android.content.Context;
9
+ import android.content.Intent;
10
+ import android.os.Build;
11
+ import android.os.Bundle;
12
+ import android.os.IBinder;
13
+ import android.text.SpannableString;
14
+ import android.text.style.ForegroundColorSpan;
15
+ import android.util.Log;
16
+ import android.widget.RemoteViews;
17
+
18
+ import androidx.annotation.Nullable;
19
+
20
+ @SuppressLint("NewApi")
21
+ public class VoIPService extends VoIPBaseService {
22
+
23
+ private String TAG = "VOIP_SERVICE_TAG";
24
+
25
+ @Override
26
+ public int onStartCommand(Intent intent, int flags, int startId) {
27
+ sharedInstance = this;
28
+ if(!isAcknowledgeCall()) { stopSelf(); return START_NOT_STICKY; }
29
+ Bundle bundle = intent.getExtras();
30
+ if (!notificationsDisabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
31
+ showIncomingNotification(bundle);
32
+ } else {
33
+ SharedUtils.navigateMainApp(this, bundle);
34
+ }
35
+ return START_NOT_STICKY;
36
+ }
37
+
38
+ protected void showIncomingNotification(Bundle bundle) {
39
+ String notificationTitle = bundle.getString("title");
40
+ if(notificationTitle == null) notificationTitle = "Cuộc gọi đến";
41
+ else bundle.remove("title");
42
+
43
+ String notificationDescription = bundle.getString("description");
44
+ if(notificationDescription == null) notificationDescription = "...";
45
+ else bundle.remove("description");
46
+
47
+ long timeoutAfter = (long)bundle.getDouble("timeoutAfter");
48
+ if(timeoutAfter == 0) timeoutAfter = 60000;
49
+ else bundle.remove("timeoutAfter");
50
+
51
+ Intent intentComingCall;
52
+ Boolean isDeviceLocked = SharedUtils.getDeviceLocked(this.getApplicationContext());
53
+ Log.d(TAG, "isDeviceLocked: isDeviceLocked" + isDeviceLocked);
54
+ if (isDeviceLocked) {
55
+ intentComingCall = new Intent(this, ComingCallActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
56
+ .putExtras(bundle);
57
+ } else {
58
+ intentComingCall = new Intent(this, SharedUtils.getMainActivityClass(this.getApplicationContext())).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
59
+ .putExtras(bundle);
60
+ }
61
+
62
+
63
+ Notification.Builder builder = new Notification.Builder(this)
64
+ .setContentTitle(notificationTitle)
65
+ .setContentText(notificationDescription)
66
+ .setSmallIcon(android.R.drawable.sym_action_call)
67
+ .setAutoCancel(true)
68
+ .setPriority(Notification.PRIORITY_MAX)
69
+ .setOngoing(true)
70
+ .setShowWhen(true)
71
+ .setContentIntent(
72
+ PendingIntent.getActivity(
73
+ this,
74
+ 0,
75
+ intentComingCall,
76
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
77
+ )
78
+ );
79
+
80
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
81
+ builder.setTimeoutAfter(timeoutAfter);
82
+ }
83
+
84
+ // create channel android sdk >= 26
85
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
86
+ NotificationManager NMmanager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
87
+ if (NMmanager.getNotificationChannel(NOTIFICATION_CHANNEL) == null) {
88
+ NMmanager.createNotificationChannel(
89
+ new NotificationChannel(NOTIFICATION_CHANNEL, "Nhận cuộc gọi", NotificationManager.IMPORTANCE_HIGH)
90
+ );
91
+ }
92
+ builder.setChannelId(NOTIFICATION_CHANNEL);
93
+ }
94
+
95
+ // create end PendingIntent
96
+ Intent endIntent = new Intent(this, VcCallReceiver.class).putExtras(bundle);
97
+ endIntent.setAction(getPackageName() + ".DECLINE_CALL");
98
+ CharSequence endTitle = "Từ chối";
99
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
100
+ endTitle = new SpannableString(endTitle);
101
+ ((SpannableString) endTitle).setSpan(new ForegroundColorSpan(0xFFF44336), 0, endTitle.length(), 0);
102
+ }
103
+ PendingIntent endPendingIntent = PendingIntent.getBroadcast(
104
+ this,
105
+ 0,
106
+ endIntent,
107
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
108
+ );
109
+ builder.addAction(R.drawable.button_reject, endTitle, endPendingIntent);
110
+ // create end PendingIntent
111
+
112
+ // create answer PendingIntent
113
+ Intent answerIntent = new Intent(this, SharedUtils.getMainActivityClass(this.getApplicationContext())).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
114
+ .putExtras(bundle);
115
+ answerIntent.setAction(getPackageName() + ".ANSWER_CALL");
116
+ CharSequence answerTitle = "Đồng ý";
117
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
118
+ answerTitle = new SpannableString(answerTitle);
119
+ ((SpannableString) answerTitle).setSpan(new ForegroundColorSpan(0xFF00AA00), 0, answerTitle.length(), 0);
120
+ }
121
+ PendingIntent answerPendingIntent = PendingIntent.getActivity(
122
+ this,
123
+ 0,
124
+ answerIntent,
125
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
126
+ );
127
+
128
+ builder.addAction(R.drawable.button_answer, answerTitle, answerPendingIntent);
129
+ // create answer PendingIntent
130
+
131
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
132
+ builder.setShowWhen(false);
133
+ }
134
+
135
+ Notification incomingNotification = builder.getNotification();
136
+
137
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
138
+ builder.setCategory(Notification.CATEGORY_CALL);
139
+ PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(
140
+ this,
141
+ 0,
142
+ intentComingCall,
143
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
144
+ );
145
+ builder.setFullScreenIntent(fullScreenPendingIntent, true);
146
+ RemoteViews customView = new RemoteViews(getPackageName(), R.layout.call_notification);
147
+ customView.setTextViewText(R.id.title, notificationTitle);
148
+ customView.setTextViewText(R.id.subtitle, notificationDescription);
149
+ customView.setTextViewText(R.id.answer_text, "Đồng ý");
150
+ customView.setTextViewText(R.id.decline_text, "Từ chối");
151
+ customView.setOnClickPendingIntent(R.id.container, fullScreenPendingIntent);
152
+ customView.setOnClickPendingIntent(R.id.answer_btn, answerPendingIntent);
153
+ customView.setOnClickPendingIntent(R.id.decline_btn, endPendingIntent);
154
+ incomingNotification.headsUpContentView = incomingNotification.bigContentView = customView;
155
+ }
156
+ startForeground(ID_INCOMING_CALL_NOTIFICATION, incomingNotification);
157
+ }
158
+
159
+ @Nullable
160
+ @Override
161
+ public IBinder onBind(Intent intent) {
162
+ return null;
163
+ }
164
+ }