mrmcduff
mrmcduff

Reputation: 163

How do I communicate information from a BroadcastReceiver to an Activity in Android

I'm trying to write something similar to a custom app store, and I'm having a very hard time hearing the results of the installation.

I've tried a variety of things, and none of them have functioned as it appears they should.

In my main activity class, I have the installation code as follows:

Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setDataAndType(Uri.fromFile(apkFile),
"application/vnd.android.package-archive");
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, getApplicationInfo().packageName);
startActivityForResult(intent, resultIndex);

That's pretty straightforward. The first thing I tried to get the result is to override the onActivityResult function in my main activity. That function never gets called (a logger statement on the first line never prints).

Hence, I tried creating a receiver in the manifest.

<receiver android:name=".PackageReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_ADDED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="package" />
    </intent-filter>
</receiver>

And then in the PackageReceiver class, I overrode the onReceive function. This worked in the sense that the PackageReceiver's function did get called, but I'm now stuck with the problem of how to notify the main activity that something has happened (for the purposes of my project, I need to know). I can't instantiate the PackageReciever; Android does that for me because it's in the manifest.

I tried creating a new broadcast, so my PackageReceiver's onReceive function looks like this:

@Override
public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (action.equals(Intent.ACTION_INSTALL_PACKAGE) ||
            action.equals(Intent.ACTION_PACKAGE_ADDED) ||
            action.equals(Intent.ACTION_PACKAGE_CHANGED) ){
        logger.debug("Caught action of type " + action);

        Intent i2 = new Intent();
        i2.setAction("MY.CUSTOM.ACTION");
        context.sendBroadcast(i2);
    }

}

Then, over in my main activity, I created a new BroadcastReceiver:

BroadcastReceiver myReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        logger.warn("I made it!!!! HOORAY!!");
    }
};

And registered that receiver in the onResume (and unregistered in the onPause) function, like this:

@Override
protected void onResume() {
    IntentFilter filter = new IntentFilter();
    filter.addAction("MY.CUSTOM.ACTION");
    registerReceiver(myReceiver, filter);
    logger.debug("Registering receiver in onResume.");
    super.onResume();
}

It sounded like a nice solution, but "myReceiver" never has its onRecieve function called. I've tried making sure I don't unregister when I don't want to by simply removing the unregistration, moving the registration to the onCreate method of the activity, and none of that works. The net result there is that exceptions get thrown in the logger saying I've leaked an IntentFilter, "Did you forget to unregister?" (No, I very purposefully didn't unregister... but... nevermind).

I'm running out of ideas as to how to bridge this gap. Also, I can't just poll the installed applications and check version numbers. For reasons I can't get into here, we don't use version numbers. I need to know whether or not the user completed the installation that I kicked off.

How can I send information from the PackageReceiver to the main activity? Or, how can I catch the result of the installation in the main activity itself?

Thanks to all who give it a stab. I checked other stackoverflow questions, but none seem to have the answers I'm looking for.

Upvotes: 0

Views: 1033

Answers (1)

David Wasser
David Wasser

Reputation: 95568

If you register myReceiver in onResume() and unregister it in onPause() it will never get called because when the package installation occurs your app is paused.

You need to register MyReceiver in onCreate() and don't unregister it until onDestroy().

Also, you don't need so many components to do this. In your main activity, just before you go off to install a package you can register the receiver to listen for the package installer results:

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addCategory(Intent.CATEGORY_DEFAULT);
filter.addDataScheme("package"); 
registerReceiver(myReceiver, filter);

// Now launch the package installer...

Upvotes: 3

Related Questions