diff --git a/CHANGELOG.md b/CHANGELOG.md
index a795f9c9..5d8fad4a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 2.0.0+2
+
+* Fixed some bugs.
+* Support request permission for Android 13+ `requestNotificationPermission`
+
## 2.0.0+1
* Fixed some bugs.
diff --git a/README.md b/README.md
index e3d25164..07fab3b0 100644
--- a/README.md
+++ b/README.md
@@ -118,6 +118,16 @@ A Flutter plugin to show incoming call in your Flutter app(Custom for Android/Ca
```
Note: Firebase Message: `@pragma('vm:entry-point')`
https://github.com/firebase/flutterfire/blob/master/docs/cloud-messaging/receive.md#apple-platforms-and-android
+
+ * request permission for post Notification Android 13+
+ For Android 13 and above, please `requestNotificationPermission` before `showCallkitIncoming`
+ ```dart
+ await FlutterCallkitIncoming.requestNotificationPermission({
+ "rationaleMessagePermission": "Notification permission is required, to show notification.",
+ "postNotificationMessageRequired": "Notification permission is required, Please allow notification permission from setting."
+ });
+ ```
+
* Show miss call notification
```dart
this._currentUuid = _uuid.v4();
diff --git a/android/build.gradle b/android/build.gradle
index d29e2c36..5cabe22e 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -28,7 +28,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
- compileSdkVersion 31
+ compileSdkVersion 33
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
diff --git a/android/consumer-rules.pro b/android/consumer-rules.pro
index 9eec6cb7..8cdcd047 100644
--- a/android/consumer-rules.pro
+++ b/android/consumer-rules.pro
@@ -1,3 +1,5 @@
#flutter_callkit_incoming
# Issue: https://github.com/hiennguyen92/flutter_callkit_incoming/issues/171
--keep class com.hiennv.flutter_callkit_incoming.** { *; }
\ No newline at end of file
+-keep class com.hiennv.flutter_callkit_incoming.** { *; }
+-keep class com.fasterxml.** { *; }
+-keep class org.codehaus.** { *; }
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index a372fcf7..dabdfcb3 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
+
diff --git a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt
index 9be172cc..faebc84b 100644
--- a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt
+++ b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt
@@ -1,11 +1,15 @@
package com.hiennv.flutter_callkit_incoming
+import android.Manifest
+import android.app.Activity
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
+import android.content.DialogInterface
import android.content.Intent
+import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
@@ -15,9 +19,12 @@ import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
+import android.provider.Settings
import android.text.TextUtils
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 com.hiennv.flutter_callkit_incoming.widgets.CircleTransform
@@ -30,6 +37,7 @@ import okhttp3.OkHttpClient
class CallkitNotificationManager(private val context: Context) {
companion object {
+ const val PERMISSION_NOTIFICATION_REQUEST_CODE = 6969
const val EXTRA_TIME_START_CALL = "EXTRA_TIME_START_CALL"
@@ -41,6 +49,7 @@ class CallkitNotificationManager(private val context: Context) {
private var notificationViews: RemoteViews? = null
private var notificationSmallViews: RemoteViews? = null
private var notificationId: Int = 9696
+ private var dataNotificationPermission: Map = HashMap()
private var targetLoadAvatarDefault = object : Target {
override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
@@ -77,14 +86,14 @@ class CallkitNotificationManager(private val context: Context) {
notificationId = data.getString(CallkitConstants.EXTRA_CALLKIT_ID, "callkit_incoming").hashCode()
createNotificationChanel(
- data.getString(
- CallkitConstants.EXTRA_CALLKIT_INCOMING_CALL_NOTIFICATION_CHANNEL_NAME,
- "Incoming Call"
- ),
- data.getString(
- CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_NOTIFICATION_CHANNEL_NAME,
- "Missed Call"
- ),
+ data.getString(
+ CallkitConstants.EXTRA_CALLKIT_INCOMING_CALL_NOTIFICATION_CHANNEL_NAME,
+ "Incoming Call"
+ ),
+ data.getString(
+ CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_NOTIFICATION_CHANNEL_NAME,
+ "Missed Call"
+ ),
)
notificationBuilder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID_INCOMING)
@@ -102,7 +111,7 @@ class CallkitNotificationManager(private val context: Context) {
notificationBuilder.setOnlyAlertOnce(true)
notificationBuilder.setSound(null)
notificationBuilder.setFullScreenIntent(
- getActivityPendingIntent(notificationId, data), true
+ getActivityPendingIntent(notificationId, data), true
)
notificationBuilder.setContentIntent(getActivityPendingIntent(notificationId, data))
notificationBuilder.setDeleteIntent(getTimeOutPendingIntent(notificationId, data))
@@ -124,25 +133,25 @@ class CallkitNotificationManager(private val context: Context) {
notificationBuilder.setChannelId(NOTIFICATION_CHANNEL_ID_INCOMING)
notificationBuilder.priority = NotificationCompat.PRIORITY_MAX
val isCustomNotification =
- data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_NOTIFICATION, false)
+ data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_NOTIFICATION, false)
val isCustomSmallExNotification =
- data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_SMALL_EX_NOTIFICATION, false)
+ data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_SMALL_EX_NOTIFICATION, false)
if (isCustomNotification) {
notificationViews =
- RemoteViews(context.packageName, R.layout.layout_custom_notification)
+ RemoteViews(context.packageName, R.layout.layout_custom_notification)
initNotificationViews(notificationViews!!, data)
if ((Build.MANUFACTURER.equals(
- "Samsung",
- ignoreCase = true
- ) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) || isCustomSmallExNotification
+ "Samsung",
+ ignoreCase = true
+ ) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) || isCustomSmallExNotification
) {
notificationSmallViews =
- RemoteViews(context.packageName, R.layout.layout_custom_small_ex_notification)
+ RemoteViews(context.packageName, R.layout.layout_custom_small_ex_notification)
initNotificationViews(notificationSmallViews!!, data)
} else {
notificationSmallViews =
- RemoteViews(context.packageName, R.layout.layout_custom_small_notification)
+ RemoteViews(context.packageName, R.layout.layout_custom_small_notification)
initNotificationViews(notificationSmallViews!!, data)
}
@@ -154,29 +163,29 @@ class CallkitNotificationManager(private val context: Context) {
val avatarUrl = data.getString(CallkitConstants.EXTRA_CALLKIT_AVATAR, "")
if (avatarUrl != null && avatarUrl.isNotEmpty()) {
val headers =
- data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap
+ data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap
getPicassoInstance(context, headers).load(avatarUrl)
- .into(targetLoadAvatarDefault)
+ .into(targetLoadAvatarDefault)
}
notificationBuilder.setContentTitle(
- data.getString(
- CallkitConstants.EXTRA_CALLKIT_NAME_CALLER,
- ""
- )
+ data.getString(
+ CallkitConstants.EXTRA_CALLKIT_NAME_CALLER,
+ ""
+ )
)
notificationBuilder.setContentText(data.getString(CallkitConstants.EXTRA_CALLKIT_HANDLE, ""))
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)
+ 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)
+ R.drawable.ic_accept,
+ if (TextUtils.isEmpty(textDecline)) context.getString(R.string.text_accept) else textAccept,
+ getAcceptPendingIntent(notificationId, data)
).build()
notificationBuilder.addAction(acceptAction)
}
@@ -187,55 +196,55 @@ class CallkitNotificationManager(private val context: Context) {
private fun initNotificationViews(remoteViews: RemoteViews, data: Bundle) {
remoteViews.setTextViewText(
- R.id.tvNameCaller,
- data.getString(CallkitConstants.EXTRA_CALLKIT_NAME_CALLER, "")
+ R.id.tvNameCaller,
+ data.getString(CallkitConstants.EXTRA_CALLKIT_NAME_CALLER, "")
)
remoteViews.setTextViewText(
- R.id.tvNumber,
- data.getString(CallkitConstants.EXTRA_CALLKIT_HANDLE, "")
+ R.id.tvNumber,
+ data.getString(CallkitConstants.EXTRA_CALLKIT_HANDLE, "")
)
remoteViews.setOnClickPendingIntent(
- R.id.llDecline,
- getDeclinePendingIntent(notificationId, data)
+ R.id.llDecline,
+ getDeclinePendingIntent(notificationId, data)
)
val textDecline = data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_DECLINE, "")
remoteViews.setTextViewText(
- R.id.tvDecline,
- if (TextUtils.isEmpty(textDecline)) context.getString(R.string.text_decline) else textDecline
+ R.id.tvDecline,
+ if (TextUtils.isEmpty(textDecline)) context.getString(R.string.text_decline) else textDecline
)
remoteViews.setOnClickPendingIntent(
- R.id.llAccept,
- getAcceptPendingIntent(notificationId, data)
+ R.id.llAccept,
+ getAcceptPendingIntent(notificationId, data)
)
val textAccept = data.getString(CallkitConstants.EXTRA_CALLKIT_TEXT_ACCEPT, "")
remoteViews.setTextViewText(
- R.id.tvAccept,
- if (TextUtils.isEmpty(textAccept)) context.getString(R.string.text_accept) else textAccept
+ R.id.tvAccept,
+ if (TextUtils.isEmpty(textAccept)) context.getString(R.string.text_accept) else textAccept
)
val avatarUrl = data.getString(CallkitConstants.EXTRA_CALLKIT_AVATAR, "")
if (avatarUrl != null && avatarUrl.isNotEmpty()) {
val headers =
- data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap
+ data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap
getPicassoInstance(context, headers).load(avatarUrl)
- .transform(CircleTransform())
- .into(targetLoadAvatarCustomize)
+ .transform(CircleTransform())
+ .into(targetLoadAvatarCustomize)
}
}
fun showMissCallNotification(data: Bundle) {
notificationId = data.getInt(
- CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_ID,
- data.getString(CallkitConstants.EXTRA_CALLKIT_ID, "callkit_incoming").hashCode() + 1
+ CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_ID,
+ data.getString(CallkitConstants.EXTRA_CALLKIT_ID, "callkit_incoming").hashCode() + 1
)
createNotificationChanel(
- data.getString(
- CallkitConstants.EXTRA_CALLKIT_INCOMING_CALL_NOTIFICATION_CHANNEL_NAME,
- "Incoming Call"
- ),
- data.getString(
- CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_NOTIFICATION_CHANNEL_NAME,
- "Missed Call"
- ),
+ data.getString(
+ CallkitConstants.EXTRA_CALLKIT_INCOMING_CALL_NOTIFICATION_CHANNEL_NAME,
+ "Incoming Call"
+ ),
+ data.getString(
+ CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_NOTIFICATION_CHANNEL_NAME,
+ "Missed Call"
+ ),
)
val missedCallSound: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val typeCall = data.getInt(CallkitConstants.EXTRA_CALLKIT_TYPE, -1)
@@ -258,78 +267,78 @@ class CallkitNotificationManager(private val context: Context) {
notificationBuilder.setSubText(if (TextUtils.isEmpty(textMissedCall)) context.getString(R.string.text_missed_call) else textMissedCall)
notificationBuilder.setSmallIcon(smallIcon)
val isCustomNotification =
- data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_NOTIFICATION, false)
+ data.getBoolean(CallkitConstants.EXTRA_CALLKIT_IS_CUSTOM_NOTIFICATION, false)
val count = data.getInt(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_COUNT, 1)
if (count > 1) {
notificationBuilder.setNumber(count)
}
if (isCustomNotification) {
notificationViews =
- RemoteViews(context.packageName, R.layout.layout_custom_miss_notification)
+ RemoteViews(context.packageName, R.layout.layout_custom_miss_notification)
notificationViews?.setTextViewText(
- R.id.tvNameCaller,
- data.getString(CallkitConstants.EXTRA_CALLKIT_NAME_CALLER, "")
+ R.id.tvNameCaller,
+ data.getString(CallkitConstants.EXTRA_CALLKIT_NAME_CALLER, "")
)
notificationViews?.setTextViewText(
- R.id.tvNumber,
- data.getString(CallkitConstants.EXTRA_CALLKIT_HANDLE, "")
+ R.id.tvNumber,
+ data.getString(CallkitConstants.EXTRA_CALLKIT_HANDLE, "")
)
notificationViews?.setOnClickPendingIntent(
- R.id.llCallback,
- getCallbackPendingIntent(notificationId, data)
+ R.id.llCallback,
+ getCallbackPendingIntent(notificationId, data)
)
val isShowCallback = data.getBoolean(
- CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_SHOW,
- true
+ CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_SHOW,
+ true
)
notificationViews?.setViewVisibility(
- R.id.llCallback,
- if (isShowCallback) View.VISIBLE else View.GONE
+ R.id.llCallback,
+ if (isShowCallback) View.VISIBLE else View.GONE
)
val textCallback = data.getString(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_TEXT, "")
notificationViews?.setTextViewText(
- R.id.tvCallback,
- if (TextUtils.isEmpty(textCallback)) context.getString(R.string.text_call_back) else textCallback
+ R.id.tvCallback,
+ if (TextUtils.isEmpty(textCallback)) context.getString(R.string.text_call_back) else textCallback
)
val avatarUrl = data.getString(CallkitConstants.EXTRA_CALLKIT_AVATAR, "")
if (avatarUrl != null && avatarUrl.isNotEmpty()) {
val headers =
- data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap
+ data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap
getPicassoInstance(context, headers).load(avatarUrl)
- .transform(CircleTransform()).into(targetLoadAvatarCustomize)
+ .transform(CircleTransform()).into(targetLoadAvatarCustomize)
}
notificationBuilder.setStyle(NotificationCompat.DecoratedCustomViewStyle())
notificationBuilder.setCustomContentView(notificationViews)
notificationBuilder.setCustomBigContentView(notificationViews)
} else {
notificationBuilder.setContentTitle(
- data.getString(
- CallkitConstants.EXTRA_CALLKIT_NAME_CALLER,
- ""
- )
+ data.getString(
+ CallkitConstants.EXTRA_CALLKIT_NAME_CALLER,
+ ""
+ )
)
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
+ data.getSerializable(CallkitConstants.EXTRA_CALLKIT_HEADERS) as HashMap
getPicassoInstance(context, headers).load(avatarUrl)
- .into(targetLoadAvatarDefault)
+ .into(targetLoadAvatarDefault)
}
val isShowCallback = data.getBoolean(
- CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_SHOW,
- true
+ CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_SHOW,
+ true
)
if (isShowCallback) {
val textCallback =
- data.getString(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_TEXT, "")
+ data.getString(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_CALLBACK_TEXT, "")
val callbackAction: NotificationCompat.Action = NotificationCompat.Action.Builder(
- R.drawable.ic_accept,
- if (TextUtils.isEmpty(textCallback)) context.getString(R.string.text_call_back) else textCallback,
- getCallbackPendingIntent(notificationId, data)
+ R.drawable.ic_accept,
+ if (TextUtils.isEmpty(textCallback)) context.getString(R.string.text_call_back) else textCallback,
+ getCallbackPendingIntent(notificationId, data)
).build()
notificationBuilder.addAction(callbackAction)
}
@@ -385,8 +394,8 @@ class CallkitNotificationManager(private val context: Context) {
}
private fun createNotificationChanel(
- incomingCallChannelName: String,
- missedCallChannelName: String,
+ incomingCallChannelName: String,
+ missedCallChannelName: String,
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getNotificationManager().apply {
@@ -395,13 +404,13 @@ class CallkitNotificationManager(private val context: Context) {
channelCall.setSound(null, null)
} else {
channelCall = NotificationChannel(
- NOTIFICATION_CHANNEL_ID_INCOMING,
- incomingCallChannelName,
- NotificationManager.IMPORTANCE_HIGH
+ NOTIFICATION_CHANNEL_ID_INCOMING,
+ incomingCallChannelName,
+ NotificationManager.IMPORTANCE_HIGH
).apply {
description = ""
vibrationPattern =
- longArrayOf(0, 1000, 500, 1000, 500)
+ longArrayOf(0, 1000, 500, 1000, 500)
lightColor = Color.RED
enableLights(true)
enableVibration(true)
@@ -415,9 +424,9 @@ class CallkitNotificationManager(private val context: Context) {
createNotificationChannel(channelCall)
val channelMissedCall = NotificationChannel(
- NOTIFICATION_CHANNEL_ID_MISSED,
- missedCallChannelName,
- NotificationManager.IMPORTANCE_DEFAULT
+ NOTIFICATION_CHANNEL_ID_MISSED,
+ missedCallChannelName,
+ NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = ""
vibrationPattern = longArrayOf(0, 1000)
@@ -433,9 +442,9 @@ class CallkitNotificationManager(private val context: Context) {
private fun getAcceptPendingIntent(id: Int, data: Bundle): PendingIntent {
val intentTransparent = TransparentActivity.getIntent(
- context,
- CallkitConstants.ACTION_CALL_ACCEPT,
- data
+ context,
+ CallkitConstants.ACTION_CALL_ACCEPT,
+ data
)
return PendingIntent.getActivity(context, id, intentTransparent, getFlagPendingIntent())
}
@@ -452,9 +461,9 @@ class CallkitNotificationManager(private val context: Context) {
private fun getCallbackPendingIntent(id: Int, data: Bundle): PendingIntent {
val intentTransparent = TransparentActivity.getIntent(
- context,
- CallkitConstants.ACTION_CALL_CALLBACK,
- data
+ context,
+ CallkitConstants.ACTION_CALL_CALLBACK,
+ data
)
return PendingIntent.getActivity(context, id, intentTransparent, getFlagPendingIntent())
}
@@ -484,18 +493,88 @@ class CallkitNotificationManager(private val context: Context) {
private fun getPicassoInstance(context: Context, headers: HashMap): Picasso {
val client = OkHttpClient.Builder()
- .addNetworkInterceptor { chain ->
- val newRequestBuilder: okhttp3.Request.Builder = chain.request().newBuilder()
- for ((key, value) in headers) {
- newRequestBuilder.addHeader(key, value.toString())
+ .addNetworkInterceptor { chain ->
+ val newRequestBuilder: okhttp3.Request.Builder = chain.request().newBuilder()
+ for ((key, value) in headers) {
+ newRequestBuilder.addHeader(key, value.toString())
+ }
+ chain.proceed(newRequestBuilder.build())
}
- chain.proceed(newRequestBuilder.build())
- }
- .build()
+ .build()
return Picasso.Builder(context)
- .downloader(OkHttp3Downloader(client))
- .build()
+ .downloader(OkHttp3Downloader(client))
+ .build()
+ }
+
+
+ fun requestNotificationPermission(activity: Activity?, map: Map) {
+ this.dataNotificationPermission = map
+ if (Build.VERSION.SDK_INT > 32) {
+ activity?.let {
+ ActivityCompat.requestPermissions(it,
+ arrayOf(Manifest.permission.POST_NOTIFICATIONS),
+ PERMISSION_NOTIFICATION_REQUEST_CODE)
+ }
+ }
+ }
+
+ fun onRequestPermissionsResult(activity: Activity?, requestCode: Int, grantResults: IntArray) {
+ when (requestCode) {
+ PERMISSION_NOTIFICATION_REQUEST_CODE -> {
+ if (grantResults.isNotEmpty() &&
+ grantResults[0] === PackageManager.PERMISSION_GRANTED) {
+ // allow
+ } else {
+ //deny
+ activity?.let {
+ if (ActivityCompat.shouldShowRequestPermissionRationale(it, Manifest.permission.POST_NOTIFICATIONS)) {
+ //showDialogPermissionRationale()
+ if (this.dataNotificationPermission["rationaleMessagePermission"] != null) {
+ showDialogMessage(it, this.dataNotificationPermission["rationaleMessagePermission"] as String) { dialog, _ ->
+ dialog?.dismiss()
+ requestNotificationPermission(activity, this.dataNotificationPermission)
+ }
+ } else {
+ requestNotificationPermission(activity, this.dataNotificationPermission)
+ }
+ } else {
+ //Open Setting
+ if (this.dataNotificationPermission["postNotificationMessageRequired"] != null) {
+ showDialogMessage(it, this.dataNotificationPermission["postNotificationMessageRequired"] as String) { dialog, _ ->
+ dialog?.dismiss()
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", it.packageName, null))
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ it.startActivity(intent)
+ }
+ } else {
+ showDialogMessage(it, it.resources.getString(R.string.text_post_notification_message_required)) { dialog, _ ->
+ dialog?.dismiss()
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", it.packageName, null))
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ it.startActivity(intent)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun showDialogMessage(activity: Activity?, message: String, okListener: DialogInterface.OnClickListener) {
+ activity?.let {
+ AlertDialog.Builder(it, R.style.DialogTheme)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.ok, okListener)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create()
+ .show()
+ }
}
}
+
+
diff --git a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt
index 9947aad7..f3db194c 100644
--- a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt
+++ b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt
@@ -1,28 +1,32 @@
package com.hiennv.flutter_callkit_incoming
+import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
import android.os.Handler
import android.os.Looper
+import android.provider.Settings
import androidx.annotation.NonNull
-import androidx.annotation.Nullable
-
+import androidx.appcompat.app.AlertDialog
+import androidx.core.app.ActivityCompat
import com.hiennv.flutter_callkit_incoming.Utils.Companion.reapCollection
-
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
-import io.flutter.plugin.common.BinaryMessenger
-import io.flutter.plugin.common.EventChannel
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.common.*
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import java.lang.ref.WeakReference
+
/** FlutterCallkitIncomingPlugin */
-class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
+class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.RequestPermissionsResultListener {
companion object {
const val EXTRA_CALLKIT_CALL_DATA = "EXTRA_CALLKIT_CALL_DATA"
@@ -76,6 +80,7 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
eventHandlers.add(WeakReference(handler))
events.setStreamHandler(handler)
}
+
}
/// The MethodChannel that will the communication between Flutter and native Android
@@ -95,10 +100,10 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
callkitNotificationManager?.showIncomingNotification(data.toBundle())
//send BroadcastReceiver
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentIncoming(
- requireNotNull(context),
- data.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentIncoming(
+ requireNotNull(context),
+ data.toBundle()
+ )
)
}
@@ -108,19 +113,19 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
public fun startCall(data: Data) {
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentStart(
- requireNotNull(context),
- data.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentStart(
+ requireNotNull(context),
+ data.toBundle()
+ )
)
}
public fun endCall(data: Data) {
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentEnded(
- requireNotNull(context),
- data.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentEnded(
+ requireNotNull(context),
+ data.toBundle()
+ )
)
}
@@ -128,10 +133,10 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
val calls = getDataActiveCalls(context)
calls.forEach {
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentEnded(
- requireNotNull(context),
- it.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentEnded(
+ requireNotNull(context),
+ it.toBundle()
+ )
)
}
removeAllCalls(context)
@@ -151,10 +156,10 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
data.from = "notification"
//send BroadcastReceiver
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentIncoming(
- requireNotNull(context),
- data.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentIncoming(
+ requireNotNull(context),
+ data.toBundle()
+ )
)
result.success("OK")
}
@@ -167,10 +172,10 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
"startCall" -> {
val data = Data(call.arguments() ?: HashMap())
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentStart(
- requireNotNull(context),
- data.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentStart(
+ requireNotNull(context),
+ data.toBundle()
+ )
)
result.success("OK")
}
@@ -194,13 +199,16 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
sendEvent(CallkitConstants.ACTION_CALL_TOGGLE_HOLD, map);
result.success("OK")
}
+ "isMuted" -> {
+ result.success(false)
+ }
"endCall" -> {
val data = Data(call.arguments() ?: HashMap())
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentEnded(
- requireNotNull(context),
- data.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentEnded(
+ requireNotNull(context),
+ data.toBundle()
+ )
)
result.success("OK")
}
@@ -212,17 +220,17 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
calls.forEach {
if (it.isAccepted) {
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentEnded(
- requireNotNull(context),
- it.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentEnded(
+ requireNotNull(context),
+ it.toBundle()
+ )
)
} else {
context?.sendBroadcast(
- CallkitIncomingBroadcastReceiver.getIntentDecline(
- requireNotNull(context),
- it.toBundle()
- )
+ CallkitIncomingBroadcastReceiver.getIntentDecline(
+ requireNotNull(context),
+ it.toBundle()
+ )
)
}
}
@@ -235,6 +243,15 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
"getDevicePushTokenVoIP" -> {
result.success("")
}
+ "requestNotificationPermission" -> {
+ val map = buildMap {
+ val args = call.arguments
+ if (args is Map<*, *>) {
+ putAll(args as Map)
+ }
+ }
+ callkitNotificationManager?.requestNotificationPermission(activity, map)
+ }
}
} catch (error: Exception) {
result.error("error", error.message, "")
@@ -247,16 +264,18 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
- this.activity = binding.activity
- this.context = binding.activity.applicationContext
+ instance.context = binding.activity.applicationContext
+ instance.activity = binding.activity
+ binding.addRequestPermissionsResultListener(this)
}
override fun onDetachedFromActivityForConfigChanges() {
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
- this.activity = binding.activity
- this.context = binding.activity.applicationContext
+ instance.context = binding.activity.applicationContext
+ instance.activity = binding.activity
+ binding.addRequestPermissionsResultListener(this)
}
override fun onDetachedFromActivity() {}
@@ -271,8 +290,8 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
fun send(event: String, body: Map) {
val data = mapOf(
- "event" to event,
- "body" to body
+ "event" to event,
+ "body" to body
)
Handler(Looper.getMainLooper()).post {
eventSink?.success(data)
@@ -283,4 +302,12 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA
eventSink = null
}
}
+
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray): Boolean {
+ instance.callkitNotificationManager?.onRequestPermissionsResult(instance.activity, requestCode, grantResults)
+ return true
+ }
+
+
+
}
diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml
index 8379abf6..955d9785 100644
--- a/android/src/main/res/values/strings.xml
+++ b/android/src/main/res/values/strings.xml
@@ -5,4 +5,5 @@
Decline
Missed call
Call back
+ Notification permission is required, Please allow notification permission from setting.
\ No newline at end of file
diff --git a/android/src/main/res/values/styles.xml b/android/src/main/res/values/styles.xml
index 732eb885..4dc06acd 100644
--- a/android/src/main/res/values/styles.xml
+++ b/android/src/main/res/values/styles.xml
@@ -9,6 +9,11 @@
+
+
+