11c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski/* 21c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * Copyright (C) 2013 The Android Open Source Project 31c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * 41c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * Licensed under the Apache License, Version 2.0 (the "License"); 51c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * you may not use this file except in compliance with the License. 61c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * You may obtain a copy of the License at 71c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * 81c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * http://www.apache.org/licenses/LICENSE-2.0 91c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * 101c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * Unless required by applicable law or agreed to in writing, software 111c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * distributed under the License is distributed on an "AS IS" BASIS, 121c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * See the License for the specific language governing permissions and 141c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * limitations under the License. 151c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski */ 161c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 171c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskipackage com.android.deskclock.alarms; 181c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 191c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.content.Context; 201c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.content.res.AssetFileDescriptor; 211c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.media.AudioManager; 221c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.media.MediaPlayer; 231c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.media.MediaPlayer.OnErrorListener; 241c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.media.RingtoneManager; 251c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.net.Uri; 261c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport android.os.Vibrator; 271c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 281c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport com.android.deskclock.Log; 291c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport com.android.deskclock.R; 301c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport com.android.deskclock.provider.AlarmInstance; 311c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 321c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskiimport java.io.IOException; 331c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 341c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski/** 351c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski * Manages playing ringtone and vibrating the device. 361c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski */ 371c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowskipublic class AlarmKlaxon { 381c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski private static final long[] sVibratePattern = new long[] { 500, 500 }; 391c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 401c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // Volume suggested by media team for in-call alarms. 411c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski private static final float IN_CALL_VOLUME = 0.125f; 421c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 431c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski private static boolean sStarted = false; 441c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski private static MediaPlayer sMediaPlayer = null; 451c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 461c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski public static void stop(Context context) { 471c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Log.v("AlarmKlaxon.stop()"); 481c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 491c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (sStarted) { 501c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sStarted = false; 511c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // Stop audio playing 521c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (sMediaPlayer != null) { 531c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer.stop(); 541c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski AudioManager audioManager = (AudioManager) 551c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski context.getSystemService(Context.AUDIO_SERVICE); 561c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski audioManager.abandonAudioFocus(null); 571c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer.release(); 581c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer = null; 591c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 601c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 611c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski ((Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE)).cancel(); 621c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 631c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 641c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 651c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski public static void start(final Context context, AlarmInstance instance, 661c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski boolean inTelephoneCall) { 671c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Log.v("AlarmKlaxon.start()"); 681c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // Make sure we are stop before starting 691c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski stop(context); 701c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 711c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (!AlarmInstance.NO_RINGTONE_URI.equals(instance.mRingtone)) { 721c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Uri alarmNoise = instance.mRingtone; 731c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // Fall back on the default alarm if the database does not have an 741c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // alarm stored. 751c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (alarmNoise == null) { 761c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski alarmNoise = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); 771c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (Log.LOGV) { 781c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Log.v("Using default alarm: " + alarmNoise.toString()); 791c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 801c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 811c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 821c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // TODO: Reuse mMediaPlayer instead of creating a new one and/or use RingtoneManager. 831c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer = new MediaPlayer(); 841c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer.setOnErrorListener(new OnErrorListener() { 851c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski @Override 861c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski public boolean onError(MediaPlayer mp, int what, int extra) { 871c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Log.e("Error occurred while playing audio. Stopping AlarmKlaxon."); 881c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski AlarmKlaxon.stop(context); 891c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski return true; 901c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 911c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski }); 921c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 931c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski try { 941c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // Check if we are in a call. If we are, use the in-call alarm 951c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // resource at a low volume to not disrupt the call. 961c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (inTelephoneCall) { 971c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Log.v("Using the in-call alarm"); 981c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME); 991c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski setDataSourceFromResource(context, sMediaPlayer, R.raw.in_call_alarm); 1001c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } else { 1011c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer.setDataSource(context, alarmNoise); 1021c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1031c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski startAlarm(context, sMediaPlayer); 1041c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } catch (Exception ex) { 1051c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Log.v("Using the fallback ringtone"); 1061c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // The alarmNoise may be on the sd card which could be busy right 1071c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // now. Use the fallback ringtone. 1081c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski try { 1091c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // Must reset the media player to clear the error state. 1101c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sMediaPlayer.reset(); 1111c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski setDataSourceFromResource(context, sMediaPlayer, R.raw.fallbackring); 1121c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski startAlarm(context, sMediaPlayer); 1131c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } catch (Exception ex2) { 1141c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // At this point we just don't play anything. 1151c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Log.e("Failed to play fallback ringtone", ex2); 1161c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1171c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1181c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1191c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 1201c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (instance.mVibrate) { 1211c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 1221c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski vibrator.vibrate(sVibratePattern, 0); 1231c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1241c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 1251c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski sStarted = true; 1261c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1271c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 1281c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // Do the common stuff when starting the alarm. 1291c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski private static void startAlarm(Context context, MediaPlayer player) throws IOException { 1301c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 1311c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski // do not play alarms if stream volume is 0 (typically because ringer mode is silent). 1321c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) { 1331c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski player.setAudioStreamType(AudioManager.STREAM_ALARM); 1341c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski player.setLooping(true); 1351c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski player.prepare(); 1361c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski audioManager.requestAudioFocus(null, 1371c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); 1381c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski player.start(); 1391c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1401c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1411c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski 1421c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski private static void setDataSourceFromResource(Context context, MediaPlayer player, int res) 1431c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski throws IOException { 1441c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski AssetFileDescriptor afd = context.getResources().openRawResourceFd(res); 1451c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski if (afd != null) { 1461c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); 1471c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski afd.close(); 1481c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1491c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski } 1501c7788b33dd4516dae81e6bcab043addc45fc1a1Paul Sliwowski} 151