Skip to content

Commit

Permalink
Merge pull request #134 from tobexyz/feat/issue52
Browse files Browse the repository at this point in the history
issue #52 using AlarmManager to avoid avtransport player stop on disp…
  • Loading branch information
tobexyz authored Dec 21, 2024
2 parents ff2a1ae + bec7b53 commit d1a9631
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 27 deletions.
8 changes: 7 additions & 1 deletion yaacc/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />


<application
android:name=".Yaacc"
android:allowBackup="false"
Expand Down Expand Up @@ -72,7 +75,10 @@
android:name=".settings.SettingsActivity"
android:label="@string/title_activity_settings" />

<receiver android:name=".imageviewer.ImageViewerBroadcastReceiver" />
<receiver
android:enabled="true"
android:name=".imageviewer.ImageViewerBroadcastReceiver" />

<receiver
android:name=".upnp.server.ServerAutostart"
android:enabled="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void onReceive(Context context, Intent intent) {
}

public void registerReceiver() {
Log.d(this.getClass().getName(), "Register Receiver");
Log.d(this.getClass().getName(), "Register BackgroundMusicBroadcastReceiver");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_PLAY);
intentFilter.addAction(ACTION_PAUSE);
Expand Down
9 changes: 0 additions & 9 deletions yaacc/src/main/java/de/yaacc/player/AVTransportPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -531,15 +531,6 @@ public String getElapsedTime() {
public void startTimer(final long duration) {
super.startTimer(duration);
Yaacc yaacc = (Yaacc) getContext().getApplicationContext();
if (yaacc.isUnplugged() && getItems().size() > 1) {
yaacc.acquireWakeLock(duration + 1000L, getWakeLockTag());
//bring current player to front
Intent i = new Intent(yaacc, AVTransportPlayerActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
i.setData(Uri.parse("http://0.0.0.0/" + getId() + "")); //just for making the intents different http://stackoverflow.com/questions/10561419/scheduling-more-than-one-pendingintent-to-same-activity-using-alarmmanager
i.putExtra(PLAYER_ID, getId());
yaacc.startActivity(i);
}
}

@Override
Expand Down
72 changes: 57 additions & 15 deletions yaacc/src/main/java/de/yaacc/player/AbstractPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package de.yaacc.player;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
Expand All @@ -26,12 +27,13 @@
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;

import java.beans.PropertyChangeListener;
Expand Down Expand Up @@ -62,10 +64,10 @@ public abstract class AbstractPlayer implements Player, ServiceConnection {
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private final List<PlayableItem> items = new ArrayList<>();
private final UpnpClient upnpClient;
private Handler playerTimer;
private int previousIndex = 0;
private int currentIndex = 0;
private Timer execTimer;
private PendingIntent alarmIntent;
private boolean isPlaying = false;
private boolean isProcessingCommand = false;
private PlayerService playerService;
Expand Down Expand Up @@ -349,8 +351,13 @@ public void clear() {
}

protected void cancelTimer() {
if (playerTimer != null) {
playerTimer.removeCallbacksAndMessages(null);

if (alarmIntent != null) {
AlarmManager alarmManager =
(AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
alarmManager.cancel(alarmIntent);
}
}
}

Expand Down Expand Up @@ -539,15 +546,50 @@ public long getRemainingTime() {
public void startTimer(final long duration) {
Log.d(getClass().getName(), "Start timer duration: " + duration);
cancelTimer();
playerTimer = new Handler(playerService.getPlayerHandlerThread().getLooper());
playerTimer.postDelayed(new Runnable() {

@Override
public void run() {
Log.d(getClass().getName(), "TimerEvent for switching to next item" + this);
AbstractPlayer.this.next();
Intent intent = new Intent();
intent.setAction(PlayerServiceBroadcastReceiver.ACTION_NEXT);
intent.putExtra(PLAYER_ID, getId());
ContextCompat.getMainExecutor(getContext()).execute(() -> {
AlarmManager alarmManager =
(AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
alarmIntent = PendingIntent.getBroadcast(getContext(), intent.hashCode(), intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (alarmManager.canScheduleExactAlarms()) {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + duration,
alarmIntent
);
Log.w(getClass().getName(), "ExactAndAllowWhileIdle alarm event in: " + (System.currentTimeMillis() + duration));
} else {
alarmManager.setAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + duration,
alarmIntent
);
Log.w(getClass().getName(), "AndAllowWhileIdle alarm event in: " + (System.currentTimeMillis() + duration));
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + duration,
alarmIntent
);
Log.w(getClass().getName(), "exact alarm event in: " + (System.currentTimeMillis() + duration));
} else {
alarmManager.set(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + duration,
alarmIntent
);
Log.d(getClass().getName(), "set alarm event in: " + (System.currentTimeMillis() + duration));
}
}, duration);


});

}

/*
Expand Down Expand Up @@ -620,11 +662,11 @@ private void showNotification() {
/**
* Cancels the notification.
*/
private void cancleNotification() {
private void cancelNotification() {
NotificationManager mNotificationManager = (NotificationManager) getContext()
.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
Log.d(getClass().getName(), "Cancle Notification with ID: " + getNotificationId());
Log.d(getClass().getName(), "Cancel Notification with ID: " + getNotificationId());
mNotificationManager.cancel(getNotificationId());
((Yaacc) getContext().getApplicationContext()).cancelYaaccGroupNotification();

Expand Down Expand Up @@ -662,7 +704,7 @@ protected abstract void startItem(PlayableItem playableItem,
@Override
public void onDestroy() {
stop();
cancleNotification();
cancelNotification();
items.clear();
if (playerService != null) {
try {
Expand Down
27 changes: 26 additions & 1 deletion yaacc/src/main/java/de/yaacc/player/PlayerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import android.os.Binder;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import android.widget.Toast;

Expand Down Expand Up @@ -52,9 +53,12 @@
public class PlayerService extends Service {

private final IBinder binder = new PlayerServiceBinder();
private PlayerServiceBroadcastReceiver playerServiceBroadcastReceiver;
private final Map<Integer, Player> currentActivePlayer = new HashMap<>();
private HandlerThread playerHandlerThread;

private PowerManager.WakeLock wakeLock;


public PlayerService() {
}
Expand Down Expand Up @@ -90,6 +94,10 @@ public Collection<Player> getPlayer() {
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.d(this.getClass().getName(), "Received start id " + startId + ": " + intent);
if (playerServiceBroadcastReceiver == null) {
playerServiceBroadcastReceiver = new PlayerServiceBroadcastReceiver(this);
playerServiceBroadcastReceiver.registerReceiver();
}
((Yaacc) getApplicationContext()).createYaaccGroupNotification();
Intent notificationIntent = new Intent(this, TabBrowserActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
Expand All @@ -102,6 +110,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
.setSmallIcon(R.drawable.ic_notification_default)
.setContentIntent(pendingIntent)
.build();

startForeground(NotificationId.PLAYER_SERVICE.getId(), notification);
initialize();

Expand Down Expand Up @@ -158,7 +167,7 @@ public List<Player> createPlayer(UpnpClient upnpClient,
}

}
Log.d(getClass().getName(), "video:" + video + " image: " + image + "audio:" + music);
Log.d(getClass().getName(), "video:" + video + " image: " + image + " audio:" + music);
for (Device<?, ?, ?> device : upnpClient.getReceiverDevices()) {
result = createPlayer(upnpClient, device, video, image, music, syncInfo);
if (result != null) {
Expand All @@ -170,6 +179,15 @@ public List<Player> createPlayer(UpnpClient upnpClient,
return resultList;
}

@Override
public boolean onUnbind(Intent intent) {
if (playerServiceBroadcastReceiver != null) {
unregisterReceiver(playerServiceBroadcastReceiver);
}
return super.onUnbind(intent);
}


/**
* creates a player for the given device
*
Expand Down Expand Up @@ -286,6 +304,11 @@ public Collection<Player> getCurrentPlayers() {
return Collections.unmodifiableCollection(currentActivePlayer.values());
}

public Player getCurrentPlayerById(Integer id) {

return currentActivePlayer.get(id);
}

/**
* returns all current players of the given type.
*
Expand Down Expand Up @@ -372,6 +395,8 @@ public void shutdown(Player player) {
stopForeground(true);
((Yaacc) getApplicationContext()).cancelYaaccGroupNotification();
}


}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2024 Tobias Schoene www.yaacc.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package de.yaacc.player;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;

/**
* @author tobexyz
*/
public class PlayerServiceBroadcastReceiver extends BroadcastReceiver {

public static String ACTION_NEXT = "de.yaacc.player.ActionNext";

private final PlayerService playerService;


public PlayerServiceBroadcastReceiver(PlayerService playerService) {
Log.d(this.getClass().getName(), "Starting Broadcast Receiver...");
assert (playerService != null);
this.playerService = playerService;

}

@Override
public void onReceive(Context context, Intent intent) {
Log.w(this.getClass().getName(), "Received Action: " + intent.getAction());
if (playerService == null) return;
Log.w(this.getClass().getName(), "Execute Action on playerService: " + playerService);
if (ACTION_NEXT.equals(intent.getAction())) {
Integer playerId = intent.getIntExtra(AbstractPlayer.PLAYER_ID, -1);
Log.w(this.getClass().getName(), "Player of intent not found: " + playerId + " Intent: " + intent.getStringExtra("ID"));
Player player = playerService.getCurrentPlayerById(playerId);
if (player != null) {
player.next();
} else {
Log.w(this.getClass().getName(), "Player of intent not found: " + playerId);
}
;
}
}

public void registerReceiver() {
Log.d(this.getClass().getName(), "Register PlayerServiceBroadcastReceiver");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_NEXT);
playerService.registerReceiver(this, intentFilter);
}

}

0 comments on commit d1a9631

Please sign in to comment.