feat: finish foreground service work

This commit is contained in:
2022-03-01 00:04:30 +02:00
parent 10b7529f98
commit 7859339a4b
8 changed files with 72 additions and 96 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.illusionware.lyricsgrabbr.lyricsgrabbr" applicationId "com.illusionware.lyricsgrabbr.lyricsgrabbr"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 30 targetSdkVersion 31
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }
+1 -1
View File
@@ -5,7 +5,7 @@
<application <application
android:label="Lyrics Grabbr" android:label="Lyrics Grabbr"
android:name=".App" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@@ -1,23 +0,0 @@
package com.illusionware.lyricsgrabbr.lyricsgrabbr
import android.app.Application
import android.os.StrictMode
class App : Application() {
override fun onCreate() {
super.onCreate()
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll() // or .detectAll() for all detectable problems
.penaltyLog()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDeath()
.build()
)
}
}
@@ -7,14 +7,12 @@ import android.util.Log
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() { class MainActivity: FlutterActivity() {
// private var streamHandler : NotificationStreamHandler? = null private var streamHandler : NotificationStreamHandler? = null
private var listenerIntent : Intent? = null
companion object { companion object {
private const val ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS" private const val ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"
@@ -25,8 +23,6 @@ class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
listenerIntent = Intent(applicationContext, NotificationListener::class.java)
val methodChannel = MethodChannel(flutterEngine!!.dartExecutor.binaryMessenger, METHOD_CHANNEL_NAME) val methodChannel = MethodChannel(flutterEngine!!.dartExecutor.binaryMessenger, METHOD_CHANNEL_NAME)
methodChannel.setMethodCallHandler { call, result -> methodChannel.setMethodCallHandler { call, result ->
when (call.method) { when (call.method) {
@@ -36,19 +32,13 @@ class MainActivity: FlutterActivity() {
"plugin.openPermissionSettings" -> { "plugin.openPermissionSettings" -> {
result.success(openPermissionSettings()) result.success(openPermissionSettings())
} }
"plugin.startService" -> {
result.success(startService())
}
"plugin.stopService" -> {
result.success(stopService())
}
else -> result.notImplemented() else -> result.notImplemented()
} }
} }
// val eventChannel = EventChannel(flutterEngine!!.dartExecutor.binaryMessenger, EVENT_CHANNEL_NAME) val eventChannel = EventChannel(flutterEngine!!.dartExecutor.binaryMessenger, EVENT_CHANNEL_NAME)
// streamHandler = NotificationStreamHandler(context) streamHandler = NotificationStreamHandler(context)
// eventChannel.setStreamHandler(streamHandler) eventChannel.setStreamHandler(streamHandler)
} }
private fun isPermissionGranted(): Boolean { private fun isPermissionGranted(): Boolean {
@@ -67,21 +57,4 @@ class MainActivity: FlutterActivity() {
context.startActivity(Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) context.startActivity(Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
return true return true
} }
private fun startService(): Boolean {
listenerIntent?.action = NotificationListener.START_FOREGROUND_SERVICE_ACTION
ContextCompat.startForegroundService(applicationContext, listenerIntent!!)
Log.d("startService", "starting")
return true
}
private fun stopService(): Boolean {
listenerIntent?.action = NotificationListener.STOP_FOREGROUND_SERVICE_ACTION
ContextCompat.startForegroundService(applicationContext, listenerIntent!!)
Log.d("stopService", "stopping")
//applicationContext.stopService(listenerIntent!!)
return true
}
} }
@@ -60,6 +60,11 @@ class NotificationListener : NotificationListenerService() {
getCurrentNotifications(applicationContext) getCurrentNotifications(applicationContext)
} }
override fun onListenerDisconnected() {
stopForegroundService()
super.onListenerDisconnected()
}
override fun onNotificationPosted(sbn: StatusBarNotification) { override fun onNotificationPosted(sbn: StatusBarNotification) {
if (sbn.packageName == SPOTIFY_PACKAGE) { if (sbn.packageName == SPOTIFY_PACKAGE) {
sendNotificationBroadcast(sbn, applicationContext) sendNotificationBroadcast(sbn, applicationContext)
@@ -140,7 +145,7 @@ class NotificationListener : NotificationListenerService() {
notificationManager?.notify(NOTIFICATION_ID, notification) notificationManager?.notify(NOTIFICATION_ID, notification)
//sendBroadcast(intent) sendBroadcast(intent)
} }
companion object { companion object {
@@ -9,20 +9,21 @@ import androidx.core.content.ContextCompat
class NotificationStreamHandler(private val context: Context) : StreamHandler { class NotificationStreamHandler(private val context: Context) : StreamHandler {
private var eventSink: EventSink? = null private var eventSink: EventSink? = null
private var receiver: NotificationReceiver? = null private var receiver: NotificationReceiver? = null
private var listenerIntent : Intent? = null
// Called whenever the event channel is subscribed to in Flutter // Called whenever the event channel is subscribed to in Flutter
override fun onListen(o: Any?, eventSink: EventSink?) { override fun onListen(o: Any?, eventSink: EventSink?) {
this.eventSink = eventSink this.eventSink = eventSink
val listenerIntent = Intent(context, NotificationListener::class.java) listenerIntent = Intent(context, NotificationListener::class.java)
listenerIntent.action = NotificationListener.START_FOREGROUND_SERVICE_ACTION listenerIntent?.action = NotificationListener.START_FOREGROUND_SERVICE_ACTION
//receiver = NotificationReceiver() receiver = NotificationReceiver()
//val intentFilter = IntentFilter() val intentFilter = IntentFilter()
//intentFilter.addAction(NotificationListener.NOTIFICATION_INTENT) intentFilter.addAction(NotificationListener.NOTIFICATION_INTENT)
//context.registerReceiver(receiver, intentFilter) context.registerReceiver(receiver, intentFilter)
ContextCompat.startForegroundService(context, listenerIntent) ContextCompat.startForegroundService(context, listenerIntent!!)
} }
// Called whenever the event channel subscription is cancelled in Flutter // Called whenever the event channel subscription is cancelled in Flutter
@@ -30,11 +31,11 @@ class NotificationStreamHandler(private val context: Context) : StreamHandler {
eventSink = null eventSink = null
Log.d("onCancel", "subscription cancelled, stopping service") Log.d("onCancel", "subscription cancelled, stopping service")
val listenerIntent = Intent(context, NotificationListener::class.java) // val listenerIntent = Intent(context, NotificationListener::class.java)
listenerIntent.action = NotificationListener.STOP_FOREGROUND_SERVICE_ACTION listenerIntent?.action = NotificationListener.STOP_FOREGROUND_SERVICE_ACTION
ContextCompat.startForegroundService(context, listenerIntent) ContextCompat.startForegroundService(context, listenerIntent!!)
//context.unregisterReceiver(receiver) context.unregisterReceiver(receiver)
} }
internal inner class NotificationReceiver : BroadcastReceiver() { internal inner class NotificationReceiver : BroadcastReceiver() {
+48 -20
View File
@@ -35,7 +35,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
late AndroidNotificationListener _notifications; late AndroidNotificationListener _notifications;
late StreamSubscription<NotificationEvent> _subscription; late StreamSubscription<NotificationEvent> _subscription;
BuildContext? permissionDialogCtx; BuildContext? permissionDialogCtx;
final List<NotificationEvent> _notifs = []; NotificationEvent? currentlyPlaying;
bool running = false; bool running = false;
@override @override
@@ -67,7 +67,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
} }
} }
void showNotificationPermDialog() { void _showNotificationPermDialog() {
showDialog( showDialog(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
@@ -107,7 +107,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
if (perm != null && perm) { if (perm != null && perm) {
startListening(); startListening();
} else { } else {
showNotificationPermDialog(); _showNotificationPermDialog();
} }
} }
@@ -116,7 +116,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
// if the app is in the foreground, update the notif, and // if the app is in the foreground, update the notif, and
// fetch the new lyrics and display them. // fetch the new lyrics and display them.
setState(() { setState(() {
_notifs.add(event); currentlyPlaying = event;
}); });
} }
@@ -125,17 +125,15 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
// that keeps track of which song is playing // that keeps track of which song is playing
// and if pressed will fetch the lyrics and display them. // and if pressed will fetch the lyrics and display them.
//_notifications = AndroidNotificationListener(); _notifications = AndroidNotificationListener();
//_subscription = _notifications.notificationStream.listen(onData); _subscription = _notifications.notificationStream.listen(onData);
AndroidNotificationListener.startService();
setState(() => running = true); setState(() => running = true);
} }
void stopListening() { void stopListening() {
setState(() => running = false); setState(() => running = false);
AndroidNotificationListener.stopService(); _subscription.cancel();
//_subscription.cancel();
} }
@override @override
@@ -144,19 +142,49 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
appBar: AppBar( appBar: AppBar(
title: Text(widget.title), title: Text(widget.title),
), ),
body: ListView.builder( body: Container(
itemCount: _notifs.length, padding: const EdgeInsets.all(20),
reverse: true, child: Center(
itemBuilder: (BuildContext context, int idx) { child: Column(
final entry = _notifs[idx]; mainAxisAlignment: MainAxisAlignment.start,
return ListTile( crossAxisAlignment: CrossAxisAlignment.center,
leading: Text(entry.songTitle), children: [
trailing: Text(entry.artist), running ? RichText(
); text: TextSpan(
}), text: currentlyPlaying?.songTitle,
style: const TextStyle(
fontSize: 24.0,
color: Colors.black,
fontWeight: FontWeight.w700,
),
children: [
const TextSpan(
text: "\n",
),
TextSpan(
text: currentlyPlaying?.artist,
style: const TextStyle(
fontSize: 20.0,
color: Color(0xFF303030),
)
)
]
),
textAlign: TextAlign.center,
) :
const Text("Listener stopped"),
running ? Text(
currentlyPlaying?.playbackState == PlaybackState.STATE_PLAYING ? "Spotify Playing" : "Spotify Paused",
style: Theme.of(context).textTheme.headline6,
) :
const Text("")
],
),
),
),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: running ? stopListening : startListening, onPressed: running ? stopListening : startListening,
tooltip: running ? 'Stop service' : "Start service", tooltip: running ? 'Stop listener' : "Start listener",
child: running ? const Icon(Icons.stop) : const Icon(Icons.play_arrow), child: running ? const Icon(Icons.stop) : const Icon(Icons.play_arrow),
), ),
); );
-8
View File
@@ -85,12 +85,4 @@ class AndroidNotificationListener {
static Future<bool?> openPermissionSettings() async { static Future<bool?> openPermissionSettings() async {
return await _methodChannel.invokeMethod('plugin.openPermissionSettings'); return await _methodChannel.invokeMethod('plugin.openPermissionSettings');
} }
static Future<bool?> startService() async {
return await _methodChannel.invokeMethod('plugin.startService');
}
static Future<bool?> stopService() async {
return await _methodChannel.invokeMethod('plugin.stopService');
}
} }