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

140 lines
5.7 KiB
Java

package za.org.treehouse.HypoAlarm;
import android.content.Context;
import android.content.SharedPreferences;
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.preference.PreferenceManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import java.io.IOException;
public class AlarmKlaxon {
private static Boolean klaxonActive = false;
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) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
if (klaxonActive) {
stop(context);
}
klaxonActive = true;
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) {
if (mediaPlayer != null) {
mediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME);
}
// or just stop the audio entirely...
//stopAudio(context);
}
}
};
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
stopAudio(context);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e("AlarmKlaxon", "Error occurred while playing audio. Stopping alarm.");
stopAudio(context);
return true;
}
});
// Get preferred ringtone, or fall back to the default alarm tone
String ringtoneStr = sharedPref.getString(context.getString(R.string.RingtonePref), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM).toString());
Uri ringtoneUri = Uri.parse(ringtoneStr);
try {
mediaPlayer.setDataSource(context, ringtoneUri);
startAudio(context);
} catch (Exception ex) {
// The ringtoneUri 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("AlarmKlaxon", "Failed to play fallback ringtone", ex2);
}
}
}
public static void stop(final Context context) {
if (klaxonActive) {
vibrator.cancel();
stopAudio(context);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
klaxonActive = false;
}
}
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();
}
}
}