I am trying to develop and app that listens and speaks back to the user. I am trying to make it as handsfree as possible.
My issue is that if the user does not respond in time, the SpeechRecognition will timeout, and the user will need to press the button to start listening again.
*Is there a way for me to do a work around where if nothing is heard by the application, it can prompt to try again and restart the listener?
CODE:
//Function i call when a user input is required.
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());
try {
startActivityForResult(intent, REQ_CODE_SPEECH_INPUT);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(),
getString(R.string.speech_not_supported),
Toast.LENGTH_SHORT).show();
}
}
/**
* Receiving speech input
* */
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
System.out.println("REQUEST CODE: " + requestCode);
switch (requestCode) {
case REQ_CODE_SPEECH_INPUT: {
System.out.println("resultCode: " + resultCode);
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
txtSpeechInput.setText(result.get(0));
input = result.get(0).toLowerCase();
}
break;
}
}
}
I also have code that will read text to the user, and then prompt for voice input after its finished.
Please let me know if i can provide more details or code. Thanks much!
To make google speech handsfree without clicking the "mic button", you have to make your own class for the recognizer, i wrote the code in xamarin-android, so it's pretty similar on java :
Public class CustomRecognizer : Java.Lang.Object, IRecognitionListener, TextToSpeech.IOnInitListener
{
private SpeechRecognizer _speech;
private Intent _speechIntent;
public string Words;
public CustomRecognizer(Context _context)
{
this._context = _context;
Words = "";
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
_speechIntent.PutExtra(RecognizerIntent.ActionRecognizeSpeech, RecognizerIntent.ExtraPreferOffline);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
}
void startover()
{
_speech.Destroy();
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
StartListening();
}
public void StartListening()
{
_speech.StartListening(_speechIntent);
}
public void StopListening()
{
_speech.StopListening();
}
public void OnBeginningOfSpeech()
{
}
public void OnBufferReceived(byte[] buffer)
{
}
public void OnEndOfSpeech()
{
}
public void OnError([GeneratedEnum] SpeechRecognizerError error)
{
Words = error.ToString();
startover();
}
When the recognizer got timeout, it will call OnError Event
. On my code, i put startover() to restart the recording.
Related
trying to use in app billing in Android at the moment.
Everything works fine and I can purchase items and query existing ones but my OnIabPurchaseFinishedListener listener is not being called during a successful purchase. It is called when there is an issue but not on a completed purchase.
I have my main activity, with fragments and a navigation drawer. (fragments are not touched here. I have a helper class that all the billing happens in.
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, MyBilling.Update {\
MyBilling bill;
OnCreate(){
bill = new MyBilling(this, this);
bill.onCreate();
}
private void RemoveAdsClick()
{
bill.purchaseRemoveAds();
}
public void NewPurchaseUpdate(){
tinydb.putBoolean("Premium", true);
nav_Menu.findItem(R.id.remove_ad_button).setVisible(false);
displaySelectedScreen(R.id.distance_check); // Reload screen
}
}
public class MyBilling extends Activity {
////Interface
public interface Update {
void NewPurchaseUpdate();
}
// Debug tag, for logging
static final String TAG = "XXXXXX";
static final String SKU_REMOVE_ADS = "remove_ads";
// (arbitrary) request code for the purchase flow
static final int RC_REQUEST = 10111;
// Activity
Activity activity;
// The helper object
IabHelper mHelper;
String base64EncodedPublicKey = "xxxxxxxx";
String payload = "xxxxx";
public boolean isAdsDisabled = false;
public boolean AdCheck = false;
////Instance of interface
Update myActivity;
public MyBilling(Activity launcher,Update activity) {
this.activity = launcher;
myActivity = activity;
}
// User clicked the "Remove Ads" button.
public void purchaseRemoveAds() {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
mHelper.launchPurchaseFlow(activity, SKU_REMOVE_ADS,
RC_REQUEST, mPurchaseFinishedListener, payload);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mHelper == null) return;
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener()
{
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: "
+ purchase);
// if we were disposed of in the meantime, quit.
if (mHelper == null)
return;
if (result.isFailure()) {
complain("Error purchasing: " + result);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_REMOVE_ADS)) {
// bought the premium upgrade!
myActivity.NewPurchaseUpdate();
Log.d(TAG, "New Purchase Update Method was called");
}
}
};
}
some googling showed that it could be an issue with onActivityResult not being in the helper class. So I made billing class extend activity and then added onActivityResult and #Override but this also is not called with any breakpoints.
As mentioned above, OnIabPurchaseFinishedListener is called for a failed purchase (already own item) but not for a successful one.
Any help here would be great, I have tried to keep the code as light as possible to help with reading. If I'm missing anything please let me know.
I have fixed this issue by ditching my helper class for now and moving the billing tasks into the main activity.
I am trying to use the Speech recognition without dialog with RecognitionListener, but it doesn't work. The following codes are the way now I use, and the bottom codes (test part) are for checking that could phone receive my commanding. Additionally, I have added permissions Audio. Finally, I don't want there have any button.
This is my first time asking question, so hope I dont violate any unspoken rules.
Thank you very much,
public class Step extends AppCompatActivity {
private final int SPEECH_RECOGNITION_CODE = 1;
private TextView txtOutput;
private Button btnMicrophone;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_step);
txtOutput = (TextView) findViewById(R.id.txt_output);
btnMicrophone = (Button) findViewById(R.id.btn_mic);
startSpeechToText();
btnMicrophone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startSpeechToText();
}
});
}
private void startSpeechToText() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "SPEAK");
try {
startActivityForResult(intent, SPEECH_RECOGNITION_CODE);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(), "Sorry! Speech recognition is not supported in this device.", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case SPEECH_RECOGNITION_CODE: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String text = result.get(0);
txtOutput.setText(text);
test(txtOutput.getText().toString());
startSpeechToText();
}
break;
}
}
}
public void test (String com) {
for(int i=0;i<com.length();i++) {
if (com.startsWith("good",i)) {
com = com + "123";
Toast.makeText(CookStep.this, com, Toast.LENGTH_SHORT).show();
}
}
if(com.compareToIgnoreCase("OK")==0){
com=com+"456";
Toast.makeText(CookStep.this, com, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(CookStep.this, com, Toast.LENGTH_SHORT).show();
}
}
}
So far in Android I know how to wall post to the user's wall via the web but I'd like, the app to detect whether the user has the facebook application installed and if so post via that. Does anyone know how to do this?
My code so far is below:
public class MainActivity extends Activity
{
private static String FACEBOOK_APP_ID = "276023232498070";
private static final String[] PERMISSIONS =
new String[] { "publish_stream","email","user_birthday","user_location" };
private Facebook facebook;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
facebook = new Facebook(FACEBOOK_APP_ID);
Bundle parameters = new Bundle();
parameters.putString("app_id", "276023232498070");
parameters.putString("link", "https://play.google.com/store/apps/details?id=myappistasty");
parameters.putString("name", "This is the name of the link set in app.");
parameters.putString("caption", "This is Text that is specified in bt the aoo");
parameters.putString("picture",
"http://i.dailymail.co.uk/i/pix/2012/11/15/article-0-1609D0FF000005DC-373_964x641.jpg");
// Posting my message, maybe here i could add paramterers like icon and a link etc..?
facebook.dialog(MainActivity.this, "feed", parameters,new PostDialogListener());
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
facebook.authorizeCallback(requestCode, resultCode, data);
Toast.makeText(getApplicationContext(), "Hello", Toast.LENGTH_LONG).show();
}
public abstract class BaseDialogListener implements DialogListener {
#Override
public void onFacebookError(FacebookError e) {
e.printStackTrace();
}
#Override
public void onError(DialogError e) {
e.printStackTrace();
}
#Override
public void onCancel() {
}
}
public class PostDialogListener extends BaseDialogListener {
#Override
public void onComplete(Bundle values) {
final String postId = values.getString("post_id");
if (postId != null) {
Log.e("","Message posted on the wall.");
MainActivity.this.finish();
} else {
Log.e("","No message posted on the wall.");
MainActivity.this.finish();
}
}
}
}
You should get list of activities that can handle Intent.ACTION_SEND and find the facebook app.
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "In Android, how do I share (intent) using the Facebook application rather than via web?");
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, "http://stackoverflow.com/questions/23495438");
PackageManager packageManager = getPackageManager();
List activityList = packageManager.queryIntentActivities(shareIntent, 0);
for (final ResolveInfo app : activityList) {
if ((app.activityInfo.name).contain("facebook")) {
final ActivityInfo activity = app.activityInfo;
final ComponentName name = new ComponentName(activity.applicationInfo.packageName, activity.name);
shareIntent.addCategory(Intent.CATEGORY_LAUNCHER);
shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
shareIntent.setComponent(name);
startActivity(shareIntent);
break;
}
}
The preferred way of doing this is via the Share Dialog for Android:
https://developers.facebook.com/docs/android/share/#linkshare
i try to write a code for android app that take a string that returned from google speech api and use it to send to other object "levenshte.testLevenshteindistance", within same thread.
the problem i can't make it to be synchronize work!
i mean my code call the object before the google speech api return value "depended on internet speed"?!
ublic class MainActivity extends Activity {
public ListView sList;
ArrayList<String> names;
int sfound;
mp3Player mp3Player;
Levenshteindistance levenshte;
public static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
voiceinputbuttons();
starVoiceRecognation();
}
private void starVoiceRecognation() {
Thread timer = new Thread(){
public void run(){
new VoiceRecognizer().execute();
//names is an ArrayList returnd by google speech api
sfound=levenshte.testLevenshteindistance(names.get(0).toString());
}
};timer.start();
}
public void voiceinputbuttons() {
sList = (ListView) findViewById(R.id.list);
//default value if create mp3player before set sName or rName or actionNumbe
names=null;
levenshte = new Levenshteindistance();
}
public void informationMenu() {
startActivity(new Intent("android.intent.action.INFOSCREEN"));
}
public void startVoiceRecognitionActivity() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,"Speech recognition demo");
try {
startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
} catch (ActivityNotFoundException e) {
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK) {
// i want the timer thread wait until assign a value to this name variable
names = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if (names.contains("information")) {
informationMenu();
}
super.onActivityResult(requestCode, resultCode, data);
}
}
private class VoiceRecognizer extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... url1) {
startVoiceRecognitionActivity();
return null;
}
}
}
i want be sure that the names not null when call the levenshte.testLevenshteindistance(names.get(0).toString());
You're set up wrong for this. You don't start voice recognition in a task and assume it will be over by the time some timer runs. Voice recognition takes time, and it will call you back in onActivityResult when its done. You should be starting your new activity there.
In addition, the voice recognition activity may return null on error. I'd do a null check anyway, just to make sure.
I am using text to speech in my app and I have been able to get it to work on all of my buttons fine. However, when I try to use the text to speech in my splash activity it crashes the app. It is a nullpointer exception so I know I am just coding it incorrectly. To clarify what I want it to do. I want it to talk during the splash activity. When the splash activity sleeps I want it to talk again to tell the user it is done loading.I have included the java for my splash activity.
public class mainj extends Activity implements OnInitListener {
private TextToSpeech myTTS;
// status check code
private int MY_DATA_CHECK_CODE = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loadscreen);
Thread logoTimer = new Thread() {
public void run() {
try {
try {
sleep(5000);
speakWords("loading");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Intent menuIntent = new Intent("android.intent.action.MENU");
startActivity(menuIntent);
Intent checkTTSIntent = new Intent();
checkTTSIntent
.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
}
finally {
finish();
}
}
};
logoTimer.start();
}
// speak the user text
private void speakWords(String speech) {
// speak straight away
myTTS.speak(speech, TextToSpeech.QUEUE_FLUSH, null);
}
// act on result of TTS data check
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// the user has the necessary data - create the TTS
myTTS = new TextToSpeech(this, this);
} else {
// no data - install it now
Intent installTTSIntent = new Intent();
installTTSIntent
.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installTTSIntent);
}
}
}
// setup TTS
public void onInit(int initStatus) {
// check for successful instantiation
if (initStatus == TextToSpeech.SUCCESS) {
if (myTTS.isLanguageAvailable(Locale.US) == TextToSpeech.LANG_AVAILABLE)
myTTS.setLanguage(Locale.US);
} else if (initStatus == TextToSpeech.ERROR) {
Toast.makeText(this, "Sorry! Text To Speech failed...",
Toast.LENGTH_LONG).show();
}
}
}
Right at the beginning of your thread after you sleep you are calling speakWords. that calls myTTS.speak. At that point looking at your code, the myTTS does not seem to be initialized and is null so will crash with an NPE.
This code should prevent the NPE, but if the initialization of the TTS engine takes too long, then you won't get it to say Loading. Also, I am guessing the 5 second (which is a really long time btw) sleep is to allow for it to get initialized?
public class mainj extends Activity implements OnInitListener {
private TextToSpeech myTTS;
// status check code
private int MY_DATA_CHECK_CODE = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loadscreen);
Intent checkTTSIntent = new Intent();
checkTTSIntent
.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
Thread logoTimer = new Thread() {
public void run() {
try {
try {
sleep(5000);
speakWords("loading");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Intent menuIntent = new Intent("android.intent.action.MENU");
startActivity(menuIntent);
}
finally {
finish();
}
}
};
logoTimer.start();
}
// speak the user text
private void speakWords(String speech) {
// speak straight away
if(myTTS != null)
{
myTTS.speak(speech, TextToSpeech.QUEUE_FLUSH, null);
}
}
// act on result of TTS data check
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// the user has the necessary data - create the TTS
myTTS = new TextToSpeech(this, this);
} else {
// no data - install it now
Intent installTTSIntent = new Intent();
installTTSIntent
.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installTTSIntent);
}
}
}
// setup TTS
public void onInit(int initStatus) {
// check for successful instantiation
if (initStatus == TextToSpeech.SUCCESS) {
if (myTTS.isLanguageAvailable(Locale.US) == TextToSpeech.LANG_AVAILABLE)
myTTS.setLanguage(Locale.US);
} else if (initStatus == TextToSpeech.ERROR) {
Toast.makeText(this, "Sorry! Text To Speech failed...",
Toast.LENGTH_LONG).show();
}
}
}
You would be better calling you're little loading snippet after the TTS engine has been loaded, so you could put the speak in OnActivityResult().
In your code you can't actually tell whether or not myTTS has been initialised when you call speak. Try it this way:
Intent menuIntent = new Intent("android.intent.action.MENU");
startActivity(menuIntent);
Intent checkTTSIntent = new Intent();
checkTTSIntent
.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
try {
sleep(5000);
speakWords("loading");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
There are two things wrong with your approach.
First, your app needs to wait for init() before it tries to speak.
Second, your app needs to handle when the speech libraries are not available.
Use this class or this one to help with the TextToSpeech initialization. It's actually kind of complex and using TextToSpeech.Engine.ACTION_CHECK_TTS_DATA is actually NOT the best way to do it.