Home | History | Annotate | Download | only in messenger
      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
     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 
     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 
    101     private String getEmojiByUnicode(int unicode){
    102         return new String(Character.toChars(unicode));
    103     }
    104 
    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      */
    119     private void sendReply(View view) {
    120         sendReply(((TextView) view).getText());
    121     }
    122 
    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 
    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 
    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
    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
    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
    218     protected void onNewIntent(Intent intent) {
    219         super.onNewIntent(intent);
    220         processIntent();
    221     }
    222 
    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
    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
    244     protected void onStop() {
    245         super.onStop();
    246         stopMessage();
    247         mTTSHelper.cleanup();
    248         mMessengerServiceBroadcastReceiver.cleanup();
    249         unbindService(mConnection);
    250     }
    251 
    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 
    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 
    266     private void updateViewForMessagePlaying() {
    267         mRightButton.setText(getString(R.string.action_stop));
    268         mRightButton.setOnClickListener(v -> stopMessage());
    269         mVoiceIcon.setVisibility(View.VISIBLE);
    270     }
    271 
    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;
    280         MessengerServiceBroadcastReceiver() {
    281             mIntentFilter = new IntentFilter();
    282             mIntentFilter.addAction(MapMessageMonitor.ACTION_MESSAGE_PLAY_START);
    283             mIntentFilter.addAction(MapMessageMonitor.ACTION_MESSAGE_PLAY_STOP);
    284         }
    285 
    286         void start() {
    287             registerReceiver(this, mIntentFilter);
    288         }
    289 
    290         void cleanup() {
    291             unregisterReceiver(this);
    292         }
    293 
    294         @Override
    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