Broadcast Receiver Not Working After Device Reboot in Android
Here's a tested and working solution on both the devices that you mentioned, OnePlus and Mi.
As you said the auto-start prevention feature on OnePlus and Mi devices prevent apps from starting up their services automatically on boot complete so as to improve the overall device boot speed and battery performance. However, there's a workaround to get your app working even when this feature is turned on.
I have noticed that if you have an AccessibilityService
in your app and it is turned on by the user, then your app passes the filter that these manufacturers apply and the app receives it's boot complete event and any other BroadcastReceiver
works as expected.
The possible explanation of this trick can be that since AccessibilityService
is a system level service, so by registering your own service you are passing the certain filter applied by these manufacturers and as soon as your custom AccessibilityService
gets triggered by the OS, your app becomes active in receiving the eligible BroadcastReceiver
that you had registered.
So, here's how to do it,
Start by adding this permission to your AndroidManifest.xml
,
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"/>
This will allow you to register your app's AccessibilityService
with the system.
Now, add a very basic configuration for your AccessibilityService
by creating a file for example my_accessibility_service.xml
inside XML folder under your res folder in your project.
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackSpoken"
android:description="@string/service_desc"
android:notificationTimeout="100"/>
There's just one more step left to do, define your custom AccessibilityService
in your project,
public class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) { }
@Override
public void onInterrupt() {
}
}
Note, since you're not needing the AccessibilityService
for any purpose rather than this workaround, you can leave the overridden methods empty.
Finally, just declare your AccessibilityService
in your AndroidManifest.xml
,
<service
android:name=".MyAccessibilityService"
android:label="@string/app_name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/my_accessibility_service"/>
</service>
That's all. Now within your app, just ask your users to turn on the accessibility service for your app from the settings and leave it on and voila! Your app works fine on all devices even where the OS puts a filter on which apps should auto-start on boot.
EDIT 1
Here's how you can check if accessibility service is turned ON or not for your app,
private static final int ACCESSIBILITY_ENABLED = 1;
public static boolean isAccessibilitySettingsOn(Context context) {
int accessibilityEnabled = 0;
final String service = context.getPackageName() + "/" + MyAccessibilityService.class.getCanonicalName();
try {
accessibilityEnabled = Settings.Secure.getInt(
context.getApplicationContext().getContentResolver(),
android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
} catch (Settings.SettingNotFoundException e) {
Log.e("AU", "Error finding setting, default accessibility to not found: "
+ e.getMessage());
}
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
if (accessibilityEnabled == ACCESSIBILITY_ENABLED) {
String settingValue = Settings.Secure.getString(
context.getApplicationContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
String accessibilityService = mStringColonSplitter.next();
if (accessibilityService.equalsIgnoreCase(service)) {
return true;
}
}
}
}
return false;
}
Hope this helps.
BroadcastReceiver is not working after reboot
I just found the solution!
AndroidManifest.xml
<receiver
android:name="com.example.a52780.nontifications.AlarmReceiver"
android:enabled="true"
android:exported="false"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<service
android:name="com.example.a52780.nontifications.BootService"
android:enabled="true"
android:exported="false"/>
Also I added BootService.java
private void setAlarm(Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
String text = intent.getStringExtra("text");
Intent mainIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, mainIntent, 0);
NotificationManager myNotificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("Wake up!")
.setContentText(text)
.setWhen(System.currentTimeMillis())
.setContentIntent(contentIntent);
myNotificationManager.notify(notificationId, builder.build());
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
setAlarm(intent);
Intent service = new Intent(this, BootService.class);
stopService(service);
}
AlarmReceiver.java
private static final String BOOT_COMPLETED =
"android.intent.action.BOOT_COMPLETED";
private static final String QUICKBOOT_POWERON =
"android.intent.action.QUICKBOOT_POWERON";
@Override
public void onReceive(Context context, Intent intent) {
// Get id & message from Intent
int notificationId = intent.getIntExtra("notificationId", 0);
String message = intent.getStringExtra("text");
String action = intent.getAction();
if (BOOT_COMPLETED.equals(action) ||
QUICKBOOT_POWERON.equals(action)) {
Intent service = new Intent(context, BootService.class);
intent.putExtra("notificationId", notificationId);
intent.putExtra("text", message);
context.startService(service);
}
}
I changed code in MainActivity that calls intent as well.
Old:
Intent intent = new Intent(MainActivity.this, AlarmReceiver.class);
intent.putExtra("notificationId", notificationId);
intent.putExtra("text", text);
intent.putExtra("alarmStartTime", alarmStartTime);
PendingIntent alarmIntent = PendingIntent.getBroadcast(MainActivity.this, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
Idk why, but it works after adding
intent.setAction("android.intent.action.BOOT_COMPLETED");
intent.setAction("android.intent.action.QUICKBOOT_POWERON");
Android After Reboot Broadcast Receiver is not running
try to put this line in your receiver's intent-filter.
<action android:name="android.intent.action.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE" />
If your application is installed on the SD card, you should register this to get the android.intent.action.BOOT_COMPLETED event.
Updated: Since your app is using alarm service, it should not be installed on external storage. Reference: http://developer.android.com/guide/topics/data/install-location.html
Related Topics
Connecting to Wifi Using Adb Shell
Phonegap Eclipse Issue - Eglcodeccommon Glutilsparamsize: Unknow Param Errors
Viewpager Detect When User Is Trying to Swipe Out of Bounds
How to Set the Language in Speech Recognition on Android
What Causes Android's Contentresolver.Query() to Return Null
Custom Uri Schemes for the Facebook Messenger
Error Loading the Sdk When Eclipse Starts
How to Add an Image in Email Body
Android: How to Open Another App from My App
Handling Buttons Inside Android Notifications
How to Hide System Navigation Bar in Tablets
Android App Bundle with In-App Locale Change
Disable Default Animation from Portrait to Landscape
List All the Files from All the Folder in a Single List