简体   繁体   中英

Android voice recognition and send data via bluetooth to Arduino. How can I send data several times?

I am a newbie of Android. My application uses Voice Recognition , TextToSpeech and send data out via Bluetooth from Android phone (SAMSUNG Galaxy Note | OS: Android 4.1.2) to Arduino. It can send data out only once a time and after it can't send (it through IOException ), so application finish() . Below is my code.

Android Code

package com.itcdroid.smarthome;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Locale;
import java.util.UUID;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements
    TextToSpeech.OnInitListener {

    //Tag for logging
    private static final String TAG = "ITCDroid";

    private static final int REQUEST_ENABLE_BT = 1;
    private BluetoothAdapter mBluetoothAdapter = null;
    private BluetoothSocket mBluetoothSocket = null;
    private OutputStream outStream = null;

    //MAC address of remote Bluetooth device
    private final String address = "98:D3:31:B4:34:EE";

    // UUID that specifies a protocol for generic bluetooth serial communication
    //Well known SPP UUID
    private static final UUID MY_UUID = 
            UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    private TextToSpeech tts;
    private String ttsText;
    private TextView txtSpeechInput;
    private ImageButton btnSpeak;
    private final int REQ_CODE_SPEECH_INPUT = 100;

    // Available commands
    private static final String[] commands = {"on", "off", "turn on the light", "turn off the light"};
    boolean foundCommand;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        checkBtState();

        tts = new TextToSpeech(this, this);
        txtSpeechInput = (TextView) findViewById(R.id.txtSpeechInput);
        btnSpeak = (ImageButton) findViewById(R.id.btnSpeak);

        // hide the action bar
        //getActionBar().hide();

        //mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        //checkBtState();

        btnSpeak.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                promptSpeechInput();
            }
        });

    }

    @Override
    public void onResume() {
        super.onResume();

        Log.d(TAG, "...In onResume - Attempting client connect...");

        //Set up a pointer to the remote node using it's address.
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

        // Two things are needed to make a connection:
        // A MAC address, which we got above.
        // A Service ID or UUID. in this case we are using the UUID for SPP
        try {
            mBluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
        }

        // Discovery is resource intensive. Make sure it isn't going on
        // when you attempt to connect and pass your message.
        mBluetoothAdapter.cancelDiscovery();

        // Establish the connection. This will block until is connects.
        Log.d(TAG, "...Connecting to Remote...");
        try {
            mBluetoothSocket.connect();
            Log.d(TAG, "...Connection established and data link opened...");
        } catch(IOException e) {
            try {
                mBluetoothSocket.close();
            } catch (IOException e2) {
                errorExit("Fatal Error", "In onResume() and unable to close socket during connection failture" + e2.getMessage() + ".");
            }
        }

        //Create a data stream so we can talk to server.
        Log.d(TAG, "...Creating Socket...");

        try {
            outStream = mBluetoothSocket.getOutputStream();
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and output stream creation failture: " + e.getMessage() + ".");
        }
    }

    @Override
    public void onPause(){
        super.onPause();
        Log.d(TAG, "...In onPause()...");

        if (outStream != null) {
            try {
                outStream.flush();
            } catch (IOException e) {
                errorExit("Fatal Error", "In onPause() and failed to flush output stream: " + e.getMessage() + ".");
            }
        }
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mBluetoothSocket.close();
        } catch (IOException e) { }
    }

    private void checkBtState() {
        // TODO Auto-generated method stub
        //Check for Bluetooth support and then check to make sure it is turned on
        if (mBluetoothAdapter == null) {
            errorExit("Fatal Error", "Bluetooth Not supported. Aborting.");
        } else {
            if (mBluetoothAdapter.isEnabled()) {
                Log.d(TAG, "...Bluetooth is enabled...");
            } else {
                //Prompt user to turn on Bluetooth
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            }
        }

    }

    /**
     * Showing google speech input dialog
     * */
    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();
        }
    }

    /**
     * Receiving speech input
     * */
    @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);

                foundCommand = false;
                for(String command : commands) {
                    if(result.contains(command)) {
                        foundCommand = true;
                        if(command == "on") {
                            txtSpeechInput.setText("You say -on-");
                            ttsText = "The light is turn on now.";
                            speakOut();
                            sentData("1");
                        }
                        else if(command == "off") {
                            txtSpeechInput.setText("You say -off-");
                            ttsText = "The light is turn off now.";
                            speakOut();
                            sentData("2");
                        }
                        else if(command == "turn on the light") {
                            txtSpeechInput.setText("You say -turn on the light-");
                            ttsText = "The light is turn on now.";
                            speakOut();
                            sentData("1");
                        }
                        else if(command == "turn off the light") {
                            txtSpeechInput.setText("You say -turn off the light-");
                            ttsText = "The light is turn off now.";
                            speakOut();
                            sentData("2");
                        }
                    }
                }

                if (!foundCommand) {
                    txtSpeechInput.setText("Unknown what you say");
                    ttsText = "I don't know what you want!";
                    speakOut();
                }
                //txtSpeechInput.setText(result.get(0));
            }
            break;
        }

        }
    }

    @Override
    public void onDestroy() {
        // Don't forget to shutdown!
        if (tts != null) {
            tts.stop();
            tts.shutdown();
        }
        super.onDestroy();
    }

    @Override
    public void onInit(int status) {
        // TODO Auto-generated method stub

        if (status == TextToSpeech.SUCCESS) {

            int result = tts.setLanguage(Locale.US);

            // tts.setPitch(5); // set pitch level

            // tts.setSpeechRate(2); // set speech speed rate

            if (result == TextToSpeech.LANG_MISSING_DATA
                    || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Log.e("TTS", "Language is not supported");
            } else {
                //btnSpeak.setEnabled(true);
                speakOut();
            }

        } else {
            Log.e("TTS", "Initilization Failed");
        }

    }

    //@SuppressWarnings("deprecation")
    private void speakOut() {

        String text = ttsText;

        tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
    }

    private void sentData(String message) {
        // TODO Auto-generated method stub
        byte[] msgBuffer = message.getBytes();

        Log.d(TAG, "...Sending data: " + message + "...");
        try {
            outStream.write(msgBuffer);
            outStream.close();
            reConnectBT();
        } catch (IOException e) {
            String msg = "In onResume() and an exception occurred during write:" + e.getMessage();
            msg = msg + ".\n\nCheck that the SPP UUID: " + MY_UUID.toString() + "exists on server.\n\n";

            errorExit("sentData IOException", msg);
        }

    }

    private void reConnectBT() {
        // TODO Auto-generated method stub
        Log.d(TAG, "...In reConnectBT - Attempting client connect...");

        //Set up a pointer to the remote node using it's address.
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

        // Two things are needed to make a connection:
        // A MAC address, which we got above.
        // A Service ID or UUID. in this case we are using the UUID for SPP
        try {
            mBluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
        }

        // Discovery is resource intensive. Make sure it isn't going on
        // when you attempt to connect and pass your message.
        mBluetoothAdapter.cancelDiscovery();

        // Establish the connection. This will block until is connects.
        Log.d(TAG, "...Connecting to Remote...");
        try {
            mBluetoothSocket.connect();
            Log.d(TAG, "...Connection established and data link opened...");
        } catch(IOException e) {
            try {
                mBluetoothSocket.close();
            } catch (IOException e2) {
                errorExit("Fatal Error", "In onResume() and unable to close socket during connection failture" + e2.getMessage() + ".");
            }
        }

        //Create a data stream so we can talk to server.
        Log.d(TAG, "...Creating Socket...");

        try {
            outStream = mBluetoothSocket.getOutputStream();
        } catch (IOException e) {
            errorExit("Fatal Error", "In onResume() and output stream creation failture: " + e.getMessage() + ".");
        }

    }

    private void errorExit(String title, String message) {
        // TODO Auto-generated method stub
        Toast msg= Toast.makeText(getBaseContext(),
                title, Toast.LENGTH_SHORT);
        msg.show();
        finish();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

It seems that you're doing a lot of juggling with connecting and disconnecting from your bluetooth device, which can harm your performance. Another thing you're doing is managing all of the heavy Bluetooth processes directly in your UI thread, which will make your app lock up until the connections complete.

Here's a link to my project's repository, I'm doing simple Bluetooth connections in it and made a BluetoothConnection class as a wrapper for managing the connection state. Feel free to use the source code, but be wary that I'm always actively changing it. If you choose to use it your code, the implementation would go something like this:

InputStream mInputStream;
OutputStream mOutputStream;

BluetoothConnection mConnection = new BluetoothConnection("Connection Name", "98:D3:31:B4:34:EE");
mConnection.setOnConnectStatusChangedListener(this, new onConnectStatusChangedListener() {
  @Override
  public void onConnect() {
    /*
     * Connecting to bluetooth takes some time, it won't be ready immediately.
     * Set some actions here that let your program know that the connection
     * finished successfully. For example,
     */
    mInputStream = mConnection.getInputStream();
    mOutputStream = mConnection.getOutputStream();

    //Use some method of your own to write data
    sendDataToBluetoothDevice(mOutputStream);
  }

  @Override
  public void onDisconnect() {
    /*
     * Same thing applies to disconnecting, set some actions to occur
     * when the disconnect is confirmed.
     */
  }
}

/* 
 * Internally, this launches an AsyncTask to handle connecting,
 * which is why we need the onConnectStatusChangedListener
 * callbacks.
 */
mConnection.connect();

//To disconnect:
mConnection.disconnect();

This should simplify things for you by handling all of the heavy lifting in background processes. As far as reading and writing more than once, as long as you use the InputStream and OutputStream correctly you should be golden.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM