The background for the EditText is created by the following markup in the drawable folder,
The following function fires the ACTION_OPEN_DOCUMENT intent,
- public void open() {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("*/*");
- startActivityForResult(intent, OPEN_FILE);
- }
The above code triggers the execution of the following code in the onActivityResult() method which opens the selected file using stream classes and displays its contents on an EditText control,
- if (resultCode == RESULT_OK) {
- try {
- Uri uri = data.getData();
- String filename = uri.toString().substring(uri.toString().indexOf("%")).replace("%2F", "/").replace("%3A", "/storage/emulated/0/");
-
-
- FileInputStream stream = new FileInputStream(new File(filename));
- InputStreamReader reader = new InputStreamReader(stream);
- BufferedReader br = new BufferedReader(reader);
- StringBuffer buffer = new StringBuffer();
- String s = br.readLine();
- while (s != null) {
- buffer.append(s + "\n");
- s = br.readLine();
- }
- txtFileContents.setText(buffer.toString().trim());
- br.close();
- reader.close();
- stream.
- } catch (Exception ex) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setCancelable(true);
- builder.setTitle("Error");
- builder.setMessage(ex.getMessage());
- builder.setIcon(R.drawable.error);
- AlertDialog dialog = builder.create();
- dialog.show();
- }
- }
Similarly, the following function fires the ACTION_CREATE_DOCUMENT intent,
- public void save() {
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("text/plain");
- intent.putExtra(Intent.EXTRA_TITLE, "newfile.txt");
- startActivityForResult(intent, SAVE_FILE);
- }
And this results in the execution of the following code to save the contents of the EditText control to a file,
- if (resultCode == RESULT_OK) {
- try {
- Uri uri = data.getData();
- String filename = uri.toString().substring(uri.toString().indexOf("%")).replace("%2F", "/").replace("%3A", "/storage/emulated/0/");
- FileOutputStream stream = new FileOutputStream(new File(filename));
- OutputStreamWriter writer = new OutputStreamWriter(stream);
- BufferedWriter bw = new BufferedWriter(writer);
- bw.write(txtFileContents.getText().toString(), 0,
- txtFileContents.getText().toString().length());
- bw.close();
- writer.close();
- stream.close();
- } catch (Exception ex) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setCancelable(true);
- builder.setTitle("Error");
- builder.setMessage(ex.getMessage());
- builder.setIcon(R.drawable.error);
- AlertDialog dialog = builder.create();
- dialog.show();
- }
- }
In order to speak the contents of the EditText control, the following user defined function is used,
- public void speak() {
- if (txtFileContents.getText().toString().trim().length() == 0) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setCancelable(true);
- builder.setTitle("Error");
- builder.setMessage("Nothing to speak. Please type or record some text.");
- builder.setIcon(R.drawable.error);
- AlertDialog dialog = builder.create();
- dialog.show();
- } else {
- tts = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
- public void onInit(int status) {
- if (status != TextToSpeech.ERROR) {
- tts.setLanguage(Locale.US);
- String str = txtFileContents.getText().toString();
- tts.speak(str, TextToSpeech.QUEUE_ADD, null);
- }
- }
- });
- }
- }
The above code initializes the TextToSpeech engine and sets the language to Locale.US. Then it retrieves the contents of the EditText control into a string variable and finally calls the speak() function to convert the text to speech.
The following code is used to record speech using the ACTION_RECOGNIZE_SPEECH intent,
- public void record() {
- 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);
- if (voiceCommandMode && !recording) {
- intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak a command to be executed...");
- } else {
- intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say something to record...");
- }
- startActivityForResult(intent, RECORD_VOICE);
- }
The above code checks whether we are executing a voice command or recording normal speech and displays a different prompt depending upon that. It then triggers the execution of the following code in the onActivityResult() function,
- if (resultCode == RESULT_OK) {
- ArrayList result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
- if (voiceCommandMode) {
- String command = result.get(0);
- if (command.toUpperCase().equals("OPEN") || command.toUpperCase().startsWith("OP") ||
- command.toUpperCase().startsWith("OB")) {
- Toast.makeText(getBaseContext(), "Executing Open Command", Toast.LENGTH_SHORT).show();
- open();
- } else if (command.toUpperCase().equals("SAVE") || command.toUpperCase().startsWith("SA") ||
- command.toUpperCase().startsWith("SE")) {
- Toast.makeText(getBaseContext(), "Executing Save Command", Toast.LENGTH_SHORT).show();
- save();
- } else if (command.toUpperCase().equals("SPEAK") || command.toUpperCase().startsWith("SPA") ||
- command.toUpperCase().startsWith("SPE") || command.toUpperCase().startsWith("SPI")) {
- Toast.makeText(getBaseContext(), "Executing Speak Command", Toast.LENGTH_SHORT).show();
- speak();
- } else if (command.toUpperCase().equals("RECORD") || command.toUpperCase().startsWith("REC") ||
- command.toUpperCase().startsWith("RAC") || command.toUpperCase().startsWith("RAK") ||
- command.toUpperCase().startsWith("REK")) {
- Toast.makeText(getBaseContext(), "Executing Record Command", Toast.LENGTH_SHORT).show();
- recording = true;
- record();
- } else if (command.toUpperCase().equals("CLEAR") || command.toUpperCase().equals("KLEAR") ||
- command.toUpperCase().startsWith("CLA") || command.toUpperCase().startsWith("CLE") ||
- command.toUpperCase().startsWith("CLI") || command.toUpperCase().startsWith("KLA") ||
- command.toUpperCase().startsWith("KLE") || command.toUpperCase().startsWith("KLI")) {
- Toast.makeText(getBaseContext(), "Executing Clear Command", Toast.LENGTH_SHORT).show();
- clear();
- } else if (command.toUpperCase().equals("HELP") || command.toUpperCase().startsWith("HAL") ||
- command.toUpperCase().startsWith("HEL") || command.toUpperCase().startsWith("HIL") ||
- command.toUpperCase().startsWith("HUL")) {
- Toast.makeText(getBaseContext(), "Executing Help Command", Toast.LENGTH_SHORT).show();
- help();
- } else if (command.toUpperCase().equals("ABOUT") || command.toUpperCase().startsWith("ABA") ||
- command.toUpperCase().startsWith("ABO")) {
- Toast.makeText(getBaseContext(), "Executing About Command", Toast.LENGTH_SHORT).show();
- about();
- } else {
- Toast.makeText(getBaseContext(), "Unrecognized command", Toast.LENGTH_SHORT).show();
- }
- voiceCommandMode = false;
- } else {
- txtFileContents.setText(result.get(0));
- }
- }
The above code executes one of the voice commands if we had clicked on the "Voice Command" button. Otherwise, it simply displays the spoken text on the EditText control. The code uses the getStringArrayListExtra() method with the EXTRA_RESULTS parameter to get the result ArrayList. Then it extracts the spoken text as the first element using the get() method.
Note
To avoid the problems of voice commands not getting recognized, I have compared the speech with similar sounding words. I am not sure if it is the best way out but it seemed to be a quick solution.
Commands can also be executed by clicking on buttons. The following code in the onClick() method initiates the actions depending on the button clicked,
This is one example of a voice based Android app using TextToSpeech API. Many more such exciting apps can be created using TextToSpeech API.