Skip to content
This repository has been archived by the owner on Feb 4, 2023. It is now read-only.

Add sleep timer support to playing notification #411

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@
android:name=".appshortcuts.AppShortcutLauncherActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity
android:name=".ui.activities.SleepTimerActivity"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:theme="@style/Theme.AppCompat.Dialog" />
<activity android:name=".ui.activities.PurchaseActivity" />

<service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.kabouzeid.gramophone.ui.activities.PurchaseActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.kabouzeid.gramophone.util.SleepTimerUtil;
import com.triggertrap.seekarc.SeekArc;

import butterknife.BindView;
Expand All @@ -50,6 +51,9 @@ public class SleepTimerDialog extends DialogFragment {
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
timerUpdater.cancel();
if (getActivity() instanceof DismissListener) {
((DismissListener) getActivity()).onDismissed();
}
}

@NonNull
Expand All @@ -73,24 +77,25 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {

final int minutes = seekArcProgress;

PendingIntent pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntent pi = SleepTimerUtil.createTimer(getActivity());

final long nextSleepTimerElapsedTime = SystemClock.elapsedRealtime() + minutes * 60 * 1000;
PreferenceUtil.getInstance(getActivity()).setNextSleepTimerElapsedRealtime(nextSleepTimerElapsedTime);
AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSleepTimerElapsedTime, pi);

getActivity().sendBroadcast(new Intent(MusicService.SLEEP_TIMER_CHANGED));
Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_set, minutes), Toast.LENGTH_SHORT).show();
})
.onNeutral((dialog, which) -> {
if (getActivity() == null) {
return;
}
final PendingIntent previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE);
final PendingIntent previous = SleepTimerUtil.getCurrentTimer(getActivity());
if (previous != null) {
AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
am.cancel(previous);
previous.cancel();
getActivity().sendBroadcast(new Intent(MusicService.SLEEP_TIMER_CHANGED));
Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show();
}

Expand All @@ -101,7 +106,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
}
})
.showListener(dialog -> {
if (makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) != null) {
if (SleepTimerUtil.isTimerRunning(getActivity())) {
timerUpdater.start();
}
})
Expand Down Expand Up @@ -199,4 +204,8 @@ public void onFinish() {
updateCancelButton();
}
}

public interface DismissListener {
void onDismissed();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
public static final String REPEAT_MODE_CHANGED = PHONOGRAPH_PACKAGE_NAME + ".repeatmodechanged";
public static final String SHUFFLE_MODE_CHANGED = PHONOGRAPH_PACKAGE_NAME + ".shufflemodechanged";
public static final String MEDIA_STORE_CHANGED = PHONOGRAPH_PACKAGE_NAME + ".mediastorechanged";
public static final String SLEEP_TIMER_CHANGED = PHONOGRAPH_PACKAGE_NAME + ".sleeptimerchanged";

public static final String SAVED_POSITION = "POSITION";
public static final String SAVED_POSITION_IN_TRACK = "POSITION_IN_TRACK";
Expand Down Expand Up @@ -169,6 +170,14 @@ public void onReceive(Context context, @NonNull Intent intent) {
}
}
};

private final BroadcastReceiver sleepTimerReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, @NonNull Intent intent) {
updateNotification();
}
};

private ContentObserver mediaStoreObserver;
private boolean notHandledMetaChangedForCurrentTrack;

Expand Down Expand Up @@ -203,6 +212,7 @@ public void onCreate() {
uiThreadHandler = new Handler();

registerReceiver(widgetIntentReceiver, new IntentFilter(APP_WIDGET_UPDATE));
registerReceiver(sleepTimerReceiver, new IntentFilter(SLEEP_TIMER_CHANGED));

initNotification();

Expand Down Expand Up @@ -354,6 +364,7 @@ public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
@Override
public void onDestroy() {
unregisterReceiver(widgetIntentReceiver);
unregisterReceiver(sleepTimerReceiver);
if (becomingNoisyReceiverRegistered) {
unregisterReceiver(becomingNoisyReceiver);
becomingNoisyReceiverRegistered = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.RequiresApi;

import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
import com.kabouzeid.gramophone.ui.activities.SleepTimerActivity;
import com.kabouzeid.gramophone.util.SleepTimerUtil;

import static android.content.Context.NOTIFICATION_SERVICE;

Expand Down Expand Up @@ -41,6 +46,24 @@ public synchronized void stop() {
notificationManager.cancel(NOTIFICATION_ID);
}

PendingIntent clickAction() {
Intent intent = new Intent(service, MainActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
return PendingIntent.getActivity(service, 0, intent, 0);
}

PendingIntent playbackAction(final String action) {
Intent intent = new Intent(service, MusicService.class).setAction(action);
return PendingIntent.getService(service, 0, intent, 0);
}

PendingIntent deleteAction() {
return PendingIntent.getService(service, 0, SleepTimerUtil.getTimerAction(service), 0);
}

PendingIntent sleepTimerAction() {
return PendingIntent.getActivity(service, 0, new Intent(service, SleepTimerActivity.class), 0);
}

void updateNotifyModeAndPostNotification(Notification notification) {
int newNotifyMode;
if (service.isPlaying()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import android.app.Notification;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
Expand All @@ -29,11 +28,17 @@
import com.kabouzeid.gramophone.util.ImageUtil;
import com.kabouzeid.gramophone.util.PhonographColorUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.kabouzeid.gramophone.util.SleepTimerUtil;

import java.util.concurrent.TimeUnit;

public class PlayingNotificationImpl extends PlayingNotification {

private Target<BitmapPaletteWrapper> target;

private CountDownTimer countdown;
private long timerStopTime;

@Override
public synchronized void update() {
stopped = false;
Expand All @@ -45,6 +50,38 @@ public synchronized void update() {
final RemoteViews notificationLayout = new RemoteViews(service.getPackageName(), R.layout.notification);
final RemoteViews notificationLayoutBig = new RemoteViews(service.getPackageName(), R.layout.notification_big);

if (SleepTimerUtil.isTimerRunning(service)) {
long stopTime = PreferenceUtil.getInstance(service).getNextSleepTimerElapsedRealTime();

if (countdown != null && stopTime != timerStopTime) {
countdown.cancel();
countdown = null;
}

if (countdown == null) {
timerStopTime = stopTime;
countdown = new CountDownTimer(timerStopTime - SystemClock.elapsedRealtime(), 60 * 1000) {
@Override
public void onTick(long millisUntilFinished) {
update();
}

@Override
public void onFinish() {
countdown = null;
}
};
countdown.start();
}

notificationLayoutBig.setViewVisibility(R.id.sleep_timer, View.VISIBLE);
} else if (countdown != null) {
countdown.cancel();
countdown = null;

notificationLayoutBig.setViewVisibility(R.id.sleep_timer, View.GONE);
}

if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
notificationLayout.setViewVisibility(R.id.media_titles, View.INVISIBLE);
} else {
Expand All @@ -64,15 +101,10 @@ public synchronized void update() {

linkButtons(notificationLayout, notificationLayoutBig);

Intent action = new Intent(service, MainActivity.class);
action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
final PendingIntent clickIntent = PendingIntent.getActivity(service, 0, action, 0);
final PendingIntent deleteIntent = buildPendingIntent(service, MusicService.ACTION_QUIT, null);

final Notification notification = new NotificationCompat.Builder(service, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(clickIntent)
.setDeleteIntent(deleteIntent)
.setContentIntent(clickAction())
.setDeleteIntent(deleteAction())
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
Expand Down Expand Up @@ -135,6 +167,7 @@ private void setNotificationContent(boolean dark) {
Bitmap prev = ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, primary), 1.5f);
Bitmap next = ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, primary), 1.5f);
Bitmap playPause = ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp, primary), 1.5f);
Bitmap sleepTimer = ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_timer_white_24dp, primary), 1.5f);

notificationLayout.setTextColor(R.id.title, primary);
notificationLayout.setTextColor(R.id.text, secondary);
Expand All @@ -145,40 +178,43 @@ private void setNotificationContent(boolean dark) {
notificationLayoutBig.setTextColor(R.id.title, primary);
notificationLayoutBig.setTextColor(R.id.text, secondary);
notificationLayoutBig.setTextColor(R.id.text2, secondary);
notificationLayoutBig.setTextColor(R.id.sleep_timer, primary);
notificationLayoutBig.setImageViewBitmap(R.id.action_prev, prev);
notificationLayoutBig.setImageViewBitmap(R.id.action_next, next);
notificationLayoutBig.setImageViewBitmap(R.id.action_play_pause, playPause);
notificationLayoutBig.setImageViewBitmap(R.id.action_sleep_timer, sleepTimer);

if (SleepTimerUtil.isTimerRunning(service)) {
long millis = PreferenceUtil.getInstance(service).getNextSleepTimerElapsedRealTime() - SystemClock.elapsedRealtime();
long minutes = TimeUnit.MINUTES.convert(millis, TimeUnit.MILLISECONDS) + 1;
String text = String.format("%d min left", minutes) ;
notificationLayoutBig.setTextViewText(R.id.sleep_timer, text);
notificationLayoutBig.setViewVisibility(R.id.sleep_timer,View.VISIBLE);
} else {
notificationLayoutBig.setViewVisibility(R.id.sleep_timer, View.GONE);
}
}
});
}
});
}

private void linkButtons(final RemoteViews notificationLayout, final RemoteViews notificationLayoutBig) {
PendingIntent pendingIntent;

final ComponentName serviceName = new ComponentName(service, MusicService.class);
PendingIntent previous = playbackAction(MusicService.ACTION_REWIND);
notificationLayout.setOnClickPendingIntent(R.id.action_prev, previous);
notificationLayoutBig.setOnClickPendingIntent(R.id.action_prev, previous);

// Previous track
pendingIntent = buildPendingIntent(service, MusicService.ACTION_REWIND, serviceName);
notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent);
notificationLayoutBig.setOnClickPendingIntent(R.id.action_prev, pendingIntent);
PendingIntent playPause = playbackAction(MusicService.ACTION_TOGGLE_PAUSE);
notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, playPause);
notificationLayoutBig.setOnClickPendingIntent(R.id.action_play_pause, playPause);

// Play and pause
pendingIntent = buildPendingIntent(service, MusicService.ACTION_TOGGLE_PAUSE, serviceName);
notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent);
notificationLayoutBig.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent);

// Next track
pendingIntent = buildPendingIntent(service, MusicService.ACTION_SKIP, serviceName);
notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent);
notificationLayoutBig.setOnClickPendingIntent(R.id.action_next, pendingIntent);
}
PendingIntent next = playbackAction(MusicService.ACTION_SKIP);
notificationLayout.setOnClickPendingIntent(R.id.action_next, next);
notificationLayoutBig.setOnClickPendingIntent(R.id.action_next, next);

private PendingIntent buildPendingIntent(Context context, final String action, final ComponentName serviceName) {
Intent intent = new Intent(action);
intent.setComponent(serviceName);
return PendingIntent.getService(context, 0, intent, 0);
PendingIntent sleepTimer = sleepTimerAction();
notificationLayout.setOnClickPendingIntent(R.id.action_sleep_timer, sleepTimer);
notificationLayoutBig.setOnClickPendingIntent(R.id.action_sleep_timer, sleepTimer);
}

}
Loading