Move looping ringtone code to its own class. Use looped playback for RingtonePickerDialog.
This commit is contained in:
parent
c44eefc472
commit
c7fd4ac93f
@ -2,14 +2,14 @@ package com.philliphsu.clock2;
|
|||||||
|
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.media.Ringtone;
|
|
||||||
import android.media.RingtoneManager;
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
|
|
||||||
|
import com.philliphsu.clock2.ringtone.RingtoneLoop;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Phillip Hsu on 9/3/2016.
|
* Created by Phillip Hsu on 9/3/2016.
|
||||||
* <p></p>
|
* <p></p>
|
||||||
@ -31,7 +31,7 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
|
|||||||
private RingtoneManager mRingtoneManager;
|
private RingtoneManager mRingtoneManager;
|
||||||
private OnRingtoneSelectedListener mOnRingtoneSelectedListener;
|
private OnRingtoneSelectedListener mOnRingtoneSelectedListener;
|
||||||
private Uri mRingtoneUri;
|
private Uri mRingtoneUri;
|
||||||
private Ringtone mRingtone;
|
private RingtoneLoop mRingtone;
|
||||||
|
|
||||||
public interface OnRingtoneSelectedListener {
|
public interface OnRingtoneSelectedListener {
|
||||||
void onRingtoneSelected(Uri ringtoneUri);
|
void onRingtoneSelected(Uri ringtoneUri);
|
||||||
@ -66,12 +66,12 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
|
|||||||
.setSingleChoiceItems(cursor, checkedItem, labelColumn, new DialogInterface.OnClickListener() {
|
.setSingleChoiceItems(cursor, checkedItem, labelColumn, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (mRingtone != null) {
|
||||||
|
destroyLocalPlayer();
|
||||||
|
}
|
||||||
// Here, 'which' param refers to the position of the item clicked.
|
// Here, 'which' param refers to the position of the item clicked.
|
||||||
mRingtoneUri = mRingtoneManager.getRingtoneUri(which);
|
mRingtoneUri = mRingtoneManager.getRingtoneUri(which);
|
||||||
mRingtone = mRingtoneManager.getRingtone(which);
|
mRingtone = new RingtoneLoop(getActivity(), mRingtoneUri);
|
||||||
// TODO: Deprecated, but setAudioAttributes() is for 21+, so what is the
|
|
||||||
// pre-21 alternative?
|
|
||||||
mRingtone.setStreamType(AudioManager.STREAM_ALARM);
|
|
||||||
mRingtone.play();
|
mRingtone.play();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -81,9 +81,7 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onDismiss(DialogInterface dialog) {
|
public void onDismiss(DialogInterface dialog) {
|
||||||
super.onDismiss(dialog);
|
super.onDismiss(dialog);
|
||||||
if (mRingtone != null && mRingtone.isPlaying()) {
|
destroyLocalPlayer();
|
||||||
mRingtone.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -98,4 +96,11 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
|
|||||||
public void setOnRingtoneSelectedListener(OnRingtoneSelectedListener onRingtoneSelectedListener) {
|
public void setOnRingtoneSelectedListener(OnRingtoneSelectedListener onRingtoneSelectedListener) {
|
||||||
mOnRingtoneSelectedListener = onRingtoneSelectedListener;
|
mOnRingtoneSelectedListener = onRingtoneSelectedListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void destroyLocalPlayer() {
|
||||||
|
if (mRingtone != null) {
|
||||||
|
mRingtone.stop();
|
||||||
|
mRingtone = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,63 @@
|
|||||||
|
package com.philliphsu.clock2.ringtone;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Phillip Hsu on 9/5/2016.
|
||||||
|
*
|
||||||
|
* A MediaPlayer configured to play a ringtone in a loop.
|
||||||
|
*/
|
||||||
|
public final class RingtoneLoop {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final AudioManager mAudioManager;
|
||||||
|
private final Uri mUri;
|
||||||
|
|
||||||
|
private MediaPlayer mMediaPlayer;
|
||||||
|
|
||||||
|
public RingtoneLoop(Context context, Uri uri) {
|
||||||
|
mContext = context;
|
||||||
|
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
mUri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play() {
|
||||||
|
try {
|
||||||
|
mMediaPlayer = new MediaPlayer();
|
||||||
|
mMediaPlayer.setDataSource(mContext, mUri);
|
||||||
|
if (mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
|
||||||
|
// "Must call this method before prepare() or prepareAsync() in order
|
||||||
|
// for the target stream type to become effective thereafter."
|
||||||
|
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
|
||||||
|
mMediaPlayer.setLooping(true);
|
||||||
|
// There is prepare() and prepareAsync().
|
||||||
|
// "For files, it is OK to call prepare(), which blocks until
|
||||||
|
// MediaPlayer is ready for playback."
|
||||||
|
mMediaPlayer.prepare();
|
||||||
|
mMediaPlayer.start();
|
||||||
|
}
|
||||||
|
} catch (SecurityException | IOException e) {
|
||||||
|
destroyLocalPlayer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (mMediaPlayer != null) {
|
||||||
|
destroyLocalPlayer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyLocalPlayer() {
|
||||||
|
if (mMediaPlayer != null) {
|
||||||
|
mMediaPlayer.reset();
|
||||||
|
mMediaPlayer.release();
|
||||||
|
mMediaPlayer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -7,7 +7,6 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaPlayer;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@ -19,7 +18,6 @@ import android.util.Log;
|
|||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.util.LocalBroadcastHelper;
|
import com.philliphsu.clock2.util.LocalBroadcastHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +39,7 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
|
|||||||
public static final String EXTRA_RINGING_OBJECT = RingtoneActivity.EXTRA_RINGING_OBJECT;
|
public static final String EXTRA_RINGING_OBJECT = RingtoneActivity.EXTRA_RINGING_OBJECT;
|
||||||
|
|
||||||
private AudioManager mAudioManager;
|
private AudioManager mAudioManager;
|
||||||
private MediaPlayer mMediaPlayer;
|
private RingtoneLoop mRingtone;
|
||||||
private Vibrator mVibrator;
|
private Vibrator mVibrator;
|
||||||
private T mRingingObject;
|
private T mRingingObject;
|
||||||
|
|
||||||
@ -97,7 +95,7 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Play ringtone, if not already playing
|
// Play ringtone, if not already playing
|
||||||
if (mAudioManager == null && mMediaPlayer == null) {
|
if (mAudioManager == null && mRingtone == null) {
|
||||||
// TOneverDO: Pass 0 as the first argument
|
// TOneverDO: Pass 0 as the first argument
|
||||||
startForeground(R.id.ringtone_service_notification, getForegroundNotification());
|
startForeground(R.id.ringtone_service_notification, getForegroundNotification());
|
||||||
|
|
||||||
@ -110,23 +108,8 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
|
|||||||
// Request permanent focus, as ringing could last several minutes
|
// Request permanent focus, as ringing could last several minutes
|
||||||
AudioManager.AUDIOFOCUS_GAIN);
|
AudioManager.AUDIOFOCUS_GAIN);
|
||||||
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
try {
|
mRingtone = new RingtoneLoop(this, getRingtoneUri());
|
||||||
mMediaPlayer = new MediaPlayer();
|
mRingtone.play();
|
||||||
mMediaPlayer.setDataSource(this, getRingtoneUri());
|
|
||||||
if (mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
|
|
||||||
// "Must call this method before prepare() or prepareAsync() in order
|
|
||||||
// for the target stream type to become effective thereafter."
|
|
||||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
|
|
||||||
mMediaPlayer.setLooping(true);
|
|
||||||
// There is prepare() and prepareAsync().
|
|
||||||
// "For files, it is OK to call prepare(), which blocks until
|
|
||||||
// MediaPlayer is ready for playback."
|
|
||||||
mMediaPlayer.prepare();
|
|
||||||
mMediaPlayer.start();
|
|
||||||
}
|
|
||||||
} catch (SecurityException | IOException e) {
|
|
||||||
destroyLocalPlayer();
|
|
||||||
}
|
|
||||||
if (doesVibrate()) {
|
if (doesVibrate()) {
|
||||||
mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
||||||
mVibrator.vibrate(new long[] { // apply pattern
|
mVibrator.vibrate(new long[] { // apply pattern
|
||||||
@ -156,7 +139,7 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
Log.d(TAG, "onDestroy()");
|
Log.d(TAG, "onDestroy()");
|
||||||
destroyLocalPlayer();
|
mRingtone.stop();
|
||||||
mAudioManager.abandonAudioFocus(null); // no listener was set
|
mAudioManager.abandonAudioFocus(null); // no listener was set
|
||||||
if (mVibrator != null) {
|
if (mVibrator != null) {
|
||||||
mVibrator.cancel();
|
mVibrator.cancel();
|
||||||
@ -205,12 +188,4 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
|
|||||||
protected final T getRingingObject() {
|
protected final T getRingingObject() {
|
||||||
return mRingingObject;
|
return mRingingObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void destroyLocalPlayer() {
|
|
||||||
if (mMediaPlayer != null) {
|
|
||||||
mMediaPlayer.reset();
|
|
||||||
mMediaPlayer.release();
|
|
||||||
mMediaPlayer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user