diff options
author | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-09-05 11:18:20 -0400 |
---|---|---|
committer | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-09-05 11:18:20 -0400 |
commit | d5e31f5350acfd341bca23430ce9be43699851c6 (patch) | |
tree | d6df0e2a64ed70dfc4b25fffe1396393003d324f /core/src/main/java/de/danoeh/antennapod | |
parent | 26ca16bfa205638ca45610c5c766921a87d8f9d7 (diff) | |
parent | 59f257a67866360061db4f5a63bc6212d39250b8 (diff) | |
download | AntennaPod-d5e31f5350acfd341bca23430ce9be43699851c6.zip |
Merge pull request #1072 from mfietz/feature/shake_sleeptimer
Sleep Timer: Shake to reset, lower volume, vibrate, remember preferences
Diffstat (limited to 'core/src/main/java/de/danoeh/antennapod')
5 files changed, 169 insertions, 52 deletions
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..80ba4fca7 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 @@ -19,7 +19,6 @@ import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.media.RemoteControlClient; import android.media.RemoteControlClient.MetadataEditor; -import android.os.AsyncTask; import android.os.Binder; import android.os.Build; import android.os.IBinder; @@ -33,12 +32,9 @@ import android.widget.Toast; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.request.animation.GlideAnimation; -import com.bumptech.glide.request.target.SimpleTarget; import org.apache.commons.lang3.StringUtils; -import java.io.IOException; import java.util.List; import java.util.concurrent.ExecutionException; @@ -405,11 +401,21 @@ public class PlaybackService extends Service { } @Override + public void onSleepTimerAlmostExpired() { + mediaPlayer.setVolume(0.1f); + } + + @Override public void onSleepTimerExpired() { mediaPlayer.pause(true, true); + mediaPlayer.setVolume(1.0f); sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0); } + @Override + public void onSleepTimerReset() { + mediaPlayer.setVolume(1.0f); + } @Override public void onWidgetUpdaterTick() { @@ -652,10 +658,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..4872dd7bd 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,86 @@ 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; + + 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..446061ea6 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java @@ -0,0 +1,65 @@ +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() { + // only a precaution, the user should actually not be able to activate shake to reset + // when the accelerometer is not available + 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); } } |