I'm working on the app that will start two alarms as the following:
Repeating alarm at every hour once it's started
Non-repeating alarm at either 1 to 10 hours based on the user selection
Both of the alarms are using ELAPSED_REALTIME_WAKEUP type. The problem I'm facing now is that the same codes work fine on Android 2.3.5 but Android 4.0.4. I have done some research on google and the problem doesn't seem to link to the issue of "no broadcast receiver will be triggered until the app is launched manually for the first time".
The following are the codes for setting up the pending intent for both the alarms:
private class AlarmEvent {
private Intent mIntent;
private PendingIntent mPendingIntent;
protected AlarmEvent(Context ctx, Class<?> cls, int pendingIntentType,
int requestCode, int flags, String intentAction) {
mIntent = new Intent(ctx, cls);
mIntent.setAction(intentAction);
switch(pendingIntentType) {
case PENDING_BROADCAST:
mPendingIntent = PendingIntent.getBroadcast(ctx, requestCode, mIntent, flags);
break;
case PENDING_SERVICE:
mPendingIntent = PendingIntent.getService(ctx, requestCode, mIntent, flags);
break;
default:
Log.w(TAG, "AlarmEvent:Invalid pending intent type=" + pendingIntentType);
}
}
protected PendingIntent getPendingIntent() {
return mPendingIntent;
}
}
The following are the codes to create the AlarmEvent:
//Create polling event
mPollingEvent = new AlarmEvent(mCtx, EventRouter.class, PENDING_BROADCAST,
POLLING_REQUEST_CODE, PendingIntent.FLAG_CANCEL_CURRENT,
EventRouter.POLLING_ACTION);
//Create monitor event
mReminderEvent = new AlarmEvent(mCtx, EventRouter.class, PENDING_BROADCAST,
REMINDER_REQUEST_CODE, PendingIntent.FLAG_CANCEL_CURRENT,
EventRouter.REMINDER_ACTION);
The following are the codes to start the alarms:
//Get AlarmManager instance
AlarmManager alarm = (AlarmManager)mCtx.getSystemService(AS);
long triggerAtTime = 0;
//Process the request
switch(type) {
case POLLING:
triggerAtTime = SystemClock.elapsedRealtime();
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime,
POLLING_INTERVAL_MS, mPollingEvent.getPendingIntent());
Log.d(TAG, "alarmRequest:Polling starts at " + System.currentTimeMillis());
break;
case REMINDER:
triggerAtTime = SystemClock.elapsedRealtime() + when;
alarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, mReminderEvent.getPendingIntent());
Log.d(TAG, "alarmRequest:Reminder to be fired after " + when + " ms");
break;
}
The following are the codes of the EventRouter:
public class EventRouter extends BroadcastReceiver {
public static final String POLLING_ACTION = "com.xxxxxx.POLLING";
public static final String REMINDER_ACTION = "com.xxxxxx.REMINDER";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "onReceive:Action=" + action);
if(POLLING_ACTION.equals(action)) {
//TODO: Polling handling
}
else if(REMINDER_ACTION.equals(action)) {
//TODO: Reminder handling to fire a status bar notification
}
}
}
The Android manifest for my app:
<application
...
...>
<activity
android:name=".AlarmActivity"
...>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name=".EventRouter" android:enabled="true" android:exported="true"/>
</application>
Both of the alarms are registered properly by executing the following command on terminal:
adb -d shell dumpsys alarm
However, only the POLLING alarm is delivered to my receiver. I have been struggling on this issue for a while and could not find a solution. Can you help to review the way I set up my pending intent to see if there is any mistake?
You should add your actions as an intent filter to your receiver declaration in your manifest file so that it can capture those actions.
<receiver android:name=".EventRouter" android:enabled="true" android:exported="true"
<intent-filter>
<action android:name="your.receiver.package.name.POLLING_ACTION"></action>
</intent-filter>
<intent-filter>
<action android:name="your.receiver.package.name.REMINDER_ACTION"></action>
</intent-filter>
<receiver/>
This is the first mistake that caught my eye.
Related
I've been stuck on this problem for days. I want to set an alarm and then send a notification when the alarm goes off. works well when the app is open, but it should work when the app is closed too.
here's the code:
Android Manifest:
<receiver android:name=".note.AlertReceiver"
android:enabled="true"
android:exported="true" ></receiver>
<service android:name=".note.AlarmNotificationService"
android:enabled="true"
android:exported="true" ></service>
AlertReceiver:
public class AlertReceiver extends BroadcastReceiver {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onReceive(Context context, Intent intent) {
Log.d("done", "done");
Intent serviceIntent = new Intent(context,AlarmNotificationService.class);
context.startService(serviceIntent);
}
}
AlarmNotificationService:
public class AlarmNotificationService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("done","done1");
return START_NOT_STICKY;
}
MainActivity:
#RequiresApi(api = Build.VERSION_CODES.N)
private void setAlarm(Calendar calendar){
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this , AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,REQUEST_CODE_alarm,intent,0);
alarmManager.setExact(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendingIntent);
}
setAlarm is triggered after TimePicker dialog is closed. I won't add the time picker code because it works with the app open.
when the app is closed. done won't appear in logcat so I'm assuming that there BroadcastReceiver isn't receiving anything
I haven't used AlarmManager with Service therefore it is hard for me to understand why it works only in foreground in your case, but, what I can do is give you a working example that executes in both foreground/background.
From there you should be able to figure out the solution that works for you.
Again, keep in mind that we are not going to use Service class.
AndroidManifest.xml
<receiver
android:name="com.example.name.Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>
Alarm.kt
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, Receiver::class.java)
// Used for filtering inside Broadcast receiver
intent.action = "MyBroadcastReceiverAction"
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
// In this particular example we are going to set it to trigger after 30 seconds.
// You can work with time later when you know this works for sure.
val msUntilTriggerHour: Long = 30000
val alarmTimeAtUTC: Long = System.currentTimeMillis() + msUntilTriggerHour
// Depending on the version of Android use different function for setting an
// Alarm.
// setAlarmClock() - used for everything lower than Android M
// setExactAndAllowWhileIdle() - used for everything on Android M and higher
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(alarmTimeAtUTC, pendingIntent),
pendingIntent
)
} else {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
alarmTimeAtUTC,
pendingIntent
)
}
BroadcastReceiver.kt
class Receiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// We use this to make sure that we execute code, only when this exact
// Alarm triggered our Broadcast receiver
if (intent?.action == "MyBroadcastReceiverAction") {
Log.d("ALARM", "RECEIVED")
}
}
}
The code is in Kotlin, but you should have no trouble using it in your project or just rewrite to Java.
I'm attempting to make it so my app runs some code once per day at 6AM. This works just fine when the app is open and in the foreground, but if the app is closed by swiping it away, the code is never called at the appropriate time.
AlarmReceiver.java (For testing purposes, I have it just trying to display a Toast to verify it runs)
public class AlarmReceiver extends BroadcastReceiver {
public static final String intentAction = "com.mpagliaro98.action.NOTIFICATIONS";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(intentAction)) {
Toast.makeText(context, "RECEIVER CALLED", Toast.LENGTH_LONG).show();
}
}
}
MainActivity.java (Where the alarm is being set)
public class MainActivity extends AppCompatActivity {
...
private void setRecurringAlarm() {
// Set this to run at 6am
Calendar updateTime = Calendar.getInstance();
updateTime.setTimeZone(TimeZone.getDefault());
updateTime.set(Calendar.HOUR_OF_DAY, 6);
updateTime.set(Calendar.MINUTE, 0);
updateTime.set(Calendar.SECOND, 0);
updateTime.set(Calendar.MILLISECOND, 0);
// Build the pending intent and set the alarm
Intent i = new Intent(AlarmReceiver.intentAction);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(),
0, i, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
assert am != null;
am.setRepeating(AlarmManager.RTC, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
}
}
AndroidManifest.xml (Just the relevant parts)
<uses-permission android:name="android.permission.SET_ALARM" />
<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.mpagliaro98.action.NOTIFICATIONS" />
</intent-filter>
</receiver>
I've read through dozens of similar problems to this on this site and elsewhere and I'm seriously at a loss for why this won't work. Any help would be appreciated.
Try changing receiver to
<receiver android:process=":remote" android:name="AlarmReceiver"></receiver>
Should I use android: process =":remote" in my receiver?
I have implemented a service to run with the alarm manager.
I read this link: Should I use android: process =“:remote” in my receiver?
I thought this would be a nice feature for my app, since i want the service to keep running after my app is down.
But when i add this line of configuration to my receiver on the manifest, my service stops being called.
Any clues?
Here is my receiver declaration:
This works:
<receiver
android:name=".service.MyAlarmReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name=".service.MyAlarmReceiver"></action>
</intent-filter>
</receiver>
This wont'n work:
<receiver
android:name=".service.MyAlarmReceiver"
android:enabled="true"
android:process=":remote"
android:exported="false">
<intent-filter>
<action android:name=".service.MyAlarmReceiver"></action>
</intent-filter>
</receiver>
public class MyAlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Time to start scan service!");
Intent intent = new Intent(context, BeaconFinderService.class);
context.startService(intent);
}
}
This is how i start my alarm manager:
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(getApplicationContext(), MyAlarmReceiver.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(getApplicationContext(), MyAlarmReceiver.REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), Constants.BLE_SERVICE_LOOP_TIME, pIntent);
When you configure your service to run in remote mode (android:process=":remote"), you will have to debug the process :remote instead as usual .
Personal bug:
So I was having an exception when trying to access FirebaseUser on the service. When in remote mode, you can't access the FirebaseUser, since your process runs on another context.
I had to pass the user through intent extras when initializing the service.
That was all!
I have done an app as tutorial to learn how to restart deleted alarms after phone is rebooted. After reboot BroadcastReceiver receives BOOT_COMPLETED action and launches a service, which restarts all alarms. Alarms create notification when they are called. After first tests I have received notifications at expected time and then forgot about this tutorial app and didn't turn the phone off.
However, I'm still getting notifications on my screen as if the app has restarted alarms again. During the day I have received twice and all of them are unclear why. The only thing that may launch the restarting alarms is BOOT_COMPLETED action. What's going wrong here?
Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.marat.recyclerviewtutorial">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
// list of activities
<service android:name=".BootService"/>
<receiver android:name=".AlarmBroadcastReceiver"/>
<receiver android:name=".RestartAlarmsReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
RestartAlarmsReceiver.java
public class RestartAlarmsReceiver extends BroadcastReceiver {
private static final String TAG = "myTag";
#Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent i = new Intent(context, BootService.class);
ComponentName service = context.startService(i);
if (null == service) {
// something really wrong here
Log.e(TAG, "Could not start service ");
}
else {
Log.e(TAG, "Successfully started service ");
}
} else {
Log.e(TAG, "Received unexpected intent " + intent.toString());
}
}
}
BootService.java
public class BootService extends Service {
private static final String TAG = "myTag";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
Database db = new Database(this);
db.open();
ArrayList<ArrayList<String>> data = new ArrayList<ArrayList<String>>();
data = db.getData();
db.close();
Log.d(TAG, "db is openned");
for (int i=0; i<data.size(); i++) {
Intent notif = new Intent(this, AlarmBroadcastReceiver.class);
notif.putExtra("Text", data.get(i).get(2));
notif.putExtra("Position", data.get(i).get(0));
int sec = Integer.parseInt(data.get(i).get(3));
Log.d(TAG, "intent is openned");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, Integer.parseInt(data.get(i).get(0)), notif, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (sec * 1000), pendingIntent);
Log.d(TAG, "Alarm is restarted");
}
Log.d(TAG, "before returning service");
return Service.START_STICKY;
}
}
It's already huge portion of code. But if you will need other parts of my app I will include them.
Thanks in advance!
I think this is because of START_STICKY. I think during the day the system closes your running Service to free resources, and START_STICKY forces it to restart. And on restart onStartCommand() is triggered again.
The decision may to use IntentService instead. I don't see the need of using Service here.
I have 3 applications that are dependent on each other. for instance, Client app, Browser and launcher. My requirement is when the client is uninstalled(only when the client) i want the other two apps to be uninstalled as well. For this what i have done so far is, i have written a broadcast receiver(in both the apps) that listens for package removed. if the package removed is my client, i start an alarm that launches the uninstall procedure(individually on both apps). Why the alarm? because i want the uninstall pop up to come up til the user uninstalls the app. The issue i am currently facing is that, sometimes the launcher app does not get the broadcast or so i think. and hence it does not initiate the uninstall. Sometimes it does and sometimes it doesn't. I am not able to figure out the cause of this problem. below is the code written in the launcher:
The broadcast receiver :
public class UnistallBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {
String packagename = intent.getData().getSchemeSpecificPart();
if (packagename.equalsIgnoreCase("com.android.nanoheal")) {
Calendar calendar = new GregorianCalendar();
calendar.setTimeZone(TimeZone.getDefault());
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
Intent intent1 = new Intent(context, AlarmIntent.class);
intent1.putExtra("appnamel", "com.nanoheal.launcher");
PendingIntent pi = PendingIntent.getBroadcast(context, 325,
intent1, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 1000 * 30, pi);
}
}
}
}
the Alarm Intent:
public class AlarmIntent extends BroadcastReceiver {
Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
Log.d("AlarmIntent", "Intent fired by Launcher");
mContext = context;
try {
String appLauncher = intent.getStringExtra("appnamel");
if (appLauncher != null) {
if (isAppInstalled(appLauncher)) {
Uri packageURI2 = Uri.parse("package:" + appLauncher);
Intent uninstallIntent2 = new Intent(
Intent.ACTION_UNINSTALL_PACKAGE, packageURI2);
uninstallIntent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(uninstallIntent2);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean isAppInstalled(String packageName) {
PackageManager pm = mContext.getPackageManager();
boolean installed = false;
try {
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
installed = true;
} catch (PackageManager.NameNotFoundException e) {
installed = false;
}
Log.d("AlarmIntent", "Launcher-IsAppInstalled " + packageName + " "
+ installed);
return installed;
}
}
I am not very certain about the details of how and why.
But i changed this
<receiver android:name="package.UnistallBroadcast" >
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
to
<receiver android:name="package.UnistallBroadcast" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
and it worked fine. As far as i know if the priority is set for a receiver the one with the highest priority should get the action first. but strangely, in my case i was not getting the action for the receiver i gave priority.