2015-04-20 22:39:35 +02:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge.externalevents;
|
2015-01-07 14:00:18 +01:00
|
|
|
|
2015-09-01 21:58:36 +02:00
|
|
|
import android.annotation.SuppressLint;
|
2015-04-04 23:20:28 +02:00
|
|
|
import android.app.ActivityManager;
|
2015-01-07 14:00:18 +01:00
|
|
|
import android.app.Notification;
|
2016-05-19 16:34:59 +02:00
|
|
|
import android.app.NotificationManager;
|
2015-08-31 22:27:25 +02:00
|
|
|
import android.app.PendingIntent;
|
2015-07-21 01:25:22 +02:00
|
|
|
import android.content.BroadcastReceiver;
|
|
|
|
import android.content.Context;
|
2015-01-07 14:00:18 +01:00
|
|
|
import android.content.Intent;
|
2015-07-21 01:25:22 +02:00
|
|
|
import android.content.IntentFilter;
|
2015-09-25 00:53:40 +02:00
|
|
|
import android.content.pm.ApplicationInfo;
|
|
|
|
import android.content.pm.PackageManager;
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
import android.media.MediaMetadata;
|
|
|
|
import android.media.session.MediaController;
|
|
|
|
import android.media.session.MediaSession;
|
|
|
|
import android.media.session.PlaybackState;
|
|
|
|
import android.os.Build;
|
2015-01-07 14:00:18 +01:00
|
|
|
import android.os.Bundle;
|
2015-03-04 23:47:47 +01:00
|
|
|
import android.os.PowerManager;
|
2015-01-07 14:00:18 +01:00
|
|
|
import android.service.notification.NotificationListenerService;
|
|
|
|
import android.service.notification.StatusBarNotification;
|
2016-01-09 17:54:17 +01:00
|
|
|
import android.support.v4.app.NotificationCompat;
|
|
|
|
import android.support.v4.app.RemoteInput;
|
2015-07-21 01:25:22 +02:00
|
|
|
import android.support.v4.content.LocalBroadcastManager;
|
2015-05-12 06:28:11 +02:00
|
|
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
2015-01-07 14:00:18 +01:00
|
|
|
|
2016-01-09 17:54:17 +01:00
|
|
|
import java.util.List;
|
|
|
|
|
2015-08-21 00:58:18 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
2016-06-07 19:34:37 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
2015-09-24 14:45:21 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
2015-09-16 01:09:03 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
2016-01-09 17:54:17 +01:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
2016-04-25 23:18:55 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
2015-04-20 22:39:35 +02:00
|
|
|
|
2015-01-07 14:00:18 +01:00
|
|
|
public class NotificationListener extends NotificationListenerService {
|
|
|
|
|
2015-05-12 06:28:11 +02:00
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(NotificationListener.class);
|
2015-01-07 14:00:18 +01:00
|
|
|
|
2015-07-21 01:25:22 +02:00
|
|
|
public static final String ACTION_DISMISS
|
|
|
|
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.dismiss";
|
2015-09-01 21:58:36 +02:00
|
|
|
public static final String ACTION_DISMISS_ALL
|
|
|
|
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.dismiss_all";
|
2015-08-31 22:27:25 +02:00
|
|
|
public static final String ACTION_OPEN
|
|
|
|
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.open";
|
2015-09-25 00:53:40 +02:00
|
|
|
public static final String ACTION_MUTE
|
|
|
|
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.mute";
|
2016-01-09 17:54:17 +01:00
|
|
|
public static final String ACTION_REPLY
|
|
|
|
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.reply";
|
|
|
|
|
|
|
|
private LimitedQueue mActionLookup = new LimitedQueue(16);
|
2015-07-21 01:25:22 +02:00
|
|
|
|
2015-11-23 23:04:46 +01:00
|
|
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
2016-09-11 00:38:26 +02:00
|
|
|
@SuppressLint("NewApi")
|
2015-07-21 01:25:22 +02:00
|
|
|
@Override
|
|
|
|
public void onReceive(Context context, Intent intent) {
|
|
|
|
String action = intent.getAction();
|
2015-09-25 00:53:40 +02:00
|
|
|
switch (action) {
|
2016-04-03 00:49:54 +02:00
|
|
|
case GBApplication.ACTION_QUIT:
|
|
|
|
stopSelf();
|
|
|
|
break;
|
2015-09-25 00:53:40 +02:00
|
|
|
case ACTION_MUTE:
|
|
|
|
case ACTION_OPEN: {
|
|
|
|
StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications();
|
|
|
|
int handle = intent.getIntExtra("handle", -1);
|
|
|
|
for (StatusBarNotification sbn : sbns) {
|
2016-09-11 00:38:26 +02:00
|
|
|
if ((int) sbn.getPostTime() == handle) {
|
2015-09-25 00:53:40 +02:00
|
|
|
if (action.equals(ACTION_OPEN)) {
|
|
|
|
try {
|
|
|
|
PendingIntent pi = sbn.getNotification().contentIntent;
|
|
|
|
if (pi != null) {
|
|
|
|
pi.send();
|
|
|
|
}
|
|
|
|
} catch (PendingIntent.CanceledException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// ACTION_MUTE
|
|
|
|
LOG.info("going to mute " + sbn.getPackageName());
|
|
|
|
GBApplication.addToBlacklist(sbn.getPackageName());
|
2015-08-31 22:27:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-25 00:53:40 +02:00
|
|
|
break;
|
2015-08-31 22:27:25 +02:00
|
|
|
}
|
2015-09-25 00:53:40 +02:00
|
|
|
case ACTION_DISMISS: {
|
|
|
|
StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications();
|
|
|
|
int handle = intent.getIntExtra("handle", -1);
|
|
|
|
for (StatusBarNotification sbn : sbns) {
|
2016-09-11 00:38:26 +02:00
|
|
|
if ((int) sbn.getPostTime() == handle) {
|
2015-09-25 00:53:40 +02:00
|
|
|
if (GBApplication.isRunningLollipopOrLater()) {
|
|
|
|
String key = sbn.getKey();
|
|
|
|
NotificationListener.this.cancelNotification(key);
|
|
|
|
} else {
|
|
|
|
int id = sbn.getId();
|
|
|
|
String pkg = sbn.getPackageName();
|
|
|
|
String tag = sbn.getTag();
|
|
|
|
NotificationListener.this.cancelNotification(pkg, tag, id);
|
|
|
|
}
|
2015-09-01 21:58:36 +02:00
|
|
|
}
|
|
|
|
}
|
2015-09-25 00:53:40 +02:00
|
|
|
break;
|
2015-09-01 21:58:36 +02:00
|
|
|
}
|
2015-09-25 00:53:40 +02:00
|
|
|
case ACTION_DISMISS_ALL:
|
|
|
|
NotificationListener.this.cancelAllNotifications();
|
|
|
|
break;
|
2016-01-09 17:54:17 +01:00
|
|
|
case ACTION_REPLY:
|
|
|
|
int id = intent.getIntExtra("handle", -1);
|
|
|
|
String reply = intent.getStringExtra("reply");
|
|
|
|
NotificationCompat.Action replyAction = (NotificationCompat.Action) mActionLookup.lookup(id);
|
|
|
|
if (replyAction != null && replyAction.getRemoteInputs() != null) {
|
|
|
|
RemoteInput[] remoteInputs = replyAction.getRemoteInputs();
|
|
|
|
PendingIntent actionIntent = replyAction.getActionIntent();
|
|
|
|
Intent localIntent = new Intent();
|
|
|
|
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
Bundle extras = new Bundle();
|
|
|
|
extras.putCharSequence(remoteInputs[0].getResultKey(), reply);
|
|
|
|
RemoteInput.addResultsToIntent(remoteInputs, localIntent, extras);
|
|
|
|
|
|
|
|
try {
|
|
|
|
LOG.info("will send reply intent to remote application");
|
|
|
|
actionIntent.send(context, 0, localIntent);
|
|
|
|
mActionLookup.remove(id);
|
|
|
|
} catch (PendingIntent.CanceledException e) {
|
|
|
|
LOG.warn("replyToLastNotification error: " + e.getLocalizedMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-07-21 01:25:22 +02:00
|
|
|
}
|
2015-09-01 21:58:36 +02:00
|
|
|
|
2015-07-21 01:25:22 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-01-07 14:00:18 +01:00
|
|
|
@Override
|
|
|
|
public void onCreate() {
|
|
|
|
super.onCreate();
|
2015-07-21 01:25:22 +02:00
|
|
|
IntentFilter filterLocal = new IntentFilter();
|
2016-04-03 00:49:54 +02:00
|
|
|
filterLocal.addAction(GBApplication.ACTION_QUIT);
|
2015-08-31 22:27:25 +02:00
|
|
|
filterLocal.addAction(ACTION_OPEN);
|
2015-09-01 21:58:36 +02:00
|
|
|
filterLocal.addAction(ACTION_DISMISS);
|
|
|
|
filterLocal.addAction(ACTION_DISMISS_ALL);
|
2015-09-25 00:53:40 +02:00
|
|
|
filterLocal.addAction(ACTION_MUTE);
|
2016-01-09 17:54:17 +01:00
|
|
|
filterLocal.addAction(ACTION_REPLY);
|
2015-07-21 01:25:22 +02:00
|
|
|
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
2015-01-07 14:00:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
2015-07-21 01:25:22 +02:00
|
|
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
|
2015-01-07 14:00:18 +01:00
|
|
|
super.onDestroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onNotificationPosted(StatusBarNotification sbn) {
|
2015-04-04 23:20:28 +02:00
|
|
|
/*
|
2015-08-04 01:01:14 +02:00
|
|
|
* return early if DeviceCommunicationService is not running,
|
2015-04-04 23:20:28 +02:00
|
|
|
* else the service would get started every time we get a notification.
|
|
|
|
* unfortunately we cannot enable/disable NotificationListener at runtime like we do with
|
|
|
|
* broadcast receivers because it seems to invalidate the permissions that are
|
2015-08-06 22:24:44 +02:00
|
|
|
* necessary for NotificationListenerService
|
2015-04-04 23:20:28 +02:00
|
|
|
*/
|
2015-08-06 22:24:44 +02:00
|
|
|
if (!isServiceRunning()) {
|
2015-04-04 23:20:28 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-03-04 23:47:47 +01:00
|
|
|
|
2016-05-19 23:58:13 +02:00
|
|
|
switch (GBApplication.getGrantedInterruptionFilter()) {
|
|
|
|
case NotificationManager.INTERRUPTION_FILTER_ALL:
|
|
|
|
break;
|
|
|
|
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
|
|
|
|
case NotificationManager.INTERRUPTION_FILTER_NONE:
|
|
|
|
return;
|
|
|
|
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
|
|
|
|
// FIXME: Handle Reminders and Events if they are enabled in Do Not Disturb
|
|
|
|
return;
|
2016-05-19 16:34:59 +02:00
|
|
|
}
|
2015-03-04 23:47:47 +01:00
|
|
|
|
2015-05-08 12:50:42 +02:00
|
|
|
String source = sbn.getPackageName();
|
2015-01-07 14:00:18 +01:00
|
|
|
Notification notification = sbn.getNotification();
|
2015-01-18 22:44:38 +01:00
|
|
|
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
if (handleMediaSessionNotification(notification))
|
|
|
|
return;
|
2016-06-07 19:34:37 +02:00
|
|
|
|
2016-06-09 23:39:00 +02:00
|
|
|
Prefs prefs = GBApplication.getPrefs();
|
|
|
|
if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) {
|
|
|
|
PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE);
|
|
|
|
if (powermanager.isScreenOn()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 17:33:10 +02:00
|
|
|
//don't forward group summary notifications to the wearable, they are meant for the android device only
|
|
|
|
if ((notification.flags & Notification.FLAG_GROUP_SUMMARY) == Notification.FLAG_GROUP_SUMMARY) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-08 12:50:42 +02:00
|
|
|
if ((notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-18 22:44:38 +01:00
|
|
|
/* do not display messages from "android"
|
|
|
|
* This includes keyboard selection message, usb connection messages, etc
|
|
|
|
* Hope it does not filter out too much, we will see...
|
|
|
|
*/
|
2015-01-24 12:21:15 +01:00
|
|
|
|
|
|
|
if (source.equals("android") ||
|
2015-04-09 18:48:52 +02:00
|
|
|
source.equals("com.android.systemui") ||
|
2015-01-24 12:21:15 +01:00
|
|
|
source.equals("com.android.dialer") ||
|
2015-09-05 21:32:46 +02:00
|
|
|
source.equals("com.cyanogenmod.eleven")) {
|
2015-01-18 22:44:38 +01:00
|
|
|
return;
|
2015-01-24 12:21:15 +01:00
|
|
|
}
|
2015-01-18 22:44:38 +01:00
|
|
|
|
2015-09-05 21:32:46 +02:00
|
|
|
if (source.equals("com.fsck.k9")) {
|
2016-04-25 23:18:55 +02:00
|
|
|
if (!"never".equals(prefs.getString("notification_mode_k9mail", "when_screen_off"))) {
|
2015-09-05 21:32:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-22 21:30:50 +01:00
|
|
|
if (source.equals("com.moez.QKSMS") ||
|
|
|
|
source.equals("com.android.mms") ||
|
|
|
|
source.equals("com.sonyericsson.conversations") ||
|
|
|
|
source.equals("com.android.messaging") ||
|
|
|
|
source.equals("org.smssecure.smssecure")) {
|
2016-04-25 23:18:55 +02:00
|
|
|
if (!"never".equals(prefs.getString("notification_mode_sms", "when_screen_off"))) {
|
2015-09-13 22:47:56 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-25 00:53:40 +02:00
|
|
|
if (GBApplication.blacklist != null && GBApplication.blacklist.contains(source)) {
|
2015-09-12 00:19:36 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-24 14:45:21 +02:00
|
|
|
NotificationSpec notificationSpec = new NotificationSpec();
|
2015-09-25 00:53:40 +02:00
|
|
|
|
|
|
|
// determinate Source App Name ("Label")
|
|
|
|
PackageManager pm = getPackageManager();
|
|
|
|
ApplicationInfo ai = null;
|
|
|
|
try {
|
|
|
|
ai = pm.getApplicationInfo(source, 0);
|
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
if (ai != null) {
|
|
|
|
notificationSpec.sourceName = (String) pm.getApplicationLabel(ai);
|
|
|
|
}
|
2015-12-27 19:22:10 +01:00
|
|
|
|
2015-09-13 13:48:21 +02:00
|
|
|
switch (source) {
|
|
|
|
case "org.mariotaku.twidere":
|
|
|
|
case "com.twitter.android":
|
|
|
|
case "org.andstatus.app":
|
|
|
|
case "org.mustard.android":
|
2015-09-24 14:45:21 +02:00
|
|
|
notificationSpec.type = NotificationType.TWITTER;
|
2015-09-13 13:48:21 +02:00
|
|
|
break;
|
|
|
|
case "com.fsck.k9":
|
|
|
|
case "com.android.email":
|
2016-10-11 11:54:52 +02:00
|
|
|
notificationSpec.type = NotificationType.GENERIC_EMAIL;
|
2015-09-13 13:48:21 +02:00
|
|
|
break;
|
2015-09-13 22:47:56 +02:00
|
|
|
case "com.moez.QKSMS":
|
2015-09-24 17:26:40 +02:00
|
|
|
case "com.android.mms":
|
2015-12-27 19:22:10 +01:00
|
|
|
case "com.android.messaging":
|
2015-12-19 14:30:35 +01:00
|
|
|
case "com.sonyericsson.conversations":
|
2016-01-22 21:30:50 +01:00
|
|
|
case "org.smssecure.smssecure":
|
2016-10-11 11:54:52 +02:00
|
|
|
notificationSpec.type = NotificationType.GENERIC_SMS;
|
2015-09-13 22:47:56 +02:00
|
|
|
break;
|
2015-09-13 13:48:21 +02:00
|
|
|
case "eu.siacs.conversations":
|
2016-10-11 11:54:52 +02:00
|
|
|
notificationSpec.type = NotificationType.CONVERSATIONS;
|
|
|
|
break;
|
2015-12-06 16:09:07 +01:00
|
|
|
case "org.thoughtcrime.securesms":
|
2016-10-11 11:54:52 +02:00
|
|
|
notificationSpec.type = NotificationType.SIGNAL;
|
2015-09-13 13:48:21 +02:00
|
|
|
break;
|
2016-09-21 21:31:23 +02:00
|
|
|
case "org.telegram.messenger":
|
|
|
|
notificationSpec.type = NotificationType.TELEGRAM;
|
|
|
|
break;
|
|
|
|
case "com.facebook.katana":
|
2015-09-13 13:48:21 +02:00
|
|
|
case "org.indywidualni.fblite":
|
2015-09-24 14:45:21 +02:00
|
|
|
notificationSpec.type = NotificationType.FACEBOOK;
|
2015-09-13 13:48:21 +02:00
|
|
|
break;
|
2016-10-11 11:54:52 +02:00
|
|
|
case "com.facebook.orca":
|
|
|
|
notificationSpec.type = NotificationType.FACEBOOK_MESSENGER;
|
|
|
|
break;
|
2015-09-13 13:48:21 +02:00
|
|
|
default:
|
2016-10-10 23:06:44 +02:00
|
|
|
notificationSpec.type = NotificationType.UNKNOWN;
|
2015-09-13 13:48:21 +02:00
|
|
|
break;
|
2015-09-13 00:39:53 +02:00
|
|
|
}
|
|
|
|
|
2015-05-12 06:28:11 +02:00
|
|
|
LOG.info("Processing notification from source " + source);
|
2015-01-22 22:49:50 +01:00
|
|
|
|
2015-11-23 22:49:11 +01:00
|
|
|
dissectNotificationTo(notification, notificationSpec);
|
2016-09-11 00:38:26 +02:00
|
|
|
notificationSpec.id = (int) sbn.getPostTime(); //FIMXE: a truly unique id would be better
|
|
|
|
|
2016-01-09 17:54:17 +01:00
|
|
|
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(notification);
|
|
|
|
List<NotificationCompat.Action> actions = wearableExtender.getActions();
|
2016-09-22 09:31:14 +02:00
|
|
|
|
|
|
|
if (actions.isEmpty() && notificationSpec.type == NotificationType.TELEGRAM) {
|
|
|
|
return; // workaround for duplicate telegram message
|
|
|
|
}
|
|
|
|
|
2016-01-09 17:54:17 +01:00
|
|
|
for (NotificationCompat.Action act : actions) {
|
|
|
|
if (act != null && act.getRemoteInputs() != null) {
|
|
|
|
LOG.info("found wearable action: " + act.getTitle() + " " + sbn.getTag());
|
|
|
|
mActionLookup.add(notificationSpec.id, act);
|
|
|
|
notificationSpec.flags |= NotificationSpec.FLAG_WEARABLE_REPLY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-23 22:09:47 +01:00
|
|
|
GBApplication.deviceService().onNotification(notificationSpec);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void dissectNotificationTo(Notification notification, NotificationSpec notificationSpec) {
|
2015-01-07 14:00:18 +01:00
|
|
|
Bundle extras = notification.extras;
|
2015-11-23 22:09:47 +01:00
|
|
|
CharSequence title = extras.getCharSequence(Notification.EXTRA_TITLE);
|
|
|
|
if (title != null) {
|
|
|
|
notificationSpec.title = title.toString();
|
|
|
|
}
|
2015-05-10 15:07:28 +02:00
|
|
|
if (extras.containsKey(Notification.EXTRA_TEXT)) {
|
2015-01-26 18:52:19 +01:00
|
|
|
CharSequence contentCS = extras.getCharSequence(Notification.EXTRA_TEXT);
|
|
|
|
if (contentCS != null) {
|
2015-09-24 14:45:21 +02:00
|
|
|
notificationSpec.body = contentCS.toString();
|
2015-01-26 18:52:19 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-07 14:00:18 +01:00
|
|
|
}
|
|
|
|
|
2015-08-06 22:24:44 +02:00
|
|
|
private boolean isServiceRunning() {
|
|
|
|
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
|
|
|
|
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
|
|
|
if (DeviceCommunicationService.class.getName().equals(service.service.getClassName())) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-07 19:34:37 +02:00
|
|
|
/**
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
* Try to handle media session notifications that tell info about the current play state.
|
|
|
|
*
|
2016-06-07 19:34:37 +02:00
|
|
|
* @param notification The notification to handle.
|
|
|
|
* @return true if notification was handled, false otherwise
|
|
|
|
*/
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
public boolean handleMediaSessionNotification(Notification notification) {
|
|
|
|
|
|
|
|
// this code requires Android 5.0 or newer
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-07 19:34:37 +02:00
|
|
|
MusicSpec musicSpec = new MusicSpec();
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
MusicStateSpec stateSpec = new MusicStateSpec();
|
2016-06-07 19:34:37 +02:00
|
|
|
|
|
|
|
Bundle extras = notification.extras;
|
|
|
|
if (extras == null)
|
|
|
|
return false;
|
|
|
|
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
if (extras.get(Notification.EXTRA_MEDIA_SESSION) == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
MediaController c;
|
|
|
|
try {
|
|
|
|
c = new MediaController(getApplicationContext(), (MediaSession.Token) extras.get(Notification.EXTRA_MEDIA_SESSION));
|
|
|
|
} catch (NullPointerException e) {
|
|
|
|
return false;
|
2016-06-07 19:34:37 +02:00
|
|
|
}
|
|
|
|
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
PlaybackState s = c.getPlaybackState();
|
2016-06-11 23:37:03 +02:00
|
|
|
stateSpec.position = (int) (s.getPosition() / 1000);
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
stateSpec.playRate = Math.round(100 * s.getPlaybackSpeed());
|
|
|
|
stateSpec.repeat = 1;
|
|
|
|
stateSpec.shuffle = 1;
|
|
|
|
switch (s.getState()) {
|
|
|
|
case PlaybackState.STATE_PLAYING:
|
2016-06-09 20:00:14 +02:00
|
|
|
stateSpec.state = MusicStateSpec.STATE_PLAYING;
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
break;
|
|
|
|
case PlaybackState.STATE_STOPPED:
|
2016-06-09 20:00:14 +02:00
|
|
|
stateSpec.state = MusicStateSpec.STATE_STOPPED;
|
|
|
|
break;
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
case PlaybackState.STATE_PAUSED:
|
2016-06-09 20:00:14 +02:00
|
|
|
stateSpec.state = MusicStateSpec.STATE_PAUSED;
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
break;
|
|
|
|
default:
|
2016-06-09 20:00:14 +02:00
|
|
|
stateSpec.state = MusicStateSpec.STATE_UNKNOWN;
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
break;
|
|
|
|
}
|
2016-06-07 19:34:37 +02:00
|
|
|
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
MediaMetadata d = c.getMetadata();
|
|
|
|
if (d == null)
|
|
|
|
return false;
|
|
|
|
if (d.containsKey(MediaMetadata.METADATA_KEY_ARTIST))
|
|
|
|
musicSpec.artist = d.getString(MediaMetadata.METADATA_KEY_ARTIST);
|
|
|
|
if (d.containsKey(MediaMetadata.METADATA_KEY_ALBUM))
|
|
|
|
musicSpec.album = d.getString(MediaMetadata.METADATA_KEY_ALBUM);
|
|
|
|
if (d.containsKey(MediaMetadata.METADATA_KEY_TITLE))
|
|
|
|
musicSpec.track = d.getString(MediaMetadata.METADATA_KEY_TITLE);
|
|
|
|
if (d.containsKey(MediaMetadata.METADATA_KEY_DURATION))
|
2016-06-09 20:02:01 +02:00
|
|
|
musicSpec.duration = (int)d.getLong(MediaMetadata.METADATA_KEY_DURATION) / 1000;
|
2016-06-10 22:20:55 +02:00
|
|
|
if (d.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS))
|
|
|
|
musicSpec.trackCount = (int)d.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS);
|
|
|
|
if (d.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER))
|
|
|
|
musicSpec.trackNr = (int)d.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER);
|
2016-06-07 19:34:37 +02:00
|
|
|
|
|
|
|
// finally, tell the device about it
|
|
|
|
GBApplication.deviceService().onSetMusicInfo(musicSpec);
|
Add handling for media session notifications
Since Android 5.0, media players can have interactive notifications that
reside in the notification area, and offer up to 5 control buttons
(play/pause, next, previous, etc), and information about the currentlu
playing media file.
We use these notifications to get information about the currently
playing media file such as:
- artist
- track (title)
- album
- duration (length of the media file)
- play state (playing, paused, stopped)
- position
- play rate (how fast is the media file being played)
We then send this information up to the device.
On Pebble, the music app will display the title and the artist, as
well as a progress bar showing the current position. The progress bar is
animated when the media file is being played, and if it is being paused,
it displays a pause symbol.
This code will be skipped when GadgetBridge is run on a device with
Android version older than 5.0 (lollipop).
2016-06-08 20:33:20 +02:00
|
|
|
GBApplication.deviceService().onSetMusicState(stateSpec);
|
|
|
|
|
2016-06-07 19:34:37 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-01-07 14:00:18 +01:00
|
|
|
@Override
|
|
|
|
public void onNotificationRemoved(StatusBarNotification sbn) {
|
|
|
|
|
|
|
|
}
|
2015-09-13 00:39:53 +02:00
|
|
|
}
|