summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2018-08-06 16:51:15 -0700
committerXin Li <delphij@google.com>2018-08-06 16:51:15 -0700
commitbc0a323aa825030c639b2f85c5f1171e385fa217 (patch)
tree425350d783f248ea11209938273ce0d214ffc07d
parentd56ef7d13feb6a3c43f9b2235dd64ebabc3d5d5d (diff)
parentdce3f073732f0e94ee623669fd53e42129809889 (diff)
downloadMessenger-master-cuttlefish-testing-release.tar.gz
Bug: 112104996 Change-Id: If7bba1133ed2fef69205ab44f390a079e8136b05
-rw-r--r--Android.mk19
-rw-r--r--res/drawable/circle_bg.xml4
-rw-r--r--res/drawable/rounded_corner_btn_bg.xml2
-rw-r--r--res/layout/play_message_layout.xml111
-rw-r--r--res/values/dimens.xml1
-rw-r--r--res/values/styles.xml9
-rw-r--r--src/com/android/car/messenger/MapMessage.java3
-rw-r--r--src/com/android/car/messenger/MapMessageMonitor.java56
-rw-r--r--src/com/android/car/messenger/PlayMessageActivity.java25
-rw-r--r--src/com/android/car/messenger/tts/AndroidTTSEngine.java9
-rw-r--r--src/com/android/car/messenger/tts/FakeTTSEngine.java5
-rw-r--r--src/com/android/car/messenger/tts/TTSEngine.java5
-rw-r--r--src/com/android/car/messenger/tts/TTSHelper.java41
-rw-r--r--tests/robotests/Android.mk10
-rw-r--r--tests/robotests/src/com/android/car/messenger/tts/TTSHelperTest.java6
15 files changed, 184 insertions, 122 deletions
diff --git a/Android.mk b/Android.mk
index 7ea9b8d..0404ee0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -38,15 +38,17 @@ LOCAL_PRIVILEGED_MODULE := true
LOCAL_USE_AAPT2 := true
-LOCAL_STATIC_ANDROID_LIBRARIES += android-support-v4
-LOCAL_STATIC_JAVA_LIBRARIES += car-messenger-glide-target
-LOCAL_STATIC_JAVA_LIBRARIES += car-massenger-gifdecoder-target
-LOCAL_STATIC_JAVA_LIBRARIES += car-messenger-disklrucache-target
+LOCAL_STATIC_ANDROID_LIBRARIES += \
+ androidx.car_car \
+ car-apps-common
-LOCAL_DEX_PREOPT := false
+LOCAL_STATIC_JAVA_LIBRARIES += \
+ androidx.annotation_annotation \
+ car-messenger-glide-target \
+ car-massenger-gifdecoder-target \
+ car-messenger-disklrucache-target
-include packages/apps/Car/libs/car-stream-ui-lib/car-stream-ui-lib.mk
-include packages/apps/Car/libs/car-apps-common/car-apps-common.mk
+LOCAL_DEX_PREOPT := false
include $(BUILD_PACKAGE)
@@ -56,6 +58,7 @@ LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE := car-messenger-disklrucache-target
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := ../../../../prebuilts/maven_repo/bumptech/com/github/bumptech/glide/disklrucache/SNAPSHOT/disklrucache-SNAPSHOT$(COMMON_JAVA_PACKAGE_SUFFIX)
+LOCAL_JETIFIER_ENABLED := true
LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_PREBUILT)
@@ -66,6 +69,7 @@ LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE := car-massenger-gifdecoder-target
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := ../../../../prebuilts/maven_repo/bumptech/com/github/bumptech/glide/gifdecoder/SNAPSHOT/gifdecoder-SNAPSHOT$(COMMON_JAVA_PACKAGE_SUFFIX)
+LOCAL_JETIFIER_ENABLED := true
LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_PREBUILT)
@@ -76,6 +80,7 @@ LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE := car-messenger-glide-target
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := ../../../../prebuilts/maven_repo/bumptech/com/github/bumptech/glide/glide/SNAPSHOT/glide-SNAPSHOT$(COMMON_JAVA_PACKAGE_SUFFIX)
+LOCAL_JETIFIER_ENABLED := true
LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_PREBUILT)
diff --git a/res/drawable/circle_bg.xml b/res/drawable/circle_bg.xml
index 1770aab..9bdfa0f 100644
--- a/res/drawable/circle_bg.xml
+++ b/res/drawable/circle_bg.xml
@@ -19,6 +19,6 @@
android:shape="oval">
<solid android:color="@color/car_blue_grey_900" />
<size
- android:height="@dimen/car_touch_target"
- android:width="@dimen/car_touch_target" />
+ android:height="@dimen/car_touch_target_size"
+ android:width="@dimen/car_touch_target_size" />
</shape> \ No newline at end of file
diff --git a/res/drawable/rounded_corner_btn_bg.xml b/res/drawable/rounded_corner_btn_bg.xml
index dba56a6..27762ee 100644
--- a/res/drawable/rounded_corner_btn_bg.xml
+++ b/res/drawable/rounded_corner_btn_bg.xml
@@ -20,6 +20,6 @@
<solid android:color="@color/car_blue_grey_900" />
<corners android:radius="55dp"/>
<size
- android:height="@dimen/car_touch_target"
+ android:height="@dimen/car_touch_target_size"
android:width="@dimen/big_btn_bg_width" />
</shape> \ No newline at end of file
diff --git a/res/layout/play_message_layout.xml b/res/layout/play_message_layout.xml
index 058414d..452adb1 100644
--- a/res/layout/play_message_layout.xml
+++ b/res/layout/play_message_layout.xml
@@ -24,67 +24,82 @@
android:background="@drawable/round_corner"
android:animateLayoutChanges="true"
android:alpha="0"
- android:layout_marginStart="@dimen/side_margin"
- android:layout_marginEnd="@dimen/side_margin"
+ android:layout_marginStart="@dimen/car_margin"
+ android:layout_marginEnd="@dimen/car_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <GridLayout
+ <LinearLayout
android:id="@+id/message_container"
android:visibility="gone"
+ android:layout_marginStart="@dimen/car_keyline_3"
+ android:layout_marginEnd="@dimen/car_keyline_3"
+ android:orientation="vertical"
android:layout_weight="1"
- android:layout_marginStart="@dimen/stream_card_keyline_3"
- android:layout_marginEnd="@dimen/stream_card_keyline_3"
android:layout_height="0dp"
- android:layout_width="match_parent"
- android:useDefaultMargins="true"
- android:alignmentMode="alignBounds"
- android:columnOrderPreserved="false"
- android:columnCount="4"
- >
- <TextView
- android:id="@+id/emoji1"
- style="@style/MessageEmoji">
- </TextView>
- <TextView
- android:id="@+id/emoji2"
- style="@style/MessageEmoji">
- </TextView>
- <TextView
- android:id="@+id/emoji3"
- style="@style/MessageEmoji">
- </TextView>
- <TextView
- android:id="@+id/emoji4"
- style="@style/MessageEmoji">
- </TextView>
- <TextView
- android:id="@+id/emoji5"
- style="@style/MessageEmoji">
- </TextView>
+ android:layout_width="match_parent" >
+ <!-- expandable spacing -->
+ <View
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"/>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/emoji1"
+ style="@style/MessageEmoji">
+ </TextView>
+ <!-- expandable spacing -->
+ <View
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1"/>
+ <TextView
+ android:id="@+id/emoji2"
+ style="@style/MessageEmoji">
+ </TextView>
+ <!-- expandable spacing -->
+ <View
+ android:layout_height="match_parent"
+ android:layout_width="0dp"
+ android:layout_weight="1"/>
+ <TextView
+ android:id="@+id/emoji3"
+ style="@style/MessageEmoji">
+ </TextView>
+ </LinearLayout>
+ <!-- expandable spacing -->
+ <View
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"/>
<TextView
android:id="@+id/canned_message"
- style="@style/CarBody1.Light"
- android:layout_column="1"
- android:layout_rowSpan="1"
- android:layout_columnSpan="3"
+ style="@style/TextAppearance.Car.Body1.Light"
android:gravity="center"
android:textStyle="italic"
android:layout_gravity="center"
android:background="@drawable/rounded_corner_btn_bg"
android:text="@string/caned_message_driving_right_now"
- android:layout_width="614dp"
- android:layout_height="@dimen/car_touch_target">
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/car_touch_target_size">
</TextView>
- </GridLayout>
+ <!-- expandable spacing -->
+ <View
+ android:layout_height="0dp"
+ android:layout_width="match_parent"
+ android:layout_weight="1"/>
+ </LinearLayout>
<TextView
android:id="@+id/reply_notice"
- style="@style/CarBody1"
+ style="@style/TextAppearance.Car.Body1"
android:layout_gravity="center"
android:gravity="center"
android:visibility="gone"
android:layout_width="match_parent"
- android:layout_height="@dimen/single_line_item_height">
+ android:layout_height="@dimen/car_single_line_list_item_height">
</TextView>
<LinearLayout
@@ -92,16 +107,16 @@
android:background="@color/car_card"
android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="@dimen/single_line_item_height">
+ android:layout_height="@dimen/car_single_line_list_item_height">
<TextView
android:id="@+id/left_btn"
- style="@style/CarBody1"
+ style="@style/TextAppearance.Car.Body1"
android:layout_weight="1"
android:gravity="center"
android:layout_gravity="center_vertical"
android:textAllCaps="true"
android:maxLines="1"
- android:layout_marginStart="@dimen/stream_content_keyline_1"
+ android:layout_marginStart="@dimen/car_keyline_1"
android:layout_marginEnd="@dimen/voice_plate_button_margin"
android:layout_width="0dp"
android:layout_height="wrap_content">
@@ -109,8 +124,8 @@
<ImageView
android:id="@+id/voice_icon"
- android:layout_width="@dimen/stream_button_icon_size"
- android:layout_height="@dimen/stream_button_icon_size"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
android:layout_gravity="center"
android:src="@drawable/ic_voice_out"
android:scaleType="fitCenter">
@@ -118,16 +133,16 @@
<TextView
android:id="@+id/right_btn"
- style="@style/CarBody1"
+ style="@style/TextAppearance.Car.Body1"
android:layout_weight="1"
android:gravity="center"
android:layout_gravity="center_vertical"
android:textAllCaps="true"
android:maxLines="1"
android:layout_marginStart="@dimen/voice_plate_button_margin"
- android:layout_marginEnd="@dimen/stream_content_keyline_1"
+ android:layout_marginEnd="@dimen/car_keyline_1"
android:layout_width="0dp"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b0eafa5..1fb98d7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -15,6 +15,7 @@
~ limitations under the License
-->
<resources>
+ <dimen name="car_card_view_elevation">8dp</dimen>
<dimen name="notification_contact_photo_size">300dp</dimen>
<dimen name="voice_plate_button_margin">32dp</dimen>
<dimen name="big_btn_bg_width">614dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index c9ae141..05912be 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -26,13 +26,12 @@
<item name="android:windowNoTitle">true</item>
</style>
- <style name="MessageEmoji" parent="@style/CarBody1">
+ <style name="MessageEmoji" parent="@style/TextAppearance.Car.Body1">
<item name="android:background">@drawable/circle_bg</item>
<item name="android:textSize">@dimen/car_emoji_size</item>
<item name="android:gravity">center</item>
<item name="android:layout_gravity">center</item>
- <item name="android:layout_columnWeight">1</item>
- <item name="android:layout_rowWeight">1</item>
- <item name="android:layout_height">@dimen/car_touch_target</item>
+ <item name="android:layout_height">@dimen/car_touch_target_size</item>
+ <item name="android:layout_width">@dimen/car_touch_target_size</item>
</style>
-</resources> \ No newline at end of file
+</resources>
diff --git a/src/com/android/car/messenger/MapMessage.java b/src/com/android/car/messenger/MapMessage.java
index 2bca390..998e933 100644
--- a/src/com/android/car/messenger/MapMessage.java
+++ b/src/com/android/car/messenger/MapMessage.java
@@ -19,7 +19,8 @@ package com.android.car.messenger;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
import android.content.Intent;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.Nullable;
/**
* Represents a message obtained via MAP service from a connected Bluetooth device.
diff --git a/src/com/android/car/messenger/MapMessageMonitor.java b/src/com/android/car/messenger/MapMessageMonitor.java
index b07d263..3c427dd 100644
--- a/src/com/android/car/messenger/MapMessageMonitor.java
+++ b/src/com/android/car/messenger/MapMessageMonitor.java
@@ -35,20 +35,19 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
-import android.media.AudioManager;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.ContactsContract;
import android.provider.Settings;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+
import com.android.car.apps.common.LetterTileDrawable;
import com.android.car.messenger.tts.TTSHelper;
-
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
@@ -93,8 +92,6 @@ class MapMessageMonitor {
private final Map<SenderKey, NotificationInfo> mNotificationInfos = new HashMap<>();
private final TTSHelper mTTSHelper;
private final HashMap<String, Boolean> mReplyFeatureMap = new HashMap<>();
- private final AudioManager mAudioManager;
- private final AudioManager.OnAudioFocusChangeListener mNoOpAFChangeListener = (f) -> {};
MapMessageMonitor(Context context) {
mContext = context;
@@ -103,8 +100,6 @@ class MapMessageMonitor {
mNotificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mTTSHelper = new TTSHelper(mContext);
-
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}
public boolean isPlaying() {
@@ -347,34 +342,29 @@ class MapMessageMonitor {
ttsMessages.add(mContext.getString(R.string.tts_sender_says, notificationInfo.mSenderName));
ttsMessages.add(ttsMessage);
- int result = mAudioManager.requestAudioFocus(mNoOpAFChangeListener,
- // Use the music stream.
- AudioManager.STREAM_MUSIC,
- // Request permanent focus.
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
- mTTSHelper.requestPlay(ttsMessages,
- new TTSHelper.Listener() {
- @Override
- public void onTTSStarted() {
- Intent intent = new Intent(ACTION_MESSAGE_PLAY_START);
- mContext.sendBroadcast(intent);
- }
+ mTTSHelper.requestPlay(ttsMessages,
+ new TTSHelper.Listener() {
+ @Override
+ public void onTTSStarted() {
+ Intent intent = new Intent(ACTION_MESSAGE_PLAY_START);
+ mContext.sendBroadcast(intent);
+ }
- @Override
- public void onTTSStopped(boolean error) {
- mAudioManager.abandonAudioFocus(mNoOpAFChangeListener);
- Intent intent = new Intent(ACTION_MESSAGE_PLAY_STOP);
- mContext.sendBroadcast(intent);
- if (error) {
- Toast.makeText(mContext, R.string.tts_failed_toast,
- Toast.LENGTH_SHORT).show();
- }
+ @Override
+ public void onTTSStopped(boolean error) {
+ Intent intent = new Intent(ACTION_MESSAGE_PLAY_STOP);
+ mContext.sendBroadcast(intent);
+ if (error) {
+ Toast.makeText(mContext, R.string.tts_failed_toast,
+ Toast.LENGTH_SHORT).show();
}
- });
- } else {
- Log.w(TAG, "failed to require audio focus.");
- }
+ }
+
+ @Override
+ public void onAudioFocusFailed() {
+ Log.w(TAG, "failed to require audio focus.");
+ }
+ });
}
void stopPlayout() {
diff --git a/src/com/android/car/messenger/PlayMessageActivity.java b/src/com/android/car/messenger/PlayMessageActivity.java
index 0381c15..7bfc5f9 100644
--- a/src/com/android/car/messenger/PlayMessageActivity.java
+++ b/src/com/android/car/messenger/PlayMessageActivity.java
@@ -91,15 +91,11 @@ public class PlayMessageActivity extends Activity {
private void setupEmojis() {
TextView emoji1 = (TextView) findViewById(R.id.emoji1);
- emoji1.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_ok_hand_sign)));
+ emoji1.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_thumb_up)));
TextView emoji2 = (TextView) findViewById(R.id.emoji2);
- emoji2.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_thumb_up)));
+ emoji2.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_thumb_down)));
TextView emoji3 = (TextView) findViewById(R.id.emoji3);
- emoji3.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_thumb_down)));
- TextView emoji4 = (TextView) findViewById(R.id.emoji4);
- emoji4.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_heart)));
- TextView emoji5 = (TextView) findViewById(R.id.emoji5);
- emoji5.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_smiling_face)));
+ emoji3.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_smiling_face)));
}
private String getEmojiByUnicode(int unicode){
@@ -115,8 +111,6 @@ public class PlayMessageActivity extends Activity {
findViewById(R.id.emoji1).setOnClickListener(this::sendReply);
findViewById(R.id.emoji2).setOnClickListener(this::sendReply);
findViewById(R.id.emoji3).setOnClickListener(this::sendReply);
- findViewById(R.id.emoji4).setOnClickListener(this::sendReply);
- findViewById(R.id.emoji5).setOnClickListener(this::sendReply);
}
/**
@@ -165,6 +159,11 @@ public class PlayMessageActivity extends Activity {
}
finish();
}
+
+ @Override
+ public void onAudioFocusFailed() {
+ Log.w(TAG, "failed to require audio focus.");
+ }
});
}
@@ -199,7 +198,6 @@ public class PlayMessageActivity extends Activity {
|| event.getY() < mContainer.getY()
|| event.getY() > mContainer.getY() + mContainer.getHeight()) {
finish();
-
}
}
return super.onTouchEvent(event);
@@ -245,6 +243,7 @@ public class PlayMessageActivity extends Activity {
@Override
protected void onStop() {
super.onStop();
+ stopMessage();
mTTSHelper.cleanup();
mMessengerServiceBroadcastReceiver.cleanup();
unbindService(mConnection);
@@ -270,7 +269,7 @@ public class PlayMessageActivity extends Activity {
mVoiceIcon.setVisibility(View.VISIBLE);
}
- private void updateViewFoeMessageStopped() {
+ private void updateViewForMessageStopped() {
mRightButton.setText(getString(R.string.action_repeat));
mRightButton.setOnClickListener(v -> playMessage());
mVoiceIcon.setVisibility(View.INVISIBLE);
@@ -299,7 +298,7 @@ public class PlayMessageActivity extends Activity {
updateViewForMessagePlaying();
break;
case MapMessageMonitor.ACTION_MESSAGE_PLAY_STOP:
- updateViewFoeMessageStopped();
+ updateViewForMessageStopped();
break;
default:
break;
@@ -315,7 +314,7 @@ public class PlayMessageActivity extends Activity {
if (mMessengerService.isPlaying()) {
updateViewForMessagePlaying();
} else {
- updateViewFoeMessageStopped();
+ updateViewForMessageStopped();
}
}
diff --git a/src/com/android/car/messenger/tts/AndroidTTSEngine.java b/src/com/android/car/messenger/tts/AndroidTTSEngine.java
index 1428f4a..70d0aff 100644
--- a/src/com/android/car/messenger/tts/AndroidTTSEngine.java
+++ b/src/com/android/car/messenger/tts/AndroidTTSEngine.java
@@ -39,7 +39,9 @@ class AndroidTTSEngine implements TTSEngine {
@Override
public void stop() {
- mTextToSpeech.stop();
+ if (mTextToSpeech != null) {
+ mTextToSpeech.stop();
+ }
}
@Override
@@ -52,4 +54,9 @@ class AndroidTTSEngine implements TTSEngine {
mTextToSpeech.shutdown();
mTextToSpeech = null;
}
+
+ @Override
+ public int getStream() {
+ return TextToSpeech.Engine.DEFAULT_STREAM;
+ }
}
diff --git a/src/com/android/car/messenger/tts/FakeTTSEngine.java b/src/com/android/car/messenger/tts/FakeTTSEngine.java
index 0870379..6af64e4 100644
--- a/src/com/android/car/messenger/tts/FakeTTSEngine.java
+++ b/src/com/android/car/messenger/tts/FakeTTSEngine.java
@@ -53,6 +53,11 @@ class FakeTTSEngine implements TTSEngine {
mOnInitListener = null;
}
+ @Override
+ public int getStream() {
+ return TextToSpeech.Engine.DEFAULT_STREAM;
+ }
+
void startRequest(String utteranceId) {
mProgressListener.onStart(utteranceId);
}
diff --git a/src/com/android/car/messenger/tts/TTSEngine.java b/src/com/android/car/messenger/tts/TTSEngine.java
index ed1313f..e789327 100644
--- a/src/com/android/car/messenger/tts/TTSEngine.java
+++ b/src/com/android/car/messenger/tts/TTSEngine.java
@@ -48,4 +48,9 @@ public interface TTSEngine {
* using this engine.
*/
void shutdown();
+
+ /**
+ * Returns the stream used by this TTS engine.
+ */
+ int getStream();
}
diff --git a/src/com/android/car/messenger/tts/TTSHelper.java b/src/com/android/car/messenger/tts/TTSHelper.java
index 08dfcd6..aef20d7 100644
--- a/src/com/android/car/messenger/tts/TTSHelper.java
+++ b/src/com/android/car/messenger/tts/TTSHelper.java
@@ -17,13 +17,15 @@
package com.android.car.messenger.tts;
import android.content.Context;
+import android.media.AudioManager;
import android.os.Handler;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
-import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.Pair;
+import androidx.annotation.VisibleForTesting;
+
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -56,6 +58,12 @@ public class TTSHelper {
* not considered an error.
*/
void onTTSStopped(boolean error);
+
+ /**
+ * Called when request to get audio focus failed. This happens before the requested TTS
+ * is played.
+ */
+ void onAudioFocusFailed();
}
private static final String TAG = "Messenger.TTSHelper";
@@ -66,6 +74,8 @@ public class TTSHelper {
private final Handler mHandler = new Handler();
private final Context mContext;
+ private final AudioManager mAudioManager;
+ private final AudioManager.OnAudioFocusChangeListener mNoOpAFChangeListener = (f) -> {};
private final long mShutdownDelayMillis;
private TTSEngine mTTSEngine;
private int mInitStatus;
@@ -83,6 +93,7 @@ public class TTSHelper {
@VisibleForTesting
TTSHelper(Context context, TTSEngine ttsEngine, long shutdownDelayMillis) {
mContext = context;
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mTTSEngine = ttsEngine;
mShutdownDelayMillis = shutdownDelayMillis;
// OnInitListener will only set to SUCCESS/ERROR. So we initialize to STOPPED.
@@ -129,6 +140,7 @@ public class TTSHelper {
* until then. Only one batch is supported at a time; If a previous batch is waiting engine
* setup, that batch is dropped. If a previous batch is playing, the play-out is stopped and
* next one is passed to the TTS Engine. Callbacks are issued on the provided {@code listener}.
+ * Will request audio focus first, failure will trigger onAudioFocusFailed in listener.
*
* NOTE: Underlying engine may have limit on length of text in each element of the batch; it
* will reject anything longer. See {@link TextToSpeech#getMaxSpeechInputLength()}.
@@ -137,16 +149,23 @@ public class TTSHelper {
* @param listener Observer that will receive callbacks about play-out progress.
*/
public void requestPlay(List<CharSequence> textToSpeak, Listener listener) {
- if (textToSpeak == null || textToSpeak.size() < 1) {
+ if (textToSpeak == null || textToSpeak.isEmpty()) {
throw new IllegalArgumentException("Empty/null textToSpeak");
}
+ int result = mAudioManager.requestAudioFocus(mNoOpAFChangeListener,
+ getStream(),
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ listener.onAudioFocusFailed();
+ return;
+ }
initMaybeAndKeepAlive();
// Check if its still initializing.
if (mInitStatus == TextToSpeech.STOPPED) {
// Squash any already queued request.
if (mPendingRequest != null) {
- mPendingRequest.mListener.onTTSStopped(false /* error */);
+ onTtsStopped(mPendingRequest.mListener, false /* error */);
}
mPendingRequest = new SpeechRequest(textToSpeak, listener);
} else {
@@ -163,10 +182,16 @@ public class TTSHelper {
return mTTSEngine.isSpeaking();
}
+ // wrap call back to listener.onTTSStopped with adandonAudioFocus.
+ private void onTtsStopped(Listener listener, boolean error) {
+ mAudioManager.abandonAudioFocus(mNoOpAFChangeListener);
+ mHandler.post(() -> listener.onTTSStopped(error));
+ }
+
private void playInternal(List<CharSequence> textToSpeak, Listener listener) {
if (mInitStatus == TextToSpeech.ERROR) {
Log.e(TAG, "TTS setup failed!");
- mHandler.post(() -> listener.onTTSStopped(true /* error */));
+ onTtsStopped(listener, true /* error */);
return;
}
@@ -188,7 +213,7 @@ public class TTSHelper {
mTTSEngine.stop();
currentBatchId = null;
Log.e(TAG, "Queuing text failed!");
- mHandler.post(() -> listener.onTTSStopped(true /* error */));
+ onTtsStopped(listener, true /* error */);
return;
}
index--;
@@ -206,6 +231,10 @@ public class TTSHelper {
shutdownEngine();
}
+ public int getStream() {
+ return mTTSEngine.getStream();
+ }
+
private void shutdownEngine() {
if (mTTSEngine.isInitialized()) {
if (DBG) {
@@ -324,7 +353,7 @@ public class TTSHelper {
// Handles terminal callbacks for the batch. We invoke stopped and remove ourselves.
// No further callbacks will be handled for the batch.
private void handleBatchFinished(Pair<String, Integer> parsedId, boolean error) {
- mListener.onTTSStopped(error);
+ onTtsStopped(mListener, error);
mListeners.remove(parsedId.first);
}
}
diff --git a/tests/robotests/Android.mk b/tests/robotests/Android.mk
index 357eb80..77c65f7 100644
--- a/tests/robotests/Android.mk
+++ b/tests/robotests/Android.mk
@@ -8,12 +8,12 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
# Include the testing libraries (JUnit4 + Robolectric libs).
LOCAL_STATIC_JAVA_LIBRARIES := \
- platform-system-robolectric \
- truth-prebuilt
+ truth-prebuilt \
+ mockito-robolectric-prebuilt
LOCAL_JAVA_LIBRARIES := \
junit \
- platform-robolectric-prebuilt
+ platform-robolectric-3.6.1-prebuilt
LOCAL_INSTRUMENTATION_FOR := CarMessengerApp
LOCAL_MODULE := CarMessengerRoboTests
@@ -36,4 +36,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
LOCAL_TEST_PACKAGE := CarMessengerApp
-include prebuilts/misc/common/robolectric/run_robotests.mk
+LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src
+
+include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
diff --git a/tests/robotests/src/com/android/car/messenger/tts/TTSHelperTest.java b/tests/robotests/src/com/android/car/messenger/tts/TTSHelperTest.java
index f9745f4..dbbb5e4 100644
--- a/tests/robotests/src/com/android/car/messenger/tts/TTSHelperTest.java
+++ b/tests/robotests/src/com/android/car/messenger/tts/TTSHelperTest.java
@@ -156,5 +156,9 @@ public class TTSHelperTest {
mStopped = true;
mError = error;
}
+
+ @Override
+ public void onAudioFocusFailed() {
+ }
}
-} \ No newline at end of file
+}