Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Work Manager with Broadcast Receiver does not work when the app is closed

I just want to keep bluetooth on, and to do that I listen the bluetooth state and if it is turned of, the broadcast receiver could enable it. And I want it to run when the app is closed too. So I am trying to run the bluetooth broadcast receiver even after the app is closed (when it is not working). To do that, I learned that I need to use a Work Manager to support all devices. I tried to combine Broadcast Receiver and Work Manager. But I could not manage to make it run when the app is closed.

This is my MainActivity.java In here I enqueued the work request.

package com.example.workmanagersample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class).build();
        WorkManager.getInstance().enqueue(workRequest);

    }
}

The following class is my MyWorker.java In here I registered the receiver.

package com.example.workmanagersample;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import androidx.work.Worker;
import androidx.work.WorkerParameters;


public class MyWorker extends Worker {
    private BlueToothBroadcastReceiver myReceiver;

    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    /*
     * This method is responsible for doing the work
     * so whatever work that is needed to be performed
     * we will put it here
     *
     * For example, here I am calling the method displayNotification()
     * It will display a notification
     * So that we will understand the work is executed
     * */

    @NonNull
    @Override
    public Result doWork() {
        displayNotification("My Worker", "Hey I finished my work");


        setReceiver();

        return Worker.Result.success();
    }

    /*
     * The method is doing nothing but only generating
     * a simple notification
     * If you are confused about it
     * you should check the Android Notification Tutorial
     * */
    private void displayNotification(String title, String task) {
        NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("simplifiedcoding", "simplifiedcoding", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "simplifiedcoding")
                .setContentTitle(title)
                .setContentText(task)
                .setSmallIcon(R.mipmap.ic_launcher);

        notificationManager.notify(1, notification.build());
    }


    private void setReceiver() {
        myReceiver = new BlueToothBroadcastReceiver();
        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
        getApplicationContext().registerReceiver(myReceiver, filter);

    }
}

The following class is my BlueToothBroadcastReceiver.java In here I listen if the bluetooth state is changed and I tried to open it if it turned off. It was working when app is running. But I wanted it to work also if the app is closed but I could not achieve it.

package com.example.workmanagersample;

import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BlueToothBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();

        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                    BluetoothAdapter.ERROR);
            switch (state) {
                case BluetoothAdapter.STATE_OFF:
                    setBluetooth(true);
                    // Bluetooth has been turned off;
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                    setBluetooth(true);
                    // Bluetooth is turning off;
                    break;
                case BluetoothAdapter.STATE_ON:
                    // Bluetooth has been on
                    break;
                case BluetoothAdapter.STATE_DISCONNECTING:
                    setBluetooth(true);
                    // Bluetooth is turning on
                    break;

                case BluetoothAdapter.STATE_DISCONNECTED:
                    setBluetooth(true);
                    // Bluetooth is turning on
                    break;
            }
        }
    }

    public static boolean setBluetooth(boolean enable) {
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        boolean isEnabled = bluetoothAdapter.isEnabled();
        if (enable && !isEnabled) {
            return bluetoothAdapter.enable();
        }
        else if(!enable && isEnabled) {
            return bluetoothAdapter.disable();
        }
        // No need to change bluetooth state
        return true;
    }
}

Lastly my Manifest file;

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

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver
            android:name=".BlueToothBroadcastReceiver"
            android:enabled="true">
            <intent-filter>
                <action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
                <action android:name="android.bluetooth.adapter.action.STATE_OFF"/>
                <action android:name="android.bluetooth.adapter.action.STATE_TURNING_OFF"/>
                <action android:name="android.bluetooth.adapter.action.STATE_ON"/>
                <action android:name="android.bluetooth.adapter.action.STATE_DISCONNECTING"/>
                <action android:name="android.bluetooth.adapter.action.STATE_DISCONNECTED"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

I choosed to use Work Manager after researching during my weekend but it did not work when I closed the app. Is there anything that I am missing or is there any restriction? If so, how can I solve that? Any help would be really appreciated! Thanks!

like image 648
Hilal Avatar asked Jun 10 '19 02:06

Hilal


1 Answers

WorkManager is intended for executing tasks even if your application is in the background. You can assign some constraints to your Worker classes so that they are executed only when these constraints are met (i.e. having a Constraints on a WiFi connection being available if you need to upload some data to a server).

THIS is why WorkManager uses broadcast receivers (up to API level 22) or JobScheduler: to know when these constraints change.

As other have replied, you need to use a Service (and probably a Foreground Service is a good idea if you need to run this for long time). Few things you should evaluate:

  1. First check the scenarios for Foreground Services. Consider this blog post
  2. Then the documentation on foreground services.
  3. Finally the Bluetooth overview.
like image 98
pfmaggi Avatar answered Sep 22 '22 17:09

pfmaggi