Настройка будильника для приложения Android с помощью AlarmReceiver и OnBootReceiver

64
8

Я просмотрел многочисленные обучающие материалы StackOverflow и Youtube, чтобы создать службу аварийной сигнализации (которая будет использоваться как часть более крупного приложения, которое я создаю), но кажется, что все они дают разные, неработающие ответы или полагаются на устаревшие методы, которые больше не работают.

Моя текущая проблема со следующим кодом заключается в том, что, когда я достигаю следующего кода: alrmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendInt); он, похоже, не отправляет соответствующее время диспетчеру тревоги (он более или менее всегда отправляет текущее время).

Тем не менее, я знаю, что calendar.getTimeInMillis() дает мне время, которое я установил (корректно изменяется текстовый редактор setAlarmText). Мне было интересно, есть ли у кого-нибудь опыт?

Кроме того, класс AlarmReceiver никогда не называется, даже если у меня создалось впечатление, что AlarmManager позаботится об этом для вас.

Код прилагается ниже:

public class AlarmStartPage extends Activity {
AlarmManager alrmMgr;
PendingIntent pendInt;
private TimePicker alrmTimePicker;
private static AlarmStartPage inst;
Intent myIntent;
private TextView alrmStatusView;'

protected static AlarmStartPage instance() {
return inst; // returns an instance of the current Activity
}

@Override
public void onStart() {
super.onStart(); // calls the super classes onStart, and then sets the instance to the current one
inst = this;
}

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_start_page); // sets the various buttons and other containers on the website
alrmTimePicker = (TimePicker) findViewById(R.id.alarmTimePicker);
ToggleButton alrmTogg = (ToggleButton) findViewById(R.id.toggleAlarmButton);
alrmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alrmStatusView = (TextView) findViewById(R.id.alarmStatus);

setVolumeControlStream(AudioManager.STREAM_ALARM); // sets the volume to be controlled to the audiomanager so that the user can control the alarm volume
}

public void onToggleClicked(View view) {
if (((ToggleButton) view).isChecked()) {
Log.d("MyActivity", "Alarm On!");
int hourToSet, minuteToSet; // if the toggle button is pushed, then it creates an alarm. Otherwise it cancels a previously created alarm
Calendar calendar = Calendar.getInstance();
if (Build.VERSION.SDK_INT >= 23) // the code here and the one below in the else statement are identical except for which API they cater to
{
hourToSet = alrmTimePicker.getHour();
minuteToSet = alrmTimePicker.getMinute(); // gets the TimePicker time that the user wants if using Android Marshmallow
} else {
hourToSet = alrmTimePicker.getCurrentHour(); // gets the TimePicker time that the user wants if using any Android Lolipop or below
minuteToSet = alrmTimePicker.getCurrentMinute();
}
// this is the code to actually do the "magic" of the REM time
int currhr = calendar.get(Calendar.HOUR_OF_DAY); // gets the current time from the system clock
int currmin = calendar.get(Calendar.MINUTE);

boolean lessThan90 = false; // boolean to check if the current alarm is less than 90 Minutes away (1 REM cycle)
int hrDiff = 0;
int minDiff = 0;

if (hourToSet >= currhr) {
hrDiff = hourToSet - currhr; // calculating the difference between the current hour and the hour of the alarm to get the difference in the time
if (hrDiff == 0) {
if (minuteToSet > currmin) // if the alarm is for after the current time, but same hour, then it is less than 1 hour away
minDiff = minuteToSet - currmin;
else {
hrDiff = 23; // otherwise the alarm us for more than 23 hours away (same hour, but earlier time)
minDiff = 60 - (currmin - minuteToSet);
}
} else {
if (minuteToSet > currmin)
minDiff = minuteToSet - currmin;
else {
hrDiff--;
minDiff = 60 - (currmin - minuteToSet);
}
}

if (60 * hrDiff + minDiff < 90) // if prior to the 15 min shift, the alarm time is less than 90 minutes away, then it will be set as the alarm time
lessThan90 = true;
}

currmin += 15; // add 15 min to the current time, and below, change the hour and minute accordingly
if (currmin >= 60) {
currmin = currmin % 60;
currhr++;
if (currhr >= 24)
currhr = currhr % 24;
}
if (!lessThan90) // only if the alarm time is more than 90 minutes away, it will try to do this (which it will try to do
{ // by defualt since lessThan90 is initalized to false (or it is set to true by the above if else statement
if (hourToSet >= currhr) {
hrDiff = hourToSet - currhr;
if (hrDiff == 0) // same logic as earlier, checks if the same hour as the alarm, then checks if the alarm is before or after the current time
{
if (minuteToSet > currmin) // if the alarm is set for a later time (which means that it is less than 90 minutes away)
minDiff = minuteToSet - currmin;
else // otherwise the alarm is set for 23 hours and some minutes away
{
minDiff = 60 - (currmin - minuteToSet);
hrDiff = 23;
}
} else {
if (minuteToSet > currmin)
minDiff = minuteToSet - currmin;
else {
hrDiff--;
minDiff = 60 - (currmin - minuteToSet);
}
}
} else if (hourToSet < currhr) // if the alarm time is before the current time (then it must loop over midnight and restart from 0 again)
hrDiff = 24 - (currhr - hourToSet);
}

int totalMinutesInBetween = 60 * hrDiff + minDiff;

if (totalMinutesInBetween < 90) // if the total minutes between the alarm and the current time (after the 15 min shift) is less than 90 minutes
lessThan90 = true; // it is less than 1 REM shift away

if (!lessThan90) // If there are more than 90 minutes of difference, then a REM cycle is ACTUALLY possible
{
int possibleRem = totalMinutesInBetween / 90; // the possible amount of REM cycles between now and the alarm time
for (int i = 0; i < possibleRem; i++) {
currhr++; // the time is altered by 90 minute cycles (looping around after 60 minutes or after 24 hours) to get the appropiate REM time
if (currhr >= 24)
currhr = currhr % 24;
currmin += 30;
if (currmin >= 60) {
currmin = currmin % 60; // looping the minutes over 60
currhr++;
if (currhr >= 24)
currhr = currhr % 24; // looping the hours after 24 hours
}
}
hourToSet = currhr;
minuteToSet = currmin;
}

calendar.set(Calendar.HOUR_OF_DAY, hourToSet); // the calendar sets the final REM time
calendar.set(Calendar.MINUTE, minuteToSet);

myIntent = new Intent(AlarmStartPage.this, AlarmReceiver.class);
pendInt = PendingIntent.getBroadcast(AlarmStartPage.this, 0, myIntent, 0); // new intent as well as a pending intent to notify the system of the alarm (uses Alarm Receiver and Alarm Service)

alrmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendInt); // alarmmanager is used to set the alarm
if (minuteToSet > 9)
setAlarmText("An alarm has been placed for " + hourToSet + ":" + minuteToSet + " (in military time). If you shut down" +
" this app, please do not open it again until the alarm that you set is over (otherwise the alarm will reset itself)."); // alarm text is changed to notify the user
else
setAlarmText("An alarm has been placed for " + hourToSet + ":0" + minuteToSet + " (in military time). If you shut down" +
" this app, please do not open it again until the alarm that you set is over (otherwise the alarm will reset itself).");
} else {
alrmMgr.cancel(pendInt); //cancels the current Intent (effectively stopping the alarm)
stopService(myIntent);
setAlarmText("The previous alarm was canceled."); // changes the text on the textbox under the time picker
Log.d("MyActivity", "Alarm OFF");
}
}

public void setAlarmText(String textToShow) {
alrmStatusView.setText(textToShow); // sets the text for the textbox below the TimePicker
}

@Override
public void onDestroy() {
super.onDestroy(); // calls the super classes destroy method to destroy the activity
}
}

AlarmReceiver:

public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {'

Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); //this will sound the alarm tone
Log.d("Creating Alarm", "Used ALARM for ringtone " + alarmUri);
System.out.println("logging that it got to this part");
if (alarmUri == null) {
Log.d("Creating Alarm", "Used the notification instead of alarm for ringtone");
alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}

Ringtone ringtone = RingtoneManager.getRingtone(context, alarmUri);

ringtone.play(); // plays the ringtone of the phone as the alarm

Intent service_intent = new Intent(context, AlarmService.class);
context.startService(service_intent);
//ComponentName comp = new ComponentName(context.getPackageName(), AlarmService.class.getName());
//startWakefulService(context, (intent.setComponent(comp))); // sends the notification message and wakes up the phone
setResultCode(Activity.RESULT_OK);
}
}

AlarmService.java:

public class AlarmService extends IntentService {
private NotificationManager alarmNotificationManager;'

public AlarmService() {
super("AlarmService");
}

@Override
public void onHandleIntent(Intent intent) {
sendNotification("Wake Up! Your alarm has been rung!!!!"); // sends the notification to the phone that the alarm is ringing
}

private void sendNotification(String msg) {
Log.d("AlarmService", "Preparing to send notification...: " + msg);
alarmNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, AlarmStartPage.class), 0); // creates the notification and sets the icon for the notification

NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(
this).setContentTitle("Alarm").setSmallIcon(R.mipmap.ic_launcher).setStyle(new NotificationCompat.BigTextStyle().bigText(msg)).setContentText(msg);

alarmNotificationBuilder.setContentIntent(contentIntent);

alarmNotificationManager.notify(1, alarmNotificationBuilder.build());
Log.d("AlarmService", "Notification sent.");
}
}

OnBootReceiver:

public class OnBootReceiver extends BroadcastReceiver {
private static final int WAITING_PERIOD = 10000; // 10 seconds (aka 10000 milliseconds)'

@Override
public void onReceive(Context context, Intent intent)
{
AlarmManager aMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); // allows previously created alarms to still exist on bootup.
Intent i = new Intent(context, AlarmReceiver.class);
PendingIntent pI = PendingIntent.getBroadcast(context, 0, i, 0);

aMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), WAITING_PERIOD, pI);
}
}

Код также можно найти на странице https://github.com/sahilmgandhi/REM.my/tree/master/app/src/main/java/com/sahilmgandhi/remmy

Любая помощь будет оценена по достоинству.

Редактировать:

Это решение, с которым мы столкнулись, если это кому-то помогает:

Ник: Таким образом, трансляция запускает службу, которая запускает уведомление, но проблема заключается в том, что звук должен быть изменен, а это не так?

Nick: Хорошо, есть ли у вас какая-то причина, по которой у вас есть звуковая игра от приемника, и не воспроизводить звук прямо из объекта уведомления? Я думаю, что это сработает

Me: Хм, я следовал нескольким различным учебникам, и все они, похоже, были в приемнике.

Ник: в сервисе метода sendNotification попытайтесь изменить это:

    private void sendNotification(String msg) {
Log.d("AlarmService", "Preparing to send notification...: " + msg);
alarmNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, AlarmStartPage.class), 0); // creates the notification and sets the icon for the notification

Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(
this)
.setContentTitle("Alarm")
.setSmallIcon(R.mipmap.ic_launcher)
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg)
.setSound(soundUri);

alarmNotificationBuilder.setContentIntent(contentIntent);

alarmNotificationManager.notify(1, alarmNotificationBuilder.build());
Log.d("AlarmService", "Notification sent.");
}

Ник: Довольно уверен, что теперь правильно звучит уведомление. Старый способ с Ringtone, вероятно, устарел. Прокомментируйте часть мелодии звонка на данный момент

Ник: И правильный способ запуска службы из AlarmManager состоит в том, чтобы он запускал BroadcastReceiver, который затем запускает IntentService.

Nick: Я точно забыл, почему это так, но вы определенно хотите сделать это именно так. Я думал о запуске всего в приемнике, но лучше всего это сделать, будильник → приемник → IntentService со всем кодом в нем

спросил(а) 2021-01-25T08:57:10+03:00 6 месяцев назад
1
Решение
64

Чтобы запустить будильник в AlarmStartPage время, добавьте эту строку после того, как вы AlarmStartPage экземпляр своего объекта Calendar в своей активности AlarmStartPage:

calendar.setTimeInMillis(System.currentTimeMillis());

Таким образом, ваш код должен выглядеть так, когда вы создаете свой Календарь:

Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());

Это позволит убедиться, что другие параметры Календаря установлены правильно, потому что перед тем, как вы просто установили час/минуту, но остальные не были полностью настроены.

ответил(а) 2021-01-25T08:57:10+03:00 6 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема