2016-12-15 2 views
1

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

Моя текущая проблема со следующим кодом заключается в том, что при достижении следующего кода: 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's 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's time that the user wants if using Android Marshmallow 
      } else { 
       hourToSet = alrmTimePicker.getCurrentHour();       // gets the TimePicker's 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's 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

Любая помощь будет принята с благодарностью.

Edit:

Это решение, которое мы придумали в случае, если это поможет кто-нибудь:

Ник: Так широковещательный делает запустить службу, которая запускает уведомление, но вопрос, где звук должен быть изменен, а это не так?

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

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.

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

+0

Возможно, это не проблема, но сначала попробуйте это и посмотрите, не изменит ли она что-либо. Добавьте 'calendar.setTimeInMillis (System.currentTimeMillis());' прямо после этой строки: 'Calendar calendar = Calendar.getInstance();' в вашем 'AlarmStartPage'. –

+0

Добавление этой строки помогло так, чтобы она больше не создавала тревогу в текущее время, а скорее в то время, которое задано TimePicker. Спасибо! Однако по какой-то причине, даже если я установил точку останова в AlarmReceiver.java, программа никогда не войдет в нее (даже несмотря на то, что будильник в конечном итоге звонит и делается тост). –

+0

Прохладный! Я добавил ответную часть для этой части вопроса. Я не совсем понимаю, что вы имеете в виду в своем AlarmReceiver, чего именно вы пытаетесь достичь? Я надеюсь, что все пойму. –

ответ

1

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

calendar.setTimeInMillis(System.currentTimeMillis()); 

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^