From 0158fc3a7aca021d975c6b3f0e4de0d046c4e6e8 Mon Sep 17 00:00:00 2001 From: Matthew Simmons Date: Wed, 23 Feb 2011 15:39:24 -0500 Subject: [PATCH] merge --- .../services/FroyoStatusAnnouncerTask.java | 81 +++++++++++++++++++ .../services/StatusAnnouncerFactory.java | 6 +- .../services/StatusAnnouncerTask.java | 8 +- .../apps/mytracks/util/ApiFeatures.java | 4 + 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 MyTracks/src/com/google/android/apps/mytracks/services/FroyoStatusAnnouncerTask.java diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/FroyoStatusAnnouncerTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/FroyoStatusAnnouncerTask.java new file mode 100644 index 000000000..c5a4c7afc --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/FroyoStatusAnnouncerTask.java @@ -0,0 +1,81 @@ +/* + * Copyright 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.android.apps.mytracks.services; + +import static com.google.android.apps.mytracks.MyTracksConstants.TAG; + +import android.content.Context; +import android.media.AudioManager; +import android.media.AudioManager.OnAudioFocusChangeListener; +import android.speech.tts.TextToSpeech; +import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener; +import android.util.Log; + +import java.util.HashMap; + +/** + * This class will periodically announce the user's trip statistics for Froyo and future handsets. + * This class will request and release audio focus. + * + * @author Sandor Dornbush + */ +public class FroyoStatusAnnouncerTask + extends StatusAnnouncerTask + implements OnUtteranceCompletedListener, OnAudioFocusChangeListener { + + private AudioManager audioManager; + private final static HashMap SPEECH_PARAMS = new HashMap(); + static { + SPEECH_PARAMS.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "not_used"); + } + + public FroyoStatusAnnouncerTask(Context context) { + super(context); + audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + } + + @Override + protected void onTtsInit(int status) { + super.onTtsInit(status); + if (status == TextToSpeech.SUCCESS) { + tts.setOnUtteranceCompletedListener(this); + } + } + + @Override + protected void speakAnnouncment(String announcement) { + int result = audioManager.requestAudioFocus(this, + TextToSpeech.Engine.DEFAULT_STREAM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); + if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { + Log.w(TAG, "FroyoStatusAnnouncerTask: Request audio focus failed."); + } + // We don't care about the utterance id. + // It is supplied here to force onUtteranceCompleted to be called. + tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, SPEECH_PARAMS); + } + + @Override + public void onUtteranceCompleted(String utteranceId) { + Log.d(TAG, "FroyoStatusAnnouncerTask: Abandoning audio focus."); + audioManager.abandonAudioFocus(this); + } + + @Override + public void onAudioFocusChange(int focusChange) { + // We don't care. + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactory.java b/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactory.java index c7ab903fd..01216a164 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactory.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactory.java @@ -41,7 +41,11 @@ public class StatusAnnouncerFactory { */ public PeriodicTask create(Context context) { if (hasTts) { - return new StatusAnnouncerTask(context); + if (ApiFeatures.getInstance().isAudioFocusSupported()) { + return new FroyoStatusAnnouncerTask(context); + } else { + return new StatusAnnouncerTask(context); + } } else { return null; } diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerTask.java index 8fe01eacb..756f1393e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerTask.java @@ -59,7 +59,7 @@ public class StatusAnnouncerTask implements PeriodicTask { /** * The interface to the text to speech engine. */ - private TextToSpeech tts; + protected TextToSpeech tts; /** * The response received from the TTS engine after initialization. @@ -98,7 +98,7 @@ public class StatusAnnouncerTask implements PeriodicTask { /** * Called when the TTS engine is initialized. */ - private void onTtsInit(int status) { + protected void onTtsInit(int status) { Log.i(MyTracksConstants.TAG, "TrackRecordingService.TTS init: " + status); this.ready = status == TextToSpeech.SUCCESS; @@ -146,6 +146,10 @@ public class StatusAnnouncerTask implements PeriodicTask { String announcement = getAnnouncement(service.getTripStatistics()); Log.d(MyTracksConstants.TAG, "Announcement: " + announcement); + speakAnnouncment(announcement); + } + + protected void speakAnnouncment(String announcement) { tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java b/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java index 7bca3ad1b..cb89e5cb7 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java @@ -107,6 +107,10 @@ public class ApiFeatures { return getApiLevel() >= 9; } + public boolean isAudioFocusSupported() { + return getApiLevel() >= 8; + } + /** * There's a bug (#1587) in Cupcake and Donut which prevents you from * using a SQLiteQueryBuilder twice. That is, if you call buildQuery