summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
authorMartin Fietz <Martin.Fietz@gmail.com>2015-08-09 11:42:43 +0200
committerMartin Fietz <Martin.Fietz@gmail.com>2015-09-05 00:50:44 +0200
commit771b1e2a16545cc6a8bca433be6089e93a649359 (patch)
treeca6c821645c3f4c57cbe951c05b08a5d3087b727 /core/src/main
parent946d5ef50c109549f2d15160c0345b0b8b2f4d84 (diff)
downloadAntennaPod-771b1e2a16545cc6a8bca433be6089e93a649359.zip
Vibrate and lower volume when timer is about to expire, shake to reset timer
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/AndroidManifest.xml1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java26
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java107
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java63
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java4
6 files changed, 169 insertions, 48 deletions
diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml
index f5b000abf..47bd8b666 100644
--- a/core/src/main/AndroidManifest.xml
+++ b/core/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application
android:allowBackup="true"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index f6ea38ab5..ae927e6d6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -405,11 +405,20 @@ public class PlaybackService extends Service {
}
@Override
+ public void onSleepTimerAlmostExpired() {
+ mediaPlayer.setVolume(0.5f);
+ }
+
+ @Override
public void onSleepTimerExpired() {
mediaPlayer.pause(true, true);
sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
}
+ @Override
+ public void onSleepTimerReset() {
+ mediaPlayer.setVolume(1.0f);
+ }
@Override
public void onWidgetUpdaterTick() {
@@ -652,10 +661,9 @@ public class PlaybackService extends Service {
}
}
- public void setSleepTimer(long waitingTime) {
- Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime)
- + " milliseconds");
- taskManager.setSleepTimer(waitingTime);
+ public void setSleepTimer(long waitingTime, boolean shakeToReset, boolean vibrate) {
+ Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime) + " milliseconds");
+ taskManager.setSleepTimer(waitingTime, shakeToReset, vibrate);
sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index 835a8c1d1..f1aa50c91 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -619,6 +619,32 @@ public class PlaybackServiceMediaPlayer {
return retVal;
}
+ /**
+ * Sets the playback speed.
+ * This method is executed on an internal executor service.
+ */
+ public void setVolume(final float volume) {
+ executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ setVolumeSync(volume);
+ }
+ });
+ }
+
+ /**
+ * Sets the playback speed.
+ * This method is executed on the caller's thread.
+ */
+ private void setVolumeSync(float volume) {
+ playerLock.lock();
+ if (media != null && media.getMediaType() == MediaType.AUDIO) {
+ mediaPlayer.setVolume(volume, volume);
+ Log.d(TAG, "Media player volume was set to " + volume);
+ }
+ playerLock.unlock();
+ }
+
public MediaType getCurrentMediaType() {
return mediaType;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
index fc73c9446..0a89860a8 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
+import android.os.Vibrator;
import android.util.Log;
import org.apache.commons.lang3.Validate;
@@ -14,12 +15,10 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.QueueEvent;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.playback.Playable;
-
import de.greenrobot.event.EventBus;
@@ -168,7 +167,7 @@ public class PlaybackServiceTaskManager {
public synchronized void cancelPositionSaver() {
if (isPositionSaverActive()) {
positionSaverFuture.cancel(false);
- if (BuildConfig.DEBUG) Log.d(TAG, "Cancelled PositionSaver");
+ Log.d(TAG, "Cancelled PositionSaver");
}
}
@@ -186,9 +185,9 @@ public class PlaybackServiceTaskManager {
widgetUpdaterFuture = schedExecutor.scheduleWithFixedDelay(widgetUpdater, WIDGET_UPDATER_NOTIFICATION_INTERVAL,
WIDGET_UPDATER_NOTIFICATION_INTERVAL, TimeUnit.MILLISECONDS);
- if (BuildConfig.DEBUG) Log.d(TAG, "Started WidgetUpdater");
+ Log.d(TAG, "Started WidgetUpdater");
} else {
- if (BuildConfig.DEBUG) Log.d(TAG, "Call to startWidgetUpdater was ignored.");
+ Log.d(TAG, "Call to startWidgetUpdater was ignored.");
}
}
@@ -199,16 +198,14 @@ public class PlaybackServiceTaskManager {
*
* @throws java.lang.IllegalArgumentException if waitingTime <= 0
*/
- public synchronized void setSleepTimer(long waitingTime) {
+ public synchronized void setSleepTimer(long waitingTime, boolean shakeToReset, boolean vibrate) {
Validate.isTrue(waitingTime > 0, "Waiting time <= 0");
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime)
- + " milliseconds");
+ Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime) + " milliseconds");
if (isSleepTimerActive()) {
sleepTimerFuture.cancel(true);
}
- sleepTimer = new SleepTimer(waitingTime);
+ sleepTimer = new SleepTimer(waitingTime, shakeToReset, vibrate);
sleepTimerFuture = schedExecutor.schedule(sleepTimer, 0, TimeUnit.MILLISECONDS);
}
@@ -216,7 +213,11 @@ public class PlaybackServiceTaskManager {
* Returns true if the sleep timer is currently active.
*/
public synchronized boolean isSleepTimerActive() {
- return sleepTimer != null && sleepTimerFuture != null && !sleepTimerFuture.isCancelled() && !sleepTimerFuture.isDone() && sleepTimer.isWaiting;
+ return sleepTimer != null
+ && sleepTimerFuture != null
+ && !sleepTimerFuture.isCancelled()
+ && !sleepTimerFuture.isDone()
+ && sleepTimer.getWaitingTime() > 0;
}
/**
@@ -224,8 +225,7 @@ public class PlaybackServiceTaskManager {
*/
public synchronized void disableSleepTimer() {
if (isSleepTimerActive()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Disabling sleep timer");
+ Log.d(TAG, "Disabling sleep timer");
sleepTimerFuture.cancel(true);
}
}
@@ -255,7 +255,7 @@ public class PlaybackServiceTaskManager {
public synchronized void cancelWidgetUpdater() {
if (isWidgetUpdaterActive()) {
widgetUpdaterFuture.cancel(false);
- if (BuildConfig.DEBUG) Log.d(TAG, "Cancelled WidgetUpdater");
+ Log.d(TAG, "Cancelled WidgetUpdater");
}
}
@@ -284,16 +284,14 @@ public class PlaybackServiceTaskManager {
Runnable chapterLoader = new Runnable() {
@Override
public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Chapter loader started");
+ Log.d(TAG, "Chapter loader started");
if (media.getChapters() == null) {
media.loadChapterMarks();
if (!Thread.currentThread().isInterrupted() && media.getChapters() != null) {
callback.onChapterLoaded(media);
}
}
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Chapter loader stopped");
+ Log.d(TAG, "Chapter loader stopped");
}
};
chapterLoaderFuture = schedExecutor.submit(chapterLoader);
@@ -324,63 +322,88 @@ public class PlaybackServiceTaskManager {
/**
* Sleeps for a given time and then pauses playback.
*/
- private class SleepTimer implements Runnable {
+ protected class SleepTimer implements Runnable {
private static final String TAG = "SleepTimer";
- private static final long UPDATE_INTERVALL = 1000L;
- private volatile long waitingTime;
- private volatile boolean isWaiting;
-
- public SleepTimer(long waitingTime) {
+ private static final long UPDATE_INTERVAL = 1000L;
+ private static final long NOTIFICATION_THRESHOLD = 10000;
+ private long waitingTime;
+ private final boolean shakeToReset;
+ private final boolean vibrate;
+ private ShakeListener shakeListener;
+
+ public SleepTimer(long waitingTime, boolean shakeToReset, boolean vibrate) {
super();
this.waitingTime = waitingTime;
- isWaiting = true;
+ this.shakeToReset = shakeToReset;
+ this.vibrate = vibrate;
}
@Override
public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting");
+ Log.d(TAG, "Starting");
+ boolean notifiedAlmostExpired = false;
+ long lastTick = System.currentTimeMillis();
while (waitingTime > 0) {
try {
- Thread.sleep(UPDATE_INTERVALL);
- waitingTime -= UPDATE_INTERVALL;
-
+ Thread.sleep(UPDATE_INTERVAL);
+ long now = System.currentTimeMillis();
+ waitingTime -= now - lastTick;
+ lastTick = now;
+
+ Log.d(TAG, "time left: " + waitingTime);
+
+ if(waitingTime < NOTIFICATION_THRESHOLD && !notifiedAlmostExpired) {
+ Log.d(TAG, "Sleep timer is about to expire");
+ if(vibrate) {
+ Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ if(v != null) {
+ v.vibrate(500);
+ }
+ }
+ if(shakeListener == null && shakeToReset) {
+ shakeListener = new ShakeListener(context, this);
+ }
+ callback.onSleepTimerAlmostExpired();
+ notifiedAlmostExpired = true;
+ }
if (waitingTime <= 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Waiting completed");
- postExecute();
+ Log.d(TAG, "Sleep timer expired");
+ shakeListener.pause();
+ shakeListener = null;
if (!Thread.currentThread().isInterrupted()) {
callback.onSleepTimerExpired();
}
-
}
} catch (InterruptedException e) {
Log.d(TAG, "Thread was interrupted while waiting");
+ e.printStackTrace();
break;
}
}
- postExecute();
- }
-
- protected void postExecute() {
- isWaiting = false;
}
public long getWaitingTime() {
return waitingTime;
}
- public boolean isWaiting() {
- return isWaiting;
+ public void onShake() {
+ setSleepTimer(15 * 60 * 1000, shakeToReset, vibrate);
+ callback.onSleepTimerReset();
+ shakeListener.pause();
+ shakeListener = null;
}
}
- public static interface PSTMCallback {
+ public interface PSTMCallback {
void positionSaverTick();
+ void onSleepTimerAlmostExpired();
+
void onSleepTimerExpired();
+ void onSleepTimerReset();
+
void onWidgetUpdaterTick();
void onChapterLoaded(Playable media);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
new file mode 100644
index 000000000..77d765a85
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
@@ -0,0 +1,63 @@
+package de.danoeh.antennapod.core.service.playback;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.util.FloatMath;
+import android.util.Log;
+
+public class ShakeListener implements SensorEventListener
+{
+ private static final String TAG = ShakeListener.class.getSimpleName();
+
+ private Sensor mAccelerometer;
+ private SensorManager mSensorMgr;
+ private PlaybackServiceTaskManager.SleepTimer mSleepTimer;
+ private Context mContext;
+
+ public ShakeListener(Context context, PlaybackServiceTaskManager.SleepTimer sleepTimer) {
+ mContext = context;
+ mSleepTimer = sleepTimer;
+ resume();
+ }
+
+ public void resume() {
+ mSensorMgr = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+ if (mSensorMgr == null) {
+ throw new UnsupportedOperationException("Sensors not supported");
+ }
+ mAccelerometer = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (!mSensorMgr.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_UI)) { // if not supported
+ mSensorMgr.unregisterListener(this);
+ throw new UnsupportedOperationException("Accelerometer not supported");
+ }
+ }
+
+ public void pause() {
+ if (mSensorMgr != null) {
+ mSensorMgr.unregisterListener(this);
+ mSensorMgr = null;
+ }
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ float gX = event.values[0] / SensorManager.GRAVITY_EARTH;
+ float gY = event.values[1] / SensorManager.GRAVITY_EARTH;
+ float gZ = event.values[2] / SensorManager.GRAVITY_EARTH;
+
+ float gForce = FloatMath.sqrt(gX*gX + gY*gY + gZ*gZ);
+ if (gForce > 2.25f) {
+ Log.d(TAG, "Detected shake " + gForce);
+ mSleepTimer.onShake();
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ return;
+ }
+
+} \ No newline at end of file
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index ba5428b81..42aa3b713 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -652,9 +652,9 @@ public abstract class PlaybackController {
}
}
- public void setSleepTimer(long time) {
+ public void setSleepTimer(long time, boolean shakeToReset, boolean vibrate) {
if (playbackService != null) {
- playbackService.setSleepTimer(time);
+ playbackService.setSleepTimer(time, shakeToReset, vibrate);
}
}