10

We have an app that scans for Bluetooth devices. The code responsible for scanning should only run when bluetooth is enabled. Also we want to disable/enable this feature at any point in time.

We choose to implement a BroadcastReceiver that registers for the BluetoothAdapter.ACTION_STATE_CHANGED broadcast.

Here some of the problems we encountered:

Programmatically enable the BroadcastReceiver:

public void registerForBroadcasts(Context context) {
    IntentFilter bluetooth = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
    context.registerReceiver(this, bluetooth);
}
  1. When the app is killed, the BroadcastReceiver is also not active anymore. So if the user multi-tasks-swipes the app to death, it is not being woken up again.
  2. We have full control, when to start the BroadcastReceiver.

Declare the BroadcastReceiver in the Manifest

<receiver android:name="com.mypackage.BroadcastReceiver">
    <intent-filter>
        <action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
    </intent-filter>
</receiver>
  1. The BroadcastReceiver is active right after the app start.
  2. The BroadcastReceiver cannot be disabled.

Declare the BroadcastReceiver in the Manifest as disabled + enable it programmatically

<receiver android:name="com.mypackage.BroadcastReceiver"
          android:enabled="false" >
    <intent-filter>
        <action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
    </intent-filter>
</receiver>

Then enable the component if you need it.

public void registerForBroadcasts(Context context) {
    ComponentName component = new ComponentName(context, BroadcastReceiver.class);
    PackageManager pm = context.getPackageManager();
    pm.setComponentEnabledSetting(
                component,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
}

My tests have shown, the state is persisted with the system, so the BroadcastReceiver will stay enabled. It combines the advantages of both methods.

  1. BroadcastReceiver can be disabled
  2. BroadcastReceiver can be on or off by default
  3. BroadcastReceiver keeps activation even if app is disabled and phone rebooted.

Am I missing something, does this method seem legit?

Cœur
  • 37,241
  • 25
  • 195
  • 267
volkersfreunde
  • 1,095
  • 1
  • 12
  • 22
  • just notice that you have used BroadcastReceiver.class in getting the component, you should use your MyBroadcastReceiver.class instead to get the right broadcast component – ndori Sep 05 '17 at 07:42

2 Answers2

13

It is possible to enable/disable the receiver programatically.

To Enable programatically

PackageManager pm  = Re_editActivity.this.getPackageManager();
ComponentName componentName = new ComponentName(currentActivity.this, name_of_your_receiver.class);        
pm.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                                PackageManager.DONT_KILL_APP);

To Disable programatically

PackageManager pm  = Re_editActivity.this.getPackageManager();
ComponentName componentName = new ComponentName(currentActivity.this, name_of_your_receiver.class);
pm.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                            PackageManager.DONT_KILL_APP);

Manifest receiver

<receiver android:name="name_of_your_receiver" android:enabled="false">
        <intent-filter >                
            <action android:name="android.intent.action.BOOT_COMPLETED"/>                
        </intent-filter>
    </receiver>
Kumar M
  • 994
  • 6
  • 21
7

The BroadcastReceiver cannot be disabled.

Sure it can. Use PackageManager and setComponentEnabledSetting(), as you did in your third scenario.

Am I missing something, does this method seem legit?

It is very legit, at least in terms of managing the BroadcastReceiver. I don't know if there are any Bluetooth-specific hiccups, though I would doubt it. This technique is used for various broadcasts, such as only listening to ACTION_BOOT_COMPLETED when you really do have something that needs to be done at boot time.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491