package com.alimuzaffar.ramadanalarm.scheduler;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Build;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;
import com.alimuzaffar.ramadanalarm.BuildConfig;
import com.alimuzaffar.ramadanalarm.Constants;
import com.alimuzaffar.ramadanalarm.R;
import com.alimuzaffar.ramadanalarm.RingAlarmActivity;
import com.alimuzaffar.ramadanalarm.util.AppSettings;
import com.alimuzaffar.ramadanalarm.util.PrayTime;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.TimeZone;
/**
* When the alarm fires, this WakefulBroadcastReceiver receives the broadcast Intent
* and then starts the IntentService {@code SampleSchedulingService} to do some work.
*/
public class SalaatAlarmReceiver extends WakefulBroadcastReceiver implements Constants {
// The app's AlarmManager, which provides access to the system alarm services.
private AlarmManager alarmMgr;
// The pending intent that is triggered when the alarm fires.
private PendingIntent alarmIntent;
@Override
public void onReceive(Context context, Intent intent) {
// BEGIN_INCLUDE(alarm_onreceive)
/*
* If your receiver intent includes extras that need to be passed along to the
* service, use setComponent() to indicate that the service should handle the
* receiver's intent. For example:
*
* ComponentName comp = new ComponentName(context.getPackageName(),
* MyService.class.getName());
*
* // This intent passed in this call will include the wake lock extra as well as
* // the receiver intent contents.
* startWakefulService(context, (intent.setComponent(comp)));
*
* In this example, we simply create a new intent to deliver to the service.
* This intent holds an extra identifying the wake lock.
*/
String prayerName = intent.getStringExtra(EXTRA_PRAYER_NAME);
long prayerTime = intent.getLongExtra(EXTRA_PRAYER_TIME, -1);
boolean timePassed = (prayerTime != -1 && Math.abs(System.currentTimeMillis() - prayerTime) > FIVE_MINUTES);
AppSettings settings = AppSettings.getInstance(context);
if (settings.isAlarmSetFor(0)) {
if (!timePassed) {
Intent service = new Intent(context, SalaatSchedulingService.class);
service.putExtra(EXTRA_PRAYER_NAME, prayerName);
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, service);
// END_INCLUDE(alarm_onreceive)
// START THE ALARM ACTIVITY
Intent newIntent = new Intent(context, RingAlarmActivity.class);
Log.d("SalaatAlarmReceiver", "Alarm Receiver Got " + prayerName);
newIntent.putExtra(EXTRA_PRAYER_NAME, prayerName);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
}
//SET THE NEXT ALARM
setAlarm(context);
}
}
// BEGIN_INCLUDE(set_alarm)
/**
* Sets a repeating alarm that runs once a day at approximately 8:30 a.m. When the
* alarm fires, the app broadcasts an Intent to this WakefulBroadcastReceiver.
*
* @param context
*/
public void setAlarm(Context context) {
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, SalaatAlarmReceiver.class);
Calendar now = Calendar.getInstance(TimeZone.getDefault());
now.setTimeInMillis(System.currentTimeMillis());
// Set the alarm's trigger time to 8:30 a.m.
int alarmIndex = 0;
Calendar then = Calendar.getInstance(TimeZone.getDefault());
then.setTimeInMillis(System.currentTimeMillis());
AppSettings settings = AppSettings.getInstance(context);
double lat = settings.getLatFor(alarmIndex);
double lng = settings.getLngFor(alarmIndex);
LinkedHashMap<String, String> prayerTimes = PrayTime.getPrayerTimes(context, alarmIndex, lat, lng, PrayTime.TIME_24);
List<String> prayerNames = new ArrayList<>(prayerTimes.keySet());
boolean nextAlarmFound = false;
String nameOfPrayerFound = null;
for (String prayer : prayerNames) {
if (!isAlarmEnabledForPrayer(settings, prayer, alarmIndex)) {
continue;
}
then = getCalendarFromPrayerTime(then, prayerTimes.get(prayer));
if (then.after(now)) {
// this is the alarm to set
nameOfPrayerFound = prayer;
nextAlarmFound = true;
break;
}
}
if (!nextAlarmFound) {
for (String prayer : prayerNames) {
if (!isAlarmEnabledForPrayer(settings, prayer, alarmIndex)) {
continue;
}
then = getCalendarFromPrayerTime(then, prayerTimes.get(prayer));
if (then.before(now)) {
// this is the next day.
nameOfPrayerFound = prayer;
nextAlarmFound = true;
then.add(Calendar.DAY_OF_YEAR, 1);
break;
}
}
}
if (!nextAlarmFound) {
return; //something went wrong, abort!
}
nameOfPrayerFound = getPrayerNameFromIndex(context, getPrayerIndexFromName(nameOfPrayerFound));
intent.putExtra(EXTRA_PRAYER_NAME, nameOfPrayerFound);
intent.putExtra(EXTRA_PRAYER_TIME, then.getTimeInMillis());
alarmIntent = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
//lollipop_mr1 is 22, this is only 23 and above
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, then.getTimeInMillis(), alarmIntent);
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
//JB_MR2 is 18, this is only 19 and above.
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, then.getTimeInMillis(), alarmIntent);
} else {
//available since api1
alarmMgr.set(AlarmManager.RTC_WAKEUP, then.getTimeInMillis(), alarmIntent);
}
// SET PASSIVE LOCATION RECEIVER
Intent passiveIntent = new Intent(context, PassiveLocationChangedReceiver.class);
PendingIntent locationListenerPassivePendingIntent = PendingIntent.getActivity(context, PASSIVE_LOCATION_ID, passiveIntent, PendingIntent.FLAG_UPDATE_CURRENT);
requestPassiveLocationUpdates(context, locationListenerPassivePendingIntent);
// Enable {@code SampleBootReceiver} to automatically restart the alarm when the
// device is rebooted.
ComponentName receiver = new ComponentName(context, SalaatBootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
// END_INCLUDE(set_alarm)
/**
* Cancels the alarm.
*
* @param context
*/
// BEGIN_INCLUDE(cancel_alarm)
public void cancelAlarm(Context context) {
// If the alarm has been set, cancel it.
if (alarmMgr == null) {
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
if (alarmMgr != null) {
if (alarmIntent == null) {
Intent intent = new Intent(context, SalaatAlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
alarmMgr.cancel(alarmIntent);
//REMOVE PASSIVE LOCATION RECEIVER
Intent passiveIntent = new Intent(context, PassiveLocationChangedReceiver.class);
PendingIntent locationListenerPassivePendingIntent = PendingIntent.getActivity(context, PASSIVE_LOCATION_ID, passiveIntent, PendingIntent.FLAG_UPDATE_CURRENT);
removePassiveLocationUpdates(context, locationListenerPassivePendingIntent);
}
// Disable {@code SampleBootReceiver} so that it doesn't automatically restart the
// alarm when the device is rebooted.
ComponentName receiver = new ComponentName(context, SalaatBootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
// END_INCLUDE(cancel_alarm)
public void requestPassiveLocationUpdates(Context context, PendingIntent pendingIntent) {
long oneHourInMillis = 1000 * 60 * 60;
long fiftyKinMeters = 50000;
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
try {
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
oneHourInMillis, fiftyKinMeters, pendingIntent);
} catch (SecurityException se) {
Log.w("SetAlarmReceiver", se.getMessage(), se);
//do nothing. We should always have permision in order to reach this screen.
}
}
public void removePassiveLocationUpdates(Context context, PendingIntent pendingIntent) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
try {
locationManager.removeUpdates(pendingIntent);
} catch (SecurityException se) {
//do nothing. We should always have permision in order to reach this screen.
}
}
private int getPrayerIndexFromName(String prayerName) {
String name = prayerName.toLowerCase();
char index = name.charAt(0);
switch (index) {
case 'f':
return 0;
case 'd':
return 1;
case 'a':
return 2;
case 'm':
return 3;
case 'i':
return 4;
}
return -1;
}
private String getPrayerKeyFromIndex(AppSettings settings, int prayerIndex, int index) {
String key = null;
switch (prayerIndex) {
case 0:
key = settings.getKeyFor(AppSettings.Key.IS_FAJR_ALARM_SET, index);
break;
case 1:
key = settings.getKeyFor(AppSettings.Key.IS_DHUHR_ALARM_SET, index);
break;
case 2:
key = settings.getKeyFor(AppSettings.Key.IS_ASR_ALARM_SET, index);
break;
case 3:
key = settings.getKeyFor(AppSettings.Key.IS_MAGHRIB_ALARM_SET, index);
break;
case 4:
key = settings.getKeyFor(AppSettings.Key.IS_ISHA_ALARM_SET, index);
break;
}
return key;
}
private String getPrayerNameFromIndex(Context context, int prayerIndex) {
String prayerName = null;
switch (prayerIndex) {
case 0:
prayerName = context.getString(R.string.fajr);
break;
case 1:
prayerName = context.getString(R.string.dhuhr);
break;
case 2:
prayerName = context.getString(R.string.asr);
break;
case 3:
prayerName = context.getString(R.string.maghrib);
break;
case 4:
prayerName = context.getString(R.string.isha);
break;
}
return prayerName;
}
private boolean isAlarmEnabledForPrayer(AppSettings settings, String prayer, int alarmIndex) {
if (prayer.equalsIgnoreCase("sunrise") || prayer.equalsIgnoreCase("sunset")) {
return false;
}
int prayerIndex = getPrayerIndexFromName(prayer);
String key = getPrayerKeyFromIndex(settings, prayerIndex, alarmIndex);
return settings.getBoolean(key);
}
private Calendar getCalendarFromPrayerTime(Calendar cal, String prayerTime) {
String[] time = prayerTime.split(":");
cal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(time[0]));
cal.set(Calendar.MINUTE, Integer.valueOf(time[1]));
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
}