Merge Android Pie into master

Bug: 112104996
Change-Id: If7bba1133ed2fef69205ab44f390a079e8136b05
diff --git a/Android.mk b/Android.mk
index 7ea9b8d..0404ee0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -38,16 +38,18 @@
 
 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_STATIC_JAVA_LIBRARIES += \
+    androidx.annotation_annotation \
+    car-messenger-glide-target \
+    car-massenger-gifdecoder-target \
+    car-messenger-disklrucache-target
 
 LOCAL_DEX_PREOPT := false
 
-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
-
 include $(BUILD_PACKAGE)
 
 include $(CLEAR_VARS)
@@ -56,6 +58,7 @@
 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 := 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 := 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 @@
 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.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 @@
     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 @@
         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 @@
         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 @@
 
     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 @@
         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 @@
                         }
                         finish();
                     }
+
+                    @Override
+                    public void onAudioFocusFailed() {
+                        Log.w(TAG, "failed to require audio focus.");
+                    }
                 });
     }
 
@@ -199,7 +198,6 @@
                     || event.getY() < mContainer.getY()
                     || event.getY() > mContainer.getY() + mContainer.getHeight()) {
                 finish();
-
             }
         }
         return super.onTouchEvent(event);
@@ -245,6 +243,7 @@
     @Override
     protected void onStop() {
         super.onStop();
+        stopMessage();
         mTTSHelper.cleanup();
         mMessengerServiceBroadcastReceiver.cleanup();
         unbindService(mConnection);
@@ -270,7 +269,7 @@
         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 @@
                     updateViewForMessagePlaying();
                     break;
                 case MapMessageMonitor.ACTION_MESSAGE_PLAY_STOP:
-                    updateViewFoeMessageStopped();
+                    updateViewForMessageStopped();
                     break;
                 default:
                     break;
@@ -315,7 +314,7 @@
             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 @@
 
     @Override
     public void stop() {
-        mTextToSpeech.stop();
+        if (mTextToSpeech != null) {
+            mTextToSpeech.stop();
+        }
     }
 
     @Override
@@ -52,4 +54,9 @@
         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 @@
         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 @@
      * 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 @@
          *              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 @@
 
     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 @@
     @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 @@
      * 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 @@
      * @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 @@
         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 @@
                 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 @@
         shutdownEngine();
     }
 
+    public int getStream() {
+        return mTTSEngine.getStream();
+    }
+
     private void shutdownEngine() {
         if (mTTSEngine.isInitialized()) {
             if (DBG) {
@@ -324,7 +353,7 @@
         // 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 @@
 
 # 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_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 @@
             mStopped = true;
             mError = error;
         }
+        
+        @Override
+        public void onAudioFocusFailed() {
+        }
     }
-}
\ No newline at end of file
+}