Adding Android Voice Recognition to an existing App - android

I have a working application that I would like to add voice commands. The current application transmits data back and forth over bluetooth on a periodic (timer) basis. The user can press Buttons and NumberPickers to modify the data being sent over bluetooth. There is also data received from the bluetooth link, and displayed in textViews. This application is currently working correctly.
What I would like to do is add voice command capability, so that the user has either the choice of pressing the Buttons/NumberPickers, or can change the values with only voice commands.
I have tested some of the Speech-to-Text examples that can be found on various websites. I have succesfully tested an App that uses RecognizerIntent. Upon a button press, a dialog pops up and you can speak words or phrases, and it correctly displays the result on the screen.
So, I think that I am close, but I'm not really sure how I can combine the Speech-to-Text with my current Bluetooth App. I don't want the user to have to press a button, I just want the App to be constantly listening. Also, I don't want the pop-up Voice Dialog on the screen.
My hardware is a Samsung tablet running Android 4.1.
I am relatively new to Android programming, so any advice (no matter how basic) is appreciated. Thanks.

To prevent the pop-up Voice Dialog on the screen, you can use the ACTION_RECOGNIZE_SPEECH intent:
private static int SR_CODE = 123;
/**
* Initializes the speech recognizer and starts listening to the user input
*/
private void listen() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
//Specify language
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.ENGLISH)
// Specify language model
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
// Specify how many results to receive
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
// Start listening
startActivityForResult(intent, SR_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SR_CODE && resultCode == RESULT_OK) {
if(data!=null) {
//Retrieves the best list SR result
ArrayList<String> nBestList = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String bestResult = nBestList.get(0);
Toast.makeText(getApplicationContext(), bestResult, Toast.LENGTH_LONG).show;
}else {
//Reports error in recognition error in log
Log.e(LOGTAG, "Recognition was not successful");
}
}
Concerning the other issue, " I don't want the user to have to press a button, I just want the App to be constantly listening":
I'll recommend using CMUSphinx to recognize speech continuously. To achieve continuous speech recognition using google speech recognition api, you might have to resort to a loop in a background service which will take too much resources and drains the device battery.
On the other hand, Pocketsphinx works really great. It's fast enough to spot a key phrase and recognize voice commands behind the lock screen without users touching their device. And it does all this offline.
You can try the demo.
If you really want to use google's api as I've demonstrated above, see this

Related

Turning notifications to text-to-speech when driving

I have an application that according to some events, changes a normal notification to text-to-speech in order to since sometimes the phone isn't available to users, and it'll be safer not to handle the phone.
For example, when you're driving, this is dangerous, so i want to turn the notifications to text-to-speech.
I've looked for a long time some explanation for turning text-to-speech when driving, but i can't find any reference for that no where i search.
For generating text-to-speech, i have this part, which works fine :
private TextToSpeech mTextToSpeech;
public void sayText(Context context, final String message) {
mTextToSpeech = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
try {
if (mTextToSpeech != null && status == TextToSpeech.SUCCESS) {
mTextToSpeech.setLanguage(Locale.US);
mTextToSpeech.speak(message, TextToSpeech.QUEUE_ADD, null);
}
} catch (Exception ex) {
System.out.print("Error handling TextToSpeech GCM notification " + ex.getMessage());
}
}
});
}
But, i don't know how to check if i'm currently driving or not.
As Ashwin suggested, you can use Activity recognition Api, but there's a downside of that, the driving samples you'll receive, has a field of 'confidence' which isn't always accurate, so you'll have to do extra work(such as check locations to see if you actually moved) in order to fully know if the user moved.
You can use google's FenceApi which allows you to define a fence of actions such as driving, walking, running, etc. This api launched recently. If you want a sample for using it, you can use this answer.
You can pull this git project (everything free), which does exactly what you want : adds to the normal notification a text-to-speech when you're driving.
In order to know whether you are driving or not you can use Activity Recognition API
Here is a great tutorial that might help you out Tutorial and Source Code

Barcode Scan With Both Hard and Soft Trigger EMDK

We have a custom scanner to scan barcode using, which works with SOFT trigger (Using App Button) by using Motorola's emdk library.
barcodeManager = (BarcodeManager) this.emdkManager.getInstance(EMDKManager.FEATURE_TYPE.BARCODE);
scanner = barcodeManager.getDevice(BarcodeManager.DeviceIdentifier.DEFAULT);
scanner.addStatusListener(articleListener);
scanner.addDataListener(new Scanner.DataListener() {
#Override
public void onData(ScanDataCollection scanDataCollection) {
processData(scanDataCollection);
}
});
scanner.addDataListener(dataListener);
scanner.triggerType = Scanner.TriggerType.SOFT_ALWAYS;
scanner.enable();
How can i have both soft and Hard trigger to scan the data?
and with datalistener process the data received from both?
Zebra Technologies acquire Motorola Solution enterprise business in Oct. 2014, most of the updated documentation is now available under the Zebra Launchpad.
Scanner.TriggerType controls how you want to activate the barcode scanner on Zebra Android devices, usually you can set it up or Hard (scan is activated pressing the hardware trigger button) or Soft (scan is activated as soon as you call the Scanner.read() method).
To have an application that can use the Hardware trigger and having an on screen button to activate the scanner you can leave set the triggerType to Scanner.TriggerType.HARD and implement a login in the click event handler for the soft scan button so that you set the TriggerType to Scanner.TriggerType.SOFT_ONCE and then you call the Scanner.read() method. You can eventually check if there's another read active.
This is a sample implementation that you can test adding a button in the Barcode API sample included in the EMDK for Android (latest is v4.0):
private void softScan() {
if (scanner != null) {
try {
// Reset continuous flag
bContinuousMode = false;
if (scanner.isReadPending()) {
// Cancel the pending read.
scanner.cancelRead();
}
scanner.triggerType = TriggerType.SOFT_ONCE;
scanner.read();
new AsyncUiControlUpdate().execute(true);
} catch (ScannerException e) {
textViewStatus.setText("Status: " + e.getMessage());
}
}
}
So, usually you work with a TriggerType.HARD, but when you press the SCAN button you disable any pending read and you switch to TriggerType.SCAN_ONCE.
The implementation of the status listener needs to switch back the scanner to TriggerType.HARD and call the read() method.
You can find a complete sample at this github repository where I've added a Soft Scan button to the standard Zebra's EMDK Barcode API sample.
All the data are received by the same Data Listener.

Bluetooth pairing - how to show the simple Cancel/Pair dialog?

I have prepared a simple test project for this question at GitHub.
I am trying to create an Android app, which would scan a QR code from a computer screen and then use the data (MAC address and PIN or hash) for easy pairing (bonding) with a Bluetooth device.
Similar to the popular InstaWifi app - but for Classic Bluetooth.
For testing purposes I don't do any barcode scanning yet, but just display a list of devices:
After user touches one of the devices, pairing is tried in MainActivity.java:
private void startBluetoothPairing(BluetoothDevice device) {
Intent pairingIntent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_PIN);
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, 1234);
//device.setPin(new byte[]{1,2,3,4}); <- DOES NOT CHANGE ANYTHING
//device.setPairingConfirmation(false);
startActivityForResult(pairingIntent, REQUEST_BT_SETTINGS);
}
Unfortunately, the popup still asks for PIN:
Because I have actually specified a PIN in my source code, I was actually expecting another, simpler system dialog to be shown (this one is shown when doing NFC OOB pairing):
From searching for solutions, I know that there is a setPin() method, but it is not applicable here (or is it?) - because I am trying to pair the whole smartphone to the Bluetooth device and not just the app...
My question: How to make Android OS to show the simple Cancel/Pair dialog?
Searching for Bluetooth pairing request string at GitHub has not shown any hints...
UPDATE: On unrealsoul007's suggestion (thanks) I have update the source code in MainActivity.java and now the simple Cancel/Pair dialog is displayed:
private void startBluetoothPairing(BluetoothDevice device) {
Intent pairingIntent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
pairingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(pairingIntent, REQUEST_BT_PAIRING);
}
However I am not sure how to complete the pairing process - because onActivityResult is called with resultCode=0 even before the dialog is closed:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// this is called before user clicks Cancel or Pair in the dialog
if (requestCode == REQUEST_BT_PAIRING) {
if (resultCode == Activity.RESULT_OK) { // 0 != -1
Log.d("XXX", "Let#s pair!!!!"); // NOT CALLED
}
return;
}
}
You are being prompted for entering the pin because that is what you are requesting in your pairingIntent.
Instead of using
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_PIN);
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, 1234);
Use
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PASSKEY_CONFIRMATION);
As mentioned here,
The user will be prompted to confirm the passkey displayed on the
screen or an app will confirm the passkey for the user.

How to override voice input key on Android keyboard?

I created an Activity with a button, which when clicked, starts an Intent to launch the voice input as follows:
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak Now");
startActivityForResult(intent, SPEECH_REQUEST_CODE);
Then, I get the results and display them in a dialog so that the user can select the closest match.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SPEECH_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
final ArrayList<String> list_voice_input = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
// I use this ArrayList to create a dialog.
}
super.onActivityResult(requestCode, resultCode, data);
}
So the Activity works as follows: Click the button, speak, and then a dialog pops up listing the closest matches and you can select one.
I have used a button-click to implement this. But Android's keyboard already has inbuilt voice input. When I use it to speak, it types out what I am saying, automatically detecting the closest match.
What I need:
I wish to make use of the default keyboard instead of a button, detecting when the user has chosen to speak instead of type (in a text field), and display a dialog box with the closest matches.
Any ideas on how I can do this?
Edit:
My question was marked as a duplicate, but I am not trying to get rid of the pop-up dialog that comes when you are recording your voice. My question is different.
When you are typing text, in the Android keyboard, there is a voice input option already inbuilt. You can use that to speak text. So, my question is, instead of automically printing out the closest match, can I show the user a list of closest matches in a dialog and ask them to select one?
No, you can't change the behavior of the default keyboard like that. There's no API to do so, to override what a single key does. If you want this you need to interact with the speech to text API yourself, without using the keyboard. This is built into Android (assuming the phone has a voice provider downloaded), and the API allows the voice provider to return multiple possible results. Whether a given voice provider does or not (remember the user and OEM can install any speech to text provider they want) is something you'd have to experiment and find out.

Android App Integrated with OK Google

Is there a way to issue a voice command something like:
OK GOOGLE ASK XXX Some App Specific Question or Command
And have it launch "APP" with the recognized text: "Some App Specific Question or Command"
My app has speech recognition as a service ... but when using my APP I can't ask questions that OK Google can handle ...
Through the Voice Actions API, your app can register for system actions, one of which is 'search' (so you could do 'search for Some Question or command on APP').
In the past, some developers were able to submit a custom voice action request. Upon approval, users could do a specific action with your app via voice. This is no longer an option.
This is actually pretty simple, With the built in voice Actions API you can do that both in online and offline mode. Here a short demo for you,
First prompt the user to input some voice,
private void promptSpeechInput() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
getString(R.string.speech_prompt));
try {
startActivityForResult(intent, REQ_CODE_SPEECH_INPUT);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(),
getString(R.string.speech_not_supported),
Toast.LENGTH_SHORT).show();
}
}
This will bring up the built in Google speech input screen and will take the voice inputs. Now after a voice input check the result and get the voice into a converted string,
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQ_CODE_SPEECH_INPUT: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
// here the string converted from your voice
String converted_text = (result.get(0);
}
break;
}
}
}
Now you can manipulate the string in any way you want or Compare them with pre-defined action strings to execute a specific action and many more....
UPDATE:
To make the app work on after saying a specific command e.g. "OK Google", Just define a static String called "OK Google" and compare each voice input with this pre-defined String. If that matches the "OK Google" String then move to the next worlds and execute the instructions. For example,
"OK Google speak the the current time"
Here you can compare the first two words "OK Google" if that matches your pre-defined String move to the next words which is "speak the current time". For this you may save a set of arrays containing your commands like "speak the current time" will speak out the time.
To make it look more intelligent you can implement a background service and keeps listening to user's voice input.
PS: I'm not sure if that would be an efficient way but it's just another approach of doing this.
To integrate "OK Google" in your app is easy with following two steps.
First we need to declare in the manifest File
<activity..
<intent-filter>
<action android:name="com.google.android.gms.actions.SEARCH_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
/>
Now we need to declare in the Activity onCreate
if (getIntent().getAction() != null && getIntent().getAction().equals("com.google.android.gms.actions.SEARCH_ACTION")) {
query = getIntent().getStringExtra(SearchManager.QUERY);
Log.e("Query:",query); //query is the search word
}
User should follow the syntax to detect by "Ok google", When a user says, “OK Google, search for phrase on app name”, Google first checks if there is an app called app name installed which has declared itself to be capable of handling such queries.

Categories

Resources