Move looping ringtone code to its own class. Use looped playback for RingtonePickerDialog.

This commit is contained in:
Phillip Hsu 2016-09-05 02:59:51 -07:00
parent c44eefc472
commit c7fd4ac93f
3 changed files with 83 additions and 40 deletions

View File

@ -2,14 +2,14 @@ package com.philliphsu.clock2;
import android.content.DialogInterface;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import com.philliphsu.clock2.ringtone.RingtoneLoop;
/**
* Created by Phillip Hsu on 9/3/2016.
* <p></p>
@ -31,7 +31,7 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
private RingtoneManager mRingtoneManager;
private OnRingtoneSelectedListener mOnRingtoneSelectedListener;
private Uri mRingtoneUri;
private Ringtone mRingtone;
private RingtoneLoop mRingtone;
public interface OnRingtoneSelectedListener {
void onRingtoneSelected(Uri ringtoneUri);
@ -66,12 +66,12 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
.setSingleChoiceItems(cursor, checkedItem, labelColumn, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (mRingtone != null) {
destroyLocalPlayer();
}
// Here, 'which' param refers to the position of the item clicked.
mRingtoneUri = mRingtoneManager.getRingtoneUri(which);
mRingtone = mRingtoneManager.getRingtone(which);
// TODO: Deprecated, but setAudioAttributes() is for 21+, so what is the
// pre-21 alternative?
mRingtone.setStreamType(AudioManager.STREAM_ALARM);
mRingtone = new RingtoneLoop(getActivity(), mRingtoneUri);
mRingtone.play();
}
});
@ -81,9 +81,7 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (mRingtone != null && mRingtone.isPlaying()) {
mRingtone.stop();
}
destroyLocalPlayer();
}
@Override
@ -98,4 +96,11 @@ public class RingtonePickerDialog extends BaseAlertDialogFragment {
public void setOnRingtoneSelectedListener(OnRingtoneSelectedListener onRingtoneSelectedListener) {
mOnRingtoneSelectedListener = onRingtoneSelectedListener;
}
private void destroyLocalPlayer() {
if (mRingtone != null) {
mRingtone.stop();
mRingtone = null;
}
}
}

View File

@ -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;
}
}
}

View File

@ -7,7 +7,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@ -19,7 +18,6 @@ import android.util.Log;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.util.LocalBroadcastHelper;
import java.io.IOException;
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;
private AudioManager mAudioManager;
private MediaPlayer mMediaPlayer;
private RingtoneLoop mRingtone;
private Vibrator mVibrator;
private T mRingingObject;
@ -97,7 +95,7 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
}
}
// Play ringtone, if not already playing
if (mAudioManager == null && mMediaPlayer == null) {
if (mAudioManager == null && mRingtone == null) {
// TOneverDO: Pass 0 as the first argument
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
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
try {
mMediaPlayer = new MediaPlayer();
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();
}
mRingtone = new RingtoneLoop(this, getRingtoneUri());
mRingtone.play();
if (doesVibrate()) {
mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
mVibrator.vibrate(new long[] { // apply pattern
@ -156,7 +139,7 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy()");
destroyLocalPlayer();
mRingtone.stop();
mAudioManager.abandonAudioFocus(null); // no listener was set
if (mVibrator != null) {
mVibrator.cancel();
@ -205,12 +188,4 @@ public abstract class RingtoneService<T extends Parcelable> extends Service {
protected final T getRingingObject() {
return mRingingObject;
}
private void destroyLocalPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
}