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

512 lines
23 KiB
Java

package za.org.treehouse.hypoalarm;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.text.InputType;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TimePicker;
import android.widget.Toast;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// Settings: alarm time, phone number, custom message, grace period length
// Set alarm
// Display alarm notification
// Display countdown (in seconds) or time till alarm fires (in minutes)
// Reset alarm
// Send SMS
// Possible settings:
// More than one phone number?
// Alerts via Whatsapp and other protocols?
// TODO: klaxon
// TODO: glowpad dismissal (or circular seekbar)
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;
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;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new MainFragment())
.commit();
}
}
// Main screen
public static class MainFragment extends Fragment {
public MainFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
public void onStart() {
super.onStart();
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
// Allow alarm to activate
Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), true);
alarmActiveSwitch = (Switch) getActivity().findViewById(R.id.alarm_active_switch);
alarmActiveSwitch.setChecked(alarmActive);
alarmActiveSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
AlarmManager alarmManager, graceManager;
PendingIntent alarmPendingIntent, gracePendingIntent;
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(getString(R.string.AlarmActivePref), b);
editor.commit();
if (!b) {
// Cancel any current alarm
alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(getActivity(), AlarmReceiver.class);
alarmPendingIntent = PendingIntent.getBroadcast(getActivity(), ALARM_REQUEST, alarmIntent, 0);
alarmManager.cancel(alarmPendingIntent);
// 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);
// Stop any notifications
getActivity().stopService(new Intent(getActivity(), AlarmNotify.class));
Log.d("MainActivity", "Alarms cancelled");
Toast.makeText(getActivity().getApplicationContext(), getString(R.string.alarmCancelled), Toast.LENGTH_SHORT).show();
} else {
// Activate the alarm
DialogFragment alarmFragment = new TimePickerFragment();
alarmFragment.show(getActivity().getSupportFragmentManager(), "alarmTimePicker");
alarmFragment.dismiss();
}
}
});
// Set alarm time
String defaultTimeStr = "09:00";
String alarmTimeStr = verifyTimeString(sharedPref.getString(getString(R.string.AlarmTimePref), defaultTimeStr));
alarmTimeButton = (Button) getActivity().findViewById(R.id.alarm_time);
if (HYPOALARM_DEBUG) {
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, 1);
alarmTimeStr = CalendarToTimeString(c);
}
alarmTimeButton.setText(alarmTimeStr);
alarmTimeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DialogFragment alarmFragment = new TimePickerFragment();
alarmFragment.show(getActivity().getSupportFragmentManager(), "alarmTimePicker");
}
});
if (HYPOALARM_DEBUG) {
DialogFragment alarmFragment = new TimePickerFragment();
alarmFragment.show(getActivity().getSupportFragmentManager(), "alarmTimePicker");
alarmFragment.dismiss();
}
// Set grace period
int defaultGrace = 60;
int gracePeriod = sharedPref.getInt(getString(R.string.GracePeriodPref), defaultGrace);
gracePeriodSpinner = (Spinner) getActivity().findViewById(R.id.grace_period);
gracePeriodSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
Object value = parent.getItemAtPosition(pos);
SharedPreferences.Editor editor = sharedPref.edit();
int minutes = GracePeriodToMinutes(value.toString());
editor.putInt(getString(R.string.GracePeriodPref), minutes);
editor.commit();
/*
CharSequence text = "Grace period is " + GracePeriodToMinutes(value.toString()) + " or " + MinutesToGracePeriodStr(GracePeriodToMinutes(value.toString()))+ ".";
Toast.makeText(getActivity().getApplicationContext(), text, Toast.LENGTH_SHORT).show();
*/
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
// Set value of drop-down list to value of gracePeriodStr
ArrayAdapter gracePeriodSpinnerAdapter = (ArrayAdapter) gracePeriodSpinner.getAdapter();
int spinnerPosition = gracePeriodSpinnerAdapter.getPosition(MinutesToGracePeriodStr(gracePeriod));
gracePeriodSpinner.setSelection(spinnerPosition);
// Set phone number
String phoneNumberStr = sharedPref.getString(getString(R.string.PhoneNumberPref), null);
phoneNumberButton = (EditText) getActivity().findViewById(R.id.phone_number);
phoneNumberButton.setText(phoneNumberStr);
phoneNumberButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DialogFragment phoneFragment = new PhonePickerFragment();
phoneFragment.show(getActivity().getSupportFragmentManager(), "phoneNumberPicker");
}
});
// Set message
String messageStr = sharedPref.getString(getString(R.string.MessagePref), getString(R.string.defaultMessage));
messageButton = (EditText) getActivity().findViewById(R.id.message);
messageButton.setText(messageStr);
messageButton.setOnClickListener(new View.OnClickListener() {
SharedPreferences sharedPref;
@Override
public void onClick(View view) {
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
String messageStr = sharedPref.getString(getString(R.string.MessagePref), getString(R.string.defaultMessage));
final InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
final EditText messageInput = new EditText(getActivity());
messageInput.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_FLAG_MULTI_LINE |
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES |
InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
if (messageButton != null) {
messageInput.setText(messageButton.getText().toString());
}
messageInput.setSelection(messageInput.getText().length());
alert.setView(messageInput);
alert.setMessage(getString(R.string.setMessage));
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String value = messageInput.getText().toString();
if (value.compareTo("") == 0) {
value = getString(R.string.defaultMessage);
}
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(getString(R.string.MessagePref), value);
editor.commit();
messageButton.setText(value);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
// Canceled.
}
});
alert.show();
messageInput.requestFocus();
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
});
}
}
// Alarm time picker
public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
SharedPreferences sharedPref;
private AlarmManager alarmManager;
private PendingIntent alarmPendingIntent, preNotifyPendingIntent;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
// Use the current set time as the default value for the picker
String alarmTimeStr = alarmTimeButton.getText().toString();
Calendar cal = TimeStringToCalendar(alarmTimeStr);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
// Create a new instance of TimePickerDialog and return it
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
String alarmStr = HourMinuteToTimeString(hourOfDay, minute);
Boolean alarmActive = sharedPref.getBoolean(getString(R.string.AlarmActivePref), true);
// Set time preference
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(getString(R.string.AlarmTimePref), alarmStr);
editor.commit();
Button alarm_time = (Button) getActivity().findViewById(R.id.alarm_time);
alarm_time.setText(alarmStr);
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, 0);
if (alarmActive) {
// Initialise alarm, which displays a dialog and system alert, and
// calls AlarmManager with grace_period as the delay
// which in turn, sends SMS if dialog is not exited.
alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(getActivity(), AlarmReceiver.class);
alarmPendingIntent = PendingIntent.getBroadcast(getActivity(), ALARM_REQUEST, alarmIntent, 0);
// Cancel any existing alarms
alarmManager.cancel(alarmPendingIntent);
// Set or reset alarm
if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmPendingIntent);
}
Log.d("MainActivity", "Setting alarm for " + MainActivity.debugDate(cal));
// Set an alarm for the pre-alarm notification, half an hour before the alarm
Calendar preNotifyCal = cal;
preNotifyCal.add(Calendar.MINUTE, -30);
Intent preNotifyIntent = new Intent(getActivity(), PreAlarmReceiver.class);
preNotifyPendingIntent = PendingIntent.getBroadcast(getActivity(), PRENOTIFY_REQUEST, preNotifyIntent, 0);
// Cancel any existing alarms
alarmManager.cancel(preNotifyPendingIntent);
// Set or reset alarm
if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, preNotifyCal.getTimeInMillis(), preNotifyPendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, preNotifyCal.getTimeInMillis(), preNotifyPendingIntent);
}
Log.d("MainActivity", "Setting pre-alarm for " + MainActivity.debugDate(preNotifyCal));
// Set boot receiver, so alarm restarts on boot
ComponentName receiver = new ComponentName(getActivity(), BootReceiver.class);
PackageManager pm = getActivity().getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
// Display toast
CharSequence text = getString(R.string.alarmSetToast) + " " + alarmStr;
Toast.makeText(getActivity().getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
}
}
public static class PhonePickerFragment extends DialogFragment {
SharedPreferences sharedPref;
EditText phoneButton;
EditText phoneInput;
Button contactsButton;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setMessage(R.string.setPhoneNumber);
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.phone_dialog, null);
alert.setView(dialogView);
phoneButton = (EditText) getActivity().findViewById(R.id.phone_number);
phoneInput = (EditText) dialogView.findViewById(R.id.dialog_phone_number);
phoneInput.setText(phoneButton.getText().toString());
phoneInput.setSelection(phoneInput.getText().length());
contactsButton = (Button) dialogView.findViewById(R.id.dialog_contacts_button);
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String value = phoneInput.getText().toString();
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(getString(R.string.PhoneNumberPref), value);
editor.commit();
phoneButton.setText(value);
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Cancelled
}
});
contactsButton.setOnClickListener(new View.OnClickListener() {
@Override
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);
}
});
return alert.create();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (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);
if (c != null && c.moveToFirst()) {
String number = c.getString(0);
phoneInput.setText(number);
}
} finally {
if (c != null) {
c.close();
}
}
}
}
}
}
public static String verifyTimeString(String timeStr) {
return CalendarToTimeString(TimeStringToCalendar(timeStr));
}
public static String HourMinuteToTimeString(int hour, int minute) {
return CalendarToTimeString(TimeStringToCalendar(hour + ":" + minute));
}
public static Calendar TimeStringToCalendar(String dateString) {
Date date;
Calendar cal;
final String FORMAT="HH:mm"; // z = time zone
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault());
sdf.format(new Date());
try {
date = sdf.parse(dateString);
// date has the correct hour and minute, but the incorrect day,
// month and year information. To get information out of it, we need to
// convert it to a Calendar.
Calendar dateCal = Calendar.getInstance();
dateCal.setTime(date);
// Create a new calendar with the correct day, month and year,
// and set the hour and minute by hand.
cal = Calendar.getInstance();
cal.set(Calendar.HOUR, dateCal.get(Calendar.HOUR));
cal.set(Calendar.MINUTE, dateCal.get(Calendar.MINUTE));
cal.set(Calendar.SECOND, 0);
return cal;
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
public static String CalendarToTimeString(Calendar cal) {
final String FORMAT="HH:mm";
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT, Locale.getDefault());
return sdf.format(cal.getTime());
}
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?)?");
Matcher m = p.matcher(gracePeriod);
if (m.find()) {
int hours = 0;
int minutes = 0;
if (m.group(1) != null) {
hours = Integer.parseInt(m.group(1));
}
if (m.group(2) != null) {
minutes = Integer.parseInt(m.group(2));
}
minutes = minutes + (hours * 60);
return minutes;
}
return 0;
}
public static String MinutesToGracePeriodStr(int minutes) {
int hours = minutes / 60;
int remMinutes = minutes % 60;
String hourStr = " hours";
if (hours == 1) {
hourStr = " hour";
}
String minStr = " minutes";
if (remMinutes == 1) {
minStr = " minute";
}
if (hours > 0) {
if (remMinutes == 0) {
return hours + hourStr;
}
return hours + hourStr + " " + remMinutes + minStr;
}
return remMinutes + minStr;
}
}