diff options
author | Martin Fietz <Martin.Fietz@gmail.com> | 2015-08-09 11:42:43 +0200 |
---|---|---|
committer | Martin Fietz <Martin.Fietz@gmail.com> | 2015-09-05 00:50:44 +0200 |
commit | 771b1e2a16545cc6a8bca433be6089e93a649359 (patch) | |
tree | ca6c821645c3f4c57cbe951c05b08a5d3087b727 /core | |
parent | 946d5ef50c109549f2d15160c0345b0b8b2f4d84 (diff) | |
download | AntennaPod-771b1e2a16545cc6a8bca433be6089e93a649359.zip |
Vibrate and lower volume when timer is about to expire, shake to reset timer
Diffstat (limited to 'core')
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); } } |