Чак Норрис и Google Glass — что общего, а вот…

    Недавно мне (несказанно поперло) выпал шанс купить Google Glass по Explorers Program. Стоило только заказать, как на следующее утро почтальон разбудил меня стуком в деверь — вам посылка. Не умываясь и не чистя зубы…

    Под вечер возникла возможность попрограммировать. Изучив пару-тройку примеров и настроив окружение — я взялся за дело. Возникла идея написать приложение которое будет вытаскивать шутку про Чака Норриса из веб-сервиса, парсить JSON, и читать вслух.


    Итак начнем.

    Голосовая активация:


    Наша шутилка будет активироваться голосовой командой. Для этого определяем сервис в манифесте:

            <service
                    android:name="com.chucknorris.JokeService"
                    android:icon="@drawable/icon"
                    android:label="@string/app_name"
                    android:enabled="true"
                    android:exported="true">
                <intent-filter>
                    <action android:name="com.google.android.glass.action.VOICE_TRIGGER"/>
                </intent-filter>
                <meta-data
                        android:name="com.google.android.glass.VoiceTrigger"
                        android:resource="@xml/voice_trigger_start"/>
            </service>
    


    Ключевым элементом здесь, в отличие от обычных андроид приложений, является VoiceTrigger.

    xml/voice_trigger_start выглядит просто:

    <?xml version="1.0" encoding="utf-8"?>
    <trigger keyword="@string/chuck_norris_joke" />
    


    Ну и наконец, строка, которая задает фразу, по которой в свою очередь наш сервис запустится:

    <string name="chuck_norris_joke">say Chuck Norris joke</string>
    


    Примечание: согласно правилам, которые Google выдвигает по отношению к активационным фразам — они должны начинаться с глагола. Мне лично это правило не очень нравится, но сапожник не вправе судить выше сапога. Просто уж больно много фраз будет начинаться с «show», «get», «say», «start»
    Более подробно здесь

    Теперь, когда мы определили VoiceTrigger, наш сервис будет стартовать, если мы скажем «ok glass, say Chuck Norris joke»
    К слову, Activity тоже можно запустить с помощью голосовой команды. Кусочек манифеста будет таковым:

           <activity
             android:name="com.google.android.glass.sample.waveform.WaveformActivity" >
                <intent-filter>
                    <action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
                </intent-filter>
                <meta-data android:name="com.google.android.glass.VoiceTrigger"
                    android:resource="@xml/voice_trigger_start" />
            </activity>
    


    Начинка сервиса

    Очень хочется рассказать о Card и LiveCard, но как-нибудь в другой раз. Наша шутилка не будет показывать ничего, просто будет шутить вслух.

    Раз шутку нужно вытащить из интернет-ресурса, то не забудем задекларировать сие намерение в AndroidManifest.xml:
    <uses-permission android:name="android.permission.INTERNET"/>
    


    В UI Thread лазить в интернет воспрещается, заведем для этой цели AsyncTask

    doInBackground выполняет запрос на веб сервис:

            HttpClient client = new DefaultHttpClient();
            HttpGet getRequest = new HttpGet();
    
            try {
                // construct a URI object
                getRequest.setURI(new URI(urls[0]));
            } catch (URISyntaxException e) {
                Log.e("URISyntaxException", e.toString());
            }
    
            // buffer reader to read the response
            BufferedReader in = null;
            // the service response
            HttpResponse response = null;
            try {
                // execute the request
                response = client.execute(getRequest);
            } catch (ClientProtocolException e) {
                Log.e("ClientProtocolException", e.toString());
            } catch (IOException e) {
                Log.e("IO exception", e.toString());
            }
    
            try {
                in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            } catch (IllegalStateException e) {
                Log.e("IllegalStateException", e.toString());
            } catch (IOException e) {
                Log.e("IO exception", e.toString());
            }
            StringBuffer buff = new StringBuffer("");
            String line = "";
            try {
                while ((line = in.readLine()) != null) {
                    buff.append(line);
                }
            } catch (IOException e) {
                Log.e("IO exception", e.toString());
                return e.getMessage();
            }
    
            try {
                in.close();
            } catch (IOException e) {
                Log.e("IO exception", e.toString());
            }
    


    затем парсит JSON:

            String joke = "";
            try {
                JSONObject jObject = new JSONObject(buff.toString());
                joke = jObject.getJSONObject("value").getString("joke");
            } catch (JSONException e) {
                Log.e("JSON exception", e.toString());
            }
    
    


    ok glass скажи шось


    AsyncTask предоставляет метод onPostExecute. Стало быть, когда запрос выполнен и шутка получена, вытащена из JSON оболочки — самое время произнести ее вслух. Android любезно помогает нам не только распознать речь но и произнести текст с помощью TextToSpeech.

    TextToSpeech инициализируем в сервисе и передаем в AsyncTask через параметр конструктора.
            tts = new TextToSpeech(this, new TextToSpeech.OnInitListener(){
                @Override
                public void onInit(int i) {
                      //TODO по-хорошему надо бы подождать инициализации
                }
            });
    


    в onPostExecute вызываем новый метод readOutLoud
        protected void onPostExecute(String joke) {
            if (exception != null) {
                return;
            }
            readOutLoud(joke);
        }
    


    чтение шутки вслух:
        private void readOutLoud(String joke) {
            tts.speak(joke, TextToSpeech.QUEUE_FLUSH, null);
        }
    


    Отладка и загладка

    Теперь осталось подключить очки через USB, собрать apk, align, sign, deploy (IDE все сделает за нас). Никакой Activity запускать не нужно.

    итак, барабанная дробь
    «ok glass, say Chuck Norris Joke»
    «Chuck Norris can read from an input stream.»

    Вместо послесловия


    Пользуясь случаем, хочу поблагодарить www.icndb.com. Я думаю надо бы сделать похожий сервис с шутками про Штирлица. Если будет время — займусь.

    Насчет голосового воспроизведения

    наверняка есть дополнительные настройки скорости чтения и/или голоса. На OS X они есть.

    Возвращаясь к пункту «а что показывать»

    небольшой фрагмент, который позволяет создать статическую карточку с картинкой слева и текстом шутки:

        private void publishJokeCard(String joke) {
            Card card = new Card(ctx);
            card.setText(joke);
            card.addImage(R.drawable.chuck);
    
            TimelineManager.from(ctx).insert(card);
        }
    


    Немного больше о карточках — в следующий раз, надо немного разобраться. Пока писал одно приложение — задеплоил на очки — а там уже новая версия SDK. Благо кто-то на форуме поделился опытом, что вышло обновление день назад (на тот момент). Как выглядят карточки можно посмотреть здесь

    Картинки

    Иконку подготовить не трудно — основное требование — белая, на прозрачном фоне и 50х50 пикселей.

    Картинка для карточки — ну в принципе любая, но лучше — где-то треть размера ширины карточки и полный размер высоты карточки.
    На последок, пожалуй скажу, что не все шутки одинаково приличны. Чтоб не ввести пользователя в конфуз — лучше добавить к URL "?type=nerdy".

    Код

    Если кому интересно, код целиком
    Официальные примеры здесь
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 16

      +30
      > Chuck Norris can read from an input stream
      сдаётся мне, что «can write to» все-таки, иначе в чем шутка.
        0
        Ну как же. «can write to» может любой нормальный человек, например, обычной клавиатурой писать в input stream reader. А вот читать соостветственно может только сама программа. )
          0
          Да уж, ставить минусы всякий гаразд, а сказал бы кто по делу) В чем же шутка тогда с «write to»?
          int main()
          {	
              istringstream buffer("Chuck");
              cin.rdbuf(buffer.rdbuf());
          
              string test;
              cin >> test;
              cout << test;
              return 0;
          }
          

          Вау, магия. И есть много других способов писать в… минутки-минутку… input stream, ведь это всего лишь обёртка над streambuf. Поэтому «write to» тривиально как с программной стороны, так и со стороны пользователя, поэтому Чаку здесь делать нечего.
          0
          Вот такие они «nerdy» шутки.
          +2
          Блин, зашел почитать шутки про Чака Норриса, а тут всего одна и та кажется с ошибкой :)
          +1
          Если бы автор перед публикацией этой статьи изменил бы своё местоположение на «Россия, ...» — была бы очень суровая интрига после фразы « на следующее утро почтальон разбудил меня ...».

          Иллюзорные мечты…
            +1
            Разбудил стуком в деверь, а усыпил поглаживанием в сноху.
              –1
              Извините, гложет червь непонимания. Сноха — это та что жена сына или какая-то другая? Уже и представил себе почтальона, поглаживающего сноху. И пробовал заменить «сноху» на «соху» — никак не складывается картинка. Поясните пжлст.
                0
                Прочитайте внимательно.
              +1
              Чак Норрис настолько крут, что ему без всякого программирования на любые команды отвечают любые очки.
                0
                Или «Чак Норрис натолько крут, что может писать рабочий код даже для самых обычных солнечных очков»
                  +1
                  При распознавании фразы «roundhouse kick» или «Чак Норрис» Google Glass пакуется в противоударный чехол.
                    0
                    Когда Чак Норрис надевает Google Glass, прибор, на всякий случай, начинает выполнять и не заложенные в него команды.
                +2
                По-английски следует говорить «tell a joke», а не «say a joke».
                  0
                  В оригинале, активационной фразой была «Chuck Norris joke». С вашей поправкой согласен наполовину. «say a joke» правильнее чем «say joke». «tell me a joke» правилнее чем «tell a joke». Впредь буду рад вашим поправкам, присланым в личку. спсб.

                Only users with full accounts can post comments. Log in, please.