Skip to content

Commit

Permalink
Merge pull request phonegap#149 from koolspin/master
Browse files Browse the repository at this point in the history
Add an Android Speech Recognition plugin
  • Loading branch information
macdonst committed Sep 16, 2011
2 parents de2785f + 7239e27 commit ce53551
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 0 deletions.
75 changes: 75 additions & 0 deletions Android/SpeechRecognizer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Android SpeechRecognizer plugin for Phonegap #

This plugin will recognize commands, phrases, etc as spoken by the user.
A collection of possible matches (strings) are returned to your app.

## Adding the Plugin to your project ##

Of course this plugin requires [Android PhoneGap](http://github.com/phonegap/phonegap-android).

1. To install the plugin, copy SpeechRecognizer.js to your project's www folder.
2. Add SpeechRecognizer.js to your html file, eg: `<script type="text/javascript" charset="utf-8" src="SpeechRecognizer.js"></script>`
3. Create an 'com/urbtek/phonegap' path under 'src' and add the SpeechRecognizer.java file to it
4. Add the plugin to the 'res/xml/plugins.xml' file. eg: `<plugin name="SpeechRecognizer" value="com.urbtek.phonegap.SpeechRecognizer"/>`

### Example
```javascript
function onDeviceReady()
{
window.plugins.speechrecognizer.init(speechInitOk, speechInitFail);
// etc.
}

function speechInitOk() {
// we're good
}
function speechInitFail(m) {
// recognizer not present?
}

function recognizeSpeech() {
var requestCode = 1234;
var maxMatches = 5;
var promptString = "Please say a command";
window.plugins.speechrecognizer.startRecognize(speechOk, speechFail, requestCode, maxMatches, promptString);
}

function speechOk(result) {
var match, respObj, requestCode;
if (result) {
respObj = JSON.parse(result);
if (respObj) {
// This is the code that was sent with the original request
requestCode = respObj.speechMatches.requestCode;

for (match in respObj.speechMatches.speechMatch) {
console.log("possible match: " + match);
// regex comes in handy for dealing with these match strings
}
}
}
}

function speechFail(m) {
console.log("speechFail: " + m.toString());
}

```

## RELEASE NOTES ##

### September 16, 2011 ###

* Initial release

## License

The MIT License

Copyright (c) 2011 Colin Turner (github.com/koolspin)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
181 changes: 181 additions & 0 deletions Android/SpeechRecognizer/SpeechRecognizer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/**
* SpeechRecognizer.java
* Speech Recognition PhoneGap plugin (Android)
*
* @author Colin Turner
*
* Copyright (c) 2011, Colin Turner
*
* MIT Licensed
*/
package com.urbtek.phonegap;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;

import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import com.phonegap.api.PluginResult.Status;

import android.util.Log;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.speech.RecognizerIntent;

/**
* Style and such borrowed from the TTS and PhoneListener plugins
*/
public class SpeechRecognizer extends Plugin {
private static final String LOG_TAG = SpeechRecognizer.class.getSimpleName();
public static final String ACTION_INIT = "init";
public static final String ACTION_SPEECH_RECOGNIZE = "startRecognize";
public static final String NOT_PRESENT_MESSAGE = "Speech recognition is not present or enabled";

private String speechRecognizerCallbackId = "";
private boolean recognizerPresent = false;

/* (non-Javadoc)
* @see com.phonegap.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String)
*/
@Override
public PluginResult execute(String action, JSONArray args, String callbackId) {
// Dispatcher
if (ACTION_INIT.equals(action)) {
// init
if (DoInit())
return new PluginResult(Status.OK);
else
return new PluginResult(Status.ERROR, NOT_PRESENT_MESSAGE);
}
else if (ACTION_SPEECH_RECOGNIZE.equals(action)) {
// recognize speech
if (!recognizerPresent) {
return new PluginResult(PluginResult.Status.ERROR, NOT_PRESENT_MESSAGE);
}
if (!this.speechRecognizerCallbackId.isEmpty()) {
return new PluginResult(PluginResult.Status.ERROR, "Speech recognition is in progress.");
}

this.speechRecognizerCallbackId = callbackId;
startSpeechRecognitionActivity(args);
PluginResult res = new PluginResult(Status.NO_RESULT);
res.setKeepCallback(true);
return res;
}
else {
// Invalid action
String res = "Unknown action: " + action;
return new PluginResult(PluginResult.Status.INVALID_ACTION, res);
}
}

/**
* Initialize the speech recognizer by checking if one exists.
*/
private boolean DoInit() {
this.recognizerPresent = IsSpeechRecognizerPresent();
return this.recognizerPresent;
}

/**
* Checks if a recognizer is present on this device
*/
private boolean IsSpeechRecognizerPresent() {
PackageManager pm = ctx.getPackageManager();
List activities = pm.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
return !activities.isEmpty();
}

/**
* Fire an intent to start the speech recognition activity.
*
* @param args Argument array with the following string args: [req code][number of matches][prompt string]
*/
private void startSpeechRecognitionActivity(JSONArray args) {
int reqCode = 42; //Hitchhiker?
int maxMatches = 0;
String prompt = "";

try {
if (args.length() > 0) {
// Request code - passed back to the caller on a successful operation
String temp = args.getString(0);
reqCode = Integer.parseInt(temp);
}
if (args.length() > 1) {
// Maximum number of matches, 0 means the recognizer decides
String temp = args.getString(1);
maxMatches = Integer.parseInt(temp);
}
if (args.length() > 2) {
// Optional text prompt
prompt = args.getString(2);
}
}
catch (Exception e) {
Log.e(LOG_TAG, String.format("startSpeechRecognitionActivity exception: %s", e.toString()));
}

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
if (maxMatches > 0)
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, Integer.toString(maxMatches));
if (!prompt.isEmpty())
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
ctx.startActivityForResult(this, intent, reqCode);
}

/**
* Handle the results from the recognition activity.
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
// Fill the list view with the strings the recognizer thought it could have heard
ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
ReturnSpeechResults(requestCode, matches);
}
else {
// Failure - Let the caller know
ReturnSpeechFailure(resultCode);
}

super.onActivityResult(requestCode, resultCode, data);
}

private void ReturnSpeechResults(int requestCode, ArrayList<String> matches) {
boolean firstValue = true;
StringBuilder sb = new StringBuilder();
sb.append("{\"speechMatches\": {");
sb.append("\"requestCode\": ");
sb.append(Integer.toString(requestCode));
sb.append(", \"speechMatch\": [");

Iterator<String> iterator = matches.iterator();
while(iterator.hasNext()) {
String match = iterator.next();

if (firstValue == false)
sb.append(", ");
firstValue = false;
sb.append(JSONObject.quote(match));
}
sb.append("]}}");

PluginResult result = new PluginResult(PluginResult.Status.OK, sb.toString());
result.setKeepCallback(false);
this.success(result, this.speechRecognizerCallbackId);
this.speechRecognizerCallbackId = "";
}

private void ReturnSpeechFailure(int resultCode) {
PluginResult result = new PluginResult(PluginResult.Status.ERROR, Integer.toString(resultCode));
result.setKeepCallback(false);
this.error(result, this.speechRecognizerCallbackId);
}
}
46 changes: 46 additions & 0 deletions Android/SpeechRecognizer/SpeechRecognizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* SpeechRecognizer.js
* Speech Recognizer PhoneGap plugin (Android)
*
* @author Colin Turner
*
* MIT Licensed
*/

/**
* c'tor
*/
function SpeechRecognizer() {
}

/**
* Initialize
*
* @param successCallback
* @param errorCallback
*/
SpeechRecognizer.prototype.init = function(successCallback, errorCallback) {
return PhoneGap.exec(successCallback, errorCallback, "SpeechRecognizer", "init", []);
};

/**
* Recognize speech and return a list of matches
*
* @param successCallback
* @param errorCallback
* @param reqCode User-defined integer request code which will be returned when recognition is complete
* @param maxMatches The maximum number of matches to return. 0 means the service decides how many to return.
* @param promptString An optional string to prompt the user during recognition
*/
SpeechRecognizer.prototype.startRecognize = function(successCallback, errorCallback, reqCode, maxMatches, promptString) {
return PhoneGap.exec(successCallback, errorCallback, "SpeechRecognizer", "startRecognize", [reqCode, maxMatches, promptString]);
};

/**
* Load
*/
PhoneGap.addConstructor(function() {
PhoneGap.addPlugin("speechrecognizer", new SpeechRecognizer());
});


0 comments on commit ce53551

Please sign in to comment.