summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2017-12-06 11:52:06 -0800
committerXin Li <delphij@google.com>2017-12-06 14:24:52 -0800
commitc6afb36e77d24ebbad4a693ab8c5f66d66ea8e41 (patch)
tree43d8e691aeb3fc8ae219f0f119e5c33eb326cea5
parent917af90df473a739aca62bc0404fa2f25977307d (diff)
parent811cfca9026ae98a15718a678d1089c9b7c6c63a (diff)
downloadMessenger-c6afb36e77d24ebbad4a693ab8c5f66d66ea8e41.tar.gz
DO NOT MERGE: Merge Oreo MR1 into masterandroid-wear-8.0.0_r1
Exempt-From-Owner-Approval: Changes already landed internally Change-Id: I10a690d9f43a511569c94a9d0e4eb444d9ec0b9d
-rw-r--r--Android.mk4
-rw-r--r--AndroidManifest.xml4
-rw-r--r--res/anim/trans_bottom_in.xml32
-rw-r--r--res/anim/trans_bottom_out.xml32
-rw-r--r--res/drawable/circle_bg.xml24
-rw-r--r--res/drawable/gradient_transparent.xml26
-rw-r--r--res/drawable/ic_voice_out.xml29
-rw-r--r--res/drawable/round_corner.xml29
-rw-r--r--res/drawable/rounded_corner_btn_bg.xml25
-rw-r--r--res/layout/play_message_layout.xml128
-rw-r--r--res/values/dimens.xml3
-rw-r--r--res/values/integers.xml26
-rw-r--r--res/values/strings.xml10
-rw-r--r--res/values/styles.xml38
-rw-r--r--src/com/android/car/messenger/MapMessageMonitor.java218
-rw-r--r--src/com/android/car/messenger/MessengerService.java17
-rw-r--r--src/com/android/car/messenger/PlayMessageActivity.java237
17 files changed, 746 insertions, 136 deletions
diff --git a/Android.mk b/Android.mk
index bd4ed6e..9fc5f09 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,6 +14,8 @@
# limitations under the License.
#
+ifneq ($(TARGET_BUILD_PDK), true)
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -79,3 +81,5 @@ include $(BUILD_PREBUILT)
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call all-makefiles-under,$(LOCAL_PATH))
endif
+
+endif
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 096e699..b0e4502 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -42,7 +42,9 @@
<category android:name="android.intent.category.APP_MESSAGING"/>
</intent-filter>
</activity>
- <activity android:name=".PlayMessageActivity" android:exported="true">
+ <activity android:name=".PlayMessageActivity" android:exported="true"
+ android:launchMode="singleTop"
+ android:theme="@style/FloatingWindow">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.APP_MESSAGING"/>
diff --git a/res/anim/trans_bottom_in.xml b/res/anim/trans_bottom_in.xml
new file mode 100644
index 0000000..0635de3
--- /dev/null
+++ b/res/anim/trans_bottom_in.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:interpolator="@android:interpolator/decelerate_quint"
+ android:valueFrom="100dp"
+ android:valueTo="0dp"
+ android:valueType="floatType"
+ android:propertyName="translationY"
+ android:duration="@integer/anim_time" />
+ <objectAnimator
+ android:interpolator="@android:interpolator/decelerate_quint"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:propertyName="alpha"
+ android:duration="@integer/anim_time" />
+</set> \ No newline at end of file
diff --git a/res/anim/trans_bottom_out.xml b/res/anim/trans_bottom_out.xml
new file mode 100644
index 0000000..81295e8
--- /dev/null
+++ b/res/anim/trans_bottom_out.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:interpolator="@android:interpolator/decelerate_quint"
+ android:valueFrom="0dp"
+ android:valueTo="-100dp"
+ android:valueType="floatType"
+ android:propertyName="translationY"
+ android:duration="@integer/anim_time" />
+ <objectAnimator
+ android:interpolator="@android:interpolator/decelerate_quint"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:propertyName="alpha"
+ android:duration="@integer/anim_time" />
+</set> \ No newline at end of file
diff --git a/res/drawable/circle_bg.xml b/res/drawable/circle_bg.xml
new file mode 100644
index 0000000..1770aab
--- /dev/null
+++ b/res/drawable/circle_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="@color/car_blue_grey_900" />
+ <size
+ android:height="@dimen/car_touch_target"
+ android:width="@dimen/car_touch_target" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/gradient_transparent.xml b/res/drawable/gradient_transparent.xml
new file mode 100644
index 0000000..369ccef
--- /dev/null
+++ b/res/drawable/gradient_transparent.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient android:endColor="@android:color/transparent"
+ android:startColor="#88000000"
+ android:angle="90"
+ android:type="linear"
+ android:useLevel="true"
+ />
+</shape> \ No newline at end of file
diff --git a/res/drawable/ic_voice_out.xml b/res/drawable/ic_voice_out.xml
new file mode 100644
index 0000000..a4a3c07
--- /dev/null
+++ b/res/drawable/ic_voice_out.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+
+<vector android:height="24dp" android:viewportHeight="48.0"
+ android:viewportWidth="50.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#00796B" android:pathData="M22,0h6v48h-6z"
+ android:strokeColor="#00000000" android:strokeWidth="1"/>
+ <path android:fillColor="#00796B" android:pathData="M33,10h6v28h-6z"
+ android:strokeColor="#00000000" android:strokeWidth="1"/>
+ <path android:fillColor="#00796B" android:pathData="M11,10h6v28h-6z"
+ android:strokeColor="#00000000" android:strokeWidth="1"/>
+ <path android:fillColor="#00796B" android:pathData="M0,19h6v10h-6z"
+ android:strokeColor="#00000000" android:strokeWidth="1"/>
+ <path android:fillColor="#00796B" android:pathData="M44,19h6v10h-6z"
+ android:strokeColor="#00000000" android:strokeWidth="1"/>
+</vector>
diff --git a/res/drawable/round_corner.xml b/res/drawable/round_corner.xml
new file mode 100644
index 0000000..0b5dba7
--- /dev/null
+++ b/res/drawable/round_corner.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+
+ <solid android:color="@color/car_card" />
+ <padding
+ android:bottom="5dp"
+ android:left="5dp"
+ android:right="5dp"
+ android:top="5dp" />
+ <corners android:topLeftRadius="20dp"
+ android:topRightRadius="20dp"/>
+
+</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
new file mode 100644
index 0000000..dba56a6
--- /dev/null
+++ b/res/drawable/rounded_corner_btn_bg.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/car_blue_grey_900" />
+ <corners android:radius="55dp"/>
+ <size
+ android:height="@dimen/car_touch_target"
+ 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 b6bc788..058414d 100644
--- a/res/layout/play_message_layout.xml
+++ b/res/layout/play_message_layout.xml
@@ -15,27 +15,119 @@
~ limitations under the License
-->
-<!-- Eng mock, waiting for UX spec -->
-<RelativeLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:orientation="vertical"
+ android:layout_gravity="bottom"
+ android:elevation="@dimen/car_card_view_elevation"
+ 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_width="match_parent"
- android:layout_height="match_parent" >
- <TextView
- android:id="@+id/play_pause_btn"
- style="@style/CarBody1"
- android:layout_centerInParent="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- </TextView>
+ android:layout_height="wrap_content">
+ <GridLayout
+ android:id="@+id/message_container"
+ android:visibility="gone"
+ 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>
+ <TextView
+ android:id="@+id/canned_message"
+ style="@style/CarBody1.Light"
+ android:layout_column="1"
+ android:layout_rowSpan="1"
+ android:layout_columnSpan="3"
+ 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">
+ </TextView>
+ </GridLayout>
<TextView
- android:id="@+id/exit_btn"
+ android:id="@+id/reply_notice"
style="@style/CarBody1"
- android:text="Exit"
- android:layout_centerHorizontal="true"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="100dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/single_line_item_height">
</TextView>
-</RelativeLayout>
+
+ <LinearLayout
+ android:id="@+id/voice_plate"
+ android:background="@color/car_card"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/single_line_item_height">
+ <TextView
+ android:id="@+id/left_btn"
+ style="@style/CarBody1"
+ 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_marginEnd="@dimen/voice_plate_button_margin"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content">
+ </TextView>
+
+ <ImageView
+ android:id="@+id/voice_icon"
+ android:layout_width="@dimen/stream_button_icon_size"
+ android:layout_height="@dimen/stream_button_icon_size"
+ android:layout_gravity="center"
+ android:src="@drawable/ic_voice_out"
+ android:scaleType="fitCenter">
+ </ImageView>
+
+ <TextView
+ android:id="@+id/right_btn"
+ style="@style/CarBody1"
+ 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_width="0dp"
+ android:layout_height="wrap_content">
+ </TextView>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7308708..b0eafa5 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,4 +16,7 @@
-->
<resources>
<dimen name="notification_contact_photo_size">300dp</dimen>
+ <dimen name="voice_plate_button_margin">32dp</dimen>
+ <dimen name="big_btn_bg_width">614dp</dimen>
+ <dimen name="car_emoji_size">56dp</dimen>
</resources>
diff --git a/res/values/integers.xml b/res/values/integers.xml
new file mode 100644
index 0000000..bb8aa4b
--- /dev/null
+++ b/res/values/integers.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ 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
+ -->
+
+<resources>
+ <integer name="emoji_thumb_up">0x1F44D</integer>
+ <integer name="emoji_thumb_down">0x1F44E</integer>
+ <integer name="emoji_ok_hand_sign">0x1F44C</integer>
+ <integer name="emoji_heart">0x1F49B</integer>
+ <integer name="emoji_smiling_face">0x1F642</integer>
+
+ <integer name="anim_time">1000</integer>
+</resources> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9509e86..66d69ad 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -23,14 +23,18 @@
</plurals>
<string name="action_mute">Mute</string>
+ <string name="action_unmute">Unmute</string>
<string name="action_play">Play</string>
+ <string name="action_repeat">Repeat</string>
+ <string name="action_reply">Reply</string>
<string name="action_stop">Stop</string>
- <string name="action_auto_reply">Reply: I\'m driving</string>
-
- <string name="auto_reply_message">I\'m driving right now</string>
+ <string name="action_close_messages">Close</string>
<string name="auto_reply_failed_message">Unable to send reply. Please try again.</string>
<string name="tts_sender_says">%s says</string>
<string name="tts_failed_toast">Text playout failed!</string>
+ <string name="reply_message_display_template">\"%s\"</string>
+ <string name="caned_message_driving_right_now">Auto-reply: I’m driving.</string>
+ <string name="message_sent_notice">Reply sent to %s</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100644
index 0000000..c9ae141
--- /dev/null
+++ b/res/values/styles.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ 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.
+-->
+
+<resources>
+ <!-- Pop up window that does not block interaction to other activity behind it. -->
+ <style name="FloatingWindow" parent="@android:style/Theme.Dialog">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@drawable/gradient_transparent</item>
+ <item name="android:background">@android:color/transparent</item>
+ <item name="android:backgroundDimEnabled">false</item>
+ <item name="android:windowCloseOnTouchOutside">true</item>
+ <item name="android:windowIsFloating">false</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
+ <style name="MessageEmoji" parent="@style/CarBody1">
+ <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>
+ </style>
+</resources> \ No newline at end of file
diff --git a/src/com/android/car/messenger/MapMessageMonitor.java b/src/com/android/car/messenger/MapMessageMonitor.java
index 1d12ee9..b07d263 100644
--- a/src/com/android/car/messenger/MapMessageMonitor.java
+++ b/src/com/android/car/messenger/MapMessageMonitor.java
@@ -35,14 +35,14 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
+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.telecom.PhoneAccount;
+import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
@@ -79,6 +79,9 @@ class MapMessageMonitor {
// reply or "upload" feature is indicated by the 3rd bit
private static final int REPLY_FEATURE_POS = 3;
+ private static final int REQUEST_CODE_VOICE_PLATE = 1;
+ private static final int REQUEST_CODE_AUTO_REPLY = 2;
+ private static final int ACTION_COUNT = 2;
private static final String TAG = "Messenger.MsgMonitor";
private static final boolean DBG = MessengerService.DBG;
@@ -89,8 +92,9 @@ class MapMessageMonitor {
private final Map<MessageKey, MapMessage> mMessages = new HashMap<>();
private final Map<SenderKey, NotificationInfo> mNotificationInfos = new HashMap<>();
private final TTSHelper mTTSHelper;
- private final Ringtone mNotificationTone;
private final HashMap<String, Boolean> mReplyFeatureMap = new HashMap<>();
+ private final AudioManager mAudioManager;
+ private final AudioManager.OnAudioFocusChangeListener mNoOpAFChangeListener = (f) -> {};
MapMessageMonitor(Context context) {
mContext = context;
@@ -100,9 +104,7 @@ class MapMessageMonitor {
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mTTSHelper = new TTSHelper(mContext);
- // Fetch default notification ringtone.
- Uri notificationUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
- mNotificationTone = RingtoneManager.getRingtone(mContext, notificationUri);
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}
public boolean isPlaying() {
@@ -115,7 +117,7 @@ class MapMessageMonitor {
}
try {
MapMessage message = MapMessage.parseFrom(intent);
- if (MessengerService.VDBG) {
+ if (MessengerService.DBG) {
Log.v(TAG, "Parsed message: " + message);
}
MessageKey messageKey = new MessageKey(message);
@@ -142,10 +144,6 @@ class MapMessageMonitor {
mNotificationInfos.put(senderKey, notificationInfo);
}
notificationInfo.mMessageKeys.add(messageKey);
- // Play notification when handling new message, if not muted.
- if (!notificationInfo.muted) {
- mNotificationTone.play();
- }
updateNotificationFor(senderKey, notificationInfo);
}
@@ -153,23 +151,29 @@ class MapMessageMonitor {
ContactsContract.PhoneLookup._ID
};
- private static int getContactIdFromNumber(ContentResolver cr, String number) {
- if (number == null || number.isEmpty()) {
+ private static int getContactIdFromName(ContentResolver cr, String name) {
+ if (DBG) {
+ Log.d(TAG, "getting contactId for: " + name);
+ }
+ if (TextUtils.isEmpty(name)) {
return 0;
}
- Uri uri = Uri.withAppendedPath(
- ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(number));
- Cursor cursor = cr.query(uri, CONTACT_ID, null, null, null);
+ String[] mSelectionArgs = { name };
+ Cursor cursor =
+ cr.query(
+ ContactsContract.Contacts.CONTENT_URI,
+ CONTACT_ID,
+ ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?",
+ mSelectionArgs,
+ null);
try {
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
return id;
}
- }
- finally {
+ } finally {
if (cursor != null) {
cursor.close();
}
@@ -187,11 +191,9 @@ class MapMessageMonitor {
long lastReceivedTimeMs =
mMessages.get(notificationInfo.mMessageKeys.getLast()).getReceivedTimeMs();
- String phoneNumber = notificationInfo.mSenderContactUri.substring(
- (PhoneAccount.SCHEME_TEL + ":").length());
Uri photoUri = ContentUris.withAppendedId(
- ContactsContract.Contacts.CONTENT_URI, getContactIdFromNumber(
- mContext.getContentResolver(), phoneNumber));
+ ContactsContract.Contacts.CONTENT_URI, getContactIdFromName(
+ mContext.getContentResolver(), notificationInfo.mSenderName));
if (DBG) {
Log.d(TAG, "start Glide loading... " + photoUri);
}
@@ -219,22 +221,21 @@ class MapMessageMonitor {
LetterTileDrawable letterTileDrawable =
new LetterTileDrawable(mContext.getResources());
letterTileDrawable.setContactDetails(
- notificationInfo.mSenderName, phoneNumber);
+ notificationInfo.mSenderName, notificationInfo.mSenderName);
letterTileDrawable.setIsCircular(true);
bitmap = letterTileDrawable.toBitmap(
mContext.getResources().getDimensionPixelSize(
R.dimen.notification_contact_photo_size));
}
- Intent intent = new Intent(mContext, PlayMessageActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(PlayMessageActivity.MESSAGE_KEY, senderKey);
- PendingIntent LaunchMessageActivityIntent = PendingIntent.getActivity(
- mContext, 0, intent, 0);
-
- Notification.Builder builder =
- new Notification.Builder(
- mContext, NotificationChannel.DEFAULT_CHANNEL_ID)
- .setContentIntent(LaunchMessageActivityIntent)
+ PendingIntent LaunchPlayMessageActivityIntent = PendingIntent.getActivity(
+ mContext,
+ REQUEST_CODE_VOICE_PLATE,
+ getPlayMessageIntent(senderKey, notificationInfo),
+ 0);
+
+ Notification.Builder builder = new Notification.Builder(
+ mContext, NotificationChannel.DEFAULT_CHANNEL_ID)
+ .setContentIntent(LaunchPlayMessageActivityIntent)
.setLargeIcon(bitmap)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle(notificationInfo.mSenderName)
@@ -245,57 +246,69 @@ class MapMessageMonitor {
.setDeleteIntent(buildIntentFor(
MessengerService.ACTION_CLEAR_NOTIFICATION_STATE,
senderKey, notificationInfo));
+ if (notificationInfo.muted) {
+ builder.setPriority(Notification.PRIORITY_MIN);
+ } else {
+ builder.setPriority(Notification.PRIORITY_HIGH)
+ .setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
+ }
mNotificationManager.notify(
notificationInfo.mNotificationId, builder.build());
}
});
}
- private Notification.Action[] getActionsFor(SenderKey senderKey,
+ private Intent getPlayMessageIntent(SenderKey senderKey, NotificationInfo notificationInfo) {
+ Intent intent = new Intent(mContext, PlayMessageActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(PlayMessageActivity.EXTRA_MESSAGE_KEY, senderKey);
+ intent.putExtra(
+ PlayMessageActivity.EXTRA_SENDER_NAME,
+ notificationInfo.mSenderName);
+ if (!supportsReply(senderKey.mDeviceAddress)) {
+ intent.putExtra(
+ PlayMessageActivity.EXTRA_REPLY_DISABLED_FLAG,
+ true);
+ }
+ return intent;
+ }
+
+ private boolean supportsReply(String deviceAddress) {
+ return mReplyFeatureMap.containsKey(deviceAddress)
+ && mReplyFeatureMap.get(deviceAddress);
+ }
+
+ private Notification.Action[] getActionsFor(
+ SenderKey senderKey,
NotificationInfo notificationInfo) {
// Icon doesn't appear to be used; using fixed icon for all actions.
final Icon icon = Icon.createWithResource(mContext, android.R.drawable.ic_media_play);
- // We can have upto 3 actions.
- List<Notification.Action.Builder> builders = new ArrayList<>(3);
-
- // Add play/mute.
- String playMuteAction;
- int playMuteResId;
- Intent intent = new Intent();
- if (mTTSHelper.isSpeaking()) {
- intent.setAction(MessengerService.ACTION_PLAY_MESSAGES_STARTED);
- playMuteAction = MessengerService.ACTION_STOP_PLAYOUT;
- playMuteResId = R.string.action_stop;
- } else {
- intent.setAction(MessengerService.ACTION_PLAY_MESSAGES_STOPPED);
- playMuteAction = MessengerService.ACTION_PLAY_MESSAGES;
- playMuteResId = R.string.action_play;
- }
- mContext.sendBroadcast(intent);
- PendingIntent playMuteIntent = buildIntentFor(playMuteAction,
- senderKey, notificationInfo);
- builders.add(new Notification.Action.Builder(icon,
- mContext.getString(playMuteResId), playMuteIntent));
-
- // Add auto-reply
- if (mReplyFeatureMap.containsKey(senderKey.mDeviceAddress)
- && mReplyFeatureMap.get(senderKey.mDeviceAddress)) {
- PendingIntent autoReplyIntent = buildIntentFor(MessengerService.ACTION_AUTO_REPLY,
- senderKey, notificationInfo);
+ List<Notification.Action.Builder> builders = new ArrayList<>(ACTION_COUNT);
+
+ // show auto reply options of device supports it
+ if (supportsReply(senderKey.mDeviceAddress)) {
+ Intent replyIntent = getPlayMessageIntent(senderKey, notificationInfo);
+ replyIntent.putExtra(PlayMessageActivity.EXTRA_SHOW_REPLY_LIST_FLAG, true);
+ PendingIntent autoReplyIntent = PendingIntent.getActivity(
+ mContext, REQUEST_CODE_AUTO_REPLY, replyIntent, 0);
builders.add(new Notification.Action.Builder(icon,
- mContext.getString(R.string.action_auto_reply), autoReplyIntent));
+ mContext.getString(R.string.action_reply), autoReplyIntent));
}
- // Optionally add mute.
- if (!notificationInfo.muted) {
+ // add mute/unmute.
+ if (notificationInfo.muted) {
+ PendingIntent muteIntent = buildIntentFor(MessengerService.ACTION_UNMUTE_CONVERSATION,
+ senderKey, notificationInfo);
+ builders.add(new Notification.Action.Builder(icon,
+ mContext.getString(R.string.action_unmute), muteIntent));
+ } else {
PendingIntent muteIntent = buildIntentFor(MessengerService.ACTION_MUTE_CONVERSATION,
senderKey, notificationInfo);
builders.add(new Notification.Action.Builder(icon,
mContext.getString(R.string.action_mute), muteIntent));
}
-
Notification.Action actions[] = new Notification.Action[builders.size()];
for (int i = 0; i < builders.size(); i++) {
actions[i] = builders.get(i).build();
@@ -325,48 +338,60 @@ class MapMessageMonitor {
Log.e(TAG, "Unknown senderKey! " + senderKey);
return;
}
- List<CharSequence> ttsMessages =
+ List<CharSequence> ttsMessages = new ArrayList<>();
+ // TODO: play unread messages instead of the last.
+ String ttsMessage =
notificationInfo.mMessageKeys.stream().map((key) -> mMessages.get(key).getText())
- .collect(Collectors.toCollection(LinkedList::new));
+ .collect(Collectors.toCollection(LinkedList::new)).getLast();
// Insert something like "foo says" before their message content.
- ttsMessages.add(0,
- mContext.getString(R.string.tts_sender_says, notificationInfo.mSenderName));
- mTTSHelper.requestPlay(ttsMessages,
- new TTSHelper.Listener() {
- @Override
- public void onTTSStarted() {
- Intent intent = new Intent(ACTION_MESSAGE_PLAY_START);
- mContext.sendBroadcast(intent);
- updateNotificationFor(senderKey, notificationInfo);
- }
+ 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);
+ }
- @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();
+ @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();
+ }
}
- updateNotificationFor(senderKey, notificationInfo);
- }
- });
+ });
+ } else {
+ Log.w(TAG, "failed to require audio focus.");
+ }
}
void stopPlayout() {
mTTSHelper.requestStop();
}
- void muteConversation(SenderKey senderKey) {
+ void toggleMuteConversation(SenderKey senderKey, boolean mute) {
NotificationInfo notificationInfo = mNotificationInfos.get(senderKey);
if (notificationInfo == null) {
Log.e(TAG, "Unknown senderKey! " + senderKey);
return;
}
- notificationInfo.muted = true;
+ notificationInfo.muted = mute;
updateNotificationFor(senderKey, notificationInfo);
}
- boolean sendAutoReply(SenderKey senderKey, BluetoothMapClient mapClient) {
+ boolean sendAutoReply(SenderKey senderKey, BluetoothMapClient mapClient, String message) {
if (DBG) {
Log.d(TAG, "Sending auto-reply to: " + senderKey);
}
@@ -388,7 +413,6 @@ class MapMessageMonitor {
PendingIntent.getBroadcast(mContext, requestCode, new Intent(
BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY),
PendingIntent.FLAG_ONE_SHOT);
- String message = mContext.getString(R.string.auto_reply_message);
return mapClient.sendMessage(device, recipientUris, message, sentIntent, null);
}
@@ -444,8 +468,14 @@ class MapMessageMonitor {
if (DBG) {
Log.d(TAG, "get SDP record: " + intent.getExtras());
}
- SdpMasRecord masRecord =
- intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
+ Parcelable parcelable = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
+ if (!(parcelable instanceof SdpMasRecord)) {
+ if (DBG) {
+ Log.d(TAG, "not SdpMasRecord: " + parcelable);
+ }
+ return;
+ }
+ SdpMasRecord masRecord = (SdpMasRecord) parcelable;
int features = masRecord.getSupportedFeatures();
int version = masRecord.getProfileVersion();
boolean supportsReply = false;
diff --git a/src/com/android/car/messenger/MessengerService.java b/src/com/android/car/messenger/MessengerService.java
index 01a2069..01fc954 100644
--- a/src/com/android/car/messenger/MessengerService.java
+++ b/src/com/android/car/messenger/MessengerService.java
@@ -42,7 +42,6 @@ import android.widget.Toast;
public class MessengerService extends Service {
static final String TAG = "MessengerService";
static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
- static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
// Used to start this service at boot-complete. Takes no arguments.
static final String ACTION_START = "com.android.car.messenger.ACTION_START";
@@ -53,6 +52,9 @@ public class MessengerService extends Service {
// Used to stop further audio notifications from the conversation.
static final String ACTION_MUTE_CONVERSATION =
"com.android.car.messenger.ACTION_MUTE_CONVERSATION";
+ // Used to resume further audio notifications from the conversation.
+ static final String ACTION_UNMUTE_CONVERSATION =
+ "com.android.car.messenger.ACTION_UNMUTE_CONVERSATION";
// Used to clear notification state when user dismisses notification.
static final String ACTION_CLEAR_NOTIFICATION_STATE =
"com.android.car.messenger.ACTION_CLEAR_NOTIFICATION_STATE";
@@ -62,6 +64,8 @@ public class MessengerService extends Service {
// Common extra for ACTION_AUTO_REPLY and ACTION_PLAY_MESSAGES.
static final String EXTRA_SENDER_KEY = "com.android.car.messenger.EXTRA_SENDER_KEY";
+ static final String EXTRA_REPLY_MESSAGE = "com.android.car.messenger.EXTRA_REPLY_MESSAGE";
+
// Used to notify that this service started to play out the messages.
static final String ACTION_PLAY_MESSAGES_STARTED =
"com.android.car.messenger.ACTION_PLAY_MESSAGES_STARTED";
@@ -133,7 +137,9 @@ public class MessengerService extends Service {
boolean success;
if (mMapClient != null) {
success = mMessageMonitor.sendAutoReply(
- intent.getParcelableExtra(EXTRA_SENDER_KEY), mMapClient);
+ intent.getParcelableExtra(EXTRA_SENDER_KEY),
+ mMapClient,
+ intent.getStringExtra(EXTRA_REPLY_MESSAGE));
} else {
Log.e(TAG, "Unable to send reply; MAP profile disconnected!");
success = false;
@@ -147,7 +153,12 @@ public class MessengerService extends Service {
mMessageMonitor.playMessages(intent.getParcelableExtra(EXTRA_SENDER_KEY));
break;
case ACTION_MUTE_CONVERSATION:
- mMessageMonitor.muteConversation(intent.getParcelableExtra(EXTRA_SENDER_KEY));
+ mMessageMonitor.toggleMuteConversation(
+ intent.getParcelableExtra(EXTRA_SENDER_KEY), true);
+ break;
+ case ACTION_UNMUTE_CONVERSATION:
+ mMessageMonitor.toggleMuteConversation(
+ intent.getParcelableExtra(EXTRA_SENDER_KEY), false);
break;
case ACTION_STOP_PLAYOUT:
mMessageMonitor.stopPlayout();
diff --git a/src/com/android/car/messenger/PlayMessageActivity.java b/src/com/android/car/messenger/PlayMessageActivity.java
index 4d7e56b..0381c15 100644
--- a/src/com/android/car/messenger/PlayMessageActivity.java
+++ b/src/com/android/car/messenger/PlayMessageActivity.java
@@ -16,6 +16,8 @@
package com.android.car.messenger;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.BroadcastReceiver;
@@ -26,59 +28,260 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.TextView;
+import com.android.car.messenger.tts.TTSHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Controls the TTS of the message received.
*/
public class PlayMessageActivity extends Activity {
- public static final String MESSAGE_KEY = "car.messenger.MESSAGE_KEY";
- private TextView mPlayPauseBtn;
+ private static final String TAG = "PlayMessageActivity";
+
+ public static final String EXTRA_MESSAGE_KEY = "car.messenger.EXTRA_MESSAGE_KEY";
+ public static final String EXTRA_SENDER_NAME = "car.messenger.EXTRA_SENDER_NAME";
+ public static final String EXTRA_SHOW_REPLY_LIST_FLAG =
+ "car.messenger.EXTRA_SHOW_REPLY_LIST_FLAG";
+ public static final String EXTRA_REPLY_DISABLED_FLAG =
+ "car.messenger.EXTRA_REPLY_DISABLED_FLAG";
+ private View mContainer;
+ private View mMessageContainer;
+ private View mVoicePlate;
+ private TextView mReplyNotice;
+ private TextView mLeftButton;
+ private TextView mRightButton;
+ private ImageView mVoiceIcon;
private MessengerService mMessengerService;
private MessengerServiceBroadcastReceiver mMessengerServiceBroadcastReceiver =
new MessengerServiceBroadcastReceiver();
+ private MapMessageMonitor.SenderKey mSenderKey;
+ private TTSHelper mTTSHelper;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.play_message_layout);
- mPlayPauseBtn = (TextView) findViewById(R.id.play_pause_btn);
- TextView exitBtn = (TextView) findViewById(R.id.exit_btn);
- exitBtn.setOnClickListener(v -> finish());
- mPlayPauseBtn.setText(getString(R.string.action_play));
- mPlayPauseBtn.setOnClickListener(v -> playMessage());
+ mContainer = findViewById(R.id.container);
+ mMessageContainer = findViewById(R.id.message_container);
+ mReplyNotice = (TextView) findViewById(R.id.reply_notice);
+ mVoicePlate = findViewById(R.id.voice_plate);
+ mLeftButton = (TextView) findViewById(R.id.left_btn);
+ mRightButton = (TextView) findViewById(R.id.right_btn);
+ mVoiceIcon = (ImageView) findViewById(R.id.voice_icon);
+
+ mTTSHelper = new TTSHelper(this);
+ setupEmojis();
+ hideAutoReply();
+ setupAutoReply();
+ updateViewForMessagePlaying();
+
+ AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this,
+ R.anim.trans_bottom_in);
+ set.setTarget(mContainer);
+ set.start();
+ }
+
+ private void setupEmojis() {
+ TextView emoji1 = (TextView) findViewById(R.id.emoji1);
+ emoji1.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_ok_hand_sign)));
+ TextView emoji2 = (TextView) findViewById(R.id.emoji2);
+ emoji2.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_thumb_up)));
+ 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)));
+ }
+
+ private String getEmojiByUnicode(int unicode){
+ return new String(Character.toChars(unicode));
+ }
+
+ private void setupAutoReply() {
+ TextView cannedMessage = (TextView) findViewById(R.id.canned_message);
+ cannedMessage.setText(getString(R.string.reply_message_display_template,
+ getString(R.string.caned_message_driving_right_now)));
+ cannedMessage.setOnClickListener(
+ v -> sendReply(getString(R.string.caned_message_driving_right_now)));
+ 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);
+ }
+
+ /**
+ * View needs to be TextView. Leave it as View, so can take advantage of lambda syntax
+ */
+ private void sendReply(View view) {
+ sendReply(((TextView) view).getText());
+ }
+
+ private void sendReply(CharSequence message) {
+ // send auto reply
+ Intent intent = new Intent(getBaseContext(), MessengerService.class)
+ .setAction(MessengerService.ACTION_AUTO_REPLY)
+ .putExtra(MessengerService.EXTRA_SENDER_KEY, mSenderKey)
+ .putExtra(
+ MessengerService.EXTRA_REPLY_MESSAGE,
+ message);
+ startService(intent);
+
+ String messageSent = getString(
+ R.string.message_sent_notice,
+ getIntent().getStringExtra(EXTRA_SENDER_NAME));
+ // hide all view and show reply sent notice text
+ mContainer.invalidate();
+ mMessageContainer.setVisibility(View.GONE);
+ mVoicePlate.setVisibility(View.GONE);
+ mReplyNotice.setText(messageSent);
+ mReplyNotice.setVisibility(View.VISIBLE);
+ ViewGroup.LayoutParams layoutParams = mContainer.getLayoutParams();
+ layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mContainer.requestLayout();
+
+ // read out the reply sent notice. Finish activity after TTS is done.
+ List<CharSequence> ttsMessages = new ArrayList<>();
+ ttsMessages.add(messageSent);
+ mTTSHelper.requestPlay(ttsMessages,
+ new TTSHelper.Listener() {
+ @Override
+ public void onTTSStarted() {
+ }
+
+ @Override
+ public void onTTSStopped(boolean error) {
+ if (error) {
+ Log.w(TAG, "TTS error.");
+ }
+ finish();
+ }
+ });
+ }
+
+ private void showAutoReply() {
+ mContainer.invalidate();
+ mMessageContainer.setVisibility(View.VISIBLE);
+ mLeftButton.setText(getString(R.string.action_close_messages));
+ mLeftButton.setOnClickListener(v -> finish());
+ ViewGroup.LayoutParams layoutParams = mContainer.getLayoutParams();
+ layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ mContainer.requestLayout();
+ }
+
+ private void hideAutoReply() {
+ mContainer.invalidate();
+ mMessageContainer.setVisibility(View.GONE);
+ mLeftButton.setText(getString(R.string.action_reply));
+ mLeftButton.setOnClickListener(v -> showAutoReply());
+ ViewGroup.LayoutParams layoutParams = mContainer.getLayoutParams();
+ layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mContainer.requestLayout();
+ }
+
+ /**
+ * If there's a touch outside the voice plate, exit the activity.
+ */
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ if (event.getX() < mContainer.getX()
+ || event.getX() > mContainer.getX() + mContainer.getWidth()
+ || event.getY() < mContainer.getY()
+ || event.getY() > mContainer.getY() + mContainer.getHeight()) {
+ finish();
+
+ }
+ }
+ return super.onTouchEvent(event);
}
@Override
protected void onStart() {
super.onStart();
+
// Bind to LocalService
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
mMessengerServiceBroadcastReceiver.start();
+ processIntent();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ processIntent();
+ }
+
+ private void processIntent() {
+ mSenderKey = getIntent().getParcelableExtra(EXTRA_MESSAGE_KEY);
playMessage();
+ if (getIntent().getBooleanExtra(EXTRA_SHOW_REPLY_LIST_FLAG, false)) {
+ showAutoReply();
+ }
+ if (getIntent().getBooleanExtra(EXTRA_REPLY_DISABLED_FLAG, false)) {
+ mLeftButton.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this,
+ R.anim.trans_bottom_out);
+ set.setTarget(mContainer);
+ set.start();
+ super.onDestroy();
}
@Override
protected void onStop() {
super.onStop();
+ mTTSHelper.cleanup();
mMessengerServiceBroadcastReceiver.cleanup();
+ unbindService(mConnection);
}
private void playMessage() {
- MapMessageMonitor.SenderKey senderKey = getIntent().getParcelableExtra(MESSAGE_KEY);
Intent intent = new Intent(getBaseContext(), MessengerService.class)
.setAction(MessengerService.ACTION_PLAY_MESSAGES)
- .putExtra(MessengerService.EXTRA_SENDER_KEY, senderKey);
+ .putExtra(MessengerService.EXTRA_SENDER_KEY, mSenderKey);
+ startService(intent);
+ }
+
+ private void stopMessage() {
+ Intent intent = new Intent(getBaseContext(), MessengerService.class)
+ .setAction(MessengerService.ACTION_STOP_PLAYOUT)
+ .putExtra(MessengerService.EXTRA_SENDER_KEY, mSenderKey);
startService(intent);
}
+ private void updateViewForMessagePlaying() {
+ mRightButton.setText(getString(R.string.action_stop));
+ mRightButton.setOnClickListener(v -> stopMessage());
+ mVoiceIcon.setVisibility(View.VISIBLE);
+ }
+
+ private void updateViewFoeMessageStopped() {
+ mRightButton.setText(getString(R.string.action_repeat));
+ mRightButton.setOnClickListener(v -> playMessage());
+ mVoiceIcon.setVisibility(View.INVISIBLE);
+ }
+
private class MessengerServiceBroadcastReceiver extends BroadcastReceiver {
private final IntentFilter mIntentFilter;
MessengerServiceBroadcastReceiver() {
mIntentFilter = new IntentFilter();
- mIntentFilter.addAction(MessengerService.ACTION_PLAY_MESSAGES_STARTED);
- mIntentFilter.addAction(MessengerService.ACTION_PLAY_MESSAGES_STOPPED);
+ mIntentFilter.addAction(MapMessageMonitor.ACTION_MESSAGE_PLAY_START);
+ mIntentFilter.addAction(MapMessageMonitor.ACTION_MESSAGE_PLAY_STOP);
}
void start() {
@@ -92,11 +295,11 @@ public class PlayMessageActivity extends Activity {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
- case MessengerService.ACTION_PLAY_MESSAGES_STARTED:
- mPlayPauseBtn.setText(getString(R.string.action_stop));
+ case MapMessageMonitor.ACTION_MESSAGE_PLAY_START:
+ updateViewForMessagePlaying();
break;
- case MessengerService.ACTION_PLAY_MESSAGES_STOPPED:
- mPlayPauseBtn.setText(getString(R.string.action_play));
+ case MapMessageMonitor.ACTION_MESSAGE_PLAY_STOP:
+ updateViewFoeMessageStopped();
break;
default:
break;
@@ -110,9 +313,9 @@ public class PlayMessageActivity extends Activity {
MessengerService.LocalBinder binder = (MessengerService.LocalBinder) service;
mMessengerService = binder.getService();
if (mMessengerService.isPlaying()) {
- mPlayPauseBtn.setText(getString(R.string.action_stop));
+ updateViewForMessagePlaying();
} else {
- mPlayPauseBtn.setText(getString(R.string.action_play));
+ updateViewFoeMessageStopped();
}
}