Как определить, был ли поиск выполнен посредством ввода текста или распознавания голоса?

Это будет вопрос с самостоятельным ответом, потому что я хотел бы четко документировать, как определить, была ли цель поиска вызвана вводом текста или распознаванием голоса. Причиной этого было то, что я пытался записать результаты поиска в своем приложении в Google Analytics, и мне нужно было знать, печатал ли пользователь свои запросы на клавиатуре в виде текста или использовал функцию голосового поиска.

Я нашел несколько вопросов о Stackru, которые касались этого вопроса, но я обнаружил, что их трудно найти и они плохо документированы. Поэтому, надеюсь, мой ответ предоставит правильные ключевые слова и детали, которые помогут другим найти эту тему быстрее и яснее в будущем.

1 ответ

Решение

Активность поиска в моем приложении выполняется в singleTop режим, и поэтому я обрабатываю входящие поисковые запросы через @Override из onNewIntent(), В рамках этого метода первое, что вам нужно сделать, это проверить, является ли входящее намерение фактически поисковым. Мы осуществляем это следующим образом:

if (intent.getAction().equals(Intent.ACTION_SEARCH)){}

Следующая часть немного сложна и вызвала у меня некоторые ложные срабатывания на старых API. Есть два дополнения, которые прилагаются к ACTION_SEARCH цель: QUERY а также USER_QUERY, Если мы прочитаем об этих двух значениях в SearchManager документы, мы находим следующую информацию:

public static final String QUERY:

Назначение дополнительного ключа данных: используйте этот ключ с content.Intent.getStringExtra() получить строку запроса из Intent.ACTION_SEARCH,

public static final String USER_QUERY:

Назначение дополнительного ключа данных: используйте этот ключ с content.Intent.getStringExtra() получить строку запроса, набранную пользователем. Это может отличаться от значения QUERY, если намерение является результатом выбора предложения. В этом случае QUERY будет содержать значение SUGGEST_COLUMN_QUERY для предложения, а USER_QUERY будет содержать строку, введенную пользователем.

По сути, мы можем извлечь из этих двух записей в документе, что значение QUERY всегда будет содержать фактическое значение поиска, независимо от того, как поиск был выполнен. Таким образом, не имеет значения, набрал ли пользователь в поиске, произнес это с помощью распознавания голоса или выбрал поисковое предложение - это поле будет содержать необработанное значение String того, что он искал.

С другой стороны, USER_QUERY может быть или не быть нулевым, в зависимости от того, как был выполнен поиск. Если пользователь вводит в своем поиске текст, это поле будет содержать значение его поиска. Если пользователь выполняет поиск с распознаванием голоса, это значение будет нулевым.

Это дает нам отличный (хотя и в какой-то степени хакерский) способ определить, набрал ли пользователь текст в поиске или использовал функцию голосового поиска. Но вот сложная часть: как вы можете видеть в документации выше, предлагается использовать getStringExtra() чтобы получить это значение из намерения. Это не надежно, потому что ценность USER_QUERY на самом деле SpannableString не String, Это, вероятно, приведет к ClassCastException потому что если вы используете getStringExtra() вы пытаетесь разыграть SpannableString к String, который не будет работать. Исключение будет автоматически перехвачено для вас, но в результате вы можете получить ложно-положительное значение NULL, в результате чего ваш код поверит, что поиск был выполнен с помощью распознавания голоса, тогда как на самом деле введенное текстовое значение просто потеряно, потому что ClassCastException.

Таким образом, решение состоит в том, чтобы вместо этого работать с SpannableString приходящий из USER_QUERY и вместо этого проверьте нулевое значение, чтобы не вызывать исключение ClassCastException и ложноположительное значение null. Но вы заметите, что Intent не имеет метода для получения SpannableStrings, но у него есть getCharSequenceExtra() метод. поскольку SpannableString инвентарь CharSequence, мы можем просто использовать этот метод, чтобы извлечь нашу USER_QUERY SpannableString и привести ее к выходу. Итак, мы сделаем это так:

SpannableString user_query_spannable = (SpannableString) intent.getCharSequenceExtra(SearchManager.USER_QUERY);

Теперь мы можем проверить нулевое значение этого значения, чтобы безопасно определить, набрал ли пользователь текст или выполнил поиск каким-либо другим способом, таким как распознавание голоса.

Собрав все это вместе, мы получим что-то вроде этого:

@Override
protected void onNewIntent(Intent intent) {

    if (intent.getAction().equals(Intent.ACTION_SEARCH)) {

        SpannableString user_query_spannable = (SpannableString) intent.getCharSequenceExtra(SearchManager.USER_QUERY);

        //if this was a voice search
        if (user_query_spannable == null) {
            //Log, send Analytics hit, etc.
            //Then perform search as normal...
            performSearch(intent.getStringExtra(SearchManager.QUERY));

        } else {
            //Log, send Analytics hit, etc.
            //Then perform search as normal
            performSearch(intent.getStringExtra(SearchManager.QUERY));
        }
    } 
}

Как я упоминал ранее, для меня эту информацию было нелегко найти с помощью поисков в Google и в Stackru, особенно когда официальная документация по Android содержит вводящую в заблуждение информацию о том, как работать с этими значениями. Надеемся, что этот ответ предоставит гораздо более удобный источник доступа для тех, кто ищет подобную информацию.

Пакет [{android.speech.extra.RESULTS=[hello], query=hello, android.speech.extra.CONFIDENCE_SCORES=[0.9299549]}] ЭТО БУДЕТ В НАБОРЕ ДЛЯ ГОЛОСА

Другие вопросы по тегам