@cometchat/calls-sdk-react-native 4.0.9-experimental.2 → 4.1.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.
@@ -0,0 +1,93 @@
1
+ package com.CometChatCalls;
2
+
3
+ import android.app.Notification;
4
+ import android.app.NotificationChannel;
5
+ import android.app.NotificationManager;
6
+ import android.app.PendingIntent;
7
+ import android.app.Service;
8
+ import android.content.Intent;
9
+ import android.content.pm.ServiceInfo;
10
+ import android.os.Build;
11
+ import android.os.IBinder;
12
+ import android.util.Log;
13
+
14
+ import androidx.annotation.Nullable;
15
+ import androidx.annotation.RequiresApi;
16
+ import androidx.core.app.NotificationCompat;
17
+
18
+ public class CallNotificationService extends Service {
19
+
20
+ private static final String CHANNEL_ID = "CALL_NOTIFICATION_CHANNEL";
21
+ private static final int NOTIFICATION_ID = 1;
22
+ private static long startingTime = 0;
23
+
24
+ @Override
25
+ public int onStartCommand(Intent intent, int flags, int startId) {
26
+ createNotificationChannel();
27
+ Intent notificationIntent = new Intent(this, CallNotificationService.class);
28
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
29
+ if (startingTime == 0) {
30
+ startingTime = System.currentTimeMillis();
31
+ }
32
+ Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
33
+ .setCategory(NotificationCompat.CATEGORY_CALL)
34
+ .setContentTitle("Ongoing Call")
35
+ .setContentText("Tap to return to the call")
36
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
37
+ .setSmallIcon(R.drawable.callingcomponent_icons_headphones_pluged)
38
+ .setContentIntent(pendingIntent)
39
+ .setOngoing(true)
40
+ .setWhen(startingTime)
41
+ .setUsesChronometer(true)
42
+ .setAutoCancel(false)
43
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
44
+ .setOnlyAlertOnce(true)
45
+ .build();
46
+
47
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
48
+ startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK | ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
49
+ } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
50
+ startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
51
+ } else {
52
+ startForeground(NOTIFICATION_ID, notification);
53
+ }
54
+
55
+ return START_NOT_STICKY;
56
+ }
57
+
58
+ @Override
59
+ public void onDestroy() {
60
+ super.onDestroy();
61
+ stopSelf();
62
+ }
63
+
64
+
65
+ static void resetStartingTime() {
66
+ startingTime = 0;
67
+ }
68
+
69
+ @Override
70
+ public void onTaskRemoved(Intent rootIntent) {
71
+ super.onTaskRemoved(rootIntent);
72
+ stopSelf();
73
+ CallNotificationServiceModule.sendEvent("onTaskRemoved", "onTaskRemoved");
74
+ }
75
+
76
+ @Nullable
77
+ @Override
78
+ public IBinder onBind(Intent intent) {
79
+ return null;
80
+ }
81
+
82
+ private void createNotificationChannel() {
83
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
84
+ NotificationChannel serviceChannel = new NotificationChannel(
85
+ CHANNEL_ID,
86
+ "Call Notification Service",
87
+ NotificationManager.IMPORTANCE_DEFAULT
88
+ );
89
+ NotificationManager manager = getSystemService(NotificationManager.class);
90
+ manager.createNotificationChannel(serviceChannel);
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,48 @@
1
+ package com.CometChatCalls;
2
+
3
+ import android.content.Intent;
4
+
5
+ import androidx.annotation.NonNull;
6
+
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
9
+ import com.facebook.react.bridge.ReactMethod;
10
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
11
+
12
+ public class CallNotificationServiceModule extends ReactContextBaseJavaModule {
13
+
14
+ public static ReactApplicationContext reactContext;
15
+
16
+ public CallNotificationServiceModule(ReactApplicationContext reactContext) {
17
+ super(reactContext);
18
+ CallNotificationServiceModule.reactContext = reactContext;
19
+ }
20
+
21
+ public static void sendEvent(String eventName, String message) {
22
+ if (reactContext != null) {
23
+ reactContext
24
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
25
+ .emit(eventName, message);
26
+ }
27
+ }
28
+
29
+ @NonNull
30
+ @Override
31
+ public String getName() {
32
+ return "CallNotificationService";
33
+ }
34
+
35
+ @ReactMethod
36
+ public void startService() {
37
+ Intent serviceIntent = new Intent(reactContext, CallNotificationService.class);
38
+ reactContext.startService(serviceIntent);
39
+ }
40
+
41
+ @ReactMethod
42
+ public static void stopService() {
43
+ Intent serviceIntent = new Intent(reactContext, CallNotificationService.class);
44
+ reactContext.stopService(serviceIntent);
45
+ CallNotificationService.resetStartingTime();
46
+ }
47
+ }
48
+
@@ -16,20 +16,29 @@
16
16
 
17
17
  package com.CometChatCalls;
18
18
 
19
+ import androidx.annotation.NonNull;
20
+ import androidx.annotation.NonNull;
19
21
  import com.facebook.react.ReactPackage;
20
22
  import com.facebook.react.bridge.JavaScriptModule;
21
23
  import com.facebook.react.bridge.NativeModule;
22
24
  import com.facebook.react.bridge.ReactApplicationContext;
23
25
  import com.facebook.react.uimanager.ViewManager;
24
26
 
27
+ import java.util.ArrayList;
28
+ import java.util.ArrayList;
25
29
  import java.util.Collections;
26
30
  import java.util.List;
27
31
 
28
32
  public class CometChatCallsPackage implements ReactPackage {
29
33
 
34
+ @NonNull
30
35
  @Override
31
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
32
- return Collections.<NativeModule>singletonList(new AudioModeModule(reactContext));
36
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
37
+ List<NativeModule> modules = new ArrayList<>();
38
+ modules.add(new AudioModeModule(reactContext));
39
+ modules.add(new CallNotificationServiceModule(reactContext));
40
+ modules.add(new PictureInPictureModule(reactContext));
41
+ return modules;
33
42
  }
34
43
 
35
44
  // Deprecated RN 0.47
@@ -37,8 +46,9 @@ public class CometChatCallsPackage implements ReactPackage {
37
46
  return Collections.emptyList();
38
47
  }
39
48
 
49
+ @NonNull
40
50
  @Override
41
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
51
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
42
52
  return Collections.emptyList();
43
53
  }
44
54
 
@@ -0,0 +1,133 @@
1
+ package com.CometChatCalls;
2
+
3
+ import android.app.Activity;
4
+ import android.app.KeyguardManager;
5
+ import android.app.PictureInPictureParams;
6
+ import android.content.Context;
7
+ import android.media.AudioAttributes;
8
+ import android.media.AudioFocusRequest;
9
+ import android.media.AudioManager;
10
+ import android.os.Build;
11
+ import android.os.PowerManager;
12
+ import android.util.DisplayMetrics;
13
+ import android.util.Log;
14
+ import android.util.Rational;
15
+
16
+ import androidx.annotation.NonNull;
17
+ import androidx.annotation.RequiresApi;
18
+
19
+ import com.facebook.react.bridge.Promise;
20
+ import com.facebook.react.bridge.ReactApplicationContext;
21
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
22
+ import com.facebook.react.bridge.ReactMethod;
23
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
24
+
25
+ public class PictureInPictureModule extends ReactContextBaseJavaModule {
26
+ public static final String NAME = "PictureInPictureModule";
27
+ public static final String TAG = NAME;
28
+ public static boolean isPIPInitialized = false;
29
+ private ReactApplicationContext mReactContext;
30
+ public PowerManager.WakeLock wakeLock;
31
+ private AudioManager audioManager;
32
+ private static boolean isEnabled;
33
+
34
+ public PictureInPictureModule(@NonNull ReactApplicationContext reactContext) {
35
+ super(reactContext);
36
+ mReactContext = reactContext;
37
+ }
38
+
39
+ @NonNull
40
+ @Override
41
+ public String getName() {
42
+ return NAME;
43
+ }
44
+
45
+ @RequiresApi(api = Build.VERSION_CODES.O)
46
+ @ReactMethod
47
+ public void enterPictureInPictureMode() {
48
+ if (!isEnabled) {
49
+ return;
50
+ }
51
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
52
+ Activity currentActivity = getCurrentActivity();
53
+ if (currentActivity != null) {
54
+ DisplayMetrics metrics = currentActivity.getResources().getDisplayMetrics();
55
+
56
+ Rational aspectRatio = new Rational(metrics.widthPixels, metrics.heightPixels);
57
+ PictureInPictureParams params = new PictureInPictureParams.Builder()
58
+ .setAspectRatio(aspectRatio)
59
+ .build();
60
+ currentActivity.enterPictureInPictureMode(params);
61
+ }
62
+ }
63
+ }
64
+
65
+ @RequiresApi(api = Build.VERSION_CODES.O)
66
+ @ReactMethod
67
+ public void exitPictureInPictureMode() {
68
+ Activity currentActivity = getCurrentActivity();
69
+
70
+ try {
71
+ if (currentActivity != null) {
72
+ if (currentActivity.isInPictureInPictureMode()) {
73
+ currentActivity.moveTaskToBack(true);
74
+ }
75
+ }
76
+ } catch (Exception e) {
77
+ Log.e(TAG, "[exitPictureInPictureMode]", e);
78
+ }
79
+ }
80
+
81
+ @ReactMethod
82
+ public void setPictureInPictureEnabled(Boolean enabled) {
83
+ isEnabled = enabled;
84
+ }
85
+
86
+ @RequiresApi(api = Build.VERSION_CODES.O)
87
+ @ReactMethod
88
+ public void initializePictureInPictureMode() {
89
+ isPIPInitialized = true;
90
+ }
91
+
92
+ @RequiresApi(api = Build.VERSION_CODES.O)
93
+ @ReactMethod
94
+ public void getIsPIPInitialized(Promise promise) {
95
+ promise.resolve(isPIPInitialized);
96
+ }
97
+
98
+ public void notifyPipModeChanged(boolean isInPipMode) {
99
+ mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
100
+ .emit("onPipModeChanged", isInPipMode);
101
+ }
102
+
103
+ @ReactMethod
104
+ private void requestAudioFocus() {
105
+ audioManager = (AudioManager) mReactContext.getSystemService(Context.AUDIO_SERVICE);
106
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
107
+ int result = audioManager.requestAudioFocus(new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
108
+ .setAudioAttributes(
109
+ new AudioAttributes.Builder()
110
+ .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
111
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
112
+ .build()
113
+ )
114
+ .build());
115
+ if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
116
+ Log.d(TAG, "Audio focus granted");
117
+ } else {
118
+ Log.d(TAG, "Audio focus request failed");
119
+ }
120
+ }
121
+ }
122
+
123
+ @ReactMethod
124
+ public void isDeviceLocked(Promise promise) {
125
+ try {
126
+ KeyguardManager keyguardManager = (KeyguardManager) mReactContext.getSystemService(Context.KEYGUARD_SERVICE);
127
+ boolean isLocked = keyguardManager.isDeviceLocked();
128
+ promise.resolve(isLocked);
129
+ } catch (Exception e) {
130
+ promise.reject("ERROR", e.getMessage());
131
+ }
132
+ }
133
+ }