Standard Android SpeechRecognizer was working perfectly on Google Glass XE16 - XE16.2
Then the XE17 update suddenly broke everything, with the following error and no callbacks to the Listener anymore:
E/AndroidRuntime(6321): FATAL EXCEPTION: main
E/AndroidRuntime(6321): Process: com.google.glass.voice, PID: 6321
E/AndroidRuntime(6321): java.lang.NullPointerException: VoiceEngine.startListening: voiceConfig cannot be null
E/AndroidRuntime(6321): at com.google.glass.predicates.Assert.assertNotNull(Assert.java:68)
E/AndroidRuntime(6321): at com.google.glass.voice.VoiceEngine.startListening(VoiceEngine.java:650)
E/AndroidRuntime(6321): at com.google.glass.voice.VoiceService$VoiceServiceBinder.startListening(VoiceService.java:116)
E/AndroidRuntime(6321): at com.google.glass.voice.GlassRecognitionService.attachCallback(GlassRecognitionService.java:272)
E/AndroidRuntime(6321): at com.google.glass.voice.GlassRecognitionService.onStartListening(GlassRecognitionService.java:216)
E/AndroidRuntime(6321): at android.speech.RecognitionService.dispatchStartListening(RecognitionService.java:98)
E/AndroidRuntime(6321): at android.speech.RecognitionService.access$000(RecognitionService.java:36)
E/AndroidRuntime(6321): at android.speech.RecognitionService$1.handleMessage(RecognitionService.java:79)
E/AndroidRuntime(6321): at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(6321): at android.os.Looper.loop(Looper.java:149)
By disassembling the GlassVoice.apk (located in /system/priv-app/), I was able to find out that you can add these two extras to your SpeechRecognizer's Intent, and it fixes the NullPointerException :
//mSpeechIntent.putExtra( GlassSpeechRecognizer.EXTRA_VOICE_CONFIG_NAME, "Toto");
mSpeechIntent.putExtra( "voiceConfigName", "Toto");
//mSpeechIntent.putExtra( GlassSpeechRecognizer.EXTRA_VOICE_COMMANDS, new String[]{"red","green","blue"} );
mSpeechIntent.putExtra( "extraVoiceCommands", new String[] {"red","green","blue"}); // Command phrases allowed!
The problem is, as they moved the GlassVoice.apk in a private space, that you cannot load any class of it from your own app. I did not find out how to work around this -- if you know how, help would be much appreciated!
With that, I can see in the logs that one phrase has been recognized when I speak, but I don't have any callback on the usual listener.
Some of the interesting logs (word "red" recognized, but no callbacks):
I/RecognizerController(1818): attachVoiceInputCallback W/RecognizerController(1818): queueingGrecoListener was null in attachVoiceInputCallback ... I/VoiceEngine[20daf4b4](1818): Hotword recognizer triggered a recognition result ... I/SavedAudioStorage(1818): Saved SavedAudioRecord [id=null, filename=/data/data/com.google.glass.voice/recorded_audio/20140508_171311_197.pcm, recognized=true, synced=false, timestamp=1399594400939, recognizedCommands=red:2000:2620, sampleRate=16000]
How can we work around this?
EDIT WITH ANSWER!
Thanks to @pscholl, I found a workaround. If your app is simple and does not include many jars, just look at @pscholl solution.
In my case, adding GlassVoice-xe17.apk, which contains thousands of methods, made my app hit the infamous "64K methods" Android ceiling. If you don't know what this terrible limit is, just think about the "640K in MS-DOS", reinvented by Android (Dalvik VM).
First I tried to turn ProGuard on, in order to shrink my app, by removing all unused methods: the problem is that it is a nightmare to configure, and after hours of failed attempts, I was still having unexpected classes missing and cryptic errors.
So I turned to Dex loading, as explained here: https://github.com/mmin18/Dex65536. The problem is that GlassVoice.apk includes all com.google.common package, that I also use through Guava. In the Dex65536 solution, the classloader loads the class from the external APK first (nice hack, that you can't turn around), and therefore it was not working.
I ended up coding a "class pre-loader", invoked before the additional Dex ClassLoader is added. Drop me a line if you're interested in the code (but it's far from being optimal).
That was tough and ugly! I hope the Glass Dev Team will solve the voice problem soon, with a neat solution -- not like this one :-)