diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-05 07:35:11 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-05 07:35:11 +0000 |
commit | d5ddc64decfdd8757e43a90982faa9899a6d8eb3 (patch) | |
tree | 2a47c343cd33e8b2a16dea348f518e38b4c021f2 | |
parent | 3936859235d5d5b4dce09eb842043352bc887284 (diff) | |
parent | 917af90df473a739aca62bc0404fa2f25977307d (diff) | |
download | Messenger-oreo-dr1-release.tar.gz |
release-request-a2143a0f-bf92-4fa8-ad68-7346e7505126-for-git_oc-dr1-release-4067638 snap-temp-L84900000070511178android-8.0.0_r34android-8.0.0_r33android-8.0.0_r27android-8.0.0_r26android-8.0.0_r25android-8.0.0_r24android-8.0.0_r23android-8.0.0_r22android-8.0.0_r21oreo-dr3-releaseoreo-dr2-releaseoreo-dr1-release
Change-Id: Iec06c49bb4126a776864ba2303d6a382a59bd4b9
-rw-r--r-- | Android.mk | 43 | ||||
-rw-r--r-- | AndroidManifest.xml | 8 | ||||
-rw-r--r-- | res/layout/play_message_layout.xml | 41 | ||||
-rw-r--r-- | res/values/dimens.xml | 19 | ||||
-rw-r--r-- | src/com/android/car/messenger/MapMessageMonitor.java | 258 | ||||
-rw-r--r-- | src/com/android/car/messenger/MessengerService.java | 25 | ||||
-rw-r--r-- | src/com/android/car/messenger/PlayMessageActivity.java | 124 |
7 files changed, 470 insertions, 48 deletions
@@ -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; + } + }; +} |