1 /* 2 * Copyright (C) 2018 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.incallui; 18 19 import android.annotation.TargetApi; 20 import android.os.Handler; 21 import android.os.HandlerThread; 22 import android.os.Looper; 23 import android.telecom.Call.RttCall; 24 import com.android.dialer.common.LogUtil; 25 import com.android.dialer.common.concurrent.ThreadUtil; 26 import com.android.dialer.rtt.RttTranscript; 27 import com.android.incallui.InCallPresenter.InCallState; 28 import com.android.incallui.InCallPresenter.InCallStateListener; 29 import com.android.incallui.call.CallList; 30 import com.android.incallui.call.DialerCall; 31 import com.android.incallui.rtt.protocol.RttCallScreen; 32 import com.android.incallui.rtt.protocol.RttCallScreenDelegate; 33 import java.io.IOException; 34 35 /** 36 * Logic related to the {@link RttCallScreen} and for managing changes to the RTT calling surfaces 37 * based on other user interface events and incoming events. 38 */ 39 @TargetApi(28) 40 public class RttCallPresenter implements RttCallScreenDelegate, InCallStateListener { 41 42 private RttCallScreen rttCallScreen; 43 private RttCall rttCall; 44 private HandlerThread handlerThread; 45 private RemoteMessageHandler remoteMessageHandler; 46 47 @Override initRttCallScreenDelegate(RttCallScreen rttCallScreen)48 public void initRttCallScreenDelegate(RttCallScreen rttCallScreen) { 49 this.rttCallScreen = rttCallScreen; 50 } 51 52 @Override onLocalMessage(String message)53 public void onLocalMessage(String message) { 54 if (rttCall == null) { 55 LogUtil.w("RttCallPresenter.onLocalMessage", "Rtt Call is not started yet"); 56 return; 57 } 58 remoteMessageHandler.writeMessage(message); 59 } 60 61 @Override onRttCallScreenUiReady()62 public void onRttCallScreenUiReady() { 63 LogUtil.enterBlock("RttCallPresenter.onRttCallScreenUiReady"); 64 InCallPresenter.getInstance().addListener(this); 65 startListenOnRemoteMessage(); 66 DialerCall call = CallList.getInstance().getCallById(rttCallScreen.getCallId()); 67 if (call != null) { 68 rttCallScreen.onRestoreRttChat(call.getRttTranscript()); 69 } 70 } 71 72 @Override onSaveRttTranscript()73 public void onSaveRttTranscript() { 74 LogUtil.enterBlock("RttCallPresenter.onSaveRttTranscript"); 75 DialerCall call = CallList.getInstance().getCallById(rttCallScreen.getCallId()); 76 if (call != null) { 77 saveTranscript(call); 78 } 79 } 80 81 @Override onRttCallScreenUiUnready()82 public void onRttCallScreenUiUnready() { 83 LogUtil.enterBlock("RttCallPresenter.onRttCallScreenUiUnready"); 84 InCallPresenter.getInstance().removeListener(this); 85 stopListenOnRemoteMessage(); 86 onSaveRttTranscript(); 87 } 88 saveTranscript(DialerCall dialerCall)89 private void saveTranscript(DialerCall dialerCall) { 90 LogUtil.enterBlock("RttCallPresenter.saveTranscript"); 91 RttTranscript.Builder builder = RttTranscript.newBuilder(); 92 builder 93 94 .setId(String.valueOf(dialerCall.getCreationTimeMillis())) 95 96 .setTimestamp(dialerCall.getCreationTimeMillis()) 97 .setNumber(dialerCall.getNumber()) 98 .addAllMessages(rttCallScreen.getRttTranscriptMessageList()); 99 dialerCall.setRttTranscript(builder.build()); 100 } 101 102 @Override onStateChange(InCallState oldState, InCallState newState, CallList callList)103 public void onStateChange(InCallState oldState, InCallState newState, CallList callList) { 104 LogUtil.enterBlock("RttCallPresenter.onStateChange"); 105 if (newState == InCallState.INCALL) { 106 startListenOnRemoteMessage(); 107 } 108 } 109 startListenOnRemoteMessage()110 private void startListenOnRemoteMessage() { 111 DialerCall call = CallList.getInstance().getCallById(rttCallScreen.getCallId()); 112 if (call == null) { 113 LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "call does not exist"); 114 return; 115 } 116 rttCall = call.getRttCall(); 117 if (rttCall == null) { 118 LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "RTT Call is not started yet"); 119 return; 120 } 121 if (handlerThread != null && handlerThread.isAlive()) { 122 LogUtil.i("RttCallPresenter.startListenOnRemoteMessage", "already running"); 123 return; 124 } 125 handlerThread = new HandlerThread("RttCallRemoteMessageHandler"); 126 handlerThread.start(); 127 remoteMessageHandler = 128 new RemoteMessageHandler(handlerThread.getLooper(), rttCall, rttCallScreen); 129 remoteMessageHandler.start(); 130 } 131 stopListenOnRemoteMessage()132 private void stopListenOnRemoteMessage() { 133 if (handlerThread != null && handlerThread.isAlive()) { 134 handlerThread.quit(); 135 } 136 } 137 138 private static class RemoteMessageHandler extends Handler { 139 private static final int START = 1; 140 private static final int READ_MESSAGE = 2; 141 private static final int WRITE_MESSAGE = 3; 142 143 private final RttCall rttCall; 144 private final RttCallScreen rttCallScreen; 145 RemoteMessageHandler(Looper looper, RttCall rttCall, RttCallScreen rttCallScreen)146 RemoteMessageHandler(Looper looper, RttCall rttCall, RttCallScreen rttCallScreen) { 147 super(looper); 148 this.rttCall = rttCall; 149 this.rttCallScreen = rttCallScreen; 150 } 151 152 @Override handleMessage(android.os.Message msg)153 public void handleMessage(android.os.Message msg) { 154 switch (msg.what) { 155 case START: 156 sendEmptyMessage(READ_MESSAGE); 157 break; 158 case READ_MESSAGE: 159 try { 160 final String message = rttCall.readImmediately(); 161 if (message != null) { 162 ThreadUtil.postOnUiThread(() -> rttCallScreen.onRemoteMessage(message)); 163 } 164 } catch (IOException e) { 165 LogUtil.e("RttCallPresenter.RemoteMessageHandler.handleMessage", "read message", e); 166 } 167 sendEmptyMessageDelayed(READ_MESSAGE, 200); 168 break; 169 case WRITE_MESSAGE: 170 try { 171 rttCall.write((String) msg.obj); 172 } catch (IOException e) { 173 LogUtil.e("RttCallPresenter.RemoteMessageHandler.handleMessage", "write message", e); 174 } 175 break; 176 default: // fall out 177 } 178 } 179 start()180 void start() { 181 sendEmptyMessage(START); 182 } 183 writeMessage(String message)184 void writeMessage(String message) { 185 sendMessage(obtainMessage(WRITE_MESSAGE, message)); 186 } 187 } 188 } 189