From f9204e52f328794191baffa9336178e8312f0699 Mon Sep 17 00:00:00 2001 From: tim Date: Mon, 14 Apr 2014 10:55:54 +0200 Subject: [PATCH] - Allow user to select ringtone - Display readable alarm time in pre-alarm notification --- .../hypoalarm/AlarmAlertActivity.java | 3 +- .../org/treehouse/hypoalarm/AlarmKlaxon.java | 21 ++-- .../treehouse/hypoalarm/AlarmReceiver.java | 18 ++- .../treehouse/hypoalarm/GraceReceiver.java | 1 + .../org/treehouse/hypoalarm/MainActivity.java | 112 ++++++++++++++---- .../treehouse/hypoalarm/PreAlarmNotify.java | 11 +- .../src/main/res/layout/fragment_main.xml | 22 ++++ HypoAlarm/src/main/res/raw/in_call_alarm.ogg | Bin 21153 -> 0 bytes HypoAlarm/src/main/res/values/arrays.xml | 9 ++ HypoAlarm/src/main/res/values/strings.xml | 16 +-- 10 files changed, 159 insertions(+), 54 deletions(-) delete mode 100644 HypoAlarm/src/main/res/raw/in_call_alarm.ogg create mode 100644 HypoAlarm/src/main/res/values/arrays.xml diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java index 405ae70..1eba74f 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmAlertActivity.java @@ -12,6 +12,8 @@ import android.view.WindowManager; //import com.triggertrap.seekarc.SeekArc; import net.frakbot.glowpadbackport.GlowPadView; +import java.util.Random; + public class AlarmAlertActivity extends Activity { private static Intent notifyIntent; public static Boolean alertFinished, userCancelled; @@ -45,7 +47,6 @@ public class AlarmAlertActivity extends Activity { notifyIntent = new Intent(getApplicationContext(), AlarmNotify.class); // Disable any current notifications (if we're snoozing) stopService(notifyIntent); - } @Override diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmKlaxon.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmKlaxon.java index e4a8cb5..18a3d8f 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmKlaxon.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmKlaxon.java @@ -1,12 +1,15 @@ 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.Ringtone; 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; @@ -24,11 +27,7 @@ public class AlarmKlaxon { private static Vibrator vibrator; public static void start(final Context context) { - /** - * - * TODO allow user to select alarm tone - * - */ + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); vibrator.cancel(); @@ -54,10 +53,6 @@ public class AlarmKlaxon { }; telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - // 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() { @@ -69,11 +64,15 @@ public class AlarmKlaxon { } }); + // 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, alarmNoise); + mediaPlayer.setDataSource(context, ringtoneUri); startAudio(context); } catch (Exception ex) { - // The alarmNoise may be on the sd card which could be busy right + // 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. diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java index d381f7d..7c32af2 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/AlarmReceiver.java @@ -18,10 +18,10 @@ import java.io.IOException; import java.util.Calendar; public class AlarmReceiver extends BroadcastReceiver { - private static final int SNOOZE_TIME = 1000*60; //1000*60*5; // Snooze for 5 minutes if need be - private static final int ALERT_LIFE = 1000*10; //TODO 1000*60*2; // 2 minutes + private static final int SNOOZE_TIME = 1000*60*5; // Snooze for 5 minutes if need be + private static final int ALERT_LIFE = 1000*60*2; // 2 minutes private static SharedPreferences sharedPref; - private static AlarmManager alarmManager, graceManager; + private static AlarmManager alarmManager; private static PendingIntent alarmPendingIntent, gracePendingIntent; private static Intent alertActivityIntent, notifyIntent; private static TelephonyManager telephonyManager; @@ -36,6 +36,7 @@ public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); final Boolean alarmActive = sharedPref.getBoolean(context.getString(R.string.AlarmActivePref), true); final int gracePeriod = sharedPref.getInt(context.getString(R.string.GracePeriodPref), 60); final String alarmTimeStr = sharedPref.getString(context.getString(R.string.AlarmTimePref), null); @@ -55,14 +56,13 @@ public class AlarmReceiver extends BroadcastReceiver { Calendar graceCal = Calendar.getInstance(); graceCal.set(Calendar.SECOND, 0); graceCal.add(Calendar.MINUTE, gracePeriod); - graceManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent graceIntent = new Intent(context, GraceReceiver.class); gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0); - graceManager.cancel(gracePendingIntent); + alarmManager.cancel(gracePendingIntent); if (Build.VERSION.SDK_INT >= 19) { - graceManager.setExact(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); + alarmManager.setExact(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); } else { - graceManager.set(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); + alarmManager.set(AlarmManager.RTC_WAKEUP, graceCal.getTimeInMillis(), gracePendingIntent); } Log.d("AlarmReceiver", "Setting grace alarm for " + MainActivity.debugDate(graceCal)); @@ -83,7 +83,6 @@ public class AlarmReceiver extends BroadcastReceiver { Calendar cal = MainActivity.TimeStringToCalendar(alarmTimeStr); // Advance the calendar to tomorrow cal.add(Calendar.DAY_OF_MONTH, 1); - alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmPendingIntent = PendingIntent.getBroadcast(context, MainActivity.ALARM_REQUEST, intent, 0); alarmManager.cancel(alarmPendingIntent); if (Build.VERSION.SDK_INT >= 19) { @@ -141,10 +140,9 @@ public class AlarmReceiver extends BroadcastReceiver { stopAlert(context); // Cancel the graceAlarm - AlarmManager graceManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent graceIntent = new Intent(context, GraceReceiver.class); PendingIntent gracePendingIntent = PendingIntent.getBroadcast(context, MainActivity.GRACE_REQUEST, graceIntent, 0); - graceManager.cancel(gracePendingIntent); + alarmManager.cancel(gracePendingIntent); } public static void snoozeAlarm(final Context context) { diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java index 82f7e7c..9ffb0c0 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/GraceReceiver.java @@ -42,6 +42,7 @@ public class GraceReceiver extends BroadcastReceiver { public void onConnected(Bundle bundle) { Location location = locationClient.getLastLocation(); if (location != null) { + // uri must begin with a space String uri = " http://maps.google.com?q=" + location.getLatitude() + "," + location.getLongitude(); message += uri; sendText(context); diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java index 61dbeb3..2438c62 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/MainActivity.java @@ -12,6 +12,8 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.database.Cursor; +import android.media.Ringtone; +import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -57,18 +59,20 @@ import java.util.regex.Pattern; // Alerts via Whatsapp and other protocols? public class MainActivity extends ActionBarActivity { - public static int ALARM_REQUEST = 1; - public static int GRACE_REQUEST = 2; - public static int PRENOTIFY_REQUEST = 3; - public static int CANCEL_GRACE_REQUEST = 4; - public static int CANCEL_ALARM_REQUEST = 5; + public static int ALARM_REQUEST = 1; + public static int GRACE_REQUEST = 2; + public static int PRENOTIFY_REQUEST = 3; + public static int CANCEL_GRACE_REQUEST = 4; + public static int CANCEL_ALARM_REQUEST = 5; + public static int PHONE_NUMBER_REQUEST = 6; + public static int RINGTONE_REQUEST = 7; private static Switch alarmActiveSwitch; private static Button alarmTimeButton; private static Spinner gracePeriodSpinner; private static EditText phoneNumberButton; private static EditText messageButton; - public static Boolean HYPOALARM_DEBUG=true; + public static Boolean HYPOALARM_DEBUG = true; @Override protected void onCreate(Bundle savedInstanceState) { @@ -90,7 +94,7 @@ public class MainActivity extends ActionBarActivity { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); return rootView; @@ -108,8 +112,8 @@ public class MainActivity extends ActionBarActivity { alarmActiveSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - AlarmManager alarmManager, graceManager; - PendingIntent alarmPendingIntent, gracePendingIntent; + AlarmManager alarmManager; + PendingIntent alarmPendingIntent, gracePendingIntent, preNotifyPendingIntent; SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(getString(R.string.AlarmActivePref), b); @@ -121,13 +125,18 @@ public class MainActivity extends ActionBarActivity { Intent alarmIntent = new Intent(getActivity(), AlarmReceiver.class); alarmPendingIntent = PendingIntent.getBroadcast(getActivity(), ALARM_REQUEST, alarmIntent, 0); alarmManager.cancel(alarmPendingIntent); + // Cancel any pre-alarm notification + Intent preNotifyIntent = new Intent(getActivity(), AlarmReceiver.class); + preNotifyPendingIntent = PendingIntent.getBroadcast(getActivity(), PRENOTIFY_REQUEST, alarmIntent, 0); + alarmManager.cancel(preNotifyPendingIntent); // Cancel any grace period - graceManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); Intent graceIntent = new Intent(getActivity(), GraceReceiver.class); gracePendingIntent = PendingIntent.getBroadcast(getActivity(), GRACE_REQUEST, graceIntent, 0); - graceManager.cancel(gracePendingIntent); + alarmManager.cancel(gracePendingIntent); // Stop any notifications getActivity().stopService(new Intent(getActivity(), AlarmNotify.class)); + getActivity().stopService(new Intent(getActivity(), PreAlarmNotify.class)); + Log.d("MainActivity", "Alarms cancelled"); Toast.makeText(getActivity().getApplicationContext(), getString(R.string.alarmCancelled), Toast.LENGTH_SHORT).show(); } else { @@ -194,6 +203,27 @@ public class MainActivity extends ActionBarActivity { int spinnerPosition = gracePeriodSpinnerAdapter.getPosition(MinutesToGracePeriodStr(gracePeriod)); gracePeriodSpinner.setSelection(spinnerPosition); + // Allow user to select ringtone + final Button ringtoneButton = (Button) getActivity().findViewById(R.id.ringtone); + String ringtoneStr = sharedPref.getString(getString(R.string.RingtonePref), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM).toString()); + Uri ringtoneUri = Uri.parse(ringtoneStr); + Ringtone currentRingtone = RingtoneManager.getRingtone(getActivity().getApplicationContext(), ringtoneUri); + ringtoneButton.setText(currentRingtone.getTitle(getActivity().getApplicationContext())); + ringtoneButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent ringtoneIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); + ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select ringtone:"); + ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false); + //ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); + ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM); + //ringtoneIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentRingtone); + + startActivityForResult(ringtoneIntent, RINGTONE_REQUEST); + } + }); + + // Set phone number String phoneNumberStr = sharedPref.getString(getString(R.string.PhoneNumberPref), null); phoneNumberButton = (EditText) getActivity().findViewById(R.id.phone_number); @@ -261,6 +291,29 @@ public class MainActivity extends ActionBarActivity { } }); } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.d("MainActivity", "Request code: " + requestCode); + + // If we're answering a ringtone dialogue, update the correct button + if (requestCode == RINGTONE_REQUEST && resultCode == RESULT_OK) { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + SharedPreferences.Editor editor = sharedPref.edit(); + Button ringtoneButton = (Button) getActivity().findViewById(R.id.ringtone); + + Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); + if (uri == null) { + editor.putString(getString(R.string.RingtonePref), null); + } else { + editor.putString(getString(R.string.RingtonePref), uri.toString()); + } + editor.commit(); + Ringtone currentRingtone = RingtoneManager.getRingtone(getActivity().getApplicationContext(), uri); + ringtoneButton.setText(currentRingtone.getTitle(getActivity().getApplicationContext())); + } + } } // Alarm time picker @@ -348,7 +401,6 @@ public class MainActivity extends ActionBarActivity { } public static class PhonePickerFragment extends DialogFragment { - SharedPreferences sharedPref; EditText phoneButton; EditText phoneInput; Button contactsButton; @@ -389,7 +441,7 @@ public class MainActivity extends ActionBarActivity { public void onClick(View view) { Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI); intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE); - startActivityForResult(intent, 1); + startActivityForResult(intent, PHONE_NUMBER_REQUEST); } }); return alert.create(); @@ -397,15 +449,16 @@ public class MainActivity extends ActionBarActivity { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (data != null) { + if (requestCode == PHONE_NUMBER_REQUEST && resultCode == RESULT_OK && data != null) { Uri uri = data.getData(); if (uri != null) { Cursor c = null; try { c = getActivity().getContentResolver().query(uri, new String[]{ ContactsContract.CommonDataKinds.Phone.NUMBER, - ContactsContract.CommonDataKinds.Phone.TYPE }, - null, null, null); + ContactsContract.CommonDataKinds.Phone.TYPE}, + null, null, null + ); if (c != null && c.moveToFirst()) { String number = c.getString(0); @@ -419,12 +472,12 @@ public class MainActivity extends ActionBarActivity { } } } - } public static String verifyTimeString(String timeStr) { return CalendarToTimeString(TimeStringToCalendar(timeStr)); } + public static String HourMinuteToTimeString(int hour, int minute) { return CalendarToTimeString(TimeStringToCalendar(hour + ":" + minute)); } @@ -432,7 +485,7 @@ public class MainActivity extends ActionBarActivity { public static Calendar TimeStringToCalendar(String dateString) { Date date; Calendar cal; - final String FORMAT="HH:mm"; // z = time zone + final String FORMAT = "HH:mm"; // z = time zone SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault()); sdf.format(new Date()); try { @@ -455,15 +508,28 @@ public class MainActivity extends ActionBarActivity { return null; } } + public static String CalendarToTimeString(Calendar cal) { - final String FORMAT="HH:mm"; + final String FORMAT = "HH:mm"; SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault()); return sdf.format(cal.getTime()); } + + public static String formattedTime(Context context, Calendar cal) { + String pattern; + if (Build.VERSION.SDK_INT >= 18) { + String skeleton = DateFormat.is24HourFormat(context) ? "EHm" : "Ehma"; + pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); + } else { + pattern = "EHm"; + } + return (String) DateFormat.format(pattern, cal); + } public static String debugDate(Calendar cal) { SimpleDateFormat print = new SimpleDateFormat("dd-MM-yyyy HH:mm:ssZ"); return print.format(cal.getTime()); } + public static int GracePeriodToMinutes(String gracePeriod) { Pattern p = Pattern.compile("(?:(\\d+)\\s+hours?)?\\s*(?:(\\d+)\\s+minutes?)?"); @@ -483,6 +549,7 @@ public class MainActivity extends ActionBarActivity { return 0; } + public static String MinutesToGracePeriodStr(int minutes) { int hours = minutes / 60; int remMinutes = minutes % 60; @@ -505,4 +572,9 @@ public class MainActivity extends ActionBarActivity { } return remMinutes + minStr; } -} + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } +} \ No newline at end of file diff --git a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java index a052583..076438b 100644 --- a/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java +++ b/HypoAlarm/src/main/java/za/org/treehouse/hypoalarm/PreAlarmNotify.java @@ -12,8 +12,12 @@ import android.graphics.BitmapFactory; import android.os.Build; import android.os.IBinder; import android.preference.PreferenceManager; +import android.text.format.DateFormat; import android.util.Log; +import java.util.Calendar; +import java.util.Locale; + public class PreAlarmNotify extends Service { public static final int preNotifyID = 2; @@ -36,14 +40,17 @@ public class PreAlarmNotify extends Service { Log.d("PreAlarmNotify", "Pre-notification started."); + // Get alarm time, and convert it into something readable. String alarmTimeStr = sharedPref.getString(getString(R.string.AlarmTimePref), null); + Calendar alarmCal = MainActivity.TimeStringToCalendar(alarmTimeStr); + alarmTimeStr = MainActivity.formattedTime(getApplicationContext(), alarmCal); Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_grey); final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= 11) { final Notification.Builder notification = new Notification.Builder(this) - .setContentTitle(getString(R.string.app_name)) - .setContentText(getString(R.string.preNotificationText)) + .setContentTitle(getString(R.string.preNotificationTitle)) + .setContentText(alarmTimeStr) .setSmallIcon(R.drawable.alarm_notification) .setLargeIcon(bm) .setOnlyAlertOnce(true) diff --git a/HypoAlarm/src/main/res/layout/fragment_main.xml b/HypoAlarm/src/main/res/layout/fragment_main.xml index e71e765..930db77 100644 --- a/HypoAlarm/src/main/res/layout/fragment_main.xml +++ b/HypoAlarm/src/main/res/layout/fragment_main.xml @@ -108,6 +108,28 @@ android:layout_column="1" /> + + + +