2
votes

I'm working on making my first Android App, and I cannot get the text to speech to work.

The gist of the app: user selects the time they want to set an alarm (using a TimePicker), then the app calculates the amount of time left, continuously updating the amount of time left.

I want the use the text to speech engine to verbally update the user at 5 minute intervals on how much time they have left.

Everything compiles and runs without error, but the text to speech just doesn't do anything. I've looked for days to find out how to properly initialize the TextToSpeech class in java, but everything I find seems to initialize it differently on a case by case basis.

After trying multiple different implementations, all with the same result, I decided to just make a separate inner class to make editing and trying new things easier, and I can just make a Voice class and call methods on it.

I've only been coding in Java for a few months, and this is my first Android App, so I am having a lot of trouble sorting through this on my own.

Below is the separate (inner/nested) class that I am using to initialize the TextToSpeech class:

    private class Voice implements TextToSpeech.OnInitListener {
    Context context = getApplicationContext();
    TextToSpeech tts = new TextToSpeech(context, this);

    public void onInit(int initStatus) {
        if (initStatus == TextToSpeech.SUCCESS) {
            tts.setLanguage(Locale.US);
        }
    }

    private void say(String announcement) {
        tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null);
    }
}

Here is the rest of the code in the activity ( I use a separate activity to display the countdown)

import android.content.Context;
import android.speech.tts.TextToSpeech;
import android.support.v7.app.AppCompatActivity;
import android.os.*;
import android.widget.*;
import java.util.*;
import java.lang.*;


public class TimerActivity extends AppCompatActivity{

private int alarmHour = MainActivity.alarmHour;
private int alarmMinute = MainActivity.alarmMinute;
private Calendar alarmTime;
private Calendar currentTime;
private TextView timerText;
private TextView lateText;
private int hoursLeft;
private int minutesLeft;
private long difference;
private long calculatedMinutes;
private boolean late = false;
private String lateMessageString = "LATE!";
private String timeRemainingString = "remaining";
private Handler handler = new Handler();
private TextToSpeech tts;
private double pitch = 1;
private double speed = 1;
private int MY_DATA_CHECK_CODE = 0;
private Voice voice;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_timer);
    voice = new Voice();
    voice.say("This is some bullshit.");
    initializeTimer();
}

private void initializeTimer () {
    voice.say("Yes, hello. Is it me you're looking for?");
    timerText = (TextView) findViewById(R.id.timerText);
    lateText = (TextView) findViewById(R.id.lateText);
    setAlarm();
    calculateTimeLeft();
    String timerString = getTimerString();
    timerText.setText(timerString);
    if (late) {
        lateText.setText(lateMessageString);
    }
    else {
        lateText.setText(timeRemainingString);
    }

    Timer timer = new Timer();
    timer.schedule(new UpdateTimer(),100,60000);
}



private class UpdateTimer extends TimerTask {
    public void run() {
        handler.post(new Runnable() {
            public void run() {
                calculateTimeLeft();
                String timerString = getTimerString();
                timerText.setText(timerString);
                if (late) {
                    lateText.setText(lateMessageString);
                }
                else {
                    lateText.setText(timeRemainingString);
                }
            }

        });
    }
}


private void setAlarm() {
    alarmTime = Calendar.getInstance();
    currentTime = Calendar.getInstance();
    alarmTime.setTimeInMillis(System.currentTimeMillis());
    alarmTime.set(Calendar.HOUR_OF_DAY, alarmHour);
    alarmTime.set(Calendar.MINUTE, alarmMinute);
    // If alarm is set for the past, then set the alarm for the next day at the specified time
    if (alarmTime.getTimeInMillis() - System.currentTimeMillis() < 0) {
        alarmTime.set(Calendar.DAY_OF_YEAR, alarmTime.get(Calendar.DAY_OF_YEAR) + 1);
    }
}

private void calculateTimeLeft() {
    currentTime.setTimeInMillis(System.currentTimeMillis());
    difference = alarmTime.getTimeInMillis() - System.currentTimeMillis();
    long seconds = difference/1000; // convert to seconds
    long calculatedHours = seconds / 3600; // Find the number of hours until alarm
    calculatedMinutes = (seconds % 3600) / 60; // Use mod to remove the number of hours, leaving only seconds since the last hour, then divide by 60 to get minutes

    hoursLeft = (int)Math.abs(calculatedHours); // Get the absolute value of the time left for the string
    minutesLeft = (int)Math.abs(calculatedMinutes); // Absolute value of the minutes for string use
}

private String getTimerString() {
    // Format the string showing the time remaining
    String timeLeftString;
    if (hoursLeft == 0) {
        timeLeftString = "";
    }
    else if (hoursLeft == 1) {
        timeLeftString = hoursLeft + "hr ";
    }
    else {
        timeLeftString = hoursLeft +"hrs ";
    }
    if (hoursLeft == 0) {
        timeLeftString += minutesLeft;
    }
    /*
    else if (minutesLeft < 10 && calculatedMinutes > 0) {
        timeLeftString += "0" + minutesLeft;
    }
    */
    else {
        timeLeftString += minutesLeft;
    }
    if (calculatedMinutes >= 0 && hoursLeft > 0) {
        timeLeftString += " mins";
    }
    else if (calculatedMinutes > 0) {
        timeLeftString += " mins";
    }
    else if (difference <= 0) {
        late = true;
    }
    return timeLeftString;
}




private class Voice implements TextToSpeech.OnInitListener {
    Context context = getApplicationContext();
    TextToSpeech tts = new TextToSpeech(context, this);

    public void onInit(int initStatus) {
        if (initStatus == TextToSpeech.SUCCESS) {
            tts.setLanguage(Locale.US);
        }
    }

    private void say(String announcement) {
        tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null);
    }
}

}

1

1 Answers

0
votes

I think you can't hear any voices that you want.

Because TextToSpeech class can't say immediately after you invoke constructor.

TextToSpeech class instance need to connect to system TTS service when it is initializing.

And if the instance is success to connect to service, onInit of TextToSpeech.OnInitListener will be activated!

So, you can hear the voice after onInit function is done. Try to move your voice.say functions at onInit function.

private class Voice implements TextToSpeech.OnInitListener {
    Context context = getApplicationContext();
    TextToSpeech tts = new TextToSpeech(context, this);

    public void onInit(int initStatus) {
        if (initStatus == TextToSpeech.SUCCESS) {
            tts.setLanguage(Locale.US);
            // try it!
            voice.say("Can you hear this sentence?");
            // If you want to another "say", check this log.
            // Your voice will say after you see this log at logcat.
            Log.i("TAG", "TextToSpeech instance initialization is finished.");
        }
    }

    private void say(String announcement) {
        tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null);
    }
}