I am trying to follow this answer However, it is not working in simulator nor on my phone so I have questions on the simulator logs and phone and rebooting to simulate this
Well, I found the answer
Android 8/9 Notification scheduling
I had no idea you have to google for versions.
You should look into setExactAndAllowWhileIdle From what I understand it will execute regardless of if the phone is in doze or not and exactly at the specified time.
You answered their own question here but because that answer utilizes the WorkManager API which "is intended for work that is deferrable—that is, not required to run immediately—and required to run reliably even if the app exits or the device restarts" (source) I feel that utilizing AlarmManager is the best way to handle what it seems that you are trying to do.
However, it should be noted that this will still require the alarms to be re-registered on every boot, which may seem difficult given OP's questions and concerns, but I have addressed those below. Though, you should be careful about what you do if you boot after an alarm was supposed to trigger. For example, suppose you are making an reminder app that you would like to be able to schedule notifications to go of and happen stance your phone powers off just before a reminder was supposed to be triggered and it powers on 5 minutes after it was supposed to be triggered. Do you still trigger the notification? Do you reschedule it with AlarmManager? Do you just ignore it all together? If you do trigger it, do you want it to be triggered before the user unlocks there device or is after they unlock the device acceptable?
The above questions are things that would change the exact implementation, however the basics are the same across the board.
<application>
<!-- ... -->
<receiver android:name="RECEIVER_NAME">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<!--<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/> this action is sent before the user unlocks their device-->
</intent-filter>
</receiver>
<!-- ... -->
</application>
public class PollReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
if (intent.getAction() != null) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, PollReceiver.class);//this will send the intent back to this class, you can make another broadcast receiver for handling the alarm going off though
i.setAction("ALARM_ACTION");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, i, 0);
long triggerTime = System.currentTimeMillis() + 60000; //replace this with when you want your alarm to go off (this will trigger 1 minute from now)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
} else if (intent.getAction().equals("ALARM_ACTION")) {
//Show notification or make noise, whatever you are supposed to do when the alarm goes off
}
}
}
}
Addressing the various questions/concerns throughout the question
QUESTION 1: Can the simulator not simulate [reboots] correctly?
It can, however, the issue is that you are running the project to start the emulator, which is not how a phone is powered on. Rather than pressing the run button in Android Studio to start the emulator, you should start the emulator by itself via Tools > AVD Manager > Play Button (under the actions column for the corresponding AVD) or see below for a way to restart the AVD while it is running.
I would think I could dump logs somehow to android studio?
Yes, you can, at the bottom of Android Studio there should be a tab named Logcat. This tab is where any connected virtual devices or physical devices will output logs (you will have to specify which device you would like to view if there are multiple connected). Also, there is the option to use the command line, via adb logcat
, or it is also possible via the command line to trigger a reboot via adb reboot
. You can also combine the two so that as soon as the phone is able to have adb connected you start listening to logcat, via adb reboot && adb wait-for-device logcat
. This works for both physical devices as well as the emulator, the only issue is that this outputs the logs for everything, if you want to search for specific text you can use adb reboot && adb wait-for-device logcat | grep "string-to-search-for"
(Windows can replace "grep" with "findstr")
WEIRD SCENARIO 1: If I have TWO android studio projects open and open my personal app and then open the sample link app AFTER my project, I see a Toast "Alarms scheduled". I however can find no logs on PollReceiver until that alarm goes off 5 seconds later. I was expecting to see a log from PollReceiver on start but never see that until 5 seconds. Another run of this later yielded no logs (except the toast message popped up so I know it ran that code...very weird). I added a log message then to ScheduledServiceDemoActivity and now I can't reproduce 0 logs like that one time.
The behavior you describe in the first part is correct and should happen regardless of how many Android Studio projects you have open and which app is run first. The application makes a repeating alarm that will go off in 5 seconds and then every 15 minutes after. If you added the log to the onReceive
method, you won't see it until that method is called, which it isn't until the alarm goes off. As for the second part, where you didn't get any logs, you may not have let the application run for 5 seconds so no logs would be printed. It should be noted that when you run the application through Android Studio it is not exactly the same as if you run it from the phone by clicking on the icon. Which would also explain why you were unable to recreate it after adding the log into the activity.
WEIRD SCENARIO 2: I REBOOT the phone(or it keeps launching my app and scenario 1 keeps working). Then I ONLY boot the sample link app, nothing ever happens. I wait for 90 seconds and nothing.
The sample application should trigger a log approximately every 15 minutes, not 90 seconds (900,000ms not 90,000ms). However, the sample application should trigger a log 5 seconds (not exactly 5 seconds though because of the way Android works) after starting the app, or after a reboot.
I can never get PollReceiver to fire on startup. ScheduledServiceDemoActivity seems to be the true entry point and I never added a service to my above code as I didn't want one...just wanted to be notified of being booted up to reschedule alarms. This then leads me to the possible conclusion the ScheduledServiceDemoActivity is there to fire on certain devices on bootup and the PollReceiver is for other devices on bootup? If so, what simulators can simluate this other bootup scenario?
You should really familiarize yourself with the application lifecycle and activity lifecycle. ScheduledServiceDemoActivity is there to be what opens when you start the application via running in Android Studio or by pressing its icon on the launcher, but the BroadcastReceiver is also another entry point for the application. In this case, it is triggered when Android sends an Intent with the action ACTION_BOOT_COMPLETED. ScheduledServiceDemoActivity will never be started on boot. The bundled AVD can properly simulate the bootup scenario and it will trigger PollReceiver.
EDIT (I had another thought) On my samsung phone, I checked the permissions and there is only THREE even though I added these 4 lines in my manifest
<uses-permission android:name="android.permission.CALL_PHONE" /> <!-- so we can send a text --> <uses-permission android:name="android.permission.SEND_SMS" /> <!-- So we can reschedule alarms that went off while powered off --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- read contacts so they can easily choose their friends --> <uses-permission android:name="android.permission.READ_CONTACTS" />
The receive boot is not in there. is this the issue? OR do phones not list the receive boot completed to users as it might be confusing?
Most variants of Android (if not all) that come on devices will not display the permissions that are considered "normal" by Google. Essentially the only permissions that will be displayed there are the ones that are not automatically granted at install time and are considered "dangerous" as they can impact the user's stored data or the behavior of other apps.
Try to add this to your intent-filter in your manifest:
<receiver android:name=".biz.alarm.BootupReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
It helped me when I got similar issue with some devices.