mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-10-29 11:49:33 +00:00
Rework sleep timer so it no longer uses threads and clean up PlaybackServiceTaskManager (#7713)
Reworked sleep timer to no longer use threads, instead uses PlaybackService PlaybackPositionEvent which is fired while media is playing. We use this to calculate how much time is left of the sleep timer and send the proper events.
This commit is contained in:
parent
c5cec07b0e
commit
55d3b743d1
@ -5,13 +5,10 @@ import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.filters.LargeTest;
|
||||
|
||||
import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
|
||||
import de.danoeh.antennapod.playback.service.internal.PlaybackServiceTaskManager;
|
||||
import de.danoeh.antennapod.storage.preferences.SleepTimerPreferences;
|
||||
import de.danoeh.antennapod.storage.database.PodDBAdapter;
|
||||
import de.danoeh.antennapod.ui.widget.WidgetUpdater;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -28,7 +25,6 @@ import de.danoeh.antennapod.model.playback.Playable;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Test class for PlaybackServiceTaskManager
|
||||
@ -190,7 +186,6 @@ public class PlaybackServiceTaskManagerTest {
|
||||
pstm.cancelAllTasks();
|
||||
assertFalse(pstm.isPositionSaverActive());
|
||||
assertFalse(pstm.isWidgetUpdaterActive());
|
||||
assertFalse(pstm.isSleepTimerActive());
|
||||
pstm.shutdown();
|
||||
}
|
||||
|
||||
@ -201,82 +196,9 @@ public class PlaybackServiceTaskManagerTest {
|
||||
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
|
||||
pstm.startWidgetUpdater();
|
||||
pstm.startPositionSaver();
|
||||
pstm.setSleepTimer(100000);
|
||||
pstm.cancelAllTasks();
|
||||
assertFalse(pstm.isPositionSaverActive());
|
||||
assertFalse(pstm.isWidgetUpdaterActive());
|
||||
assertFalse(pstm.isSleepTimerActive());
|
||||
pstm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetSleepTimer() throws InterruptedException {
|
||||
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
final long TIME = 2000;
|
||||
final long TIMEOUT = 2 * TIME;
|
||||
final CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
Object timerReceiver = new Object() {
|
||||
@Subscribe
|
||||
public void sleepTimerUpdate(SleepTimerUpdatedEvent event) {
|
||||
if (countDownLatch.getCount() == 0) {
|
||||
fail();
|
||||
}
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
};
|
||||
EventBus.getDefault().register(timerReceiver);
|
||||
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
|
||||
pstm.setSleepTimer(TIME);
|
||||
countDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
|
||||
EventBus.getDefault().unregister(timerReceiver);
|
||||
pstm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testDisableSleepTimer() throws InterruptedException {
|
||||
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
final long TIME = 5000;
|
||||
final long TIMEOUT = 2 * TIME;
|
||||
final CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
Object timerReceiver = new Object() {
|
||||
@Subscribe
|
||||
public void sleepTimerUpdate(SleepTimerUpdatedEvent event) {
|
||||
if (event.isOver()) {
|
||||
countDownLatch.countDown();
|
||||
} else if (event.getTimeLeft() == 1) {
|
||||
fail("Arrived at 1 but should have been cancelled");
|
||||
}
|
||||
}
|
||||
};
|
||||
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
|
||||
EventBus.getDefault().register(timerReceiver);
|
||||
pstm.setSleepTimer(TIME);
|
||||
pstm.disableSleepTimer();
|
||||
assertFalse(countDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS));
|
||||
pstm.shutdown();
|
||||
EventBus.getDefault().unregister(timerReceiver);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testIsSleepTimerActivePositive() {
|
||||
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
|
||||
pstm.setSleepTimer(1000);
|
||||
assertTrue(pstm.isSleepTimerActive());
|
||||
pstm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testIsSleepTimerActiveNegative() {
|
||||
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
|
||||
pstm.setSleepTimer(10000);
|
||||
pstm.disableSleepTimer();
|
||||
assertFalse(pstm.isSleepTimerActive());
|
||||
pstm.shutdown();
|
||||
}
|
||||
|
||||
|
||||
@ -201,7 +201,7 @@ public class SleepTimerDialog extends DialogFragment {
|
||||
chAutoEnable.setText(text);
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
@SuppressWarnings("unused")
|
||||
public void timerUpdated(SleepTimerUpdatedEvent event) {
|
||||
timeDisplay.setVisibility(event.isOver() || event.isCancelled() ? View.GONE : View.VISIBLE);
|
||||
|
||||
@ -55,6 +55,7 @@ import androidx.media.MediaBrowserServiceCompat;
|
||||
|
||||
import de.danoeh.antennapod.event.PlayerStatusEvent;
|
||||
import de.danoeh.antennapod.net.sync.serviceinterface.SynchronizationQueue;
|
||||
import de.danoeh.antennapod.playback.service.internal.ClockSleepTimer;
|
||||
import de.danoeh.antennapod.playback.service.internal.LocalPSMP;
|
||||
import de.danoeh.antennapod.playback.service.internal.PlayableUtils;
|
||||
import de.danoeh.antennapod.playback.service.internal.PlaybackServiceNotificationBuilder;
|
||||
@ -80,7 +81,7 @@ import de.danoeh.antennapod.storage.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.storage.preferences.SleepTimerPreferences;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.storage.database.DBWriter;
|
||||
import de.danoeh.antennapod.playback.service.internal.PlaybackServiceTaskManager.SleepTimer;
|
||||
import de.danoeh.antennapod.playback.service.internal.SleepTimer;
|
||||
import de.danoeh.antennapod.ui.common.IntentUtils;
|
||||
import de.danoeh.antennapod.net.common.NetworkUtils;
|
||||
import de.danoeh.antennapod.event.MessageEvent;
|
||||
@ -159,6 +160,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
private PlaybackServiceMediaPlayer mediaPlayer;
|
||||
private PlaybackServiceTaskManager taskManager;
|
||||
private SleepTimer sleepTimer;
|
||||
private PlaybackServiceStateManager stateManager;
|
||||
private Disposable positionEventTimer;
|
||||
private PlaybackServiceNotificationBuilder notificationBuilder;
|
||||
@ -676,7 +678,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
taskManager.restartSleepTimer();
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||
if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
|
||||
@ -689,7 +690,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
taskManager.restartSleepTimer();
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||
if (status == PlayerStatus.PLAYING) {
|
||||
@ -1188,11 +1188,25 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
public void setSleepTimer(long waitingTime) {
|
||||
Log.d(TAG, "Setting sleep timer to " + waitingTime + " milliseconds");
|
||||
taskManager.setSleepTimer(waitingTime);
|
||||
if (waitingTime <= 0) {
|
||||
throw new IllegalArgumentException("Waiting time <= 0");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting sleep timer to " + waitingTime + " milliseconds or episodes");
|
||||
if (sleepTimerActive()) {
|
||||
sleepTimer.updateRemainingTime(waitingTime);
|
||||
} else {
|
||||
sleepTimer = new ClockSleepTimer(getApplicationContext());
|
||||
sleepTimer.start(waitingTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void disableSleepTimer() {
|
||||
taskManager.disableSleepTimer();
|
||||
if (sleepTimerActive()) {
|
||||
Log.d(TAG, "Disabling sleep timer");
|
||||
sleepTimer.stop();
|
||||
}
|
||||
sleepTimer = null;
|
||||
}
|
||||
|
||||
private void sendNotificationBroadcast(int type, int code) {
|
||||
@ -1473,11 +1487,15 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
}
|
||||
|
||||
public boolean sleepTimerActive() {
|
||||
return taskManager.isSleepTimerActive();
|
||||
return sleepTimer != null && sleepTimer.isActive();
|
||||
}
|
||||
|
||||
public long getSleepTimerTimeLeft() {
|
||||
return taskManager.getSleepTimerTimeLeft();
|
||||
if (sleepTimerActive()) {
|
||||
return sleepTimer.getTimeLeft();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void bluetoothNotifyChange(PlaybackServiceMediaPlayer.PSMPInfo info, String whatChanged) {
|
||||
@ -1661,12 +1679,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
public void resume() {
|
||||
mediaPlayer.resume();
|
||||
taskManager.restartSleepTimer();
|
||||
}
|
||||
|
||||
public void prepare() {
|
||||
mediaPlayer.prepare();
|
||||
taskManager.restartSleepTimer();
|
||||
}
|
||||
|
||||
public void pause(boolean abandonAudioFocus, boolean reinit) {
|
||||
|
||||
@ -0,0 +1,137 @@
|
||||
package de.danoeh.antennapod.playback.service.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
|
||||
import de.danoeh.antennapod.storage.preferences.SleepTimerPreferences;
|
||||
|
||||
public class ClockSleepTimer implements SleepTimer {
|
||||
private static final String TAG = "ClockSleepTimer";
|
||||
|
||||
private final Context context;
|
||||
private long initialWaitingTime;
|
||||
private long timeLeft;
|
||||
private boolean isRunning = false;
|
||||
private long lastTick = 0;
|
||||
private boolean hasVibrated = false;
|
||||
private ShakeListener shakeListener;
|
||||
|
||||
public ClockSleepTimer(final Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
@SuppressWarnings("unused")
|
||||
public void playbackPositionUpdate(PlaybackPositionEvent playbackPositionEvent) {
|
||||
Log.d(TAG, "playback position updated");
|
||||
long now = System.currentTimeMillis();
|
||||
long timeSinceLastTick = now - lastTick;
|
||||
lastTick = now;
|
||||
if (timeSinceLastTick > 10 * 1000) {
|
||||
return; // Ticks should arrive every second. If they didn't, playback was paused for a while.
|
||||
}
|
||||
timeLeft -= timeSinceLastTick;
|
||||
|
||||
EventBus.getDefault().postSticky(SleepTimerUpdatedEvent.updated(timeLeft));
|
||||
if (timeLeft < NOTIFICATION_THRESHOLD) {
|
||||
notifyAboutExpiry();
|
||||
}
|
||||
if (timeLeft <= 0) {
|
||||
Log.d(TAG, "Sleep timer expired");
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
protected void vibrate() {
|
||||
final Vibrator vibrator;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
VibratorManager vibratorManager = (VibratorManager)
|
||||
context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE);
|
||||
vibrator = vibratorManager.getDefaultVibrator();
|
||||
} else {
|
||||
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
}
|
||||
if (vibrator == null) {
|
||||
return;
|
||||
}
|
||||
final int duration = 500;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
vibrator.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
} else {
|
||||
vibrator.vibrate(duration);
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyAboutExpiry() {
|
||||
Log.d(TAG, "Sleep timer is about to expire");
|
||||
if (SleepTimerPreferences.vibrate() && !hasVibrated) {
|
||||
vibrate();
|
||||
hasVibrated = true;
|
||||
}
|
||||
// start listening for shakes if shake to reset is enabled
|
||||
if (shakeListener == null && SleepTimerPreferences.shakeToReset()) {
|
||||
shakeListener = new ShakeListener(getContext(), this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return isRunning && timeLeft > 0;
|
||||
}
|
||||
|
||||
public void start(long initialWaitingTime) {
|
||||
this.initialWaitingTime = initialWaitingTime;
|
||||
this.timeLeft = initialWaitingTime;
|
||||
|
||||
// make sure we've registered for events first
|
||||
EventBus.getDefault().register(this);
|
||||
final long left = getTimeLeft();
|
||||
EventBus.getDefault().post(SleepTimerUpdatedEvent.justEnabled(left));
|
||||
|
||||
lastTick = System.currentTimeMillis();
|
||||
EventBus.getDefault().postSticky(SleepTimerUpdatedEvent.updated(timeLeft));
|
||||
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
timeLeft = 0;
|
||||
EventBus.getDefault().unregister(this);
|
||||
|
||||
if (shakeListener != null) {
|
||||
shakeListener.pause();
|
||||
}
|
||||
shakeListener = null;
|
||||
EventBus.getDefault().postSticky(SleepTimerUpdatedEvent.cancelled());
|
||||
}
|
||||
|
||||
protected Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeLeft() {
|
||||
return timeLeft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRemainingTime(long waitingTimeOrEpisodes) {
|
||||
this.timeLeft = waitingTimeOrEpisodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
updateRemainingTime(initialWaitingTime);
|
||||
}
|
||||
}
|
||||
@ -3,16 +3,12 @@ package de.danoeh.antennapod.playback.service.internal;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Vibrator;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
|
||||
import de.danoeh.antennapod.storage.preferences.SleepTimerPreferences;
|
||||
import de.danoeh.antennapod.ui.chapters.ChapterUtils;
|
||||
import de.danoeh.antennapod.ui.widget.WidgetUpdater;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
@ -49,11 +45,8 @@ public class PlaybackServiceTaskManager {
|
||||
|
||||
private ScheduledFuture<?> positionSaverFuture;
|
||||
private ScheduledFuture<?> widgetUpdaterFuture;
|
||||
private ScheduledFuture<?> sleepTimerFuture;
|
||||
private volatile Disposable chapterLoaderFuture;
|
||||
|
||||
private SleepTimer sleepTimer;
|
||||
|
||||
private final Context context;
|
||||
private final PSTMCallback callback;
|
||||
|
||||
@ -134,69 +127,6 @@ public class PlaybackServiceTaskManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new sleep timer with the given waiting time. If another sleep timer is already active, it will be
|
||||
* cancelled first.
|
||||
* After waitingTime has elapsed, onSleepTimerExpired() will be called.
|
||||
*
|
||||
* @throws java.lang.IllegalArgumentException if waitingTime <= 0
|
||||
*/
|
||||
public synchronized void setSleepTimer(long waitingTime) {
|
||||
if (waitingTime <= 0) {
|
||||
throw new IllegalArgumentException("Waiting time <= 0");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Setting sleep timer to " + waitingTime + " milliseconds");
|
||||
if (isSleepTimerActive()) {
|
||||
sleepTimerFuture.cancel(true);
|
||||
}
|
||||
sleepTimer = new SleepTimer(waitingTime);
|
||||
sleepTimerFuture = schedExecutor.schedule(sleepTimer, 0, TimeUnit.MILLISECONDS);
|
||||
EventBus.getDefault().post(SleepTimerUpdatedEvent.justEnabled(waitingTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the sleep timer is currently active.
|
||||
*/
|
||||
public synchronized boolean isSleepTimerActive() {
|
||||
return sleepTimer != null
|
||||
&& sleepTimerFuture != null
|
||||
&& !sleepTimerFuture.isCancelled()
|
||||
&& !sleepTimerFuture.isDone()
|
||||
&& sleepTimer.getWaitingTime() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the sleep timer. If the sleep timer is not active, nothing will happen.
|
||||
*/
|
||||
public synchronized void disableSleepTimer() {
|
||||
if (isSleepTimerActive()) {
|
||||
Log.d(TAG, "Disabling sleep timer");
|
||||
sleepTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the sleep timer. If the sleep timer is not active, nothing will happen.
|
||||
*/
|
||||
public synchronized void restartSleepTimer() {
|
||||
if (isSleepTimerActive()) {
|
||||
Log.d(TAG, "Restarting sleep timer");
|
||||
sleepTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current sleep timer time or 0 if the sleep timer is not active.
|
||||
*/
|
||||
public synchronized long getSleepTimerTimeLeft() {
|
||||
if (isSleepTimerActive()) {
|
||||
return sleepTimer.getWaitingTime();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the widget updater is currently running.
|
||||
*/
|
||||
@ -244,7 +174,6 @@ public class PlaybackServiceTaskManager {
|
||||
public synchronized void cancelAllTasks() {
|
||||
cancelPositionSaver();
|
||||
cancelWidgetUpdater();
|
||||
disableSleepTimer();
|
||||
|
||||
if (chapterLoaderFuture != null) {
|
||||
chapterLoaderFuture.dispose();
|
||||
@ -272,89 +201,6 @@ public class PlaybackServiceTaskManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleeps for a given time and then pauses playback.
|
||||
*/
|
||||
public class SleepTimer implements Runnable {
|
||||
private static final String TAG = "SleepTimer";
|
||||
private static final long UPDATE_INTERVAL = 1000L;
|
||||
public static final long NOTIFICATION_THRESHOLD = 10000;
|
||||
private boolean hasVibrated = false;
|
||||
private final long waitingTime;
|
||||
private long timeLeft;
|
||||
private ShakeListener shakeListener;
|
||||
|
||||
public SleepTimer(long waitingTime) {
|
||||
super();
|
||||
this.waitingTime = waitingTime;
|
||||
this.timeLeft = waitingTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Starting");
|
||||
long lastTick = System.currentTimeMillis();
|
||||
EventBus.getDefault().post(SleepTimerUpdatedEvent.updated(timeLeft));
|
||||
while (timeLeft > 0) {
|
||||
try {
|
||||
Thread.sleep(UPDATE_INTERVAL);
|
||||
} catch (InterruptedException e) {
|
||||
Log.d(TAG, "Thread was interrupted while waiting");
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
timeLeft -= now - lastTick;
|
||||
lastTick = now;
|
||||
|
||||
EventBus.getDefault().post(SleepTimerUpdatedEvent.updated(timeLeft));
|
||||
if (timeLeft < NOTIFICATION_THRESHOLD) {
|
||||
Log.d(TAG, "Sleep timer is about to expire");
|
||||
if (SleepTimerPreferences.vibrate() && !hasVibrated) {
|
||||
Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (v != null) {
|
||||
v.vibrate(500);
|
||||
hasVibrated = true;
|
||||
}
|
||||
}
|
||||
if (shakeListener == null && SleepTimerPreferences.shakeToReset()) {
|
||||
shakeListener = new ShakeListener(context, this);
|
||||
}
|
||||
}
|
||||
if (timeLeft <= 0) {
|
||||
Log.d(TAG, "Sleep timer expired");
|
||||
if (shakeListener != null) {
|
||||
shakeListener.pause();
|
||||
shakeListener = null;
|
||||
}
|
||||
hasVibrated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long getWaitingTime() {
|
||||
return timeLeft;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
EventBus.getDefault().post(SleepTimerUpdatedEvent.cancelled());
|
||||
setSleepTimer(waitingTime);
|
||||
if (shakeListener != null) {
|
||||
shakeListener.pause();
|
||||
shakeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
sleepTimerFuture.cancel(true);
|
||||
if (shakeListener != null) {
|
||||
shakeListener.pause();
|
||||
}
|
||||
EventBus.getDefault().post(SleepTimerUpdatedEvent.cancelled());
|
||||
}
|
||||
}
|
||||
|
||||
public interface PSTMCallback {
|
||||
void positionSaverTick();
|
||||
|
||||
|
||||
@ -16,10 +16,10 @@ public class ShakeListener implements SensorEventListener {
|
||||
|
||||
private Sensor mAccelerometer;
|
||||
private SensorManager mSensorMgr;
|
||||
private final PlaybackServiceTaskManager.SleepTimer mSleepTimer;
|
||||
private final SleepTimer mSleepTimer;
|
||||
private final Context mContext;
|
||||
|
||||
public ShakeListener(Context context, PlaybackServiceTaskManager.SleepTimer sleepTimer) {
|
||||
public ShakeListener(Context context, SleepTimer sleepTimer) {
|
||||
mContext = context;
|
||||
mSleepTimer = sleepTimer;
|
||||
resume();
|
||||
@ -75,7 +75,7 @@ public class ShakeListener implements SensorEventListener {
|
||||
double gForce = Math.sqrt(gX * gX + gY * gY + gZ * gZ);
|
||||
if (gForce > 2.25) {
|
||||
Log.d(TAG, "Detected shake " + gForce);
|
||||
mSleepTimer.restart();
|
||||
mSleepTimer.reset();
|
||||
vibrate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package de.danoeh.antennapod.playback.service.internal;
|
||||
|
||||
public interface SleepTimer {
|
||||
|
||||
long NOTIFICATION_THRESHOLD = 10000;
|
||||
|
||||
/**
|
||||
* @return Returns time left for this timer, in millis
|
||||
*/
|
||||
long getTimeLeft();
|
||||
|
||||
/**
|
||||
* Starts the sleep timer.
|
||||
* @param initialWaitingTime The waiting time for the sleep timer, either episodes or duration
|
||||
*/
|
||||
void start(long initialWaitingTime);
|
||||
|
||||
/**
|
||||
* Cancels (stops) current sleep timer forever, cannot be restarted.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Update sleep timer with new waiting time
|
||||
* @param waitingTimeOrEpisodes Waiting time in millis or episode count
|
||||
*/
|
||||
void updateRemainingTime(long waitingTimeOrEpisodes);
|
||||
|
||||
/**
|
||||
* Resets sleep timer to original duration.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @return True if sleep timer is active, false otherwise
|
||||
*/
|
||||
boolean isActive();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user