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!
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With