4

I am creating a simple app, I require a button called 'bVoice' to be automatically pressed after 500ms if the EditText field contains the correct information.

How do I write the handler to do this in the following code:

//Assign button clicks to got to a new activity:
public void onButtonClick_1(View v){
    if (v.getId() == R.id.bVoice){
        String str_1 = a.getText().toString();

        //Go to the relevant page if any part of the phrase or word entered in the 'EditText' field contains 'next' which is not case sensitive
        if (str_1.toLowerCase().contains("command")) {
            Intent userintent = new Intent(PocketSphinxActivity.this, Display_1.class);
            startActivity(userintent);
        } else {
            Toast.makeText(getApplicationContext(), "Incorrect Information", Toast.LENGTH_SHORT).show();
        }
    }
}

Below is the full code I have got thus far (Updated):

public class PocketSphinxActivity extends Activity implements RecognitionListener
{

private static final String KWS_SEARCH = "wakeup";

/* Keyword we are looking for to activate menu */
private static final String KEYPHRASE = "open voice command";   //adjust this keyphrase!

private SpeechRecognizer recognizer;
private HashMap<String, Integer> captions;

ListView lv;
TextView tv;
EditText a;
Button b;
Button c;

@Override
public void onCreate(Bundle state) {
    super.onCreate(state);

    // Prepare the data for UI
    captions = new HashMap<String, Integer>();
    captions.put(KWS_SEARCH, R.string.kws_caption);
    setContentView(R.layout.main);
    ((TextView) findViewById(R.id.caption_text))
            .setText("Preparing the recognizer");

    lv = (ListView) findViewById(R.id.lvVoiceReturn);
    tv = (TextView) findViewById(R.id.result_text);
    a = (EditText) findViewById(R.id.TFusername);
    b = (Button) findViewById(R.id.bVoice);
    c = (Button)findViewById(R.id.Blogin);

    // Recognizer initialization is a time-consuming and it involves IO,
    // so we execute it in async task

    new AsyncTask<Void, Void, Exception>() {
        @Override
        protected Exception doInBackground(Void... params) {
            try {
                Assets assets = new Assets(PocketSphinxActivity.this);
                File assetDir = assets.syncAssets();
                setupRecognizer(assetDir);
            } catch (IOException e) {
                return e;
            }
            return null;
        }

        @Override
        protected void onPostExecute(Exception result) {
            if (result != null) {
                ((TextView) findViewById(R.id.caption_text))
                        .setText("Failed to init recognizer " + result);
            } else {
                switchSearch(KWS_SEARCH);
            }
        }
    }.execute();
    a.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (s.toString().trim().equalsIgnoreCase("open voice command")) {
                //
                //Do your stuff here OR button.performClick()
                //

                //DELAY
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        b.performClick();
                    }
                }, 500);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });
}

@Override
public void onDestroy() {
    super.onDestroy();
    recognizer.cancel();
    recognizer.shutdown();
}

/**
 * In partial result we get quick updates about current hypothesis. In
 * keyword spotting mode we can react here, in other modes we need to wait
 * for final result in onResult.
 */
@Override
public void onPartialResult(Hypothesis hypothesis) {
    if (hypothesis == null)
        return;

    String text = hypothesis.getHypstr();
    //((TextView) findViewById(R.id.result_text)).setText(text);
    ((EditText) findViewById(R.id.TFusername)).setText(text);
}

/**
 * This callback is called when we stop the recognizer.
 */
@Override
public void onResult(Hypothesis hypothesis) {
    //((TextView) findViewById(R.id.result_text)).setText("");
    ((EditText) findViewById(R.id.TFusername)).setText("");
    if (hypothesis != null) {
        String text = hypothesis.getHypstr();
        makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();


    //a.setText((String) tv.getText());
        //tv = TextView.getText().toString();
    }
}

@Override
public void onBeginningOfSpeech() {
}

/**
 * We stop recognizer here to get a final result
 */
@Override
public void onEndOfSpeech() {
    if (!recognizer.getSearchName().equals(KWS_SEARCH))
        switchSearch(KWS_SEARCH);
}

private void switchSearch(String searchName) {
    recognizer.stop();

    // If we are not spotting, start listening with timeout (10000 ms or 10 seconds).
    if (searchName.equals(KWS_SEARCH))
        recognizer.startListening(searchName);
    else
        recognizer.startListening(searchName, 10000);

    String caption = getResources().getString(captions.get(searchName));
    ((TextView) findViewById(R.id.caption_text)).setText(caption);
}

private void setupRecognizer(File assetsDir) throws IOException {
    // The recognizer can be configured to perform multiple searches
    // of different kind and switch between them

    recognizer = defaultSetup()
            .setAcousticModel(new File(assetsDir, "en-us-ptm"))
            .setDictionary(new File(assetsDir, "cmudict-en-us.dict"))

                    // To disable logging of raw audio comment out this call (takes a lot of space on the device)
            .setRawLogDir(assetsDir)

                    // Threshold to tune for keyphrase to balance between false alarms and misses
            .setKeywordThreshold(1e-45f)

                    // Use context-independent phonetic search, context-dependent is too slow for mobile
            .setBoolean("-allphone_ci", true)

            .getRecognizer();
    recognizer.addListener(this);

    /** In your application you might not need to add all those searches.
     * They are added here for demonstration. You can leave just one.
     */

    // Create keyword-activation search.
    recognizer.addKeyphraseSearch(KWS_SEARCH, KEYPHRASE);

}

@Override
public void onError(Exception error) {
    ((TextView) findViewById(R.id.caption_text)).setText(error.getMessage());
}

@Override
public void onTimeout() {
    switchSearch(KWS_SEARCH);
}

//Assign button clicks to go to a new activity:
public void onButtonClick_1(View v){
    if (v.getId() == R.id.bVoice){
        String str_1 = a.getText().toString();
}

UPDATED text with onResume at the bottom of code:

    @Override
public void onResume(){
    super.onResume();
    isDone = false;
    a.setText("");
}
N MC
  • 207
  • 1
  • 10
  • 2
    If you want something automatic, add a TextWatcher to the EditText – OneCricketeer May 09 '16 at 02:16
  • Hmm, interesting. How would I code that? – N MC May 09 '16 at 02:46
  • Use the onTextChanged method. Otherwise, I think all you are missing is a while true loop in the Handler. Your code only runs the Handler once after 500ms... http://stackoverflow.com/questions/8543449/how-to-use-the-textwatcher-class-in-android – OneCricketeer May 09 '16 at 02:50
  • Any chance you can help me modify the code to take into account the while true loop? – N MC May 09 '16 at 03:36
  • I think you can simply put `while (true)` around the `c.performClick()` – OneCricketeer May 09 '16 at 04:01
  • yeah, I tried that but it didn't work, I have added the new code to the question to show what I have tried – N MC May 09 '16 at 04:10

1 Answers1

2

If you want to do something based on the input in the edittext, then you could use a TextWatcher.

UPDATE Create a global boolean variable:

Boolean isDone=false;

Then inside your Handler code update the code like this :

a.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (s.toString().trim().equalsIgnoreCase("open voice command"))
            {
                //
                //Do your stuff here OR button.performClick()
                //

                //DELAY
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (!isDone){
                            b.performClick();
                            isDone=true;
                        }                        }
                }, 500);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });

Just Add this code after your AsyncTask. i.e after

}.execute();

To import the Editable class, click on it and press alt+Enter. Do the same for TextWatcher, click on it and then press alt+Enter.

Whatever code you type inside onTextChanged will get executed whenever the text in the EditText changes. SOLVES your automatic problem.

Akhil Soman
  • 2,077
  • 2
  • 17
  • 30
  • This is getting somewhat confusing, any chance you can add in the code to the full java file I have now shown in the question? I just basically want to trigger the `bVoice` button automatically when the text 'open voice command' appears in the EditText field – N MC May 09 '16 at 04:54
  • I'm getting some errors, the word `TextWatcher` and `editable`, Do I need to fill up anything in your updated code? – N MC May 09 '16 at 05:39
  • just import those file by clicking on the TextWatcher and press alt+Enter(in android studio). ctrl+space(in Eclipse). – Akhil Soman May 09 '16 at 05:59
  • There are still errors even after importing them, `TextWatcher` says 'Class derived from TextWatcher must either be declared abstract or implement abstract...' and `Editable` is still shown in red in android studio – N MC May 09 '16 at 06:11
  • Answer Updated please Check – Akhil Soman May 09 '16 at 06:39
  • okay, so the code is now clicking the button but it is opening the screen every 500ms constantly and never stopping, I need it to be pressed only once – N MC May 09 '16 at 06:45
  • When the input is correct, the next activity opens up, and that's it. For me its only clicking once. – Akhil Soman May 09 '16 at 06:56
  • for me it is definitely bring it up more than once, do I need to remove my `public void onButtonClick_1(View v){...}` statement at the bottom of my code? – N MC May 09 '16 at 07:05
  • can you update the question with your current code...? – Akhil Soman May 09 '16 at 07:40
  • I have updated the question with the latest code as per your request. I hope its an easy fix to get working – N MC May 09 '16 at 09:50
  • have you had a chance to look at the updated code @Akhil Soman? I would like to accept your answer once it is working. Please reply soon – N MC May 10 '16 at 00:48
  • Answer updated please check. I have used a boolean variable to check whether the b.performClick() has already been executed. if so, then it won't trigger the second time. – Akhil Soman May 10 '16 at 04:58
  • thanks, Ill double check this later tonight. Is there any way of getting the current `RecognitionListener` to also work with `onClickListsner` or should I use `onClickListener` as a seperate activity? – N MC May 10 '16 at 06:13
  • No you can use both of them in the same activity – Akhil Soman May 10 '16 at 06:18
  • Hi @Akhil Soman, when we are using the Boolean command the one issue I have is that if I return back to this activity either by pressing the back button or coming from another different activity, it will not work again as the command has already occured once. Is there a method of getting it to reset the EditList field as well as the command everytime I return to this activity? – N MC May 10 '16 at 23:11
  • In the onResume() just reset them both. – Akhil Soman May 11 '16 at 04:26
  • How do I reset them? – N MC May 11 '16 at 05:54
  • set isDone=false; and a.setText(""); inside the onResume() – Akhil Soman May 11 '16 at 07:32
  • Hi @Akhil Soman, I have created an onResume at the end of my Java file as updated in the main question, however this works perfectly when I manually type in 'open voice command' and then go to the next window and when I press back the contents are cleared, however If I use the Speech to text option and say 'open voice command' it takes me to the next window and when I press back the text is still there and re triggers the button press again, Do I need to write something else somewhere? – N MC May 13 '16 at 00:31
  • When you receive text from the speech you might be calling the `startActivity()` seperately. Just set the string you get from the speech engine and set it into the edittext. – Akhil Soman May 17 '16 at 06:38
  • any chance you can show me where I have gone wrong in my code above? – N MC May 17 '16 at 06:47