This repository has been archived by the owner. It is now read-only.
forked from tanguyantoine/react-native-music-control
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMusicControlNotification.java
More file actions
178 lines (146 loc) · 8.28 KB
/
MusicControlNotification.java
File metadata and controls
178 lines (146 loc) · 8.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package com.tanguyantoine.react;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.res.Resources;
import android.os.IBinder;
import androidx.core.app.NotificationManagerCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.view.KeyEvent;
import com.facebook.react.bridge.ReactApplicationContext;
import java.util.Map;
public class MusicControlNotification {
protected static final String REMOVE_NOTIFICATION = "music_control_remove_notification";
protected static final String MEDIA_BUTTON = "music_control_media_button";
protected static final String PACKAGE_NAME = "music_control_package_name";
private final ReactApplicationContext context;
private final MusicControlModule module;
private int smallIcon;
private int customIcon;
private androidx.core.app.NotificationCompat.Action play, pause, stop, next, previous, skipForward, skipBackward;
public MusicControlNotification(MusicControlModule module, ReactApplicationContext context) {
this.context = context;
this.module = module;
Resources r = context.getResources();
String packageName = context.getPackageName();
// Optional custom icon with fallback to the play icon
smallIcon = r.getIdentifier("music_control_icon", "drawable", packageName);
if(smallIcon == 0) smallIcon = r.getIdentifier("play", "drawable", packageName);
}
public synchronized void setCustomNotificationIcon(String resourceName) {
if(resourceName == null) {
customIcon = 0;
return;
}
Resources r = context.getResources();
String packageName = context.getPackageName();
customIcon = r.getIdentifier(resourceName, "drawable", packageName);
}
public synchronized void updateActions(long mask, Map<String, Integer> options) {
play = createAction("play", "Play", mask, PlaybackStateCompat.ACTION_PLAY, play);
pause = createAction("pause", "Pause", mask, PlaybackStateCompat.ACTION_PAUSE, pause);
stop = createAction("stop", "Stop", mask, PlaybackStateCompat.ACTION_STOP, stop);
next = createAction("next", "Next", mask, PlaybackStateCompat.ACTION_SKIP_TO_NEXT, next);
previous = createAction("previous", "Previous", mask, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS, previous);
if (options != null && options.containsKey("skipForward") && (options.get("skipForward") == 10 || options.get("skipForward") == 5 || options.get("skipForward") == 30)) {
skipForward = createAction("skip_forward_" + options.get("skipForward").toString(), "Skip Forward", mask, PlaybackStateCompat.ACTION_FAST_FORWARD, skipForward);
} else {
skipForward = createAction("skip_forward_10", "Skip Forward", mask, PlaybackStateCompat.ACTION_FAST_FORWARD, skipForward);
}
if (options != null && options.containsKey("skipBackward") && (options.get("skipBackward") == 10 || options.get("skipBackward") == 5 || options.get("skipBackward") == 30)) {
skipBackward = createAction("skip_backward_" + options.get("skipBackward").toString(), "Skip Backward", mask, PlaybackStateCompat.ACTION_REWIND, skipBackward);
} else {
skipBackward = createAction("skip_backward_10", "Skip Backward", mask, PlaybackStateCompat.ACTION_REWIND, skipBackward);
}
}
public synchronized void show(androidx.core.app.NotificationCompat.Builder builder, boolean isPlaying) {
// Add the buttons
builder.mActions.clear();
if(previous != null) builder.addAction(previous);
if(skipBackward != null) builder.addAction(skipBackward);
if(play != null && !isPlaying) builder.addAction(play);
if(pause != null && isPlaying) builder.addAction(pause);
if(stop != null) builder.addAction(stop);
if(next != null) builder.addAction(next);
if(skipForward != null) builder.addAction(skipForward);
// Set whether notification can be closed based on closeNotification control (default PAUSED)
if(module.notificationClose == MusicControlModule.NotificationClose.ALWAYS) {
builder.setOngoing(false);
} else if(module.notificationClose == MusicControlModule.NotificationClose.PAUSED) {
builder.setOngoing(isPlaying);
} else { // NotificationClose.NEVER
builder.setOngoing(true);
}
builder.setSmallIcon(customIcon != 0 ? customIcon : smallIcon);
// Open the app when the notification is clicked
String packageName = context.getPackageName();
Intent openApp = context.getPackageManager().getLaunchIntentForPackage(packageName);
builder.setContentIntent(PendingIntent.getActivity(context, 0, openApp, 0));
// Remove notification
Intent remove = new Intent(REMOVE_NOTIFICATION);
remove.putExtra(PACKAGE_NAME, context.getApplicationInfo().packageName);
builder.setDeleteIntent(PendingIntent.getBroadcast(context, 0, remove, PendingIntent.FLAG_UPDATE_CURRENT));
// Finally show/update the notification
NotificationManagerCompat.from(context).notify("MusicControl", 0, builder.build());
}
public void hide() {
NotificationManagerCompat.from(context).cancel("MusicControl", 0);
}
/**
* Code taken from newer version of the support library located in PlaybackStateCompat.toKeyCode
* Replace this to PlaybackStateCompat.toKeyCode when React Native updates the support library
*/
private int toKeyCode(long action) {
if(action == PlaybackStateCompat.ACTION_PLAY) {
return KeyEvent.KEYCODE_MEDIA_PLAY;
} else if(action == PlaybackStateCompat.ACTION_PAUSE) {
return KeyEvent.KEYCODE_MEDIA_PAUSE;
} else if(action == PlaybackStateCompat.ACTION_SKIP_TO_NEXT) {
return KeyEvent.KEYCODE_MEDIA_NEXT;
} else if(action == PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) {
return KeyEvent.KEYCODE_MEDIA_PREVIOUS;
} else if(action == PlaybackStateCompat.ACTION_STOP) {
return KeyEvent.KEYCODE_MEDIA_STOP;
} else if(action == PlaybackStateCompat.ACTION_FAST_FORWARD) {
return KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
} else if(action == PlaybackStateCompat.ACTION_REWIND) {
return KeyEvent.KEYCODE_MEDIA_REWIND;
} else if(action == PlaybackStateCompat.ACTION_PLAY_PAUSE) {
return KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
}
return KeyEvent.KEYCODE_UNKNOWN;
}
private androidx.core.app.NotificationCompat.Action createAction(String iconName, String title, long mask, long action, androidx.core.app.NotificationCompat.Action oldAction) {
if((mask & action) == 0) return null; // When this action is not enabled, return null
if(oldAction != null) return oldAction; // If this action was already created, we won't create another instance
// Finds the icon with the given name
Resources r = context.getResources();
String packageName = context.getPackageName();
int icon = r.getIdentifier(iconName, "drawable", packageName);
// Creates the intent based on the action
int keyCode = toKeyCode(action);
Intent intent = new Intent(MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
intent.putExtra(PACKAGE_NAME, packageName);
PendingIntent i = PendingIntent.getBroadcast(context, keyCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return new androidx.core.app.NotificationCompat.Action(icon, title, i);
}
public static class NotificationService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
@Override
public void onTaskRemoved(Intent rootIntent) {
// Destroy the notification and sessions when the task is removed (closed, killed, etc)
if(MusicControlModule.INSTANCE != null) {
MusicControlModule.INSTANCE.destroy();
}
stopSelf(); // Stop the service as we won't need it anymore
}
}
}