9

With Glass you can launch an app via the 'OK, Glass' menu and it seems to pick the nearest match unless a command is miles off, and you can obviously see the list of commands.
Is there anyway from within the app, or from the voice prompt (after the initial app trigger) to have a similar list given and return the nearest match.

Random (non-real world) example, an app that shows you a colour, "OK Glass, show the colour red"

'show the colour' could be your voice trigger and seems to be matched by glass on a 'nearest neighbor' method, however 'red' is just read in as free text and could be easily misheard as 'dread' or 'head', or even 'read' as there is no way of differentiating 'read' from 'red'.

Is there a way to pass a list of pre-approved option (red, green, blue, orange*, etc.) to this stage, or to another voice prompt within the app so the user can see the list and get more accurate results when there is a finite set of expected responses (like the main ok glass screen)?

*ok well nothing rhymes with orange, we're probably safe there

Ben
  • 1,767
  • 16
  • 32

3 Answers3

20

The Google GDK doesn't support this feature yet. However, the necessary features are already available in some libraries and you can use them as long as the GDK doesn't support this natively. What you have to do:

  1. Pull the GlassVoice.apk from your Glass: adb pull /system/app/GlassVoice.apk

  2. Use dex2jar to convert this apk into a jar file.

  3. Add the jar file to your build path

Now you can use this library like this:

public class VoiceActivity extends Activity {

    private VoiceInputHelper mVoiceInputHelper;
    private VoiceConfig mVoiceConfig;

        @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.voice_activity);

        String[] items = {"red", "green", "blue", "orange"};
        mVoiceConfig = new VoiceConfig("MyVoiceConfig", items);
        mVoiceInputHelper = new VoiceInputHelper(this, new MyVoiceListener(mVoiceConfig),
                VoiceInputHelper.newUserActivityObserver(this));
    }

    @Override
    protected void onResume() {
        super.onResume();
        mVoiceInputHelper.addVoiceServiceListener();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mVoiceInputHelper.removeVoiceServiceListener();
    }

    public class MyVoiceListener implements VoiceListener {
        protected final VoiceConfig voiceConfig;

        public MyVoiceListener(VoiceConfig voiceConfig) {
            this.voiceConfig = voiceConfig;
        }

        @Override
        public void onVoiceServiceConnected() {
            mVoiceInputHelper.setVoiceConfig(mVoiceConfig, false);
        }

        @Override
        public void onVoiceServiceDisconnected() {

        }

        @Override
        public VoiceConfig onVoiceCommand(VoiceCommand vc) {
            String recognizedStr = vc.getLiteral();
            Log.i("VoiceActivity", "Recognized text: "+recognizedStr);

            return voiceConfig;
        }

        @Override
        public FormattingLogger getLogger() {
            return FormattingLoggers.getContextLogger();
        }

        @Override
        public boolean isRunning() {
            return true;
        }

        @Override
        public boolean onResampledAudioData(byte[] arg0, int arg1, int arg2) {
            return false;
        }

        @Override
        public boolean onVoiceAmplitudeChanged(double arg0) {
            return false;
        }

        @Override
        public void onVoiceConfigChanged(VoiceConfig arg0, boolean arg1) {

        }
    }

}
blueshadow
  • 401
  • 3
  • 8
  • 1
    I tried it.. and it worked perfectly. Thank you so much! – andrea.rinaldi Feb 07 '14 at 14:46
  • 2
    I just updated to XE16 and it doesn't seem to work anymore. After updating, I pulled the new apk from /system/private-app/GlassVoice.apk, used dex2jar to convert it, and added the jar to my build path. Ran the same code that worked perfectly on XE12. Now it seems that the VoiceListener never catches any VoiceCommand after the first one it detects. @blueshadow Do you have any idea why that is and how to fix it? – Rez Apr 17 '14 at 23:35
  • Sorry, but I had to give away my Google Glass. I cannot check this anymore. – blueshadow Apr 18 '14 at 12:36
  • @Rez any luck resolving this issue? I'm not even able to get the GlassVoice.apk from Glass as it doesn't exist... – rosorio Apr 22 '14 at 13:49
  • Curious about this myself too. Looking to use it on XE 16.11. – egfconnor May 01 '14 at 16:20
  • @rosorio You can pull the Glassvoice.apk but it's now in /system/private-app instead of /system/app. For the issue I mentioned above, I found a way to hack around it but it's very messy and I'm not happy with it. The hack is to change the VoiceListener's VoiceConfig every time onVoiceCommand() is fired. – Rez May 02 '14 at 18:57
  • 2
    the location seems to be /system/priv-app nowadays – M0rph3v5 May 04 '14 at 11:38
  • @Rez it seems like returning null instead of the config in the onVoiceCommand gives you the ability to keep recognizing commands one after another. – M0rph3v5 May 06 '14 at 09:58
  • To find the latest location of the APK (cause it seems to change quite a bit), you can follow these commands: http://stackoverflow.com/a/18003462/1889732 – YP_be May 09 '14 at 13:26
  • 1
    I pulled the GlassVoice.apk from /system/priv-app and obtained the jar through dex2jar tool! But also returning null in the method VoiceListener.onVoiceCommand it seems to be unable to recognize anything. My glass are up to date with XE 17. – andrea.rinaldi May 13 '14 at 14:56
  • Works for me on XE17, but only the first time I say something. –  May 14 '14 at 08:59
  • When i am in an activity where i have given command "go" to move to another activity, but i am not saying "go" instead it takes any voice command and starts forcefully the next activity. – Jay Thakkar Jun 12 '14 at 09:28
  • It worked for me! But it comes another unexpected problem: "MyVoiceListener" only trigger once in my Activity. In this case, I need to trigger MyVoiceListener for many times. Any ideas? – ohyes Jun 23 '14 at 08:05
  • 1
    I found the solution to my question - Simply return "null" in onVoiceCommand. And it works continuously :) Here's the ref: [link](http://stackoverflow.com/questions/23441199/why-does-glass-gdk-based-voicelistener-only-catch-voicecommand-once-in-xe16) – ohyes Jun 23 '14 at 10:02
  • Will Google pull the app from the Glassware Gallery if it uses such private APIs? – leocadiotine Aug 22 '14 at 19:29
  • 1
    Does anyone know why this functionality is missing from XE 22?com.google.glass.input.VoiceInputHelper and com.google.glass.input.VoiceListener are no longer in GlassVoice.apk. Have they moved, or has Google pulled the plug? – Eugene Oct 27 '14 at 03:00
  • hi guys, I updated my Glass to XE22 and now, the library obtained from the pulled apk makes my application go in "GCC overhead exceeded limit".. Are you in the same situation or is it only a problem of mine? Thanks – andrea.rinaldi Nov 06 '14 at 22:00
5

You can take advantage of the disambiguation step that occurs when multiple Activities or Services support the same Voice Trigger: simply have multiple Activities or Services in your application support "show me the color" as the voice trigger and label them with the color options.

Your manifest would look something like:

<application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:icon="@drawable/icon_50"
        >

    <activity
            android:name="com.mycompany.RedActivity"
            android:label="@string/red"
            android:icon="@drawable/icon_red"
            >
        <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/activity_start"
                />
    </activity>

    <activity
            android:name="com.mycompany.BlueActivity"
            android:label="@string/blue"
            android:icon="@drawable/icon_blue"
            >
        <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/activity_start"
                />
    </activity>
    <!-- ... -->
</application>

Those Activities or Services would only be used as a "trampoline" to launch the main logic of your app with the color selection.

Alain
  • 6,044
  • 21
  • 27
  • Thanks, this seems like an interesting work around, although feels pretty hacky and unmaintainable, especially if you have a long list of possible options, I don't suppose you know of any future plans to support this type of interaction a little more cleanly? – Ben Jan 20 '14 at 16:06
  • @Alain are you sure this solution works? Because I'm in the same situation of Ben. So the recognizer which handles VoiceTrigger intents will automatically choose the nearest of those labels? I mean.. if it understands "Read" instead of "Red", will it automatically choose "Red" instead of "Blue" because "Red" would be recognized to be more similar to the "Read" word it previously understood? – andrea.rinaldi Jan 28 '14 at 09:33
  • 1
    When using this approach, the recognizer will not be run but instead, the process used to launch an Activity/Service will trigger the correct one according to what it recognized. – Alain Jan 28 '14 at 16:59
  • Oh, ok. So it's only a tricky way to exclude wrongly-recognized speeches (hope I understood it right). I think @blueshadow's solution fits better Bob's problem, anyway you gave me a nice input: thanks man ;) – andrea.rinaldi Jan 28 '14 at 19:10
5

If you haven't already, you should take a look at contextual voice menus that were added just a few weeks ago to the GDK. I had your exact same problem just the day before it was released, looking at it the next day and finding this helped me a lot! :)

Kezo
  • 130
  • 2
  • 7
  • I just got familiar with this option, but there it is said, that commands which are not listed in VoiceTriggers.Command and ContextualMenus.Command can be used only in development mode. Maybe I missed something and I can use my own commands in production? – Scadge Jul 02 '14 at 13:54
  • No, that's true. You won't be able to distribute your glassware through MyGlass with the development permission. It is however mentioned that you are able to submit your own commands for approval so you will be able to use them. – Kezo Jul 02 '14 at 14:14
  • Yeah, I know I can submit them. Thanks, anyway. – Scadge Jul 02 '14 at 14:28