HypoAlarm/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmKlaxon.java

143 lines
5.8 KiB
Java

package za.org.treehouse.hypoalarm;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Vibrator;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import java.io.IOException;
public class AlarmKlaxon {
private static final long[] vPattern = {500, 500};
// Volume modification for alarms while a phone call is active, from com.android.deskclock.alarms
private static final float IN_CALL_VOLUME = 0.125f;
private static MediaPlayer mediaPlayer = null;
private static TelephonyManager telephonyManager;
private static PhoneStateListener phoneStateListener;
private static int initialCallState;
private static Vibrator vibrator;
public static void start(final Context context) {
/**
*
* TODO allow user to select alarm tone
* TODO add raw alarm tone to use as fallback
* TODO add in-call alarm tone
* TODO lower volume if in a call
* TODO cancel noise if a call comes in (add TelephonyManager listener which cancels the alert but calls the notification)
*
*/
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.cancel();
vibrator.vibrate(vPattern, 0);
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
initialCallState = telephonyManager.getCallState();
phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String ignored) {
// The user might already be in a call when the alarm fires. When
// we register onCallStateChanged, we get the initial in-call state
// which kills the alarm. Check against the initial call state so
// we don't kill the alarm during a call.
if (state != TelephonyManager.CALL_STATE_IDLE && state != initialCallState) {
stopAudio(context);
// TODO stop alarm from snoozing or turning off?
}
}
};
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
boolean inTelephoneCall = initialCallState != TelephonyManager.CALL_STATE_IDLE;
// TODO select alarm tone?
// Use the default alarm tone...
Uri alarmNoise = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
stopAudio(context);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e("AlarmAlertActivity", "Error occurred while playing audio. Stopping alarm.");
stopAudio(context);
return true;
}
});
try {
if (inTelephoneCall) {
Log.d("AlarmKlaxon", "Using the in-call alarm");
mediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME);
setDataSourceFromResource(context, mediaPlayer, R.raw.in_call_alarm);
} else {
mediaPlayer.setDataSource(context, alarmNoise);
startAudio(context);
}
} catch (Exception ex) {
// The alarmNoise may be on the sd card which could be busy right
// now. Use the fallback ringtone.
try {
// Reset the media player to clear the error state.
mediaPlayer.reset();
setDataSourceFromResource(context, mediaPlayer, R.raw.fallbackring);
startAudio(context);
} catch (Exception ex2) {
// At this point we just don't play anything.
Log.e("AlarmAlertActivity", "Failed to play fallback ringtone", ex2);
}
}
}
public static void stop(final Context context) {
vibrator.cancel();
stopAudio(context);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
private static void startAudio(final Context context) throws IOException {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
// do not play alarms if stream volume is 0 (typically because ringer mode is silent).
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mediaPlayer.setLooping(true);
try {
mediaPlayer.prepare();
} catch (Exception e) {
Log.e("AlarmAlertActivity", "Prepare failed. Exiting", e);
return;
}
audioManager.requestAudioFocus(null,
AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
mediaPlayer.start();
}
}
private static void stopAudio(final Context context) {
if (mediaPlayer != null) {
mediaPlayer.stop();
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioManager.abandonAudioFocus(null);
mediaPlayer.release();
mediaPlayer = null;
}
}
// Load ringtone from a resource
private static void setDataSourceFromResource(Context context, MediaPlayer player, int res) throws IOException {
AssetFileDescriptor afd = context.getResources().openRawResourceFd(res);
if (afd != null) {
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
}
}
}