diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 07de814e4..63dd80531 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -163,8 +163,6 @@ limitations under the License. - - diff --git a/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java b/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java index 02875840e..99e4defaa 100644 --- a/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java +++ b/src/main/java/de/dennisguse/opentracks/services/tasks/AnnouncementPeriodicTask.java @@ -21,8 +21,6 @@ import android.media.AudioManager; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.speech.tts.UtteranceProgressListener; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; import android.util.Log; import java.util.Locale; @@ -51,10 +49,39 @@ public class AnnouncementPeriodicTask implements PeriodicTask { private final Context context; private final AudioManager audioManager; + + private final AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { + @Override + public void onAudioFocusChange(int focusChange) { + Log.d(TAG, "Audio focus changed to " + focusChange); + + boolean stop = false; + switch (focusChange) { + case AudioManager.AUDIOFOCUS_GAIN: + stop = false; + break; + case AudioManager.AUDIOFOCUS_LOSS: + stop = true; + break; + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + stop = true; + break; + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + stop = true; + break; + } + + if (stop && tts != null && tts.isSpeaking()) { + tts.stop(); + Log.i(TAG, "Aborting current tts due to focus change " + focusChange); + } + } + }; + private final UtteranceProgressListener utteranceListener = new UtteranceProgressListener() { @Override public void onStart(String utteranceId) { - int result = audioManager.requestAudioFocus(null, TextToSpeech.Engine.DEFAULT_STREAM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + int result = audioManager.requestAudioFocus(audioFocusChangeListener, TextToSpeech.Engine.DEFAULT_STREAM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { Log.w(TAG, "Failed to request audio focus."); } @@ -70,32 +97,16 @@ public class AnnouncementPeriodicTask implements PeriodicTask { @Override public void onError(String utteranceId) { + Log.e(TAG, "An error occurred for utteranceId " + utteranceId); } }; private TextToSpeech tts; // Response from TTS after its initialization - private int initStatus = TextToSpeech.ERROR; + private int ttsInitStatus = TextToSpeech.ERROR; private boolean ttsReady = false; - // True if speech is allowed - private boolean speechAllowed; - - /** - * Listener which updates {@link #speechAllowed} when the phone state changes. - */ - private final PhoneStateListener phoneStateListener = new PhoneStateListener() { - @Override - public void onCallStateChanged(int state, String incomingNumber) { - speechAllowed = state == TelephonyManager.CALL_STATE_IDLE; - if (!speechAllowed && tts != null && tts.isSpeaking()) { - // If we're already speaking, stop it. - tts.stop(); - } - } - }; - AnnouncementPeriodicTask(Context context) { this.context = context; audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); @@ -103,16 +114,17 @@ public class AnnouncementPeriodicTask implements PeriodicTask { @Override public void start() { + Log.d(TAG, "Start"); + if (tts == null) { - tts = newTextToSpeech(context, new OnInitListener() { + tts = new TextToSpeech(context, new OnInitListener() { @Override public void onInit(int status) { - initStatus = status; + Log.i(TAG, "TextToSpeech initialized with status " + status); + ttsInitStatus = status; } }); } - speechAllowed = true; - listenToPhoneState(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); } @Override @@ -137,7 +149,7 @@ public class AnnouncementPeriodicTask implements PeriodicTask { synchronized (this) { if (!ttsReady) { - ttsReady = initStatus == TextToSpeech.SUCCESS; + ttsReady = ttsInitStatus == TextToSpeech.SUCCESS; if (ttsReady) { onTtsReady(); } @@ -148,7 +160,7 @@ public class AnnouncementPeriodicTask implements PeriodicTask { } } - if (!speechAllowed) { + if (audioManager.getMode() == AudioManager.MODE_IN_CALL || audioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) { Log.i(TAG, "Speech is not allowed at this time."); return; } @@ -157,21 +169,18 @@ public class AnnouncementPeriodicTask implements PeriodicTask { @Override public void shutdown() { - listenToPhoneState(phoneStateListener, PhoneStateListener.LISTEN_NONE); if (tts != null) { tts.shutdown(); tts = null; } + + } - /** - * Called when TTS is ready. - */ private void onTtsReady() { Locale locale = Locale.getDefault(); int languageAvailability = tts.isLanguageAvailable(locale); - if (languageAvailability == TextToSpeech.LANG_MISSING_DATA - || languageAvailability == TextToSpeech.LANG_NOT_SUPPORTED) { + if (languageAvailability == TextToSpeech.LANG_MISSING_DATA || languageAvailability == TextToSpeech.LANG_NOT_SUPPORTED) { Log.w(TAG, "Default locale not available, use English."); locale = Locale.ENGLISH; /* @@ -187,34 +196,11 @@ public class AnnouncementPeriodicTask implements PeriodicTask { tts.setOnUtteranceProgressListener(utteranceListener); } - /** - * Speaks the announcement. - * - * @param announcement the announcement - */ private void speakAnnouncement(String announcement) { - /* - * We don't care about the utterance id. It is supplied here to force - * onUtteranceCompleted to be called. - */ + // We don't care about the utterance id. It is supplied here to force onUtteranceCompleted to be called. tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null, "not used"); } - /** - * Create a new {@link TextToSpeech}. - * - * @param aContext a context - * @param onInitListener an on init listener - */ - private TextToSpeech newTextToSpeech(Context aContext, OnInitListener onInitListener) { - return new TextToSpeech(aContext, onInitListener); - } - - /** - * Gets the announcement. - * - * @param tripStatistics the trip statistics - */ private String getAnnouncement(TripStatistics tripStatistics) { boolean metricUnits = PreferencesUtils.isMetricUnits(context); boolean reportSpeed = PreferencesUtils.isReportSpeed(context); @@ -248,24 +234,6 @@ public class AnnouncementPeriodicTask implements PeriodicTask { getAnnounceTime(tripStatistics.getMovingTime()), rate); } - /** - * Listens to phone state. - * - * @param listener the listener - * @param events the interested events - */ - private void listenToPhoneState(PhoneStateListener listener, int events) { - TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - if (telephony != null) { - telephony.listen(listener, events); - } - } - - /** - * Gets the announce time. - * - * @param time the time - */ private String getAnnounceTime(long time) { int[] parts = StringUtils.getTimeParts(time); String seconds = context.getResources()