140 lines
5.7 KiB
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();
|
|
}
|
|
}
|
|
}
|