summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2017-06-05 07:35:11 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2017-06-05 07:35:11 +0000
commitd5ddc64decfdd8757e43a90982faa9899a6d8eb3 (patch)
tree2a47c343cd33e8b2a16dea348f518e38b4c021f2
parent3936859235d5d5b4dce09eb842043352bc887284 (diff)
parent917af90df473a739aca62bc0404fa2f25977307d (diff)
downloadMessenger-oreo-dr1-release.tar.gz
Change-Id: Iec06c49bb4126a776864ba2303d6a382a59bd4b9
-rw-r--r--Android.mk43
-rw-r--r--AndroidManifest.xml8
-rw-r--r--res/layout/play_message_layout.xml41
-rw-r--r--res/values/dimens.xml19
-rw-r--r--src/com/android/car/messenger/MapMessageMonitor.java258
-rw-r--r--src/com/android/car/messenger/MessengerService.java25
-rw-r--r--src/com/android/car/messenger/PlayMessageActivity.java124
7 files changed, 470 insertions, 48 deletions
diff --git a/Android.mk b/Android.mk
index a539aee..bd4ed6e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,14 +14,15 @@
# limitations under the License.
#
-
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := optional
-
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_MODULE_TAGS := optional
+
LOCAL_PACKAGE_NAME := CarMessengerApp
LOCAL_OVERRIDES_PACKAGES := messaging
@@ -33,11 +34,47 @@ LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PRIVILEGED_MODULE := true
LOCAL_STATIC_JAVA_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_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)
+
+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_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+
+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_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+
+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_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_PREBUILT)
+
# Use the following include to make our test apk.
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 574c5c1..096e699 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,6 +20,8 @@
<uses-sdk android:minSdkVersion="25" android:targetSdkVersion="25"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
@@ -40,5 +42,11 @@
<category android:name="android.intent.category.APP_MESSAGING"/>
</intent-filter>
</activity>
+ <activity android:name=".PlayMessageActivity" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.APP_MESSAGING"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/res/layout/play_message_layout.xml b/res/layout/play_message_layout.xml
new file mode 100644
index 0000000..b6bc788
--- /dev/null
+++ b/res/layout/play_message_layout.xml
@@ -0,0 +1,41 @@
+<?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
+ -->
+
+<!-- Eng mock, waiting for UX spec -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ 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>
+
+ <TextView
+ android:id="@+id/exit_btn"
+ 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">
+ </TextView>
+</RelativeLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
new file mode 100644
index 0000000..7308708
--- /dev/null
+++ b/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?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>
+ <dimen name="notification_contact_photo_size">300dp</dimen>
+</resources>
diff --git a/src/com/android/car/messenger/MapMessageMonitor.java b/src/com/android/car/messenger/MapMessageMonitor.java
index a896f70..1d12ee9 100644
--- a/src/com/android/car/messenger/MapMessageMonitor.java
+++ b/src/com/android/car/messenger/MapMessageMonitor.java
@@ -23,22 +23,37 @@ import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
+import android.bluetooth.BluetoothUuid;
+import android.bluetooth.SdpMasRecord;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+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.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.provider.ContactsContract;
import android.support.annotation.Nullable;
+import android.telecom.PhoneAccount;
import android.util.Log;
import android.widget.Toast;
+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;
+import com.bumptech.glide.request.transition.Transition;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -58,20 +73,29 @@ import java.util.stream.Collectors;
* {@link MessengerService}.
*/
class MapMessageMonitor {
+ public static final String ACTION_MESSAGE_PLAY_START =
+ "car.messenger.action_message_play_start";
+ public static final String ACTION_MESSAGE_PLAY_STOP = "car.messenger.action_message_play_stop";
+ // reply or "upload" feature is indicated by the 3rd bit
+ private static final int REPLY_FEATURE_POS = 3;
+
private static final String TAG = "Messenger.MsgMonitor";
private static final boolean DBG = MessengerService.DBG;
private final Context mContext;
private final BluetoothMapReceiver mBluetoothMapReceiver;
+ private final BluetoothSdpReceiver mBluetoothSdpReceiver;
private final NotificationManager mNotificationManager;
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<>();
MapMessageMonitor(Context context) {
mContext = context;
mBluetoothMapReceiver = new BluetoothMapReceiver();
+ mBluetoothSdpReceiver = new BluetoothSdpReceiver();
mNotificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mTTSHelper = new TTSHelper(mContext);
@@ -81,6 +105,10 @@ class MapMessageMonitor {
mNotificationTone = RingtoneManager.getRingtone(mContext, notificationUri);
}
+ public boolean isPlaying() {
+ return mTTSHelper.isSpeaking();
+ }
+
private void handleNewMessage(Intent intent) {
if (DBG) {
Log.d(TAG, "Handling new message");
@@ -103,6 +131,10 @@ class MapMessageMonitor {
private void updateNotificationInfo(MapMessage message, MessageKey messageKey) {
SenderKey senderKey = new SenderKey(message);
+ // check the version/feature of the
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.getRemoteDevice(senderKey.mDeviceAddress).sdpSearch(BluetoothUuid.MAS);
+
NotificationInfo notificationInfo = mNotificationInfos.get(senderKey);
if (notificationInfo == null) {
notificationInfo =
@@ -117,26 +149,106 @@ class MapMessageMonitor {
updateNotificationFor(senderKey, notificationInfo);
}
+ private static final String[] CONTACT_ID = new String[] {
+ ContactsContract.PhoneLookup._ID
+ };
+
+ private static int getContactIdFromNumber(ContentResolver cr, String number) {
+ if (number == null || number.isEmpty()) {
+ return 0;
+ }
+
+ Uri uri = Uri.withAppendedPath(
+ ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(number));
+ Cursor cursor = cr.query(uri, CONTACT_ID, null, null, null);
+
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
+ return id;
+ }
+ }
+ finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return 0;
+ }
+
private void updateNotificationFor(SenderKey senderKey, NotificationInfo notificationInfo) {
+ if (DBG) {
+ Log.d(TAG, "updateNotificationFor" + notificationInfo);
+ }
String contentText = mContext.getResources().getQuantityString(
R.plurals.notification_new_message, notificationInfo.mMessageKeys.size(),
notificationInfo.mMessageKeys.size());
long lastReceivedTimeMs =
mMessages.get(notificationInfo.mMessageKeys.getLast()).getReceivedTimeMs();
- // TODO(sriniv): Use right icon when switching to correct layout. b/33280056.
- Notification.Builder builder =
- new Notification.Builder(mContext, NotificationChannel.DEFAULT_CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_message)
- .setContentTitle(notificationInfo.mSenderName)
- .setContentText(contentText)
- .setWhen(lastReceivedTimeMs)
- .setShowWhen(true)
- .setActions(getActionsFor(senderKey, notificationInfo))
- .setDeleteIntent(
- buildIntentFor(
- MessengerService.ACTION_CLEAR_NOTIFICATION_STATE,
- senderKey, notificationInfo));
- mNotificationManager.notify(notificationInfo.mNotificationId, builder.build());
+
+ String phoneNumber = notificationInfo.mSenderContactUri.substring(
+ (PhoneAccount.SCHEME_TEL + ":").length());
+ Uri photoUri = ContentUris.withAppendedId(
+ ContactsContract.Contacts.CONTENT_URI, getContactIdFromNumber(
+ mContext.getContentResolver(), phoneNumber));
+ if (DBG) {
+ Log.d(TAG, "start Glide loading... " + photoUri);
+ }
+ Glide.with(mContext)
+ .asBitmap()
+ .load(photoUri)
+ .apply(RequestOptions.circleCropTransform())
+ .into(new SimpleTarget<Bitmap>() {
+ @Override
+ public void onResourceReady(Bitmap bitmap,
+ Transition<? super Bitmap> transition) {
+ sendNotification(bitmap);
+ }
+
+ @Override
+ public void onLoadFailed(@Nullable Drawable fallback) {
+ sendNotification(null);
+ }
+
+ private void sendNotification(Bitmap bitmap) {
+ if (DBG) {
+ Log.d(TAG, "Glide loaded. " + bitmap);
+ }
+ if (bitmap == null) {
+ LetterTileDrawable letterTileDrawable =
+ new LetterTileDrawable(mContext.getResources());
+ letterTileDrawable.setContactDetails(
+ notificationInfo.mSenderName, phoneNumber);
+ 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)
+ .setLargeIcon(bitmap)
+ .setSmallIcon(R.drawable.ic_message)
+ .setContentTitle(notificationInfo.mSenderName)
+ .setContentText(contentText)
+ .setWhen(lastReceivedTimeMs)
+ .setShowWhen(true)
+ .setActions(getActionsFor(senderKey, notificationInfo))
+ .setDeleteIntent(buildIntentFor(
+ MessengerService.ACTION_CLEAR_NOTIFICATION_STATE,
+ senderKey, notificationInfo));
+ mNotificationManager.notify(
+ notificationInfo.mNotificationId, builder.build());
+ }
+ });
}
private Notification.Action[] getActionsFor(SenderKey senderKey,
@@ -150,23 +262,30 @@ class MapMessageMonitor {
// 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.
- PendingIntent autoReplyIntent = buildIntentFor(MessengerService.ACTION_AUTO_REPLY,
- senderKey, notificationInfo);
- builders.add(new Notification.Action.Builder(icon,
- mContext.getString(R.string.action_auto_reply), autoReplyIntent));
+ // Add auto-reply
+ if (mReplyFeatureMap.containsKey(senderKey.mDeviceAddress)
+ && mReplyFeatureMap.get(senderKey.mDeviceAddress)) {
+ PendingIntent autoReplyIntent = buildIntentFor(MessengerService.ACTION_AUTO_REPLY,
+ senderKey, notificationInfo);
+ builders.add(new Notification.Action.Builder(icon,
+ mContext.getString(R.string.action_auto_reply), autoReplyIntent));
+ }
// Optionally add mute.
if (!notificationInfo.muted) {
@@ -214,19 +333,23 @@ class MapMessageMonitor {
mContext.getString(R.string.tts_sender_says, notificationInfo.mSenderName));
mTTSHelper.requestPlay(ttsMessages,
new TTSHelper.Listener() {
- @Override
- public void onTTSStarted() {
- updateNotificationFor(senderKey, notificationInfo);
- }
-
- @Override
- public void onTTSStopped(boolean error) {
- if (error) {
- Toast.makeText(mContext, R.string.tts_failed_toast, Toast.LENGTH_SHORT).show();
- }
- updateNotificationFor(senderKey, notificationInfo);
- }
- });
+ @Override
+ public void onTTSStarted() {
+ Intent intent = new Intent(ACTION_MESSAGE_PLAY_START);
+ mContext.sendBroadcast(intent);
+ updateNotificationFor(senderKey, notificationInfo);
+ }
+
+ @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();
+ }
+ updateNotificationFor(senderKey, notificationInfo);
+ }
+ });
}
void stopPlayout() {
@@ -263,7 +386,7 @@ class MapMessageMonitor {
final int requestCode = senderKey.hashCode();
PendingIntent sentIntent =
PendingIntent.getBroadcast(mContext, requestCode, new Intent(
- BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY),
+ 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);
@@ -297,14 +420,58 @@ class MapMessageMonitor {
void cleanup() {
mBluetoothMapReceiver.cleanup();
+ mBluetoothSdpReceiver.cleanup();
mTTSHelper.cleanup();
}
+ private class BluetoothSdpReceiver extends BroadcastReceiver {
+ BluetoothSdpReceiver() {
+ if (DBG) {
+ Log.d(TAG, "Registering receiver for sdp");
+ }
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(BluetoothDevice.ACTION_SDP_RECORD);
+ mContext.registerReceiver(this, intentFilter);
+ }
+
+ void cleanup() {
+ mContext.unregisterReceiver(this);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (BluetoothDevice.ACTION_SDP_RECORD.equals(intent.getAction())) {
+ if (DBG) {
+ Log.d(TAG, "get SDP record: " + intent.getExtras());
+ }
+ SdpMasRecord masRecord =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
+ int features = masRecord.getSupportedFeatures();
+ int version = masRecord.getProfileVersion();
+ boolean supportsReply = false;
+ // we only consider the device supports reply feature of the version
+ // is higher than 1.02 and the feature flag is turned on.
+ if (version >= 0x102 && isOn(features, REPLY_FEATURE_POS)) {
+ supportsReply = true;
+ }
+ BluetoothDevice bluetoothDevice =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ mReplyFeatureMap.put(bluetoothDevice.getAddress(), supportsReply);
+ } else {
+ Log.w(TAG, "Ignoring unknown broadcast " + intent.getAction());
+ }
+ }
+
+ private boolean isOn(int input, int postion) {
+ return ((input >> postion) & 1) == 1;
+ }
+ }
+
// Used to monitor for new incoming messages and sent-message broadcast.
private class BluetoothMapReceiver extends BroadcastReceiver {
BluetoothMapReceiver() {
if (DBG) {
- Log.d(TAG, "Registering receiver for new messages");
+ Log.d(TAG, "Registering receiver for bluetooth MAP");
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
@@ -323,6 +490,9 @@ class MapMessageMonitor {
Log.d(TAG, "SMS was sent successfully!");
}
} else if (BluetoothMapClient.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
+ if (DBG) {
+ Log.d(TAG, "SMS message received");
+ }
handleNewMessage(intent);
} else {
Log.w(TAG, "Ignoring unknown broadcast " + intent.getAction());
@@ -413,16 +583,16 @@ class MapMessageMonitor {
public static final Parcelable.Creator<SenderKey> CREATOR =
new Parcelable.Creator<SenderKey>() {
- @Override
- public SenderKey createFromParcel(Parcel source) {
- return new SenderKey(source.readString(), source.readString());
- }
-
- @Override
- public SenderKey[] newArray(int size) {
- return new SenderKey[size];
- }
- };
+ @Override
+ public SenderKey createFromParcel(Parcel source) {
+ return new SenderKey(source.readString(), source.readString());
+ }
+
+ @Override
+ public SenderKey[] newArray(int size) {
+ return new SenderKey[size];
+ }
+ };
}
/**
diff --git a/src/com/android/car/messenger/MessengerService.java b/src/com/android/car/messenger/MessengerService.java
index c1a6bd3..01a2069 100644
--- a/src/com/android/car/messenger/MessengerService.java
+++ b/src/com/android/car/messenger/MessengerService.java
@@ -25,6 +25,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
@@ -61,9 +62,24 @@ 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";
+ // 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";
+
+ // Used to notify that this service finished playing out the messages.
+ static final String ACTION_PLAY_MESSAGES_STOPPED =
+ "com.android.car.messenger.ACTION_PLAY_MESSAGES_STOPPED";
+
private MapMessageMonitor mMessageMonitor;
private MapDeviceMonitor mDeviceMonitor;
private BluetoothMapClient mMapClient;
+ private final IBinder mBinder = new LocalBinder();
+
+ public class LocalBinder extends Binder {
+ MessengerService getService() {
+ return MessengerService.this;
+ }
+ }
@Override
public void onCreate() {
@@ -145,6 +161,13 @@ public class MessengerService extends Service {
return result;
}
+ /**
+ * @return {code true} if the service is playing the TTS of the message.
+ */
+ public boolean isPlaying() {
+ return mMessageMonitor.isPlaying();
+ }
+
private boolean hasRequiredArgs(Intent intent) {
switch (intent.getAction()) {
case ACTION_AUTO_REPLY:
@@ -179,7 +202,7 @@ public class MessengerService extends Service {
@Override
public IBinder onBind(Intent intent) {
- return null;
+ return mBinder;
}
// NOTE: These callbacks are invoked on the main thread.
diff --git a/src/com/android/car/messenger/PlayMessageActivity.java b/src/com/android/car/messenger/PlayMessageActivity.java
new file mode 100644
index 0000000..4d7e56b
--- /dev/null
+++ b/src/com/android/car/messenger/PlayMessageActivity.java
@@ -0,0 +1,124 @@
+/*
+ * 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
+ */
+
+package com.android.car.messenger;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.widget.TextView;
+
+/**
+ * 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 MessengerService mMessengerService;
+ private MessengerServiceBroadcastReceiver mMessengerServiceBroadcastReceiver =
+ new MessengerServiceBroadcastReceiver();
+
+ @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());
+ }
+
+ @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();
+ playMessage();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mMessengerServiceBroadcastReceiver.cleanup();
+ }
+
+ 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);
+ startService(intent);
+ }
+
+ 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);
+ }
+
+ void start() {
+ registerReceiver(this, mIntentFilter);
+ }
+
+ void cleanup() {
+ unregisterReceiver(this);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case MessengerService.ACTION_PLAY_MESSAGES_STARTED:
+ mPlayPauseBtn.setText(getString(R.string.action_stop));
+ break;
+ case MessengerService.ACTION_PLAY_MESSAGES_STOPPED:
+ mPlayPauseBtn.setText(getString(R.string.action_play));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ MessengerService.LocalBinder binder = (MessengerService.LocalBinder) service;
+ mMessengerService = binder.getService();
+ if (mMessengerService.isPlaying()) {
+ mPlayPauseBtn.setText(getString(R.string.action_stop));
+ } else {
+ mPlayPauseBtn.setText(getString(R.string.action_play));
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0) {
+ mMessengerService = null;
+ }
+ };
+}