Added a sleep timer

This commit is contained in:
Karim Abou Zeid 2015-07-08 01:16:19 +02:00
commit 4d82b91465
25 changed files with 350 additions and 47 deletions

View file

@ -0,0 +1,175 @@
package com.kabouzeid.gramophone.dialogs;
import android.app.AlarmManager;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.triggertrap.seekarc.SeekArc;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class SleepTimerDialog extends DialogFragment {
@InjectView(R.id.seek_arc)
SeekArc seekArc;
@InjectView(R.id.timer_display)
TextView timerDisplay;
private int seekArcProgress;
private MaterialDialog materialDialog;
private TimerUpdater timerUpdater;
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
timerUpdater.cancel();
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
timerUpdater = new TimerUpdater();
materialDialog = new MaterialDialog.Builder(getActivity())
.title(getActivity().getResources().getString(R.string.action_sleep_timer))
.positiveText(R.string.action_set)
.callback(new MaterialDialog.ButtonCallback() {
@Override
public void onPositive(MaterialDialog dialog) {
if (getActivity() == null) {
return;
}
final int min = seekArcProgress;
PreferenceUtils.getInstance(getActivity()).setLastSleepTimerValue(min);
PendingIntent pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT);
final long nextSleepTimerElapsedTime = SystemClock.elapsedRealtime() + min * 60 * 1000;
PreferenceUtils.getInstance(getActivity()).setNextSleepTimerElapsedRealtime(nextSleepTimerElapsedTime);
AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSleepTimerElapsedTime, pi);
Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_set, min), Toast.LENGTH_SHORT).show();
}
@Override
public void onNeutral(MaterialDialog dialog) {
if (getActivity() == null) {
return;
}
final PendingIntent previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE);
if (previous != null) {
AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
am.cancel(previous);
previous.cancel();
Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show();
}
}
})
.showListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
if (makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) != null) {
timerUpdater.start();
}
}
})
.customView(R.layout.dialog_sleep_timer, false)
.build();
if (getActivity() == null || materialDialog.getCustomView() == null) {
return materialDialog;
}
ButterKnife.inject(this, materialDialog.getCustomView());
seekArc.post(new Runnable() {
@Override
public void run() {
int width = seekArc.getWidth();
int height = seekArc.getHeight();
int small = Math.min(width, height);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(seekArc.getLayoutParams());
layoutParams.height = small;
seekArc.setLayoutParams(layoutParams);
}
});
seekArcProgress = PreferenceUtils.getInstance(getActivity()).getLastSleepTimerValue();
updateTimeDisplayTime();
seekArc.setProgress(seekArcProgress);
seekArc.setOnSeekArcChangeListener(new SeekArc.OnSeekArcChangeListener() {
@Override
public void onProgressChanged(SeekArc seekArc, int i, boolean b) {
if (i < 1) {
seekArc.setProgress(1);
return;
}
seekArcProgress = i;
updateTimeDisplayTime();
}
@Override
public void onStartTrackingTouch(SeekArc seekArc) {
}
@Override
public void onStopTrackingTouch(SeekArc seekArc) {
}
});
return materialDialog;
}
private void updateTimeDisplayTime() {
timerDisplay.setText(seekArcProgress + " min");
}
private PendingIntent makeTimerPendingIntent(int flag) {
return PendingIntent.getService(getActivity(), 0, makeTimerIntent(), flag);
}
private Intent makeTimerIntent() {
return new Intent(getActivity(), MusicService.class)
.setAction(MusicService.ACTION_QUIT);
}
private class TimerUpdater extends CountDownTimer {
public TimerUpdater() {
super(PreferenceUtils.getInstance(getActivity()).getNextSleepTimerElapsedRealTime() - SystemClock.elapsedRealtime(), 1000);
}
@Override
public void onTick(long millisUntilFinished) {
materialDialog.setActionButton(DialogAction.NEUTRAL, materialDialog.getContext().getString(R.string.cancel_current_timer) + " (" + MusicUtil.getReadableDurationString(millisUntilFinished) + ")");
}
@Override
public void onFinish() {
materialDialog.setActionButton(DialogAction.NEUTRAL, null);
}
}
}

View file

@ -20,7 +20,7 @@ public class LastAddedLoader {
public static Cursor makeLastAddedCursor(final Context context) {
long fourWeeksAgo = (System.currentTimeMillis() / 1000) - (4 * 3600 * 24 * 7);
// possible saved timestamp caused by user "clearing" the last added playlist
long cutoff = PreferenceUtils.getInstance(context).getLastAddedCutOff() / 1000;
long cutoff = PreferenceUtils.getInstance(context).getLastAddedCutOffTimestamp() / 1000;
if (cutoff < fourWeeksAgo) {
cutoff = fourWeeksAgo;
}

View file

@ -210,6 +210,9 @@ public class MultiPlayer implements MediaPlayer.OnErrorListener,
* @return The duration in milliseconds
*/
public int duration() {
if (!mIsInitialized) {
return -1;
}
try {
return mCurrentMediaPlayer.getDuration();
} catch (IllegalStateException e) {
@ -223,6 +226,9 @@ public class MultiPlayer implements MediaPlayer.OnErrorListener,
* @return The current position in milliseconds
*/
public int position() {
if (!mIsInitialized) {
return -1;
}
try {
return mCurrentMediaPlayer.getCurrentPosition();
} catch (IllegalStateException e) {

View file

@ -27,6 +27,7 @@ import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.songadapter.AlbumSongAdapter;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager;
import com.kabouzeid.gramophone.interfaces.CabHolder;
@ -347,6 +348,9 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_sleep_timer:
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
return true;
case R.id.action_equalizer:
NavigationUtil.openEqualizer(this);
return true;

View file

@ -33,6 +33,7 @@ import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.ArtistAlbumAdapter;
import com.kabouzeid.gramophone.adapter.songadapter.ArtistSongAdapter;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager;
import com.kabouzeid.gramophone.interfaces.CabHolder;
@ -449,6 +450,9 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_sleep_timer:
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
return true;
case R.id.action_equalizer:
NavigationUtil.openEqualizer(this);
return true;

View file

@ -37,6 +37,7 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.PagerAdapter;
import com.kabouzeid.gramophone.dialogs.AboutDialog;
import com.kabouzeid.gramophone.dialogs.CreatePlaylistDialog;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.helper.SearchQueryHelper;
import com.kabouzeid.gramophone.interfaces.CabHolder;
@ -338,6 +339,9 @@ public class MainActivity extends AbsFabActivity
int id = item.getItemId();
switch (id) {
case R.id.action_sleep_timer:
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
return true;
case R.id.action_equalizer:
NavigationUtil.openEqualizer(this);
return true;

View file

@ -37,6 +37,7 @@ import com.afollestad.materialdialogs.ThemeSingleton;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.dialogs.SongDetailDialog;
import com.kabouzeid.gramophone.dialogs.SongShareDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
@ -629,6 +630,9 @@ public class MusicControllerActivity extends AbsFabActivity {
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_sleep_timer:
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
return true;
case R.id.action_toggle_favorite:
MusicUtil.toggleFavorite(this, song);
if (MusicUtil.isFavorite(this, song)) {

View file

@ -14,6 +14,7 @@ import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.songadapter.AbsPlaylistSongAdapter;
import com.kabouzeid.gramophone.adapter.songadapter.PlaylistSongAdapter;
import com.kabouzeid.gramophone.dialogs.SleepTimerDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.misc.DragSortRecycler;
@ -124,6 +125,9 @@ public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_sleep_timer:
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
return true;
case R.id.action_shuffle_playlist:
//noinspection unchecked
MusicPlayerRemote.openAndShuffleQueue(this, adapter.getDataSet(), true);

View file

@ -44,6 +44,8 @@ public final class PreferenceUtils {
public static final String GAPLESS_PLAYBACK = "gapless_playback";
public static final String LAST_ADDED_CUTOFF_TIMESTAMP = "last_added_cutoff_timestamp";
public static final String ALBUM_ART_ON_LOCKSCREEN = "album_art_on_lockscreen";
public static final String LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value";
public static final String NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time";
private static PreferenceUtils sInstance;
@ -285,7 +287,7 @@ public final class PreferenceUtils {
return mPreferences.getInt(ALBUM_GRID_COLUMNS_LAND, 3);
}
public long getLastAddedCutOff() {
public long getLastAddedCutOffTimestamp() {
return mPreferences.getLong(LAST_ADDED_CUTOFF_TIMESTAMP, 0L);
}
@ -295,4 +297,24 @@ public final class PreferenceUtils {
editor.putLong(LAST_ADDED_CUTOFF_TIMESTAMP, timestamp);
editor.commit();
}
public int getLastSleepTimerValue() {
return mPreferences.getInt(LAST_SLEEP_TIMER_VALUE, 30);
}
public void setLastSleepTimerValue(final int value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(LAST_SLEEP_TIMER_VALUE, value);
editor.apply();
}
public long getNextSleepTimerElapsedRealTime() {
return mPreferences.getLong(NEXT_SLEEP_TIMER_ELAPSED_REALTIME, -1);
}
public void setNextSleepTimerElapsedRealtime(final long value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putLong(NEXT_SLEEP_TIMER_ELAPSED_REALTIME, value);
editor.apply();
}
}