Skip to content

Commit c43f033

Browse files
Merge pull request #121 from ConnectyCube/development
release 2.5.0
2 parents 5d48e68 + c005863 commit c43f033

12 files changed

+138
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 2.5.0
2+
- (Android) Add API to manage the `Manifest.permission.USE_FULL_SCREEN_INTENT` permission;
3+
14
## 2.4.0
25
- (Android) Add the Call photo to the Call notification and the Incoming call screen;
36
- (Android) Add different icons to the Accept buttons depending on the call type;

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ getting token and displaying the Incoming call screen.
1919
- notifying the app about user action performed on the Incoming call screen (accept, reject, mute (for iOS))
2020
- providing the methods for manual managing of the Incoming screen including the manual showing the Incoming call screen
2121
- getting the data about the current call during the call session
22-
- some customizations according to your app needs (ringtone, icon, accent color(for Android))
22+
- some customizations according to your app needs (ringtone, app icon, accent color(for Android))
23+
- checking and changing the access to the `Manifest.permission.USE_FULL_SCREEN_INTENT` permission (for Android 14 and above)
2324

2425

2526
<kbd><img alt="Flutter P2P Calls code sample, incoming call in background Android" src="https://developers.connectycube.com/docs/_images/code_samples/flutter/background_call_android.png" height="440" /></kbd>
@@ -230,6 +231,20 @@ After finishing that call you should hide your app under the lock screen, do it
230231
ConnectycubeFlutterCallKit.setOnLockScreenVisibility(isVisible: false);
231232
```
232233

234+
### Check the permission `Manifest.permission.USE_FULL_SCREEN_INTENT` state (Android 14 and above)
235+
236+
```dart
237+
var canUseFullScreenIntent = await ConnectycubeFlutterCallKit.canUseFullScreenIntent();
238+
```
239+
240+
### Request the access to the `Manifest.permission.USE_FULL_SCREEN_INTENT` permission (Android 14 and above)
241+
242+
```dart
243+
ConnectycubeFlutterCallKit.provideFullScreenIntentAccess();
244+
```
245+
The function moves the user to the specific setting for your app where you can grant or deny this
246+
permission for your app.
247+
233248
## Show Incoming call screen by push notification
234249
In case you want to display the Incoming call screen automatically by push notification you can do
235250
it easily. For it, the caller should send the push notification to all call members. This push notification should contain some required parameters. If you use the [Connectycube Flutter SDK](https://pub.dev/packages/connectycube_sdk), you can do it using the next code:
@@ -262,4 +277,18 @@ createEvent(params.getEventForRequest()).then((cubeEvent) {
262277
For hiding the Incoming call screen via push notification use a similar request but with a
263278
different `signal_type`, it can be `'endCall'` or `'rejectCall'`.
264279

280+
## Android 14 features
281+
Starting from Android `Build.VERSION_CODES.UPSIDE_DOWN_CAKE`, apps may not have permission to use
282+
`Manifest.permission.USE_FULL_SCREEN_INTENT`. If permission is denied, the call notification will
283+
show up as an expanded heads up notification on lockscreen. The plugin provides the API for checking
284+
the access state and moves to the System setting for enabling it. Please follow the next code
285+
snippet to manage it:
286+
```dart
287+
var canUseFullScreenIntent = await ConnectycubeFlutterCallKit.canUseFullScreenIntent();
288+
289+
if (!canUseFullScreenIntent){
290+
ConnectycubeFlutterCallKit.provideFullScreenIntentAccess();
291+
}
292+
```
293+
265294
You can check how this plugin works in our [P2P Calls code sample](https://github.com/ConnectyCube/connectycube-flutter-samples/tree/master/p2p_call_sample).

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group 'com.connectycube.flutter.connectycube_flutter_call_kit'
2-
version '2.3.0'
2+
version '2.5.0'
33

44
buildscript {
55
ext.kotlin_version = '1.9.10'

android/src/main/kotlin/com/connectycube/flutter/connectycube_flutter_call_kit/ConnectycubeFCMReceiver.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,24 @@ class ConnectycubeFCMReceiver : BroadcastReceiver() {
4747
}
4848

4949
private fun processEndCallEvent(applicationContext: Context, data: Map<String, String>) {
50+
Log.d(TAG, "[processEndCallEvent]")
51+
5052
val callId = data["session_id"] ?: return
5153

5254

5355
processCallEnded(applicationContext, callId)
5456
}
5557

5658
private fun processInviteCallEvent(applicationContext: Context, data: Map<String, String>) {
59+
Log.d(TAG, "[processInviteCallEvent]")
5760
val callId = data["session_id"]
5861

5962
if (callId == null || CALL_STATE_UNKNOWN != getCallState(
6063
applicationContext,
6164
callId
6265
)
6366
) {
67+
Log.d(TAG, "[processInviteCallEvent] callId == null || CALL_STATE_UNKNOWN != getCallState(applicationContext, callId)")
6468
return
6569
}
6670

@@ -76,6 +80,7 @@ class ConnectycubeFCMReceiver : BroadcastReceiver() {
7680
val userInfo = data["user_info"] ?: JSONObject(emptyMap<String, String>()).toString()
7781

7882
if (callType == null || callInitiatorId == null || callInitiatorName == null || callOpponents.isEmpty()) {
83+
Log.d(TAG, "[processInviteCallEvent] callType == null || callInitiatorId == null || callInitiatorName == null || callOpponents.isEmpty()")
7984
return
8085
}
8186

android/src/main/kotlin/com/connectycube/flutter/connectycube_flutter_call_kit/ConnectycubeFCMService.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ class ConnectycubeFCMService : FirebaseMessagingService() {
1111

1212
override fun onMessageReceived(remoteMessage: RemoteMessage) {
1313
super.onMessageReceived(remoteMessage)
14+
Log.d(TAG, "[onMessageReceived]")
1415
// Added for commenting purposes;
1516
// We don't handle the message here as we already handle it in the receiver and don't want to duplicate.
1617
}
1718

1819
override fun onNewToken(token: String) {
1920
super.onNewToken(token)
20-
Log.d(TAG, "onNewToken")
21+
Log.d(TAG, "[onNewToken]")
2122

2223
LocalBroadcastManager.getInstance(applicationContext)
2324
.sendBroadcast(Intent(ACTION_TOKEN_REFRESHED).putExtra(EXTRA_PUSH_TOKEN, token))

android/src/main/kotlin/com/connectycube/flutter/connectycube_flutter_call_kit/ConnectycubeFlutterCallKitPlugin.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ package com.connectycube.flutter.connectycube_flutter_call_kit
22

33
import android.annotation.SuppressLint
44
import android.app.Activity
5+
import android.content.ActivityNotFoundException
56
import android.content.BroadcastReceiver
67
import android.content.Context
78
import android.content.Intent
89
import android.content.IntentFilter
10+
import android.net.Uri
911
import android.os.Build
1012
import android.os.Bundle
13+
import android.provider.Settings
1114
import android.text.TextUtils
1215
import android.util.Log
1316
import android.view.WindowManager
@@ -298,6 +301,30 @@ class ConnectycubeFlutterCallKitPlugin : FlutterPlugin, MethodCallHandler,
298301
result.success(null)
299302
}
300303

304+
"canUseFullScreenIntent" -> {
305+
result.success(canUseFullScreenIntent(applicationContext!!))
306+
}
307+
308+
"provideFullScreenIntentAccess" -> {
309+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
310+
try {
311+
val intent = Intent(
312+
Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT,
313+
Uri.parse("package:${applicationContext?.packageName}")
314+
)
315+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NO_HISTORY)
316+
applicationContext?.startActivity(intent)
317+
} catch (e: ActivityNotFoundException) {
318+
applicationContext?.startActivity(Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
319+
.putExtra(Settings.EXTRA_APP_PACKAGE, applicationContext?.packageName)
320+
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
321+
}
322+
} else {
323+
Log.d("ConnectycubeFlutterCallKitPlugin", "Permission request is available from API version 34 (UPSIDE_DOWN_CAKE) and above")
324+
}
325+
result.success(null)
326+
}
327+
301328
else ->
302329
result.notImplemented()
303330

android/src/main/kotlin/com/connectycube/flutter/connectycube_flutter_call_kit/IncomingCallActivity.kt

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package com.connectycube.flutter.connectycube_flutter_call_kit
22

33
import android.app.Activity
4+
import android.app.KeyguardManager
45
import android.content.BroadcastReceiver
56
import android.content.Context
67
import android.content.Intent
78
import android.content.IntentFilter
9+
import android.os.Build
810
import android.os.Bundle
911
import android.os.Handler
1012
import android.os.Looper
1113
import android.text.TextUtils
14+
import android.util.Log
1215
import android.view.View
1316
import android.view.WindowManager
1417
import android.widget.ImageView
@@ -55,7 +58,7 @@ class IncomingCallActivity : Activity() {
5558
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
5659
setContentView(resources.getIdentifier("activity_incoming_call", "layout", packageName))
5760

58-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
61+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
5962
setShowWhenLocked(true)
6063
setTurnScreenOn(true)
6164
} else {
@@ -65,10 +68,35 @@ class IncomingCallActivity : Activity() {
6568
)
6669
}
6770

68-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q){
71+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
6972
setInheritShowWhenLocked(true)
7073
}
7174

75+
with(getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager) {
76+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
77+
requestDismissKeyguard(this@IncomingCallActivity, object :
78+
KeyguardManager.KeyguardDismissCallback() {
79+
override fun onDismissError() {
80+
Log.d("IncomingCallActivity", "[KeyguardDismissCallback.onDismissError]")
81+
}
82+
83+
override fun onDismissSucceeded() {
84+
Log.d(
85+
"IncomingCallActivity",
86+
"[KeyguardDismissCallback.onDismissSucceeded]"
87+
)
88+
}
89+
90+
override fun onDismissCancelled() {
91+
Log.d(
92+
"IncomingCallActivity",
93+
"[KeyguardDismissCallback.onDismissCancelled]"
94+
)
95+
}
96+
})
97+
}
98+
}
99+
72100
processIncomingData(intent)
73101
initUi()
74102
initCallStateReceiver()

android/src/main/kotlin/com/connectycube/flutter/connectycube_flutter_call_kit/NotificationsManager.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,14 @@ fun showCallNotification(
4040
context: Context, callId: String, callType: Int, callInitiatorId: Int,
4141
callInitiatorName: String, callOpponents: ArrayList<Int>, callPhoto: String?, userInfo: String
4242
) {
43+
Log.d("NotificationsManager", "[showCallNotification]")
4344
val notificationManager = NotificationManagerCompat.from(context)
4445

46+
Log.d(
47+
"NotificationsManager",
48+
"[showCallNotification] canUseFullScreenIntent: ${notificationManager.canUseFullScreenIntent()}"
49+
)
50+
4551
val intent = getLaunchIntent(context)
4652

4753
val pendingIntent = PendingIntent.getActivity(
@@ -55,15 +61,13 @@ fun showCallNotification(
5561
var ringtone: Uri
5662

5763
val customRingtone = getString(context, "ringtone")
58-
Log.d("NotificationsManager", "customRingtone $customRingtone")
5964
if (!TextUtils.isEmpty(customRingtone)) {
6065
ringtone = Uri.parse("android.resource://" + context.packageName + "/raw/" + customRingtone)
61-
Log.d("NotificationsManager", "ringtone 1 $ringtone")
6266
} else {
6367
ringtone = Settings.System.DEFAULT_RINGTONE_URI
6468
}
6569

66-
Log.d("NotificationsManager", "ringtone 2 $ringtone")
70+
Log.d("NotificationsManager", "ringtone: $ringtone")
6771

6872
val isVideoCall = callType == 1
6973

@@ -386,3 +390,7 @@ fun setNotificationColor(context: Context, notificationBuilder: NotificationComp
386390
}
387391
}
388392
}
393+
394+
fun canUseFullScreenIntent(context: Context): Boolean {
395+
return NotificationManagerCompat.from(context).canUseFullScreenIntent()
396+
}

ios/Classes/SwiftConnectycubeFlutterCallKitPlugin.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,12 @@ public class SwiftConnectycubeFlutterCallKitPlugin: NSObject, FlutterPlugin {
193193
SwiftConnectycubeFlutterCallKitPlugin.callController.setMute(uuid: UUID(uuidString: callId)!, muted: muted)
194194
result(true)
195195
}
196+
else if call.method == "canUseFullScreenIntent" {
197+
result(true)
198+
}
199+
else if call.method == "provideFullScreenIntentAccess" {
200+
result(true)
201+
}
196202
else {
197203
result(FlutterMethodNotImplemented)
198204
}

ios/connectycube_flutter_call_kit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55
Pod::Spec.new do |s|
66
s.name = 'connectycube_flutter_call_kit'
7-
s.version = '2.4.0'
7+
s.version = '2.5.0'
88
s.summary = 'Connectycube Call Kit plugin for flutter.'
99
s.description = <<-DESC
1010
Connectycube Call Kit plugin for flutter.

lib/src/connectycube_flutter_call_kit.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,27 @@ class ConnectycubeFlutterCallKit {
279279
});
280280
}
281281

282+
/// Returns whether the app can send fullscreen intents (required for showing
283+
/// the Incoming call screen on the Lockscreen)
284+
static Future<bool> canUseFullScreenIntent() async {
285+
if (!Platform.isAndroid) return Future.value(true);
286+
287+
return _methodChannel.invokeMethod("canUseFullScreenIntent").then((result) {
288+
if (result == null) {
289+
return false;
290+
}
291+
292+
return result;
293+
});
294+
}
295+
296+
/// Opens the Setting to grant/deny permission for running the fullscreen Intents
297+
static Future<void> provideFullScreenIntentAccess() async {
298+
if (!Platform.isAndroid) return Future.value();
299+
300+
return _methodChannel.invokeMethod("provideFullScreenIntentAccess");
301+
}
302+
282303
static void _processEvent(Map<String, dynamic> eventData) {
283304
log('[ConnectycubeFlutterCallKit][_processEvent] eventData: $eventData');
284305

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: connectycube_flutter_call_kit
22
description: A Flutter plugin for displaying call screen when app in background or terminated.
3-
version: 2.4.0
3+
version: 2.5.0
44
homepage: https://connectycube.com/
55
issue_tracker: https://github.com/ConnectyCube/connectycube-flutter-call-kit/issues
66
documentation: https://github.com/ConnectyCube/connectycube-flutter-call-kit/blob/master/README.md

0 commit comments

Comments
 (0)