Search code examples
androidandroid-intentbroadcastreceiverintentfilter

Can I filter BroadcastReceiver other than using intent filters?


From what I've understood in the documentation, when i register a BroadcastReceiver using an intent filter in my manifest, the onReceive method will be called. My application uses DownloadManager to handle file downloads. I want to listen to DOWNLOAD_COMPLETE action. So, in my manifest, I have an intent filter like this:

<receiver
       android:name="com.myapp.DownloadReceiver" >
       <intent-filter>
           <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
       </intent-filter>
</receiver>

My class method is like this:

private DownloadManager manager;
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(result));
request.setTitle("MyTitle");
request.setDescription("MyDescription");
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, Test.txt);
manager.enqueue(request);

This receiver will receive all intents sent by the DownloadManager. Is there a way to restrict the filtering by listening to the completed downloads that were enqueued by my application only? If I try android:exported="false" it will not receive DownloadManager broadcasts, as they come from another application. If I filter the IDs my onReceive method is still called. What i want to achieve is avoiding that my receiver will receive ALL the events. Thank you!


Solution

  • You can not filter broadcasts sent to you by DownloadManager - as long as your receiver is registered you will receive broadcasts for all downloadmanager events.

    You can however use id returned by DownLoadManager.enqueue method. In your receiver you can get id of the download that triggered broadcast:

    Long downLoadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
    

    Also I do not recommend to register your receiver in manifest - this will invoke your application on ALL downloadmanager events, you probably dont want that. Instead register your receiver in code after you have enqueued your download and remove it when your download has been finished (successful or not). Also remember to unregister receiver before your activity is destroyed.

    If this is not acceptable ie you sometimes want to receive broadcasts when your app is not active you should register your receiver in manifest and switch it on/off as needed.

    In your manifest initially disable receiver:

    <receiver
           android:name="com.myapp.DownloadReceiver" 
           android:enabled="false" >
           <intent-filter>
               <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
           </intent-filter>
    </receiver>
    

    Then when you need it - for example after starting a download enable it:

    PackageManager pm  = getApplicationContext().getPackageManager();
    ComponentName componentName = new ComponentName("com.myapp", ".DownloadReceiver");
    pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
    

    And when you no longer dont want to receive broadcasts - for example when your download has finished disable receiver:

    pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    

    This way your application will receive broadcasts only if you need them.