Why would the following Ordered Broadcast fail in Android Oreo, unless I specifically set the package name?
final Intent vrIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
// Setting the package it will work. Omitting, it will fail
// vrIntent.setPackage("com.google.android.googlequicksearchbox");
getContext().sendOrderedBroadcast(vrIntent, null, new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
// final Bundle bundle = intent.getExtras();
final Bundle bundle = getResultExtras(true);
if (bundle != null) {
if (bundle.containsKey(RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES)) {
Log.i("TAG", "onReceive: EXTRA_SUPPORTED_LANGUAGES present");
final ArrayList<String> vrStringLocales = bundle.getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
Log.i("TAG", "onReceive: EXTRA_SUPPORTED_LANGUAGES size: " + vrStringLocales.size());
} else {
Log.w("TAG", "onReceive: missing EXTRA_SUPPORTED_LANGUAGES");
}
} else {
Log.w("TAG", "onReceive: Bundle null");
}
}, null, 1234, null, null);
If the package name is not set, EXTRA_SUPPORTED_LANGUAGES
will be missing.
I recently asked a bounty question where my 'legacy code', which didn't set the package name, was failing in Oreo, but worked successfully on previous Android versions.
Having checked all of the behavioural changes in API 26 I can see nothing that would explain this.
Can anyone shed some light on the possible cause please?
Note: The sample code and issue assumes the device has Google's 'Now' application installed to provide the RecognitionService
OK, I reproduced the problem. The 1234
result code was a red herring — it looks like the process behind RecognizerIntent
does not set a result code, so you get the initial code.
However, you do get this error message on Android 8.1 (and, presumably, 8.0):
W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.speech.action.GET_LANGUAGE_DETAILS flg=0x10 } to com.google.android.googlequicksearchbox/com.google.android.voicesearch.intentapi.IntentApiReceiver
That's the "you registered a receiver in the manifest, and we're not going to give you the broadcast, because you are in the background" error.
This lightly-tested sendImplicitOrderedBroadcast()
method works around the problem, while in principle maintaining the order of receivers (descending by priority):
private void sendImplicitOrderedBroadcast(Intent i, String receiverPermission,
BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode,
String initialData,
Bundle initialExtras) {
PackageManager pm=getPackageManager();
List<ResolveInfo> matches=pm.queryBroadcastReceivers(i, 0);
Collections.sort(matches,
(left, right) -> right.filter.getPriority()-left.filter.getPriority());
for (ResolveInfo resolveInfo : matches) {
Intent explicit=new Intent(i);
ComponentName cn=
new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);
explicit.setComponent(cn);
sendOrderedBroadcast(explicit, receiverPermission, resultReceiver,
scheduler, initialCode, initialData, initialExtras);
}
}
I took the liberty of filing an issue.