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