sendOrderedBroadcast setPackage требование в Oreo

Почему следующие Ordered Broadcast не работает в Android Oreo, если я специально не установил пакет имя?

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);

Если имя пакета не задано, EXTRA_SUPPORTED_LANGUAGES будет отсутствовать.

Недавно я задал вопрос о вознаграждении, где мой "устаревший код", который не задавал имя пакета, не работал в Oreo. , но успешно работал на предыдущих версиях Android.

Проверив все поведенческие изменения в API 26 Я не вижу ничего, что могло бы это объяснить.

Может ли кто-нибудь пролить свет на возможную причину, пожалуйста?

Примечание. В примере кода и проблеме предполагается, что на устройстве установлено Приложение Google Now, установленное для предоставления RecognitionService


person brandall    schedule 06.02.2018    source источник
comment
Что именно означает неудача в этом контексте? Имейте в виду, что вы больше не можете регистрироваться для неявных трансляций в манифесте, поэтому, если сбой означает, что вызов sendOrderedBroadcast() ничего не вызывает, то это будет проблемой в любой части Android, которая должна реагировать на ACTION_GET_LANGUAGE_DETAILS.   -  person CommonsWare    schedule 07.02.2018
comment
@CommonsWare Я уточню вопрос. Я имею в виду, что EXTRA_SUPPORTED_LANGUAGES будет отсутствовать.   -  person brandall    schedule 07.02.2018
comment
Это только то, чего не хватает, или все Intent пусто? Код результата по-прежнему 1234 (не знаю, где вы узнали...)? В последнее время я мало играл с заказными трансляциями, не говоря уже об Android 8.0+. Но я вижу, где Android может оказаться, просто вызвав ваш последний BroadcastReceiver, после того, как не найдет действительных получателей для неявной трансляции.   -  person CommonsWare    schedule 07.02.2018
comment
@CommonsWare Intent пуст. Код результата по-прежнему 1234. Хотя установка имени пакета предполагает, что оно становится «явным», получатель по-прежнему будет неявным по своей природе, учитывая несколько SpeechRecognizers, которые могут присутствовать на устройстве?   -  person brandall    schedule 07.02.2018
comment
Ну, setPackage() имеет тенденцию делать Intent достаточно явным для многих целей, в том числе для того, чтобы обойти запрет на неявное Intents. Однако вместо того, чтобы жестко кодировать это имя пакета, вы можете попробовать упорядоченный вариант метода обхода sendImplicitBroadcast(), который у меня есть ближе к концу это сообщение в блоге о запрете. Кстати, поскольку я не нашел его в документах... где этот код результата доставляется вам? Я хотел бы провести несколько экспериментов.   -  person CommonsWare    schedule 07.02.2018
comment
@CommonsWare Договорились о неявном и явном. Я всегда нахожу ваши блоги очень полезными! Вы можете получить код результата, вызвав getResultCode() внутри приемника. Я прочитаю ваш блог и проверю sendImplicitBroadcast(), с которым я не знаком. Спасибо за совет. Кстати, не по теме, если вам когда-нибудь будет скучно за кофе, я бы хотел посмотреть, что вы думаете о моем проекте github.com/brandall76/Saiy-PS :)   -  person brandall    schedule 07.02.2018
comment
Вы можете получить код результата, вызвав getResultCode() внутри приемника — ах! Я смотрел на Intent и пытался выяснить, где он хранится, но ничего не нашел. Большое спасибо! Что касается вашего проекта, спасибо за документацию. Я глубоко обеспокоен виртуальными помощниками как категорией, поэтому я не особенно хороший человек, чтобы давать отзывы о самом проекте. И спасибо за добрые слова!   -  person CommonsWare    schedule 07.02.2018
comment
@CommonsWare хорошо, если сингулярность все равно наступит, было бы лучше, по крайней мере, отправить коммит, чтобы это произошло! :)   -  person brandall    schedule 07.02.2018


Ответы (1)


Хорошо, я воспроизвел проблему. Код результата 1234 был отвлекающим маневром. Похоже, что процесс, стоящий за RecognizerIntent, не устанавливает код результата, поэтому вы получаете исходный код.

Однако вы получаете это сообщение об ошибке на Android 8.1 (и, предположительно, 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

Это ошибка "вы зарегистрировали приемник в манифесте, и мы не собираемся давать вам трансляцию, потому что вы находитесь в фоне".

Этот слегка проверенный метод sendImplicitOrderedBroadcast() решает проблему, в принципе сохраняя порядок получателей (по убыванию по приоритету):

  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);
    }
  }

Я позволил себе заявить о проблеме.

person CommonsWare    schedule 08.02.2018
comment
Большое спасибо. Я сам не мог бы написать эту поданную проблему лучше! Я сделал несколько неверных предположений: во-первых, это, очевидно, будет внесено в белый список sigh, а во-вторых, неявные намерения, объявленные в манифесте, теперь не полностью игнорируются (т. е. принимаются только регистрации во время выполнения). Теперь для меня имеет смысл то, что вы сказали в своем комментарии, относительно объявления имени пакета, изменяющего неявное на явное. Я буду использовать ваши sendImplicitOrderedBroadcast() в изобилии! Спасибо еще раз. - person brandall; 08.02.2018
comment
Итак, я действительно не понимаю, что там происходит, но, похоже, вы только что спасли мою жизнь, жизнь моего босса, жизнь нашего интегратора и жизнь конечного клиента. Спасибо. - person dim; 08.01.2019
comment
На Android 11 (Galaxy S10e) я получаю NPE из-за нулевого фильтра. Поэтому мне нужно было соответствующим образом адаптировать компаратор. - person Mark; 04.07.2021