• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.car.messenger;
18 
19 import android.animation.AnimatorInflater;
20 import android.animation.AnimatorSet;
21 import android.annotation.Nullable;
22 import android.app.Activity;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.ServiceConnection;
29 import android.os.Bundle;
30 import android.os.IBinder;
31 import android.util.Log;
32 import android.view.MotionEvent;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.widget.ImageView;
36 import android.widget.TextView;
37 
38 import com.android.car.messenger.tts.TTSHelper;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 /**
44  * Controls the TTS of the message received.
45  */
46 public class PlayMessageActivity extends Activity {
47     private static final String TAG = "PlayMessageActivity";
48 
49     public static final String EXTRA_MESSAGE_KEY = "car.messenger.EXTRA_MESSAGE_KEY";
50     public static final String EXTRA_SENDER_NAME = "car.messenger.EXTRA_SENDER_NAME";
51     public static final String EXTRA_SHOW_REPLY_LIST_FLAG =
52             "car.messenger.EXTRA_SHOW_REPLY_LIST_FLAG";
53     public static final String EXTRA_REPLY_DISABLED_FLAG =
54             "car.messenger.EXTRA_REPLY_DISABLED_FLAG";
55     private View mContainer;
56     private View mMessageContainer;
57     private View mVoicePlate;
58     private TextView mReplyNotice;
59     private TextView mLeftButton;
60     private TextView mRightButton;
61     private ImageView mVoiceIcon;
62     private MessengerService mMessengerService;
63     private MessengerServiceBroadcastReceiver mMessengerServiceBroadcastReceiver =
64             new MessengerServiceBroadcastReceiver();
65     private MapMessageMonitor.SenderKey mSenderKey;
66     private TTSHelper mTTSHelper;
67 
68     @Override
onCreate(@ullable Bundle savedInstanceState)69     protected void onCreate(@Nullable Bundle savedInstanceState) {
70         super.onCreate(savedInstanceState);
71         setContentView(R.layout.play_message_layout);
72         mContainer = findViewById(R.id.container);
73         mMessageContainer = findViewById(R.id.message_container);
74         mReplyNotice = (TextView) findViewById(R.id.reply_notice);
75         mVoicePlate = findViewById(R.id.voice_plate);
76         mLeftButton = (TextView) findViewById(R.id.left_btn);
77         mRightButton = (TextView) findViewById(R.id.right_btn);
78         mVoiceIcon = (ImageView) findViewById(R.id.voice_icon);
79 
80         mTTSHelper = new TTSHelper(this);
81         setupEmojis();
82         hideAutoReply();
83         setupAutoReply();
84         updateViewForMessagePlaying();
85 
86         AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this,
87                 R.anim.trans_bottom_in);
88         set.setTarget(mContainer);
89         set.start();
90     }
91 
setupEmojis()92     private void setupEmojis() {
93         TextView emoji1 = (TextView) findViewById(R.id.emoji1);
94         emoji1.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_thumb_up)));
95         TextView emoji2 = (TextView) findViewById(R.id.emoji2);
96         emoji2.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_thumb_down)));
97         TextView emoji3 = (TextView) findViewById(R.id.emoji3);
98         emoji3.setText(getEmojiByUnicode(getResources().getInteger(R.integer.emoji_smiling_face)));
99     }
100 
getEmojiByUnicode(int unicode)101     private String getEmojiByUnicode(int unicode){
102         return new String(Character.toChars(unicode));
103     }
104 
setupAutoReply()105     private void setupAutoReply() {
106         TextView cannedMessage = (TextView) findViewById(R.id.canned_message);
107         cannedMessage.setText(getString(R.string.reply_message_display_template,
108                 getString(R.string.caned_message_driving_right_now)));
109         cannedMessage.setOnClickListener(
110                 v -> sendReply(getString(R.string.caned_message_driving_right_now)));
111         findViewById(R.id.emoji1).setOnClickListener(this::sendReply);
112         findViewById(R.id.emoji2).setOnClickListener(this::sendReply);
113         findViewById(R.id.emoji3).setOnClickListener(this::sendReply);
114     }
115 
116     /**
117      * View needs to be TextView. Leave it as View, so can take advantage of lambda syntax
118      */
sendReply(View view)119     private void sendReply(View view) {
120         sendReply(((TextView) view).getText());
121     }
122 
sendReply(CharSequence message)123     private void sendReply(CharSequence message) {
124         // send auto reply
125         Intent intent = new Intent(getBaseContext(), MessengerService.class)
126                 .setAction(MessengerService.ACTION_AUTO_REPLY)
127                 .putExtra(MessengerService.EXTRA_SENDER_KEY, mSenderKey)
128                 .putExtra(
129                         MessengerService.EXTRA_REPLY_MESSAGE,
130                         message);
131         startService(intent);
132 
133         String messageSent = getString(
134                 R.string.message_sent_notice,
135                 getIntent().getStringExtra(EXTRA_SENDER_NAME));
136         // hide all view and show reply sent notice text
137         mContainer.invalidate();
138         mMessageContainer.setVisibility(View.GONE);
139         mVoicePlate.setVisibility(View.GONE);
140         mReplyNotice.setText(messageSent);
141         mReplyNotice.setVisibility(View.VISIBLE);
142         ViewGroup.LayoutParams layoutParams = mContainer.getLayoutParams();
143         layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
144         mContainer.requestLayout();
145 
146         // read out the reply sent notice. Finish activity after TTS is done.
147         List<CharSequence> ttsMessages = new ArrayList<>();
148         ttsMessages.add(messageSent);
149         mTTSHelper.requestPlay(ttsMessages,
150                 new TTSHelper.Listener() {
151                     @Override
152                     public void onTTSStarted() {
153                     }
154 
155                     @Override
156                     public void onTTSStopped(boolean error) {
157                         if (error) {
158                             Log.w(TAG, "TTS error.");
159                         }
160                         finish();
161                     }
162 
163                     @Override
164                     public void onAudioFocusFailed() {
165                         Log.w(TAG, "failed to require audio focus.");
166                     }
167                 });
168     }
169 
showAutoReply()170     private void showAutoReply() {
171         mContainer.invalidate();
172         mMessageContainer.setVisibility(View.VISIBLE);
173         mLeftButton.setText(getString(R.string.action_close_messages));
174         mLeftButton.setOnClickListener(v -> finish());
175         ViewGroup.LayoutParams layoutParams = mContainer.getLayoutParams();
176         layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
177         mContainer.requestLayout();
178     }
179 
hideAutoReply()180     private void hideAutoReply() {
181         mContainer.invalidate();
182         mMessageContainer.setVisibility(View.GONE);
183         mLeftButton.setText(getString(R.string.action_reply));
184         mLeftButton.setOnClickListener(v -> showAutoReply());
185         ViewGroup.LayoutParams layoutParams = mContainer.getLayoutParams();
186         layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
187         mContainer.requestLayout();
188     }
189 
190     /**
191      * If there's a touch outside the voice plate, exit the activity.
192      */
193     @Override
onTouchEvent(MotionEvent event)194     public boolean onTouchEvent(MotionEvent event) {
195         if (event.getAction() == MotionEvent.ACTION_UP) {
196             if (event.getX() < mContainer.getX()
197                     || event.getX() > mContainer.getX() + mContainer.getWidth()
198                     || event.getY() < mContainer.getY()
199                     || event.getY() > mContainer.getY() + mContainer.getHeight()) {
200                 finish();
201             }
202         }
203         return super.onTouchEvent(event);
204     }
205 
206     @Override
onStart()207     protected void onStart() {
208         super.onStart();
209 
210         // Bind to LocalService
211         Intent intent = new Intent(this, MessengerService.class);
212         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
213         mMessengerServiceBroadcastReceiver.start();
214         processIntent();
215     }
216 
217     @Override
onNewIntent(Intent intent)218     protected void onNewIntent(Intent intent) {
219         super.onNewIntent(intent);
220         processIntent();
221     }
222 
processIntent()223     private void processIntent() {
224         mSenderKey = getIntent().getParcelableExtra(EXTRA_MESSAGE_KEY);
225         playMessage();
226         if (getIntent().getBooleanExtra(EXTRA_SHOW_REPLY_LIST_FLAG, false)) {
227             showAutoReply();
228         }
229         if (getIntent().getBooleanExtra(EXTRA_REPLY_DISABLED_FLAG, false)) {
230             mLeftButton.setVisibility(View.GONE);
231         }
232     }
233 
234     @Override
onDestroy()235     protected void onDestroy() {
236         AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this,
237                 R.anim.trans_bottom_out);
238         set.setTarget(mContainer);
239         set.start();
240         super.onDestroy();
241     }
242 
243     @Override
onStop()244     protected void onStop() {
245         super.onStop();
246         stopMessage();
247         mTTSHelper.cleanup();
248         mMessengerServiceBroadcastReceiver.cleanup();
249         unbindService(mConnection);
250     }
251 
playMessage()252     private void playMessage() {
253         Intent intent = new Intent(getBaseContext(), MessengerService.class)
254                 .setAction(MessengerService.ACTION_PLAY_MESSAGES)
255                 .putExtra(MessengerService.EXTRA_SENDER_KEY, mSenderKey);
256         startService(intent);
257     }
258 
stopMessage()259     private void stopMessage() {
260         Intent intent = new Intent(getBaseContext(), MessengerService.class)
261                 .setAction(MessengerService.ACTION_STOP_PLAYOUT)
262                 .putExtra(MessengerService.EXTRA_SENDER_KEY, mSenderKey);
263         startService(intent);
264     }
265 
updateViewForMessagePlaying()266     private void updateViewForMessagePlaying() {
267         mRightButton.setText(getString(R.string.action_stop));
268         mRightButton.setOnClickListener(v -> stopMessage());
269         mVoiceIcon.setVisibility(View.VISIBLE);
270     }
271 
updateViewForMessageStopped()272     private void updateViewForMessageStopped() {
273         mRightButton.setText(getString(R.string.action_repeat));
274         mRightButton.setOnClickListener(v -> playMessage());
275         mVoiceIcon.setVisibility(View.INVISIBLE);
276     }
277 
278     private class MessengerServiceBroadcastReceiver extends BroadcastReceiver {
279         private final IntentFilter mIntentFilter;
MessengerServiceBroadcastReceiver()280         MessengerServiceBroadcastReceiver() {
281             mIntentFilter = new IntentFilter();
282             mIntentFilter.addAction(MapMessageMonitor.ACTION_MESSAGE_PLAY_START);
283             mIntentFilter.addAction(MapMessageMonitor.ACTION_MESSAGE_PLAY_STOP);
284         }
285 
start()286         void start() {
287             registerReceiver(this, mIntentFilter);
288         }
289 
cleanup()290         void cleanup() {
291             unregisterReceiver(this);
292         }
293 
294         @Override
onReceive(Context context, Intent intent)295         public void onReceive(Context context, Intent intent) {
296             switch (intent.getAction()) {
297                 case MapMessageMonitor.ACTION_MESSAGE_PLAY_START:
298                     updateViewForMessagePlaying();
299                     break;
300                 case MapMessageMonitor.ACTION_MESSAGE_PLAY_STOP:
301                     updateViewForMessageStopped();
302                     break;
303                 default:
304                     break;
305             }
306         }
307     }
308 
309     private final ServiceConnection mConnection = new ServiceConnection() {
310         @Override
311         public void onServiceConnected(ComponentName className, IBinder service) {
312             MessengerService.LocalBinder binder = (MessengerService.LocalBinder) service;
313             mMessengerService = binder.getService();
314             if (mMessengerService.isPlaying()) {
315                 updateViewForMessagePlaying();
316             } else {
317                 updateViewForMessageStopped();
318             }
319         }
320 
321         @Override
322         public void onServiceDisconnected(ComponentName arg0) {
323             mMessengerService = null;
324         }
325     };
326 }
327