Broadcast Receiver Not Working After Device Reboot in Android
Asked Answered
S

7

59

I have already checked all the related questions and have not found any solution for this problem. So this is an absolutely new problem for me.

What I Have

I have an Android app which registers a few broadcast receivers in its manifest. This is what my manifest looks like.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.app.myapp">

    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
    <uses-permission android:name="com.android.vending.BILLING" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    <uses-feature
        android:name="android.hardware.telephony"
        android:required="false" />

    <uses-feature
        android:name="android.hardware.screen.portrait"
        android:required="false" />

    <application
        android:name=".base.MyApp"
        android:allowBackup="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/label_app_name"
        android:largeHeap="true"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:replace="label, allowBackup">

        <receiver android:name=".mics.BootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
        </receiver>

        <receiver android:name=".PhoneCallReceiver">
            <intent-filter>
                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
            </intent-filter>
        </receiver>

        <receiver
            android:name=".mics.DeviceAdminReceiver"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            </intent-filter>

            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/device_admin" />
        </receiver>

        <receiver
            android:name="com.clevertap.android.sdk.InstallReferrerBroadcastReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="com.android.vending.INSTALL_REFERRER" />
            </intent-filter>
        </receiver>

        <meta-data
            android:name="com.app.myapp.utils.ImageLoaderModule"
            android:value="GlideModule" />

        <meta-data
            android:name="com.app.myapp.utils.AudioCoverLoaderModule"
            android:value="GlideModule" />

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">

            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

        <activity
            android:name=".core.activities.SplashActivity"
            android:excludeFromRecents="true"
            android:label="@string/label_app_name"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>

        <activity-alias
            android:name=".core.activities.SplashActivity-Alias"
            android:icon="@drawable/ic_launcher"
            android:label="@string/label_app_name"
            android:noHistory="true"
            android:targetActivity="com.app.myapp.core.activities.SplashActivity">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY" />
            </intent-filter>

        </activity-alias>

        <activity
            android:name=".core.flow.authFlow.activities.AuthFlowActivity"
            android:excludeFromRecents="true"
            android:label="@string/label_app_name"
            android:screenOrientation="portrait" />

        <service android:name=".features.fileCloudSync.KillNotificationService" />

    </application>

</manifest>

There are 10-15 other activities as well but have been removed for simplicity. And this is the basic boot receiver class. I start a service from here.

public class BootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            AlertUtils.showToast(context, "BOOT COMPLETED", Toast.LENGTH_LONG);
        }
    }
}

and the phone call receiver class looks something like this (it has been simplified as well),

public class PhoneCallReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
            AlertUtils.showToast(context, "PHONE CALL RECEIVED", Toast.LENGTH_LONG);
            // Simplified for brevity
        }
    }
}

The Problem

All these receivers work fine when I install the app and start it once. But after I reboot my device these receivers don't work at all. Neither the BootCompleteReceiver nor the PhoneCallReceiver gets their onReceive() method called.

My assumption was that these receivers would get registered automatically after reboot, but it just doesn't work. I need the BootCompleteReceiver to work so that I can start an important service in my app.

My Observations

I have tested this thoroughly. After rebooting the device, the receivers work fine in my Nexus 5X (Nougat), Nexus 6P (Nougat), YU Yuphoria (Lollipop) but not in my OnePlus 3 (Nougat) and Mi 4i (Lollipop).

How can the same code work perfectly on a few devices and not work at all on the other devices? I haven't changed anything at all.

What am I doing wrong here? My app is heavily dependent on these broadcasts and starts services based on these. Any help will be highly appreciated.

EDIT 1

To understand the problem better, I just created a very small test project with just a single activity and the exact same BootCompleteReceiver and PhoneCallReceiver.

But weirdly, this project works perfectly on my OnePlus 3 where my actual app's receivers don't work after a reboot. I was initially assuming that the problem is in the OS or the device somehow, but it is not.

So where is the actual problem? Is it in my app (but it works perfectly on other devices) or in the OS and device (the small test project works fine on the same OS and same device)?

It is really confusing to me. I would need some expert help on this.

EDIT 2

I have tried the suggestion given by @shadygoneinsane. Here are my observations.

1) I tried to send the BOOT_COMPLETED broadcast via ADB.

./adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.app.myapp

And I got this stack trace,

Broadcasting: Intent { act=android.intent.action.BOOT_COMPLETED pkg=com.app.myapp }
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.BOOT_COMPLETED from pid=25378, uid=2000
    at android.os.Parcel.readException(Parcel.java:1683)
    at android.os.Parcel.readException(Parcel.java:1636)
    at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:3696)
    at com.android.commands.am.Am.sendBroadcast(Am.java:778)
    at com.android.commands.am.Am.onRun(Am.java:404)
    at com.android.internal.os.BaseCommand.run(BaseCommand.java:51)
    at com.android.commands.am.Am.main(Am.java:121)
    at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
    at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:276)

Maybe because my device is not rooted. I am unable to send this broadcast in any way.

2) I tried with the PROCESS_OUTGOING_CALLS broadcast after that.

./adb shell am broadcast -a android.intent.action.PROCESS_OUTGOING_CALLS -p com.app.myapp

I got this,

Broadcasting: Intent { act=android.intent.action.PROCESS_OUTGOING_CALLS pkg=com.app.myapp }
Broadcast completed: result=0

It seems that the broadcast was successful, but I do not see any Toast or any log. I then opened my dialer to dial a number and I can then see the Toast and the log both.

So it seems that sending the broadcast via ADB didn't work, but actually opening the dialer and dialing a number did.

EDIT 3

As per the suggestion from @ChaitanyaAtkuri, I have also tried adding priority to the intent-filters but that didn't work as well.

I have used priorities like 500, 999 and even the highest integer value, but nothing works. This problem is also occurring in some of my friends apps as well. They work in some devices and doesn't work in others.

EDIT 4

I have finally found out the root cause of the problem happening in my OnePlus 3. My OnePlus 3 recently got updated to Nougat and they introduced a feature similar to Mi devices which prevent certain apps from auto-starting after reboot.

Upon disabling this feature my app started receiving broadcasts after reboot perfectly. But this still doesn't explain two things.

1) My small test project is whitelisted automatically in the list of AutoLaunch apps and that is why it works as expected. But how is this possible? Why the OS considers this small app worthy to be auto-started?

2) There are some apps like LockDown Pro, 500 Firepaper which is blacklisted in the AutoLaunch apps screen but still, it receives broadcasts after reboot in my OnePlus 3 and Mi 4i. How is that possible now? Is it somehow possible to programmatically allow my app to auto launch in these devices (OnePlus and Mi)?

EDIT 5

I have tried the solution proposed by @Rahul Chowdhury and it really seems to work very well. After adding the accessibility service the problem is re-solved.

But if the user revokes the accessibility permission after granting it then is there a way for me to programmatically check if the accessibility permission is available to my app?

Schmuck answered 7/1, 2017 at 17:40 Comment(19)
Try adding these to the Manifest declaration: android:enabled="true" and android:exported="true". Also in the boot receiver class, remove the intent.getAction conditional because there is no reason to check it because the only time that broadcast will get fired is on boot.Lebron
I just tried your suggestions and the result is still the same. Actually, these can be considered as best practices and doesn't change the implementation in any way.Schmuck
A different path. Maybe it did work and you didn't see the toast. Maybe it failed and you didn't see it fail. Change code to save something you can detect later. Remember broadcast receivers finish in 10 seconds or the app fails.Fortress
I have not tested this once and have put this question here. After several tests, I can confirm that these receivers don't work after a reboot in some of the devices mentioned above. And as you mentioned, how do I detect if it failed?Schmuck
Have you gone through this answerExplosive
@Explosive Yes, I have already gone through this answer but it is not applicable here. The user obviously opens the app once and then restarts the device but the broadcast receivers don't fire here. Maybe the app moves into a stopped state somehow, but this didn't happen for the small test project that I had created.Schmuck
Did you try testing with shell commands to send Broadcasts for Boot Completed manually using ADB Try using this to test whether your app receives a broadcast or not ! 'adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.mypackage.name'Explosive
@Explosive I have tried your suggestion and posted the observation in the question itself. Please check and let me know what should be my next step.Schmuck
Are you just relying on the toast or logs to check if the broadcast was received ?Explosive
Let us continue this discussion in chat.Explosive
@AritraRoy does your test app have any service in it? Just to understand if one plus whitelists app without services.Judon
No the test app doesn't have any service. But even if I add one, but still it is whitelisted.Schmuck
@AritraRoy Please refer to the last section of my updated answer to find out whether accessibility service is turned ON for your app or notSkein
@AritraRoy Did you not notice that this question got completely out of control? First it was a question about the cause for a failed autostart; then it morphed into a question about how the custom ROM on some devices decide which apps to whitelist; and finally, the question was how to treat permission availability/revocation. It should be split into 3 different questions at least (not to mention that some these questions might be considered off-topic / too broad). I can't even tell which of these questions the accepted answer addresses...Sympathetic
The accepted answer addresses the actual problem that I was facing and it is solved. Thanks.Schmuck
please check my answer https://mcmap.net/q/328597/-broadcast-receiver-not-working-after-device-reboot-in-androidBuffo
Had the same problem. As mentioned, Boot receiver didn't hit for one-plus (3T) and MI devices. The really strange thing was on some of the PoCs I created while trying this, boot receiver was hitting!! My observation is as follows: On one plus 3T (and possibly other versions), if you have the word 'test' in the package structure, boot receiver is hit. Else it won't!! (sounds really crazy) On MI devices, no 'test' is gonna help. The same applies for GcmNetworkManager & FirebaseJobDispatcher. Finally, the Accepted solution saved me too! Some of these make you feel switching to iOS development :)Yount
Having the same issue on my OnePlus 5.My small PoC app (called testinator, contains a service) receives the BOOT_COMPLETED as expected, but my actual app doesn't. After switching off battery optimization, both apps receive the BOOT_COMPLETED intent as expected. Still looking for a better solution since I would like to keep battery optimization on.Winepress
Hell of a investigation +1Trinl
S
40

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.

Skein answered 13/1, 2017 at 4:15 Comment(16)
Your findings are useful, but it would be a lot better if you weren't casually suggesting to use phony AccessibilityService just to pass an automated filter and receive BOOT_COMPLETE. A lot of root apps and, more importantly, actual accessibility services for impaired people may be negatively affected, if everyone starts to (mis)use such practice.Sinnard
Note: Every time the app is force stopped, the accessibility permission will be lost.Judon
Awesome. Let me give it a try and get back to you.Schmuck
Great.. Checked it with MIUI device, works well until I remove the app from recent apps. Because when I remove the app from recents, MIUI's auto start feature force stops the apps, hence none of the accessibility events trigger the accessibility service.Judon
@Judon I guess if this feature is of utmost importance for your app's use case, then you can have either a Service or a periodic Alarm that checks if accessibility is turned on for your app, and notifies the user to turn it on. Also, you can enforce a check on your app launch for the same.Skein
@Sinnard Well this is the best solution that I could come up with, but I am open to any better alternatives which is simpler and requires less permissions than this approach. :-)Skein
@RahulChowdhury Can you please tell me that in <accessibility-service> what I have to put in @string/service_desc (android:description="@string/service_desc")?Cookstove
@Cookstove It's just a description of what your service does and why the user needs to turn it on. This message will be visible to the user while the user is on the Accessibility Service settings screen for your app.Skein
@RahulChowdhury In the helper method (under edit 1) called isAccessibilitySettingsOn you've an if condition if (accessibilityEnabled == ACCESSIBILITY_ENABLED) where accessibilityEnabled is an int while ACCESSIBILITY_ENABLED is a string with value accessibility_enabled. How is this solution working?Gertrudgertruda
@MayankMohanUpadhyay Thanks for pointing it out. I missed out the constant value in this answer that I defined in my class. Updated the answer.Skein
@RahulChowdhury Thank you so much for the correction! You're awesome. Trying it out currently.Gertrudgertruda
@RahulChowdhury I received an email from Google Play Support today. It said that apps using accessibility services like android.permission.BIND_ACCESSIBILITY_SERVICE should only be used to help users with disabilities use Android devices and apps. Apps that fail to meet this requirement within 30 days may be removed from Google Play.Gertrudgertruda
@AritraRoy Hi, Please refer to the comment above. Did you receive such email as well for your apps published on Google Play Store? What is the work around?Gertrudgertruda
Using this i was able to restart my service when device restarted. Device Huawei Honor 7C, Android 8 Thanks!!Spurgeon
How do apps like Whatsapp start their services on boot then despite all these hassles?Millesimal
@Millesimal Some OEMs like Xiaomi whitelist popular apps like WhatsApp, Facebook, etc.Skein
B
6

Hi I am late to the party but I was following this question from it's start. I know that One-plus and some other OEMs maintain a list of apps which can receive BOOT_COMPLETED broadcast. If your app is not white listed then your app won't be started on boot. Now I've a solution which is very efficient in terms of memory and resources and guaranteed to start your task or service after reboot or hard boot also does not need AccessibilityService as proposed in this answer. Here it goes..

  1. Add the follwing permission in your manifest file

2.If you don't have a dependency on com.google.android.gms:play-services-gcm, add the following to your build.gradle's dependencies section:

compile 'com.firebase:firebase-jobdispatcher:0.5.2'

Otherwise add the following:

compile 'com.firebase:firebase-jobdispatcher-with-gcm-dep:0.5.2'

This is a library from firebase team which depends on google-play-service library to schedule your jobs and from my point of view google-play-service has the permission to start at boot so instead of system ,google-play-service will run your job as soon as device rebooted.

  1. Now this step is easy Just define a JobService class

public class MyJobService extends JobService {

    @Override
    public boolean onStartJob(JobParameters job) {
        Log.v("Running", "====>>>>MyJobService");

        return false; // Answers the question: "Is there still work going on?"
    }

    @Override
    public boolean onStopJob(JobParameters job) {
        Log.v("Stopping", "====>>>>MyJobService");
        return true; // Answers the question: "Should this job be retried?"
    }

}

  1. Add your Job Service in manifest file.

  2. Schedule this job anywhere you want for e.g when your app start.

    FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(getApplicationContext()));

            Bundle myExtrasBundle = new Bundle();
    
            myExtrasBundle.putString("some_key", "some_value");
    
            Job myJob = dispatcher.newJobBuilder()
                    // the JobService that will be called
                    .setService(MyJobService.class)
                    // uniquely identifies the job
                    .setTag("my-unique-tag-test")
                    // repeat the job
                    .setRecurring(true)
                    // persist past a device reboot
                    .setLifetime(Lifetime.FOREVER)
                    // start between 0 and 60 seconds from now
                    .setTrigger(Trigger.executionWindow(0, 60))
                    // don't overwrite an existing job with the same tag
                    .setReplaceCurrent(false)
                    // retry with exponential backoff
                    .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
                    // constraints that need to be satisfied for the job to run
                    .setExtras(myExtrasBundle)
    
                    .build();
    
            dispatcher.mustSchedule(myJob);
    

6.That's it!! Now you can execute your task or service on device boot no matter you are in white list or not.

There is one point to note that Google Play Service must be installed on device otherwise it won't work.

Buffo answered 23/3, 2017 at 13:4 Comment(12)
It seems to be a good solution. I will give it a try and get back to you.Schmuck
@tejshah, It's working, I tested it on MI note 4 and OnePlus3.Buffo
Yes. The app is disabled for boot in list. Have you set .setLifetime(Lifetime.FOREVER) in your Job?Buffo
run adb shell dumpsys activity service GcmService after rebooting and check if your service is there.Buffo
@tejshah i too have k5, But its not working after boot. You found a solution?Ruffo
@sanidhya09 Yes, i found it. for k5 got to setting->app->selection your applicatin->uncheck Restrick ap. then check itRoulade
What about step 5 makes the job work after reboot? Surely it isn't setTrigger(Trigger.executionWindow(0, 60)) that is looping every 1 minute...Inundate
You can say it's looping after 1 minute only if setRecurring is true. and Lifetime.FOREVER will make it work after reboot also. May be there are some devices which are having problem after reboot but for me it's works on the devices which op said.Buffo
This sounds really silly waking the device every 1 minute, could reduce battery life. Perhaps if the job will always be scheduled directly after reboot, the interval could be set to something larger like 10 mins. I'll give it a try and let you know what happensInundate
i am getting some errors trying to implement this answer. was wondering if you guys might know anything github.com/firebase/firebase-jobdispatcher-android/issues/…Inundate
@Inundate 1 minute window depends on the app functionality for e.g in critical financial app you need to fetch share market data as quickly as possible.Buffo
FirebaseJobDispatcher is deprecatedCallista
I
5

@Aritra, Try this

<receiver
            android:name=".mics.BootReceiver"
            android:enabled="true"
            android:exported="true" >
            <intent-filter android:priority="500" >
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

Remove quickBoot intent filter and try running it, as per the documentation we only required BootCompleted to acheive it. May be it is interrupting this.

Also one more important point to Note :

Don't rely completely or test on Mi devices as they have their own OS which halts the basic features of Android, like they stop the Push notifications services and background services just to optimize battery usage. To test this on Mi device, mark your app as "AutoStart" in Security app and then try.

Impediment answered 10/1, 2017 at 6:55 Comment(4)
Tried that but not working as well. If the problem is with the quick boot filter, the PhoneCallReceiver should at least work. The problem is somewhere else I think.Schmuck
Don't rely or test on Mi devices as they have their own OS which halts the basic features of Android, like they stop the Push notifications services and background services just to optimize battery usage. To test this on Mi device, mark your app as "AutoStart" in Security app and then try.Impediment
I am testing all these on OnePlus 3 on Nougat. I know this fact about Mi and that is why I am not testing on it anymore. But it is not working on my OnePlus 3 and I can confirm that.Schmuck
checked on both MI and Stock Android Phone(Moto G3) it's working fine! still if it's not working then refer to this ans's edit 2: https://mcmap.net/q/328597/-broadcast-receiver-not-working-after-device-reboot-in-androidOnstad
P
4

You can ask user for autostart permission, and direct them to the required settings page:

 private void autoStart() {
    try {
        Intent intent = new Intent();
        String manufacturer = android.os.Build.MANUFACTURER;
        if ("xiaomi".equalsIgnoreCase(manufacturer)) {
            intent.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
        } else if ("oppo".equalsIgnoreCase(manufacturer)) {
            intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity"));
        } else if ("vivo".equalsIgnoreCase(manufacturer)) {
            intent.setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
        } else if ("Letv".equalsIgnoreCase(manufacturer)) {
            intent.setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity"));
        } else if ("Honor".equalsIgnoreCase(manufacturer)) {
            intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity"));
        } else if ("oneplus".equalsIgnoreCase(manufacturer)) {
            intent.setComponent(new ComponentName("com.oneplus.security", "com.oneplus.security.chainlaunch.view.ChainLaunchAppListAct‌​ivity"));
        }

        List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        if (list.size() > 0) {
            startActivity(intent);
        }

    } catch (Exception e) {
        Log.e("exc", String.valueOf(e));
    }
}

After doing this, receiver always got triggered on reboot.

Probable answered 8/6, 2020 at 12:27 Comment(1)
Your solution seems working, But how to check if it is already turned on or not ?Hallowmas
E
2

The way IntentFilters work is that each <intent-filter></intent-filter> contains one way of firing up the component. If you have multiple ways of firing it up (like two actions that you want to listen to in one BroadcastReceiver), you'll need an independent <intent-filter></intent-filter> definition for each.

Hence, you can try changing:

<receiver android:name=".mics.BootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>

to:

<receiver android:name=".mics.BootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>

    <intent-filter>
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>

Read more here: Intents and Intent Filters | Android Developers

EDIT

If it still doesn't work, you can try to test if your manifest declaration is done correctly. Try executing the following command in your terminal, keeping the test device connected to the computer:

adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n com.app.myapp/.mics.BootReceiver

If this doesn't work, you should recheck the relative package declaration of the receiver in your manifest file.

EDIT 2

It may sound weird but try following these steps:

  • Uninstall the app from your phone (ensure it is uninstalled for all users)
  • Reboot your phone
  • Clean the project
  • Build and run the project in your device again
Eweneck answered 10/1, 2017 at 6:43 Comment(5)
Tried it, doesn't work. If multiple actions were the problem, then the PhoneCallReceiver should already be working. It has only a single action.Schmuck
Can you try executing this: adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n com.app.myapp/.mics.BootReceiver?Eweneck
Tried that, getting the same SecurityException. It is maybe because my device is not rooted.Schmuck
It may sound weird but try following these steps: Uninstall the app from your phone (ensure it is uninstalled for all users) > Reboot your phone > Clean the project > Build and run the project in your deviceEweneck
It's not about the problem in the debug build. My app is in production and there are several devices which face this problem. Even it occurs in some of the devices I own.Schmuck
F
2

I have been struggling with this issue from almost a year. In all my apps, I show a notice to users to disable battery optimization for my app.

After a lot of testing on One Plus devices, I am able to receive boot completed broadcast when battery optimization is turned off for my app. In my opinion, it is much better than the accessibility service discussed above.

The simplest way to ask the user to disable the battery optimization for your app is to show some kind of notice, and open the battery optimization page when the user clicks on it. You can use the below code to do that.

public void openPowerSettings(View v) {

    /* Make Sure to add below code to manifest
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    */

    try {
        Intent i = new Intent(android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
        startActivityForResult(i, 1);
    }  catch (Exception e) {
        Log.e (TAG, "Exception: " + e.toString());
    }

}

And you can also hide the notice if below function returns true.

public static boolean is_ignoring_battery_optimizations(Context context) {
    String PACKAGE_NAME = context.getPackageName();
    PowerManager pm = (PowerManager) context.getSystemService(context.POWER_SERVICE);
    boolean status = true;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        status = pm.isIgnoringBatteryOptimizations(PACKAGE_NAME);
    }
    return status;
}
Flummery answered 19/12, 2018 at 10:16 Comment(2)
This is not case right now as one plus is again throwing all app to batter optimization. So it's not workingFarandole
Not working in my one plus and xiomi devicesHallowmas
S
0

How to start service on device boot(autorun app, etc.)

For first: since version Android 3.1+ you don't receive BOOT_COMPLETE if user never started your app at least once or user "force closed" application. This was done to prevent malware automatically register service. This security hole was closed in newer versions of Android.

Solution:

Create app with activity. When user run it once app can receive BOOT_COMPLETE broadcast message.

For second: BOOT_COMPLETE is sent before external storage is mounted. If app is installed to external storage it won't receive BOOT_COMPLETE broadcast message.

In this case there is two solution:

  1. Install your app to internal storage
  2. Install another small app in internal storage. This app receives BOOT_COMPLETE and run second app on external storage.

If your app already installed in internal storage then code below can help you understand how to start service on device boot.


In Manifest.xml

Permission:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Register your BOOT_COMPLETED receiver:

<receiver android:name="org.yourapp.OnBoot">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

Register your service:

<service android:name="org.yourapp.YourCoolService" />

In receiver OnBoot.java:

public class OnBoot extends BroadcastReceiver
{

    @Override
    public void onReceive(Context context, Intent intent) 
    {
        // Create Intent
        Intent serviceIntent = new Intent(context, YourCoolService.class);
        // Start service
        context.startService(serviceIntent);

    }

 }

For HTC you maybe need also add in Manifest this code if device don't catch RECEIVE_BOOT_COMPLETED:

<action android:name="android.intent.action.QUICKBOOT_POWERON" />

Receiver now look like this:

<receiver android:name="org.yourapp.OnBoot">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>

How to test BOOT_COMPLETED without restart emulator or real device? It's easy. Try this:

adb -s device-or-emulator-id shell am broadcast -a android.intent.action.BOOT_COMPLETED

How to get device id? Get list of connected devices with id's:

adb devices

adb in ADT by default you can find in:

adt-installation-dir/sdk/platform-tools

Enjoy! )

Sahaptin answered 11/1, 2017 at 13:42 Comment(2)
Did you even read the entire question before answer this to get the bounty?Schmuck
Hi check this url. It may be helpful. #9354860Anandrous

© 2022 - 2024 — McMap. All rights reserved.