Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
mavenCentral()
}

dependencies {
Expand All @@ -17,7 +17,7 @@ buildscript {
rootProject.allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,39 @@ package com.emilecode.android_notification_listener2
/**
* Flutter-specific
*/
import android.app.Activity
import android.app.Service
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.EventChannel.StreamHandler
import io.flutter.plugin.common.EventChannel.EventSink
import io.flutter.plugin.common.PluginRegistry.Registrar

/**
* Android-specific
*/
import android.content.*
import android.os.Handler
import android.provider.Settings
import android.text.TextUtils
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodChannel
import io.flutter.embedding.engine.FlutterEngine

import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.embedding.engine.plugins.service.ServicePluginBinding
import java.lang.Exception
import java.lang.reflect.Method
import io.flutter.embedding.engine.plugins.service.ServiceAware as ServiceAware


/**
* AndroidNotificationListener2Plugin
*/
class AndroidNotificationListener2Plugin private constructor(private val context: Context) : StreamHandler {
class AndroidNotificationListener2Plugin : StreamHandler, FlutterPlugin {
private var eventSink: EventSink? = null
private var methodChannel: MethodChannel? = null
private var context: Context? = null

/**
* Called whenever the event channel is subscribed to in Flutter
Expand All @@ -31,7 +47,7 @@ class AndroidNotificationListener2Plugin private constructor(private val context
Start the notification service once permission has been given.
*/
val listenerIntent = Intent(context, NotificationListener::class.java)
context.startService(listenerIntent)
context!!.startService(listenerIntent)
}

/**
Expand All @@ -46,8 +62,8 @@ class AndroidNotificationListener2Plugin private constructor(private val context
* If any match is found, return true. Otherwise if no matches were found, return false.
*/
private fun permissionGiven(): Boolean {
val packageName = context.packageName
val flat = Settings.Secure.getString(context.contentResolver,
val packageName = context!!.packageName
val flat = Settings.Secure.getString(context!!.contentResolver,
ENABLED_NOTIFICATION_LISTENERS)
if (!TextUtils.isEmpty(flat)) {
val names = flat.split(":").toTypedArray()
Expand Down Expand Up @@ -83,32 +99,64 @@ class AndroidNotificationListener2Plugin private constructor(private val context
private const val ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners"
private const val ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"
private const val EVENT_CHANNEL_NAME = "notifications.eventChannel"

/** Plugin registration. */
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = EventChannel(registrar.messenger(), EVENT_CHANNEL_NAME)
val context: Context = registrar.activeContext()
val plugin = AndroidNotificationListener2Plugin(context)
channel.setStreamHandler(plugin)
}
private const val COMMAND_CHANEL = "notifications.commandChannel"
}

/**
* Plugin constructor setting the context and registering the notification service.
*/
init {

}

fun lateInit() {
/* Check if permission is given, if not then go to the notification settings screen. */
if (!permissionGiven()) {
context.startActivity(Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS))
requestPermission()
}
val receiver = NotificationReceiver()
val intentFilter = IntentFilter()
intentFilter.addAction(NotificationListener.NOTIFICATION_INTENT)
context.registerReceiver(receiver, intentFilter)
context!!.registerReceiver(receiver, intentFilter)

/* Start the notification service once permission has been given. */
val listenerIntent = Intent(context, NotificationListener::class.java)
context.startService(listenerIntent)
context!!.startService(listenerIntent)
}

private fun requestPermission() {
val intent = Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context?.startActivity(intent)
}

override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
this.context = binding.applicationContext
EventChannel(binding.binaryMessenger, EVENT_CHANNEL_NAME).setStreamHandler(this)
methodChannel = MethodChannel(binding.getBinaryMessenger(), COMMAND_CHANEL)
methodChannel!!.setMethodCallHandler { call, result ->
run {
when (call.method) {
"init" -> {
lateInit()
result.success(null)
}
"permissionGiven" -> result.success(permissionGiven())
"requestPermission" -> {
requestPermission()
result.success(null)
}
else -> { // Note the block
throw UnsupportedOperationException("Method ${call.method} is not supported")
}
}
}
}
}

override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
methodChannel?.setMethodCallHandler(null)
methodChannel = null
this.context = null
}
}
52 changes: 49 additions & 3 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,30 @@ class MyApp extends StatefulWidget {
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
AndroidNotificationListener _notifications;
StreamSubscription<NotificationEventV2> _subscription;
bool _permissionGiven = false;
bool _inited = false;

@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
initPlatformState();
}

// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
startListening();
updatePermissionState();
}

Future<void> updatePermissionState() async {
var permissionGiven = await _notifications.isPermissionGiven();
setState(() {
_permissionGiven = permissionGiven;
});
}

void onData(NotificationEventV2 event) {
Expand All @@ -35,7 +46,7 @@ class _MyAppState extends State<MyApp> {
}

void startListening() {
_notifications = new AndroidNotificationListener();
_notifications = AndroidNotificationListener.withoutInit();
try {
_subscription = _notifications.notificationStream.listen(onData);
} on NotificationExceptionV2 catch (exception) {
Expand All @@ -54,7 +65,42 @@ class _MyAppState extends State<MyApp> {
appBar: AppBar(
title: const Text('Plugin example app'),
),
),
body: Column(children: [
_permissionGiven
? Text("Permission has granted")
: Text("Permission has not grant"),
_inited
? Text("Plugin inited")
: Text("Plugin not inited"),
TextButton(
child: Text("Init"),
onPressed: () {
_notifications.init();
setState(() {
_inited = _notifications.isInited;
});
},
),
TextButton(
child: Text("request permission"),
onPressed: () {
_notifications.requestPermission();
},
),
])),
);
}

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
updatePermissionState();
}
}

@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
}
Loading