Skip to content

Commit

Permalink
Merge pull request #585 from hiennguyen92/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
hiennguyen92 authored Sep 22, 2024
2 parents 33ea47c + d726b0d commit fd7dd0d
Show file tree
Hide file tree
Showing 14 changed files with 168 additions and 69 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 2.0.4+2
* add func `requestFullIntentPermission` (Android 14+) thank @Spyspyspy https://github.com/hiennguyen92/flutter_callkit_incoming/pull/584
* set Notification call style (Android) thank @AAkira https://github.com/hiennguyen92/flutter_callkit_incoming/pull/553
* Many other issues
1. add prop `accepted` in activeCalls (iOS) thank @vasilich6107
2.

## 2.0.4+1
* Removed `Telecom Framework` (Android)

Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ Our top sponsors are shown below!
});
```

* request permission for full intent Notification/full screen locked screen Android 14+
For Android 14+, please `requestFullIntentPermission`
```dart
await FlutterCallkitIncoming.requestFullIntentPermission();
```

* Show miss call notification
```dart
this._currentUuid = _uuid.v4();
Expand Down Expand Up @@ -504,7 +510,7 @@ Our top sponsors are shown below!
| **`incomingCallNotificationChannelName`** | Notification channel name of incoming call. | `Incoming call` |
| **`missedCallNotificationChannelName`** | Notification channel name of missed call. | `Missed call` |
| **`isShowCallID`** | Show call id app inside full screen/notification. | false |
| **`isShowFullLockedScreen`** | Show full screen on Locked Screen. | true |
| **`isShowFullLockedScreen`** | Show full screen on Locked Screen(please make sure call `requestFullIntentPermission` for android 14+). | true |

<br>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ data class Data(val args: Map<String, Any?>) {
@JsonProperty("isShowFullLockedScreen")
var isShowFullLockedScreen: Boolean = true

@JsonProperty("isImportant")
var isImportant: Boolean = false
@JsonProperty("isBot")
var isBot: Boolean = false

init {
var android: Map<String, Any?>? = args["android"] as? HashMap<String, Any?>?
android = android ?: args
Expand All @@ -101,6 +106,8 @@ data class Data(val args: Map<String, Any?>) {
android["incomingCallNotificationChannelName"] as? String
missedCallNotificationChannelName = android["missedCallNotificationChannelName"] as? String
isShowFullLockedScreen = android["isShowFullLockedScreen"] as? Boolean ?: true
isImportant = android["isImportant"] as? Boolean ?: false
isBot = android["isBot"] as? Boolean ?: false

val missedNotification: Map<String, Any?>? =
args["missedCallNotification"] as? Map<String, Any?>?
Expand Down Expand Up @@ -214,6 +221,14 @@ data class Data(val args: Map<String, Any?>) {
CallkitConstants.EXTRA_CALLKIT_IS_SHOW_FULL_LOCKED_SCREEN,
isShowFullLockedScreen
)
bundle.putBoolean(
CallkitConstants.EXTRA_CALLKIT_IS_IMPORTANT,
isImportant,
)
bundle.putBoolean(
CallkitConstants.EXTRA_CALLKIT_IS_BOT,
isBot,
)
return bundle
}

Expand All @@ -237,6 +252,10 @@ data class Data(val args: Map<String, Any?>) {
bundle.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_ACCEPT, "")
data.textDecline =
bundle.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_DECLINE, "")
data.isImportant =
bundle.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_IMPORTANT, false)
data.isBot =
bundle.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_BOT, false)

data.missedNotificationId =
bundle.getInt(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,6 @@ object CallkitConstants {
const val EXTRA_CALLKIT_ACTION_FROM = "EXTRA_CALLKIT_ACTION_FROM"

const val EXTRA_CALLKIT_IS_SHOW_FULL_LOCKED_SCREEN = "EXTRA_CALLKIT_IS_SHOW_FULL_LOCKED_SCREEN"
const val EXTRA_CALLKIT_IS_IMPORTANT = "EXTRA_CALLKIT_IS_IMPORTANT"
const val EXTRA_CALLKIT_IS_BOT = "EXTRA_CALLKIT_IS_BOT"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,64 @@ class CallkitIncomingBroadcastReceiver : BroadcastReceiver() {
var silenceEvents = false

fun getIntent(context: Context, action: String, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
this.action = "${context.packageName}.${action}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
this.action = "${context.packageName}.${action}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentIncoming(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_INCOMING}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_INCOMING}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentStart(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_START}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_START}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentAccept(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_ACCEPT}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_ACCEPT}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentDecline(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_DECLINE}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_DECLINE}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentEnded(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_ENDED}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_ENDED}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentTimeout(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_TIMEOUT}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_TIMEOUT}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentCallback(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_CALLBACK}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_CALLBACK}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentHeldByCell(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_HELD}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_HELD}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}

fun getIntentUnHeldByCell(context: Context, data: Bundle?) =
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_UNHELD}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
Intent(context, CallkitIncomingBroadcastReceiver::class.java).apply {
action = "${context.packageName}.${CallkitConstants.ACTION_CALL_UNHELD}"
putExtra(CallkitConstants.EXTRA_CALLKIT_INCOMING_DATA, data)
}
}


Expand Down Expand Up @@ -190,6 +190,8 @@ class CallkitIncomingBroadcastReceiver : BroadcastReceiver() {
CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_NOTIFICATION_CHANNEL_NAME,
""
),
"isImportant" to data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_IMPORTANT, false),
"isBot" to data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_BOT, false),
)
val notification = mapOf(
"id" to data.getInt(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_ID),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.widget.RemoteViews
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person
import com.hiennv.flutter_callkit_incoming.widgets.CircleTransform
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
Expand Down Expand Up @@ -172,39 +172,53 @@ class CallkitNotificationManager(private val context: Context) {
notificationBuilder.setCustomBigContentView(notificationViews)
notificationBuilder.setCustomHeadsUpContentView(notificationSmallViews)
} else {
notificationBuilder.setContentText(
data.getString(
CallkitConstants.EXTRA_CALLKIT_HANDLE,
""
)
)
val avatarUrl = data.getString(CallkitConstants.EXTRA_CALLKIT_AVATAR, "")
if (avatarUrl != null && avatarUrl.isNotEmpty()) {
val headers =
data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap<String, Any?>
getPicassoInstance(context, headers).load(avatarUrl)
.into(targetLoadAvatarDefault)
}
notificationBuilder.setContentTitle(
data.getString(
CallkitConstants.EXTRA_CALLKIT_NAME_CALLER,
""
)
)
notificationBuilder.setContentText(
data.getString(
CallkitConstants.EXTRA_CALLKIT_HANDLE,
""
val caller = data.getString(CallkitConstants.EXTRA_CALLKIT_NAME_CALLER, "")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val person = Person.Builder()
.setName(caller)
.setImportant(
data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_IMPORTANT, false)
)
.setBot(data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_BOT, false))
.build()
notificationBuilder.setStyle(
NotificationCompat.CallStyle.forIncomingCall(
person,
getDeclinePendingIntent(notificationId, data),
getAcceptPendingIntent(notificationId, data),
)
.setIsVideo(typeCall > 0)
)
)
val textDecline = data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_DECLINE, "")
val declineAction: NotificationCompat.Action = NotificationCompat.Action.Builder(
R.drawable.ic_decline,
if (TextUtils.isEmpty(textDecline)) context.getString(R.string.text_decline) else textDecline,
getDeclinePendingIntent(notificationId, data)
).build()
notificationBuilder.addAction(declineAction)
val textAccept = data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_ACCEPT, "")
val acceptAction: NotificationCompat.Action = NotificationCompat.Action.Builder(
R.drawable.ic_accept,
if (TextUtils.isEmpty(textDecline)) context.getString(R.string.text_accept) else textAccept,
getAcceptPendingIntent(notificationId, data)
).build()
notificationBuilder.addAction(acceptAction)
} else {
notificationBuilder.setContentTitle(caller)
val textDecline = data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_DECLINE, "")
val declineAction: NotificationCompat.Action = NotificationCompat.Action.Builder(
R.drawable.ic_decline,
if (TextUtils.isEmpty(textDecline)) context.getString(R.string.text_decline) else textDecline,
getDeclinePendingIntent(notificationId, data)
).build()
notificationBuilder.addAction(declineAction)
val textAccept = data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_ACCEPT, "")
val acceptAction: NotificationCompat.Action = NotificationCompat.Action.Builder(
R.drawable.ic_accept,
if (TextUtils.isEmpty(textDecline)) context.getString(R.string.text_accept) else textAccept,
getAcceptPendingIntent(notificationId, data)
).build()
notificationBuilder.addAction(acceptAction)
}
}
val notification = notificationBuilder.build()
notification.flags = Notification.FLAG_INSISTENT
Expand Down Expand Up @@ -556,6 +570,15 @@ class CallkitNotificationManager(private val context: Context) {
}
}

fun requestFullIntentPermission(activity: Activity?) {
if (Build.VERSION.SDK_INT > 33) {
val intent = Intent(Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT).apply {
data = Uri.fromParts("package", activity?.packageName, null)
}
activity?.startActivity(intent)
}
}

fun onRequestPermissionsResult(activity: Activity?, requestCode: Int, grantResults: IntArray) {
when (requestCode) {
PERMISSION_NOTIFICATION_REQUEST_CODE -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
}
callkitNotificationManager?.requestNotificationPermission(activity, map)
}
"requestFullIntentPermission" -> {
callkitNotificationManager?.requestFullIntentPermission(activity)
}
// EDIT - clear the incoming notification/ring (after accept/decline/timeout)
"hideCallkitIncoming" -> {
val data = Data(call.arguments() ?: HashMap())
Expand Down
2 changes: 2 additions & 0 deletions example/lib/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ class HomePageState extends State<HomePage> {
textColor: '#ffffff',
incomingCallNotificationChannelName: 'Incoming Call',
missedCallNotificationChannelName: 'Missed Call',
isImportant: true,
isBot: false,
),
ios: const IOSParams(
iconName: 'CallKitLogo',
Expand Down
14 changes: 13 additions & 1 deletion ios/Classes/CallManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ class CallManager: NSObject {
func connectedCall(call: Call) {
let callItem = self.callWithUUID(uuid: call.uuid)
callItem?.connectedCall(completion: nil)

let answerAction = CXAnswerCallAction(call: call.uuid)
let transaction = CXTransaction(action: answerAction)

callController.request(transaction) { error in
if let error = error {
print("Error answering call: \(error.localizedDescription)")
} else {
// Call successfully answered
}
}
}

func endCallAlls() {
Expand All @@ -84,7 +95,8 @@ class CallManager: NSObject {
for call in calls {
let callItem = self.callWithUUID(uuid: call.uuid)
if(callItem != nil){
let item: [String: Any] = callItem!.data.toJSON()
var item: [String: Any] = callItem!.data.toJSON()
item["accepted"] = callItem?.hasConnected
json.append(item)
}else {
let item: [String: String] = ["id": call.uuid.uuidString]
Expand Down
3 changes: 3 additions & 0 deletions ios/Classes/SwiftFlutterCallkitIncomingPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ public class SwiftFlutterCallkitIncomingPlugin: NSObject, FlutterPlugin, CXProvi
case "requestNotificationPermission":
result("OK")
break
case "requestFullIntentPermission":
result("OK")
break
case "hideCallkitIncoming":
result("OK")
break
Expand Down
10 changes: 10 additions & 0 deletions lib/entities/android_params.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class AndroidParams {
this.incomingCallNotificationChannelName,
this.missedCallNotificationChannelName,
this.isShowFullLockedScreen,
this.isImportant,
this.isBot,
});

/// Using custom notifications.
Expand Down Expand Up @@ -56,6 +58,14 @@ class AndroidParams {
/// Show full locked screen.
final bool? isShowFullLockedScreen;

/// Caller is important to the user of this device with regards to how frequently they interact.
/// https://developer.android.com/reference/androidx/core/app/Person#isImportant()
final bool? isImportant;

/// Used primarily to identify automated tooling.
/// https://developer.android.com/reference/androidx/core/app/Person#isBot()
final bool? isBot;

factory AndroidParams.fromJson(Map<String, dynamic> json) =>
_$AndroidParamsFromJson(json);

Expand Down
Loading

0 comments on commit fd7dd0d

Please sign in to comment.