Skip to content

Commit 3e23bd6

Browse files
committed
Improved play notification, now including progress text and click intent
1 parent 857633a commit 3e23bd6

File tree

8 files changed

+388
-148
lines changed

8 files changed

+388
-148
lines changed

android/app/src/main/java/com/github/nicorac/plugins/audioplayer/AudioPlayerService.java

Lines changed: 89 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,34 @@
55
import android.app.PendingIntent;
66
import android.app.Service;
77
import android.content.Intent;
8-
import android.graphics.BitmapFactory;
9-
import android.media.MediaPlayer;
108
import android.net.Uri;
119
import android.os.Binder;
1210
import android.os.Build;
1311
import android.os.IBinder;
1412
import android.os.PowerManager;
1513

1614
import androidx.annotation.Nullable;
17-
import androidx.core.app.NotificationCompat;
1815

1916
import com.getcapacitor.JSObject;
2017
import com.getcapacitor.PluginCall;
2118
import com.github.nicorac.bcrgui.MainActivity;
22-
import com.github.nicorac.bcrgui.R;
2319

2420
import java.util.HashMap;
2521

2622
public class AudioPlayerService extends Service {
2723

28-
private static final String ERR_BAD_ID = "Unexisting player with this 'id'";
24+
private static final String ERR_BAD_ID = "Can't find a player instance with this 'id'";
2925

3026
private static final String NOTIFICATION_CHANNEL_ID = "BCR-GUI";
3127
private static final String NOTIFICATION_CHANNEL_NAME = "BCR-GUI - Play status";
28+
private static PendingIntent bringAppToForegroundIntent;
29+
private static NotificationManager notificationManager;
3230

3331
// wakelock to keep the service alive when playing
3432
private PowerManager.WakeLock wakeLock = null;
3533

3634
// players collection
37-
private final HashMap<Integer, MediaPlayerInstance> players = new HashMap<>();
35+
private final HashMap<Integer, MediaPlayerEx> players = new HashMap<>();
3836

3937
// reference to plugin
4038
private IJSEventSender plugin;
@@ -50,21 +48,52 @@ public AudioPlayerService getService(IJSEventSender plugin) {
5048

5149
@Override
5250
public void onCreate() {
51+
5352
super.onCreate();
5453
var powerManager = (PowerManager) getSystemService(POWER_SERVICE);
5554
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AudioPlayerService::WakelockTag");
55+
56+
// Create an Intent for the "bring-to-front" action to be linked in notifications
57+
Intent customIntent = new Intent(getApplicationContext(), MainActivity.class);
58+
customIntent.setAction(Intent.ACTION_MAIN);
59+
customIntent.addCategory(Intent.CATEGORY_LAUNCHER);
60+
61+
// get instance of NotificationManager and create notifications channel
62+
if (notificationManager == null) {
63+
notificationManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
64+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
65+
var channel = new NotificationChannel(
66+
NOTIFICATION_CHANNEL_ID,
67+
NOTIFICATION_CHANNEL_NAME,
68+
NotificationManager.IMPORTANCE_DEFAULT
69+
);
70+
notificationManager.createNotificationChannel(channel);
71+
}
72+
}
73+
74+
// Create a PendingIntent
75+
bringAppToForegroundIntent = PendingIntent.getActivity(
76+
getApplicationContext(), 0, customIntent,
77+
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
78+
);
79+
5680
}
5781

5882
@Override
5983
public void onDestroy() {
6084
super.onDestroy();
61-
for (MediaPlayerInstance i : players.values()) {
62-
destroyPlayer(i);
85+
for (MediaPlayerEx i : players.values()) {
86+
release(i);
6387
}
6488
players.clear();
6589
wakeLockUpdate();
6690
}
6791

92+
@Override
93+
public void onTaskRemoved(Intent rootIntent) {
94+
// cancel all notifications
95+
}
96+
6897
@Override
6998
public IBinder onBind(Intent intent) {
7099
return binder;
@@ -92,23 +121,34 @@ public void init(PluginCall call) {
92121
try {
93122

94123
var fileUri = Uri.parse(fileUriStr);
95-
var mediaPlayer = MediaPlayer.create(this, fileUri);
96-
mediaPlayer.setLooping(false);
97-
var mpi = new MediaPlayerInstance(
98-
id,
99-
mediaPlayer,
124+
var mpe = new MediaPlayerEx(
125+
getApplicationContext(),
126+
fileUri,
100127
notificationTitle,
101-
notificationText
128+
notificationText,
129+
new OnEventListener() {
130+
131+
@Override
132+
public PendingIntent getNotificationClickIntent() { return bringAppToForegroundIntent; }
133+
134+
@Override
135+
public void onUpdate(MediaPlayerEx player) {
136+
var res = new JSObject();
137+
res.put("id", id);
138+
res.put("position", player.getCurrentPosition());
139+
plugin.sendJSEvent("update", res);
140+
}
141+
142+
@Override
143+
public void onCompletion(MediaPlayerEx mp) {
144+
var res = new JSObject();
145+
res.put("id", id);
146+
plugin.sendJSEvent("playCompleted", res);
147+
}
148+
149+
}
102150
);
103-
players.put(id, mpi);
104-
105-
// Set completion listener
106-
mediaPlayer.setOnCompletionListener(mp -> {
107-
cancelMediaNotification(mpi);
108-
var res = new JSObject();
109-
res.put("id", id);
110-
plugin.sendJSEvent("playCompleted", res);
111-
});
151+
players.put(id, mpe);
112152

113153
} catch (Exception e) {
114154
call.reject("Error loading audio file: " + fileUriStr);
@@ -124,22 +164,24 @@ public void init(PluginCall call) {
124164
}
125165

126166
/**
127-
* Release current audio file and free linked mediaplayer
167+
* Release current audio file and free the linked mediaplayer
128168
*/
129169
public void release(PluginCall call) {
130170

131171
var id = getPlayerId(call);
132-
if (id == null) return;
172+
if (id == null) {
173+
call.reject(ERR_BAD_ID);
174+
return;
175+
};
133176

134177
// remove item
135-
var i = players.get(id);
136-
if (i == null) {
178+
var p = players.get(id);
179+
if (p == null) {
137180
call.reject(ERR_BAD_ID);
138181
return;
139182
}
140183
else {
141-
destroyPlayer(i);
142-
players.remove(id);
184+
release(p);
143185
}
144186

145187
call.resolve();
@@ -149,10 +191,11 @@ public void release(PluginCall call) {
149191
/**
150192
* Destroy a MediaPlayer instance
151193
*/
152-
private void destroyPlayer(MediaPlayerInstance i) {
194+
private void release(MediaPlayerEx p) {
153195
try {
154-
stop(i);
155-
i.player.release();
196+
stop(p);
197+
p.release();
198+
players.remove(p.id);
156199
}
157200
catch (Exception ignored) {}
158201
}
@@ -163,18 +206,17 @@ private void destroyPlayer(MediaPlayerInstance i) {
163206
public void play(PluginCall call) {
164207

165208
// get target player
166-
var i = getPlayerInstance(call);
167-
if (i == null) return;
209+
var p = getPlayerInstance(call);
210+
if (p == null) return;
168211

169212
// test if a position has been passed
170213
var position = call.getInt("position");
171214
if (position != null) {
172-
i.player.seekTo(position);
215+
p.seekTo(position);
173216
}
174-
if (!i.player.isPlaying()) {
175-
i.player.start();
217+
if (!p.isPlaying()) {
218+
p.start();
176219
wakeLockUpdate();
177-
showMediaNotification(i);
178220
}
179221
call.resolve();
180222

@@ -189,9 +231,8 @@ public void pause(PluginCall call) {
189231
var i = getPlayerInstance(call);
190232
if (i == null) return;
191233

192-
if (i.player.isPlaying()) {
193-
i.player.pause();
194-
cancelMediaNotification(i);
234+
if (i.isPlaying()) {
235+
i.pause();
195236
wakeLockUpdate();
196237
}
197238
call.resolve();
@@ -208,11 +249,10 @@ public void stop(PluginCall call) {
208249
stop(i);
209250
call.resolve();
210251
}
211-
public void stop(MediaPlayerInstance i) {
252+
public void stop(MediaPlayerEx p) {
212253

213-
if (i.player.isPlaying()) {
214-
i.player.stop();
215-
cancelMediaNotification(i);
254+
if (p.isPlaying()) {
255+
p.stop();
216256
wakeLockUpdate();
217257
}
218258

@@ -228,7 +268,7 @@ public void getDuration(PluginCall call) {
228268
if (i == null) return;
229269

230270
var res = new JSObject();
231-
res.put("duration", i.player.getDuration());
271+
res.put("duration", i.getDuration());
232272
call.resolve(res);
233273

234274
}
@@ -243,7 +283,7 @@ public void getCurrentTime(PluginCall call) {
243283
if (i == null) return;
244284

245285
var res = new JSObject();
246-
res.put("currentTime", i.player.getCurrentPosition());
286+
res.put("currentTime", i.getCurrentPosition());
247287
call.resolve(res);
248288

249289
}
@@ -258,7 +298,7 @@ private void wakeLockUpdate() {
258298
var toBeEnabled = false;
259299
try {
260300
for (var i : players.values()) {
261-
if (i.player.isPlaying()) {
301+
if (i.isPlaying()) {
262302
toBeEnabled = true;
263303
break;
264304
}
@@ -288,7 +328,7 @@ private Integer getPlayerId(PluginCall call) {
288328
* Return the existing media player instance from id
289329
*/
290330
@Nullable
291-
private MediaPlayerInstance getPlayerInstance(PluginCall call) {
331+
private MediaPlayerEx getPlayerInstance(PluginCall call) {
292332

293333
var id = getPlayerId(call);
294334
if (id == null) return null;
@@ -302,61 +342,4 @@ private MediaPlayerInstance getPlayerInstance(PluginCall call) {
302342

303343
}
304344

305-
/**
306-
* Show multimedia notification
307-
*/
308-
public void showMediaNotification(MediaPlayerInstance playerInstance) {
309-
310-
// Notification manager service
311-
var notificationManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
312-
if (notificationManager == null) {
313-
return;
314-
}
315-
316-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
317-
var channel = new NotificationChannel(
318-
NOTIFICATION_CHANNEL_ID,
319-
NOTIFICATION_CHANNEL_NAME,
320-
NotificationManager.IMPORTANCE_DEFAULT
321-
);
322-
notificationManager.createNotificationChannel(channel);
323-
}
324-
325-
// Create an Intent for the "bring-to-front"" action
326-
Intent customIntent = new Intent(getApplicationContext(), MainActivity.class);
327-
customIntent.setAction(Intent.ACTION_MAIN);
328-
customIntent.addCategory(Intent.CATEGORY_LAUNCHER);
329-
330-
// Create a PendingIntent
331-
PendingIntent pendingIntent = PendingIntent.getActivity(
332-
getApplicationContext(), 0, customIntent,
333-
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
334-
);
335-
336-
var builder = new NotificationCompat.Builder(getApplicationContext(), NOTIFICATION_CHANNEL_ID)
337-
.setContentTitle(playerInstance.title)
338-
.setContentText(playerInstance.text)
339-
.setSmallIcon(R.drawable.notification)
340-
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification))
341-
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
342-
.setContentIntent(pendingIntent) // Set the PendingIntent
343-
.setOngoing(true) // Set as "persistant"
344-
;
345-
var notification = builder.build();
346-
notificationManager.notify(playerInstance.id, notification);
347-
348-
}
349-
/**
350-
* Cancel existing multimedia notification
351-
*/
352-
public void cancelMediaNotification(MediaPlayerInstance playerInstance) {
353-
354-
// Notification manager service
355-
var notificationManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
356-
if (notificationManager != null) {
357-
notificationManager.cancel(playerInstance.id);
358-
}
359-
360-
}
361-
362345
}

0 commit comments

Comments
 (0)