Search code examples
javaandroidbroadcastreceiver

How do I detect if device is charging from background


I have searched thick and thin through the Developer notes for android and am unable to find out how to perform a specific action when a device is plugged in, and perform another action when unplugged.

I have attempted to set a Broadcast Receiver like below however it will not run:

    <receiver android:name=".PowerConnectionReceiver">
        <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
        </intent-filter>
    </receiver>

I understand that from API 26 and up, you can no longer receive some broadcasts registered in the manifest, and must register them dynamically.

I need to have this run in the background but can't figure out how? This article updated in 2019 (after api 26) implies that I should be able to do it.

The charging status can change as easily as a device can be plugged in, so it's important to monitor the charging state for changes and alter your refresh rate accordingly.

The BatteryManager broadcasts an action whenever the device is connected or disconnected from power. It's important to receive these events even while your app isn't running particularly as these events should impact how often you start your app in order to initiate a background update so you should register a BroadcastReceiver in your manifest to listen for both events by defining the ACTION_POWER_CONNECTED and ACTION_POWER_DISCONNECTED within an intent filter.

My end goal is to call the broadcast receiver whenever device is plugged in or unplugged.

How would I go about implementing this?


Solution

  • The best way to accomplish this is by having a service run in the background so that you can receive the broadcast from android without the user using the app.

    Start by registering a service in your manifest file.

    <Service android:name=".serviceName"/>
    

    Now create your class with the same name as registered in the manifest above, this class must extend Service.

        public class BackgroundService extends Service {
            private static final int NOTIF_ID = 1;
            private static final String NOTIF_CHANNEL_ID = "AppNameBackgroundService";
    
            @Nullable
            @Override
            public IBinder onBind(Intent intent) {
                return null;
            }
    
            @Override
            public int onStartCommand(Intent intent, int flags, int startId){
    
                //Add broadcast receiver for plugging in and out here
                ChargeDetection chargeDetector = new ChargeDetection(); //This is the name of the class at the bottom of this code.
    
                IntentFilter filter = new IntentFilter();
                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
                filter.addAction(Intent.ACTION_POWER_CONNECTED);
                filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
                this.registerReceiver(chargeDetector, filter);
    
                startForeground();
    
                return super.onStartCommand(intent, flags, startId);
            }
    
            private void startForeground() {
                createNotificationChannel();
                Intent notificationIntent = new Intent(this, MainActivity.class);
    
                PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                        notificationIntent, 0);
    
                startForeground(NOTIF_ID, new NotificationCompat.Builder(this,
                        NOTIF_CHANNEL_ID) // don't forget create a notification channel first
                        .setOngoing(true)
                        .setSmallIcon(R.mipmap.final_icon)
                        .setContentTitle(getString(R.string.app_name))
                        .setContentText("Background service is running")
                        .setContentIntent(pendingIntent)
                        .build());
            }
    
            private void createNotificationChannel() {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    NotificationChannel serviceChannel = new NotificationChannel(
                            NOTIF_CHANNEL_ID,
                            "Foreground Service Channel",
                            NotificationManager.IMPORTANCE_DEFAULT
                    );
                    NotificationManager manager = getSystemService(NotificationManager.class);
                    manager.createNotificationChannel(serviceChannel);
                }
            }
        }
    
        class ChargeDetection extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                //Now check if user is charging here. This will only run when device is either plugged in or unplugged.
            }
        }   
        }